From bbe28efdcf731dc6c9387b25f203af145e1f329f Mon Sep 17 00:00:00 2001
From: sgorbuno <se.gorbunov@gsi.de>
Date: Tue, 29 Sep 2020 11:51:54 +0000
Subject: [PATCH] qa task for MUCH transport level

---
 macro/run/CMakeLists.txt                     |  12 +-
 macro/run/run_qa.C                           | 245 +++++++---
 macro/run/run_qa_old.C                       | 121 +++++
 sim/detectors/much/CMakeLists.txt            |   6 +-
 sim/detectors/much/CbmMuchSimLinkDef.h       |   1 +
 sim/detectors/much/qa/CbmMuchTransportQa.cxx | 457 +++++++++++++++++++
 sim/detectors/much/qa/CbmMuchTransportQa.h   | 106 +++++
 7 files changed, 877 insertions(+), 71 deletions(-)
 create mode 100644 macro/run/run_qa_old.C
 create mode 100644 sim/detectors/much/qa/CbmMuchTransportQa.cxx
 create mode 100644 sim/detectors/much/qa/CbmMuchTransportQa.h

diff --git a/macro/run/CMakeLists.txt b/macro/run/CMakeLists.txt
index f917221899..eedd71c102 100644
--- a/macro/run/CMakeLists.txt
+++ b/macro/run/CMakeLists.txt
@@ -4,6 +4,7 @@ GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_digi.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_reco_event.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/check_overlaps.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_transport_qa.C)
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_qa.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_reco_tb_track.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_recoqa_tb_track.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_reco_analysis.C)
@@ -76,7 +77,16 @@ ForEach(setup IN LISTS cbm_setup)
   set_tests_properties(${testname} PROPERTIES FIXTURES_REQUIRED ${fixture_reco_event_mc})
   Set(fixture_digi_tb fixture_digi_tb_${testname})
   set_tests_properties(${testname} PROPERTIES FIXTURES_SETUP ${fixture_digi_tb})
-  
+
+  # --- Quality Assurance
+  Set(testname run_qa_event_mc_${setup})
+  Add_Test(${testname} ${CBMROOT_BINARY_DIR}/macro/run/run_qa.sh ${NumEvents} \"data/${setup}_test\" \"${setup}\")
+  Set_Tests_Properties(${testname} PROPERTIES TIMEOUT ${timeOutTime})
+  Set_Tests_Properties(${testname} PROPERTIES PASS_REGULAR_EXPRESSION "Test Passed;All ok")
+  Set_Tests_Properties(${testname} PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR")
+  Set_Tests_Properties(${testname} PROPERTIES FAIL_REGULAR_EXPRESSION "FATAL")
+  Set_Tests_properties(${testname} PROPERTIES FIXTURES_REQUIRED ${fixture_reco_event_mc})
+
 #  # --- Reconstruction Quality Assurance
 #  Set(testname run_reco_event_qa_${setup})
 #  Add_Test(${testname} ${CBMROOT_BINARY_DIR}/macro/run/run_reco_analysis.sh \"data/${setup}_test\" {{\"MvdCluster\",\"CbmMvdCluster\",\"MVD_Cluster_Finder\"},{\"MvdHit\",\"CbmMvdHit\",\"MVD_Hit_Finder\"},{\"StsCluster\",\"CbmStsCluster\",\"StsFindCluster\"},{\"StsHit\",\"CbmStsHit\",\"StsFindHit\"},{\"StsTrack\",\"CbmStsTrack\",\"StsFindTracksEvents\"}} {{\"sts\",{${pullDevAllowed},1,1,1}},{\"mvd\",{${pullDevAllowed},1,1,1}}} 2500 ${uploadHistJPG})
diff --git a/macro/run/run_qa.C b/macro/run/run_qa.C
index bafa1a89f0..c77ad24d82 100644
--- a/macro/run/run_qa.C
+++ b/macro/run/run_qa.C
@@ -1,47 +1,120 @@
 // --------------------------------------------------------------------------
 //
-// Macro for STS QA
+// Macro for simulation & reconstruction QA
 //
-// V. Friese   13/01/2006
+// The following naming conventions are assumed:
+// Raw data file:  [dataset].event.raw.root
+// Transport file: [dataset].tra.root
+// Parameter file:  [dataset].par.root
+// Reconstruction file: [dataset].rec.root
+//
+// S. Gorbunov 28/09/2020
 //
 // --------------------------------------------------------------------------
-void run_qa(Int_t nEvents = 1, const char* setupName = "sis100_electron") {
+
+// Includes needed for IDE
+#if !defined(__CLING__)
+#include <FairFileSource.h>
+#include <FairMonitor.h>
+#include <FairParAsciiFileIo.h>
+#include <FairParRootFileIo.h>
+#include <FairRootFileSink.h>
+#include <FairRunAna.h>
+#include <FairRuntimeDb.h>
+#include <FairSystemInfo.h>
+
+#include "CbmDefs.h"
+#include "CbmMCDataManager.h"
+#include "CbmMuchTransportQa.h"
+#include "CbmSetup.h"
+
+#include <TStopwatch.h>
+#endif
+
+void run_qa(Int_t nEvents   = 0,
+            TString dataset = "data/sis100_muon_jpsi_test",
+            TString setup   = "sis100_muon_jpsi") {
 
   // ========================================================================
   //          Adjust this part according to your requirements
 
-  // Verbosity level (0=quiet, 1=event level, 2=track level, 3=debug)
-  Int_t iVerbose = 1;
-
-  TString outDir = "data/";
-
-  // MC file
-  TString simFile =
-    outDir + setupName + "_test.mc.root";  // Input file (MC events)
+  // -----   Logger settings   ----------------------------------------------
 
-  // Reco file
-  TString recFile = outDir + setupName + "_test.eds.root";  // Output file
-
-  // Parameter file
-  TString parFile = outDir + setupName + "_params.root";  // Parameter file
+  FairLogger::GetLogger()->SetLogScreenLevel("INFO");
+  FairLogger::GetLogger()->SetLogVerbosityLevel("LOW");
+  // ------------------------------------------------------------------------
 
-  // Output file
-  TString outFile = outDir + setupName + "_test.qa.root";  // Output file
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_qa";  // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
 
-  TString srcDir   = gSystem->Getenv("VMCWORKDIR");
-  TString paramDir = srcDir + "/parameters/";
+  // -----   In- and output file names   ------------------------------------
+  TString rawFile  = dataset + ".event.raw.root";
+  TString traFile  = dataset + ".tra.root";
+  TString parFile  = dataset + ".par.root";
+  TString recFile  = dataset + ".rec.root";
+  TString sinkFile = dataset + ".qa.root";
 
+  // ------------------------------------------------------------------------
 
   // -----   Load the geometry setup   -------------------------------------
   std::cout << std::endl;
-  TString setupFile  = srcDir + "/geometry/setup/setup_" + setupName + ".C";
-  TString setupFunct = "setup_";
-  setupFunct         = setupFunct + setupName + "()";
-  std::cout << "-I- "
-            << "run_qa"
-            << ": Loading macro " << setupFile << std::endl;
-  gROOT->LoadMacro(setupFile);
-  gROOT->ProcessLine(setupFunct);
+  std::cout << "-I- " << myName << ": Loading setup " << setup << std::endl;
+  CbmSetup::Instance()->LoadSetup(setup);
+  // You can modify the pre-defined setup by using
+  // CbmSetup::Instance()->RemoveModule(ESystemId) or
+  // CbmSetup::Instance()->SetModule(ESystemId, const char*, Bool_t) or
+  // CbmSetup::Instance()->SetActive(ESystemId, Bool_t)
+  // See the class documentation of CbmSetup.
+  // ------------------------------------------------------------------------
+
+  // -----   Parameter files as input to the runtime database   -------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Defining parameter files " << std::endl;
+  TList* parFileList = new TList();
+  TString geoTag;
+
+  // - MUCH digitisation parameters
+  if (CbmSetup::Instance()->GetGeoTag(ECbmModuleId::kMuch, geoTag)) {
+    bool mcbmFlag   = geoTag.Contains("mcbm", TString::kIgnoreCase);
+    TString parFile = srcDir + "/parameters/much/much_";
+    parFile += (mcbmFlag) ? geoTag : geoTag(0, 4);
+    parFile += "_digi_sector.root";
+    {  // init geometry from the file
+      TFile* f            = new TFile(parFile, "R");
+      TObjArray* stations = (TObjArray*) f->Get("stations");
+      CbmMuchGeoScheme::Instance()->Init(stations, mcbmFlag);
+    }
+  }
+
+  // - TRD digitisation parameters
+  if (CbmSetup::Instance()->GetGeoTag(ECbmModuleId::kTrd, geoTag)) {
+    const Char_t* npar[4] = {"asic", "digi", "gas", "gain"};
+    TObjString* trdParFile(NULL);
+    for (Int_t i(0); i < 4; i++) {
+      trdParFile = new TObjString(srcDir + "/parameters/trd/trd_" + geoTag + "."
+                                  + npar[i] + ".par");
+      parFileList->Add(trdParFile);
+      std::cout << "-I- " << myName << ": Using parameter file "
+                << trdParFile->GetString() << std::endl;
+    }
+  }
+
+  // - TOF digitisation parameters
+  if (CbmSetup::Instance()->GetGeoTag(ECbmModuleId::kTof, geoTag)) {
+    TObjString* tofFile =
+      new TObjString(srcDir + "/parameters/tof/tof_" + geoTag + ".digi.par");
+    parFileList->Add(tofFile);
+    std::cout << "-I- " << myName << ": Using parameter file "
+              << tofFile->GetString() << std::endl;
+    TObjString* tofBdfFile =
+      new TObjString(srcDir + "/parameters/tof/tof_" + geoTag + ".digibdf.par");
+    parFileList->Add(tofBdfFile);
+    std::cout << "-I- " << myName << ": Using parameter file "
+              << tofBdfFile->GetString() << std::endl;
+  }
+  // ------------------------------------------------------------------------
 
   // In general, the following parts need not be touched
   // ========================================================================
@@ -51,71 +124,105 @@ void run_qa(Int_t nEvents = 1, const char* setupName = "sis100_electron") {
   timer.Start();
   // ------------------------------------------------------------------------
 
-  // -----  Analysis run   --------------------------------------------------
-  FairRunAna* fRun            = new FairRunAna();
-  FairFileSource* inputSource = new FairFileSource(recFile);
-  fRun->SetSource(inputSource);
-  //  fRun->SetInputFile(simFile);
-  //  fRun->AddFriend(recFile);
-  //  fRun->SetInputFile(recFile);
-  //  fRun->AddFriend(simFile);
-  fRun->SetOutputFile(outFile);
-  // Define output file for FairMonitor histograms
-  TString monitorFile {outFile};
+  // ----    Debug option   -------------------------------------------------
+  gDebug = 0;
+  // ------------------------------------------------------------------------
+
+  // -----   FairRunAna   ---------------------------------------------------
+  FairRunAna* run = new FairRunAna();
+
+  FairFileSource* inputSource = new FairFileSource(rawFile);
+  inputSource->AddFriend(traFile);
+  inputSource->AddFriend(recFile);
+  run->SetSource(inputSource);
+  run->SetGenerateRunInfo(kFALSE);
+
+  FairRootFileSink* sink = new FairRootFileSink(sinkFile);
+  run->SetSink(sink);
+
+  TString monitorFile {sinkFile};
   monitorFile.ReplaceAll("qa", "qa.monitor");
   FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monitorFile);
   // ------------------------------------------------------------------------
 
-
-  // -----  Parameter database   --------------------------------------------
-  FairRuntimeDb* rtdb       = fRun->GetRuntimeDb();
-  FairParRootFileIo* parIo1 = new FairParRootFileIo();
-  parIo1->open(parFile.Data(), "UPDATE");
-  rtdb->setFirstInput(parIo1);
+  // -----   MCDataManager (legacy mode)  -----------------------------------
+  CbmMCDataManager* mcManager = new CbmMCDataManager("MCDataManager", 1);
+  mcManager->AddFile(traFile);
+  run->AddTask(mcManager);
   // ------------------------------------------------------------------------
 
 
-  // -----   Intialise and run   --------------------------------------------
-  fRun->Init();
+  // ----- MUCH hit finder QA  ---------------------------------
 
-  rtdb->setOutput(parIo1);
-  rtdb->saveOutput();
-  rtdb->print();
+  if (CbmSetup::Instance()->IsActive(ECbmModuleId::kMuch)) {
+    run->AddTask(new CbmMuchTransportQa());
+  }
 
-  cout << "Starting run" << endl;
-  fRun->Run(0, nEvents);
   // ------------------------------------------------------------------------
 
+  // -----  Parameter database   --------------------------------------------
+  {
+    std::cout << std::endl << std::endl;
+    std::cout << "-I- " << myName << ": Set runtime DB" << std::endl;
+    FairRuntimeDb* rtdb       = run->GetRuntimeDb();
+    FairParRootFileIo* parIo1 = new FairParRootFileIo();
+    parIo1->open(parFile.Data(), "in");
+    rtdb->setFirstInput(parIo1);
+    if (!parFileList->IsEmpty()) {
+      FairParAsciiFileIo* parIo2 = new FairParAsciiFileIo();
+      parIo2->open(parFileList, "in");
+      rtdb->setSecondInput(parIo2);
+    }
+    rtdb->print();
+  }
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  run->Run(0, nEvents);
+  // ------------------------------------------------------------------------
+
+  //std::cout<< "Test failed" << std::endl;
 
   // -----   Finish   -------------------------------------------------------
   timer.Stop();
+
+  FairMonitor::GetMonitor()->Print();
   Double_t rtime = timer.RealTime();
   Double_t ctime = timer.CpuTime();
-  cout << endl << endl;
-  cout << "Macro finished succesfully." << endl;
-  cout << "Output file is " << outFile << endl;
-  cout << "Parameter file is " << parFile << endl;
-  cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl;
-  cout << endl;
+  std::cout << std::endl << std::endl;
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "Output file is " << sinkFile << std::endl;
+  std::cout << "Parameter file is " << parFile << std::endl;
+  std::cout << "Real time " << rtime << " s, CPU time " << ctime << " s"
+            << std::endl;
+  std::cout << std::endl;
+  std::cout << " Test passed" << std::endl;
+  std::cout << " All ok " << std::endl;
   // ------------------------------------------------------------------------
 
+
+  // -----   Resource monitoring   ------------------------------------------
   // Extract the maximal used memory an add is as Dart measurement
   // This line is filtered by CTest and the value send to CDash
   FairSystemInfo sysInfo;
   Float_t maxMemory = sysInfo.GetMaxMemory();
-  cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
-  cout << maxMemory;
-  cout << "</DartMeasurement>" << endl;
+  std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  std::cout << maxMemory;
+  std::cout << "</DartMeasurement>" << std::endl;
 
   Float_t cpuUsage = ctime / rtime;
-  cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
-  cout << cpuUsage;
-  cout << "</DartMeasurement>" << endl;
-
-  FairMonitor* tempMon = FairMonitor::GetMonitor();
-  tempMon->Print();
+  std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  std::cout << cpuUsage;
+  std::cout << "</DartMeasurement>" << std::endl;
+  // ------------------------------------------------------------------------
 
+  // -----   Function needed for CTest runtime dependency   -----------------
   RemoveGeoManager();
-  cout << " Test passed" << endl;
-  cout << " All ok " << endl;
+  // ------------------------------------------------------------------------
 }
diff --git a/macro/run/run_qa_old.C b/macro/run/run_qa_old.C
new file mode 100644
index 0000000000..51202c3919
--- /dev/null
+++ b/macro/run/run_qa_old.C
@@ -0,0 +1,121 @@
+// --------------------------------------------------------------------------
+//
+// Macro for STS QA
+//
+// V. Friese   13/01/2006
+//
+// --------------------------------------------------------------------------
+void run_qa_old(Int_t nEvents = 1, const char* setupName = "sis100_electron") {
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // Verbosity level (0=quiet, 1=event level, 2=track level, 3=debug)
+  Int_t iVerbose = 1;
+
+  TString outDir = "data/";
+
+  // MC file
+  TString simFile =
+    outDir + setupName + "_test.mc.root";  // Input file (MC events)
+
+  // Reco file
+  TString recFile = outDir + setupName + "_test.eds.root";  // Output file
+
+  // Parameter file
+  TString parFile = outDir + setupName + "_params.root";  // Parameter file
+
+  // Output file
+  TString outFile = outDir + setupName + "_test.qa.root";  // Output file
+
+  TString srcDir   = gSystem->Getenv("VMCWORKDIR");
+  TString paramDir = srcDir + "/parameters/";
+
+
+  // -----   Load the geometry setup   -------------------------------------
+  std::cout << std::endl;
+  TString setupFile  = srcDir + "/geometry/setup/setup_" + setupName + ".C";
+  TString setupFunct = "setup_";
+  setupFunct         = setupFunct + setupName + "()";
+  std::cout << "-I- "
+            << "run_qa"
+            << ": Loading macro " << setupFile << std::endl;
+  gROOT->LoadMacro(setupFile);
+  gROOT->ProcessLine(setupFunct);
+
+  // In general, the following parts need not be touched
+  // ========================================================================
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+  // -----  Analysis run   --------------------------------------------------
+  FairRunAna* fRun            = new FairRunAna();
+  FairFileSource* inputSource = new FairFileSource(recFile);
+  fRun->SetSource(inputSource);
+  //  fRun->SetInputFile(simFile);
+  //  fRun->AddFriend(recFile);
+  //  fRun->SetInputFile(recFile);
+  //  fRun->AddFriend(simFile);
+  fRun->SetOutputFile(outFile);
+  // Define output file for FairMonitor histograms
+  TString monitorFile {outFile};
+  monitorFile.ReplaceAll("qa", "qa.monitor");
+  FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monitorFile);
+  // ------------------------------------------------------------------------
+
+
+  // -----  Parameter database   --------------------------------------------
+  FairRuntimeDb* rtdb       = fRun->GetRuntimeDb();
+  FairParRootFileIo* parIo1 = new FairParRootFileIo();
+  parIo1->open(parFile.Data(), "UPDATE");
+  rtdb->setFirstInput(parIo1);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Intialise and run   --------------------------------------------
+  fRun->Init();
+
+  rtdb->setOutput(parIo1);
+  rtdb->saveOutput();
+  rtdb->print();
+
+  cout << "Starting run" << endl;
+  fRun->Run(0, nEvents);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  cout << endl << endl;
+  cout << "Macro finished succesfully." << endl;
+  cout << "Output file is " << outFile << endl;
+  cout << "Parameter file is " << parFile << endl;
+  cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl;
+  cout << endl;
+  // ------------------------------------------------------------------------
+
+  // Extract the maximal used memory an add is as Dart measurement
+  // This line is filtered by CTest and the value send to CDash
+  FairSystemInfo sysInfo;
+  Float_t maxMemory = sysInfo.GetMaxMemory();
+  cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  cout << maxMemory;
+  cout << "</DartMeasurement>" << endl;
+
+  Float_t cpuUsage = ctime / rtime;
+  cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  cout << cpuUsage;
+  cout << "</DartMeasurement>" << endl;
+
+  FairMonitor* tempMon = FairMonitor::GetMonitor();
+  tempMon->Print();
+
+  RemoveGeoManager();
+  cout << " Test passed" << endl;
+  cout << " All ok " << endl;
+}
diff --git a/sim/detectors/much/CMakeLists.txt b/sim/detectors/much/CMakeLists.txt
index ad082df4cd..3b2bb90cea 100644
--- a/sim/detectors/much/CMakeLists.txt
+++ b/sim/detectors/much/CMakeLists.txt
@@ -1,6 +1,7 @@
 
 Set(INCLUDE_DIRECTORIES
 ${CMAKE_CURRENT_SOURCE_DIR}
+${CMAKE_CURRENT_SOURCE_DIR}/qa
 
 ${CBMDETECTORBASE_DIR}/much
 
@@ -8,6 +9,7 @@ ${CBMBASE_DIR}
 ${CBMBASE_DIR}/utils
 
 ${CBMROOT_SOURCE_DIR}/sim/transport/base
+${CBMROOT_SOURCE_DIR}/core/qa
 
 ${CBMDATA_DIR} 
 ${CBMDATA_DIR}/much 
@@ -36,12 +38,14 @@ CbmMuch.cxx
 CbmMuchDigitizeGem.cxx
 CbmMuchReadoutBuffer.cxx
 CbmMuchSignal.cxx
+
+qa/CbmMuchTransportQa.cxx
 )
 
 set(LINKDEF CbmMuchSimLinkDef.h)
 Set(LIBRARY_NAME CbmMuchSim)
 Set(DEPENDENCIES
-    CbmMuchBase CbmBase CbmData Base 
+    CbmMuchBase CbmBase CbmData Base CbmQaBase
 )
 
 GENERATE_LIBRARY()
diff --git a/sim/detectors/much/CbmMuchSimLinkDef.h b/sim/detectors/much/CbmMuchSimLinkDef.h
index d46400411f..f2b5951cf5 100644
--- a/sim/detectors/much/CbmMuchSimLinkDef.h
+++ b/sim/detectors/much/CbmMuchSimLinkDef.h
@@ -12,5 +12,6 @@
 #pragma link C++ class CbmMuchDigitizeGem + ;
 #pragma link C++ class CbmMuchReadoutBuffer + ;
 #pragma link C++ class CbmMuchSignal + ;
+#pragma link C++ class CbmMuchTransportQa + ;
 
 #endif
diff --git a/sim/detectors/much/qa/CbmMuchTransportQa.cxx b/sim/detectors/much/qa/CbmMuchTransportQa.cxx
new file mode 100644
index 0000000000..0892cee664
--- /dev/null
+++ b/sim/detectors/much/qa/CbmMuchTransportQa.cxx
@@ -0,0 +1,457 @@
+/// \file   CbmMuchTransportQa.cxx
+/// \brief  Implementation of the CbmMuchTransportQa class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \author Eugeny Kryshen
+/// \author Vikas Singhal
+/// \author Ekata Nandy
+/// \date   25.09.2020
+
+#include "CbmMuchTransportQa.h"
+
+#include "FairLogger.h"
+#include "FairRootFileSink.h"
+#include "FairRootManager.h"
+#include "FairRun.h"
+#include "FairRuntimeDb.h"
+
+#include "CbmGeoMuchPar.h"
+#include "CbmMuchGeoScheme.h"
+#include "CbmMuchStation.h"
+
+#include "CbmMuchPoint.h"
+
+#include "CbmMCTrack.h"
+#include "TDatabasePDG.h"
+#include "TParticlePDG.h"
+
+
+#include "TString.h"
+
+#include "TClonesArray.h"
+
+#include "CbmQaCanvas.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TStyle.h"
+
+#include <cassert>
+#include <vector>
+
+ClassImp(CbmMuchTransportQa);
+
+// -------------------------------------------------------------------------
+CbmMuchTransportQa::CbmMuchTransportQa(const char* name, Int_t verbose)
+  : FairTask(name, verbose)
+  , fOutFolder("MuchTransportQA", "Much Transport QA")
+  , fhNevents("nEvents", 0)
+  , fvUsNtra()
+  , fvMcPointXY()
+  , fvMcPointPhiZ()
+  , fvMcPointRZ()
+  , fvFraction() {}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+CbmMuchTransportQa::~CbmMuchTransportQa() { DeInit(); }
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+void CbmMuchTransportQa::DeInit() {
+
+  fPoints   = nullptr;
+  fMcTracks = nullptr;
+
+  fOutFolder.Clear();
+  fhNevents.SetVal(0);
+
+  SafeDelete(fhUsNtraAll);
+  SafeDelete(fhUsNtraPrim);
+  SafeDelete(fhUsNtraSec);
+  SafeDelete(fhUsNtraPr);
+  SafeDelete(fhUsNtraPi);
+  SafeDelete(fhUsNtraEl);
+  SafeDelete(fhUsNtraMu);
+  SafeDelete(fhUsNtraKa);
+
+  for (uint i = 0; i < fvMcPointXY.size(); i++) {
+    SafeDelete(fvMcPointXY[i]);
+  }
+  fvMcPointXY.clear();
+  for (uint i = 0; i < fvMcPointPhiZ.size(); i++) {
+    SafeDelete(fvMcPointPhiZ[i]);
+  }
+  fvMcPointPhiZ.clear();
+  for (uint i = 0; i < fvMcPointRZ.size(); i++) {
+    SafeDelete(fvMcPointRZ[i]);
+  }
+  fvMcPointRZ.clear();
+
+  SafeDelete(fhNtracks);
+  SafeDelete(fhFractionPrim);
+  SafeDelete(fhFractionSec);
+  SafeDelete(fhFractionPr);
+  SafeDelete(fhFractionPi);
+  SafeDelete(fhFractionEl);
+  SafeDelete(fhFractionMu);
+  SafeDelete(fhFractionKa);
+
+  fvUsNtra.clear();
+  fvFraction.clear();
+
+  SafeDelete(fCanvStationXY);
+  SafeDelete(fCanvStationPhiZ);
+  SafeDelete(fCanvStationRZ);
+
+  fNstations = 0;
+  fOutFolder.Clear();
+}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+InitStatus CbmMuchTransportQa::Init() {
+
+  TDirectory* oldDirectory = gDirectory;
+
+  FairRootManager* manager = FairRootManager::Instance();
+  if (!manager) {
+    LOG(error) << "No FairRootManager found";
+    return kERROR;
+  }
+
+  fMcTracks = (TClonesArray*) manager->GetObject("MCTrack");
+  if (!fMcTracks) {
+    LOG(error) << "No MC tracks found";
+    return kERROR;
+  }
+
+  fPoints = (TClonesArray*) manager->GetObject("MuchPoint");
+  if (!fPoints) {
+    LOG(error) << "No MC points found";
+    return kERROR;
+  }
+
+  if (!CbmMuchGeoScheme::Instance()) {
+    LOG(fatal) << "No CbmMuchGeoScheme found";
+    return kFATAL;
+  }
+
+  fNstations = CbmMuchGeoScheme::Instance()->GetNStations();
+
+  if (fNstations == 0) {
+    LOG(error) << "CbmMuchGeoScheme is not initialized";
+    return kERROR;
+  }
+
+  TFolder* histFolder = fOutFolder.AddFolder("hist", "Histogramms");
+
+  fhNevents.SetVal(0);
+  histFolder->Add(&fhNevents);
+
+#define BINS_STA fNstations, 0, fNstations
+
+  {
+    fvUsNtra.clear();
+    std::vector<TH1F*>& v = fvUsNtra;
+    v.push_back(fhUsNtraAll = new TH1F("hUsNtraAll", "N tracks", BINS_STA));
+    v.push_back(fhUsNtraPrim =
+                  new TH1F("hUsNtraPrim", "N primary tracks", BINS_STA));
+    v.push_back(fhUsNtraSec =
+                  new TH1F("hUsNtraSec", "N secondary tracks", BINS_STA));
+    v.push_back(fhUsNtraPr = new TH1F("hUsNtraPr", "N protons", BINS_STA));
+    v.push_back(fhUsNtraPi = new TH1F("hUsNtraPi", "N pions", BINS_STA));
+    v.push_back(fhUsNtraEl = new TH1F("hUsNtraEl", "N electrons", BINS_STA));
+    v.push_back(fhUsNtraMu = new TH1F("hUsNtraMu", "N muons", BINS_STA));
+    v.push_back(fhUsNtraKa = new TH1F("hUsNtraKa", "N kaons", BINS_STA));
+    for (uint i = 0; i < fvUsNtra.size(); i++) {
+      TH1F* h = fvUsNtra[i];
+      h->SetStats(0);
+      h->GetXaxis()->SetTitle("Station");
+      histFolder->Add(h);
+    }
+  }
+
+  {
+    fvFraction.clear();
+    std::vector<TH1F*>& v = fvFraction;
+    v.push_back(fhNtracks =
+                  new TH1F("hNtracks", "N tracks per event", BINS_STA));
+    v.push_back(fhFractionPrim = new TH1F(
+                  "hFractionPrim", "Fraction of primary tracks", BINS_STA));
+    v.push_back(fhFractionSec = new TH1F(
+                  "hFractionSec", "Fraction of secondary tracks", BINS_STA));
+    v.push_back(fhFractionPr =
+                  new TH1F("hFractionPr", "Fraction of protons", BINS_STA));
+    v.push_back(fhFractionPi =
+                  new TH1F("hFractionPi", "Fraction of pions", BINS_STA));
+    v.push_back(fhFractionEl =
+                  new TH1F("hFractionEl", "Fraction of electrons", BINS_STA));
+    v.push_back(fhFractionMu =
+                  new TH1F("hFractionMu", "Fraction of muons", BINS_STA));
+    v.push_back(fhFractionKa =
+                  new TH1F("hFractionKa", "Fraction of kaons", BINS_STA));
+
+    for (uint i = 0; i < fvFraction.size(); i++) {
+      TH1F* h = fvFraction[i];
+      h->SetStats(0);
+      h->GetXaxis()->SetTitle("Station");
+      h->GetYaxis()->SetTitle("%");
+      histFolder->Add(h);
+    }
+  }
+
+  fvMcPointXY.resize(fNstations);
+  fvMcPointPhiZ.resize(fNstations);
+  fvMcPointRZ.resize(fNstations);
+
+  for (Int_t i = 0; i < fNstations; i++) {
+    CbmMuchStation* station = CbmMuchGeoScheme::Instance()->GetStation(i);
+    if (!station) {
+      LOG(fatal) << "Much station " << i << " doesn't exist";
+      return kFATAL;
+    }
+    Double_t rMax = station->GetRmax();
+    Double_t rMin = station->GetRmin();
+
+    fvMcPointXY[i] = new TH2F(Form("hMcPointXY%i", i + 1),
+                              Form("MC point XY : Station %i; X; Y", i + 1),
+                              100,
+                              -1.2 * rMax,
+                              1.2 * rMax,
+                              100,
+                              -1.2 * rMax,
+                              1.2 * rMax);
+    histFolder->Add(fvMcPointXY[i]);
+
+    fvMcPointPhiZ[i] =
+      new TH2F(Form("hMcPointPhiZ%i", i + 1),
+               Form("MC point Phi vs Z : Station %i; Z; Phi", i + 1),
+               100,
+               station->GetZ() - station->GetTubeDz() - 5.,
+               station->GetZ() + station->GetTubeDz() + 5.,
+               100,
+               -200.,
+               200.);
+    histFolder->Add(fvMcPointPhiZ[i]);
+
+    float dR       = rMax - rMin;
+    fvMcPointRZ[i] = new TH2F(Form("hMcPointRZ%i", i + 1),
+                              Form("MC point R vs Z : Station %i; Z; R", i + 1),
+                              100,
+                              station->GetZ() - station->GetTubeDz() - 5.,
+                              station->GetZ() + station->GetTubeDz() + 5.,
+                              100,
+                              rMin - 0.1 * dR,
+                              rMax + 0.1 * dR);
+    histFolder->Add(fvMcPointRZ[i]);
+  }
+
+  fCanvStationXY =
+    new CbmQaCanvas("cMcPointXY", "Much: MC point XY", 2 * 400, 2 * 400);
+  fCanvStationXY->Divide2D(fNstations);
+  fOutFolder.Add(fCanvStationXY);
+
+  fCanvStationPhiZ = new CbmQaCanvas(
+    "cMcPointPhiZ", "Much: MC point Phi vs Z", 2 * 800, 2 * 400);
+  fCanvStationPhiZ->Divide2D(fNstations);
+  fOutFolder.Add(fCanvStationPhiZ);
+
+  fCanvStationRZ =
+    new CbmQaCanvas("cMcPointRZ", "Much: MC point R vs Z", 2 * 800, 2 * 400);
+  fCanvStationRZ->Divide2D(fNstations);
+  fOutFolder.Add(fCanvStationRZ);
+
+  gDirectory = oldDirectory;
+
+  return kSUCCESS;
+}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+InitStatus CbmMuchTransportQa::ReInit() {
+  DeInit();
+  return Init();
+}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+void CbmMuchTransportQa::SetParContainers() {
+  // Get run and runtime database
+
+  // The code currently does not work,
+  // CbmMuchGeoScheme::Instance() must be initialised outside.
+  // - Sergey
+
+  // FairRuntimeDb* db = FairRuntimeDb::instance();
+  // if ( ! db ) Fatal("SetParContainers", "No runtime database");
+  // Get MUCH geometry parameter container
+  // CbmGeoMuchPar *fGeoPar = (CbmGeoMuchPar*)
+  // db->getContainer("CbmGeoMuchPar");  TObjArray *stations =
+  // fGeoPar->GetStations();
+  //  TString geoTag;
+  // CbmSetup::Instance()->GetGeoTag(ECbmModuleId::kMuch, geoTag);
+  // bool mcbmFlag = geoTag.Contains("mcbm", TString::kIgnoreCase);
+  // CbmMuchGeoScheme::Instance()->Init(stations, mcbmFlag);
+}
+// -------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------
+void CbmMuchTransportQa::Exec(Option_t*) {
+
+  LOG(info) << "Event: " << fhNevents.GetVal();
+
+  fhNevents.SetVal(fhNevents.GetVal() + 1);
+
+  // bitmask tells which stations were crossed by mc track
+  std::vector<UInt_t> trackStaCross(fMcTracks->GetEntriesFast(), 0);
+
+  for (Int_t i = 0; i < fPoints->GetEntriesFast(); i++) {
+
+    CbmMuchPoint* point = (CbmMuchPoint*) fPoints->At(i);
+
+    if (!point) {
+      LOG(fatal) << "Much point " << i << " doesn't exist";
+      break;
+    }
+
+    Int_t stId    = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
+    UInt_t stMask = (1 << stId);
+
+    // Check if the point corresponds to a certain  MC Track
+    Int_t trackId = point->GetTrackID();
+    if (trackId < 0 || trackId >= fMcTracks->GetEntriesFast()) {
+      LOG(fatal) << "Much point " << i << ": trackId " << trackId
+                 << " doesn't belong to [0," << fMcTracks->GetEntriesFast() - 1
+                 << "]";
+      break;
+    }
+
+    CbmMCTrack* mcTrack = (CbmMCTrack*) fMcTracks->At(trackId);
+    if (!mcTrack) {
+      LOG(fatal) << "MC track " << trackId << " doesn't exist";
+      break;
+    }
+
+    Int_t motherId = mcTrack->GetMotherId();
+
+    // Get mass
+    Int_t pdgCode = mcTrack->GetPdgCode();
+
+    //if (pdgCode == 0) continue;
+
+    TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(pdgCode);
+    if (!particle) {
+      LOG(warning) << "Particle with pdg code " << pdgCode << " doesn't exist";
+      //continue;
+    }
+    if (pdgCode == 0 || pdgCode == 22 ||  // photons
+        pdgCode == 2112)                  // neutrons
+    {
+      LOG(warning) << "Particle with pdg code " << pdgCode
+                   << " left an mc point";
+      //continue;
+    }
+
+    if (!(trackStaCross[trackId] & stMask)) {
+      fhUsNtraAll->Fill(stId);
+      if (motherId == -1) {
+        fhUsNtraPrim->Fill(stId);
+      } else {
+        fhUsNtraSec->Fill(stId);
+      }
+      switch (abs(pdgCode)) {
+        case 2212:  // proton
+          fhUsNtraPr->Fill(stId);
+          break;
+        case 211:  // pion
+          fhUsNtraPi->Fill(stId);
+          break;
+        case 11:  // electron
+          fhUsNtraEl->Fill(stId);
+          break;
+        case 13:  // muon
+          fhUsNtraMu->Fill(stId);
+          break;
+        case 321:  // kaon
+          fhUsNtraKa->Fill(stId);
+          break;
+      }
+    }
+
+    trackStaCross[trackId] |= stMask;
+
+    TVector3 v1;  // in  position of the track
+    TVector3 v2;  // out position of the track
+
+    point->PositionIn(v1);
+    point->PositionOut(v2);
+
+    fvMcPointXY[stId]->Fill(v1.X(), v1.Y());
+    fvMcPointXY[stId]->Fill(v2.X(), v2.Y());
+
+    fvMcPointPhiZ[stId]->Fill(v1.Z(), v1.Phi() * TMath::RadToDeg());
+    fvMcPointPhiZ[stId]->Fill(v2.Z(), v2.Phi() * TMath::RadToDeg());
+
+    fvMcPointRZ[stId]->Fill(v1.Z(), v1.Perp());
+    fvMcPointRZ[stId]->Fill(v2.Z(), v2.Perp());
+  }
+}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+TFolder& CbmMuchTransportQa::GetQa() {
+
+  TDirectory* oldDirectory = gDirectory;
+
+  fhNtracks->Reset();
+  fhNtracks->Add(fhUsNtraAll, 1. / fhNevents.GetVal());
+
+  {
+    std::vector<Double_t> errors(fNstations, 0.);
+    fhUsNtraAll->SetError(errors.data());
+  }
+
+  for (uint i = 1; i < fvFraction.size(); i++) {
+    fvFraction[i]->Divide(fvUsNtra[i], fhUsNtraAll);
+    fvFraction[i]->Scale(100.);
+  }
+
+  for (Int_t i = 0; i < fNstations; i++) {
+
+    fCanvStationXY->cd(i + 1);
+    gStyle->SetOptStat(0);
+    fvMcPointXY[i]->DrawCopy("colz", "");
+
+    fCanvStationPhiZ->cd(i + 1);
+    gStyle->SetOptStat(0);
+    fvMcPointPhiZ[i]->DrawCopy("colz", "");
+
+    fCanvStationRZ->cd(i + 1);
+    gStyle->SetOptStat(0);
+    fvMcPointRZ[i]->DrawCopy("colz", "");
+
+    gStyle->SetOptStat(1110);
+  }
+
+  gDirectory = oldDirectory;
+  return fOutFolder;
+}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+void CbmMuchTransportQa::Finish() {
+
+  if (!FairRootManager::Instance() || !FairRootManager::Instance()->GetSink()) {
+    LOG(error) << "No sink found";
+    return;
+  }
+  FairSink* sink = FairRootManager::Instance()->GetSink();
+  sink->WriteObject(&GetQa(), nullptr);
+}
+// -------------------------------------------------------------------------
diff --git a/sim/detectors/much/qa/CbmMuchTransportQa.h b/sim/detectors/much/qa/CbmMuchTransportQa.h
new file mode 100644
index 0000000000..b6c113ffe9
--- /dev/null
+++ b/sim/detectors/much/qa/CbmMuchTransportQa.h
@@ -0,0 +1,106 @@
+/// \file   CbmMuchTransportQa.h
+/// \brief  Definition of the CbmMuchTransportQa class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \author Eugeny Kryshen
+/// \author Vikas Singhal
+/// \author Ekata Nandy
+/// \date   25.09.2020
+
+#ifndef CbmMuchTransportQa_H
+#define CbmMuchTransportQa_H
+
+#include "FairTask.h"
+#include "TFolder.h"
+#include "TParameter.h"
+
+class CbmMuchGeoScheme;
+class TClonesArray;
+class TH1F;
+class TH2F;
+class CbmQaCanvas;
+
+/// QA for the MUCH detector after a "transport" step of the simulation.
+///
+/// The class reimplements corresponding QA checks from old CbmMuchHitFinderQa class
+/// made by E. Kryshen & V. Singhal & E. Nandy
+///
+class CbmMuchTransportQa : public FairTask {
+
+public:
+  /// Constructor
+  CbmMuchTransportQa(const char* name = "MuchHitFinderQa", Int_t verbose = 1);
+
+  /// Deactivated copy constructors
+  CbmMuchTransportQa(const CbmMuchTransportQa&) = delete;
+  CbmMuchTransportQa& operator=(const CbmMuchTransportQa&) = delete;
+
+  /// Destructor
+  virtual ~CbmMuchTransportQa();
+
+  /// FairTask methods
+  void SetParContainers();
+  InitStatus Init();
+  InitStatus ReInit();
+  void Exec(Option_t* option);
+  void Finish();
+
+  /// Prepare Qa output and return it as a reference to an internal folder.
+  /// The reference is non-const, because FairSink can not write const objects
+  TFolder& GetQa();
+
+private:
+  /// Reset varibles & deallocate memory.
+  /// When not called by destructor, need to be folloed by Init().
+  void DeInit();
+
+  /// geometry
+  Int_t fNstations = 0;
+
+  /// containers
+  TClonesArray* fPoints   = nullptr;
+  TClonesArray* fMcTracks = nullptr;
+  ///
+
+  TFolder fOutFolder;         /// output folder with histos and canvases
+  TParameter<int> fhNevents;  /// number of processed events
+
+  /// internal unscaled histogramms
+
+  TH1F* fhUsNtraAll  = nullptr;  /// number of all tracks
+  TH1F* fhUsNtraPrim = nullptr;  /// number of primary tracks
+  TH1F* fhUsNtraSec  = nullptr;  /// number of secondary tracks
+  TH1F* fhUsNtraPr   = nullptr;  /// number of protons
+  TH1F* fhUsNtraPi   = nullptr;  /// number of pions
+  TH1F* fhUsNtraEl   = nullptr;  /// number of electrons
+  TH1F* fhUsNtraMu   = nullptr;  /// number of muons
+  TH1F* fhUsNtraKa   = nullptr;  /// number of kaons
+
+  std::vector<TH1F*> fvUsNtra;  /// pointers to the above fhUsNtra* histos
+
+  /// output histograms
+
+  std::vector<TH2F*> fvMcPointXY;    /// MC point Y vs X [N stations]
+  std::vector<TH2F*> fvMcPointPhiZ;  /// MC point Phi vs Z [N stations]
+  std::vector<TH2F*> fvMcPointRZ;    /// MC point R vs Z [N stations]
+
+  TH1F* fhNtracks      = nullptr;  /// number of all tracks / event
+  TH1F* fhFractionPrim = nullptr;  /// fraction of primary tracks
+  TH1F* fhFractionSec  = nullptr;  /// fraction of secondary tracks
+  TH1F* fhFractionPr   = nullptr;  /// fraction of protons
+  TH1F* fhFractionPi   = nullptr;  /// fraction of pions
+  TH1F* fhFractionEl   = nullptr;  /// fraction of electrons
+  TH1F* fhFractionMu   = nullptr;  /// fraction of muons
+  TH1F* fhFractionKa   = nullptr;  /// fraction of kaons
+
+  std::vector<TH1F*> fvFraction;  /// pointers to the above histos
+
+  // output canvaces with histogramm collections
+
+  CbmQaCanvas* fCanvStationXY   = nullptr;
+  CbmQaCanvas* fCanvStationPhiZ = nullptr;
+  CbmQaCanvas* fCanvStationRZ   = nullptr;
+
+  ClassDef(CbmMuchTransportQa, 0)
+};
+
+#endif
-- 
GitLab