From a17cc8cbf8cba24a1f10c8971558452ef9277ac1 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Fri, 28 Jul 2023 18:14:05 +0200
Subject: [PATCH] QA: Added posibility of configuring histogram binning in
 CbmQaTask; Clean-up of CbmCaInputQaTrd

---
 core/qa/CbmQaIO.cxx                          |  20 ++
 core/qa/CbmQaIO.h                            | 163 ++++++++-
 core/qa/CbmQaTask.cxx                        |  17 -
 core/qa/CbmQaTask.h                          |  13 +-
 macro/L1/configs/CMakeLists.txt              |   1 -
 macro/L1/configs/config_ideal_hits_mcbm.yaml |   2 +-
 macro/mcbm/mcbm_qa.C                         |   5 +-
 macro/qa/CMakeLists.txt                      |   8 +-
 macro/qa/objects.yaml                        |  16 -
 macro/qa/qa_compare.C                        |   2 +-
 reco/L1/qa/CbmCaInputQaTrd.cxx               | 339 ++++++-------------
 reco/L1/qa/CbmCaInputQaTrd.h                 |  41 ++-
 12 files changed, 312 insertions(+), 315 deletions(-)
 delete mode 100644 macro/qa/objects.yaml

diff --git a/core/qa/CbmQaIO.cxx b/core/qa/CbmQaIO.cxx
index 56873a5d53..00f9ce99ce 100644
--- a/core/qa/CbmQaIO.cxx
+++ b/core/qa/CbmQaIO.cxx
@@ -27,6 +27,26 @@ CbmQaIO::~CbmQaIO() {}
 //
 void CbmQaIO::SetHistoProperties(TH1* pHist) { pHist->SetStats(true); }
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmQaIO::SetConfigName(const char* path)
+{
+  fsConfigName = path;
+  try {
+    fConfigNode = YAML::LoadFile(path)["qa"][fsPrefix.Data()];
+  }
+  catch (const YAML::BadFile& exc) {
+    std::stringstream msg;
+    msg << "configuration file for QA \"" << path << "\" does not exist";
+    throw std::runtime_error(msg.str());
+  }
+  catch (const YAML::ParserException& exc) {
+    std::stringstream msg;
+    msg << "configuration file for QA \"" << path << "\" is improperly formatted";
+    throw std::runtime_error(msg.str());
+  }
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void CbmQaIO::WriteToFile(TFile* pOutFile) const
diff --git a/core/qa/CbmQaIO.h b/core/qa/CbmQaIO.h
index 199e7603f9..a1003ea50f 100644
--- a/core/qa/CbmQaIO.h
+++ b/core/qa/CbmQaIO.h
@@ -29,8 +29,11 @@
 #include "TROOT.h"
 #include "TString.h"
 
+#include <limits>
+#include <type_traits>
 #include <vector>
 
+#include <yaml-cpp/yaml.h>
 
 class TFile;
 
@@ -79,6 +82,8 @@ public:
   /// @param args... Arguments passed to the object constructor
   template<typename T, typename... Args>
   T* MakeQaObject(TString name, Args... args);
+  /// @brief Gets config name
+  const char* GetConfigName() const { return fsConfigName.Data(); }
 
   /// @brief Creates, initializes and registers a canvas
   /// @tparam  T     Type of the canvas: TCanvas or CbmQaCanvas (\note T should not be a pointer)
@@ -101,14 +106,43 @@ public:
   template<typename T, typename... Args>
   T* MakeHisto(TString name, Args... args);
 
+  /// @brief Creates histogram, using properties defined with a tag in config
+  /// @param nameBase  Name of the histogram
+  /// @param args      The rest of the arguments, which will be passed to the histogram constructor
+  /// @note Tag is defined after the last ';' symbol in the nameBase string
+  /// @example
+  ///    nambeBase = "/foo/bar/hit_xy_occupancy_station0;xy_station0" will be decayed into:
+  ///    1) subdirectory /foo/bar
+  ///    2) name of histogram "catrd_hit_xy_occupancy_station0"
+  ///    3) tag for configuration file "xy_station0"
+  /// If configuration file or tag are not defined, default parameters will be used
+  template<typename T, typename... Args>
+  T* MakeHistoConfig(const char* nameBase, const char* title, Args... args);
+
   /// @brief Creates, initializes and registers a table
   /// @param  name  Name of the table
   /// @param  args  The rest of the arguments, which will be passed to the table constructor
   template<typename... Args>
   CbmQaTable* MakeTable(TString name, Args... args);
 
+  /// @brief Creates a ROOT object
+  /// @param name    Name of the object
+  /// @param args... Arguments passed to the object constructor
+  template<typename T, typename... Args>
+  T* MakeObject(const char* name, Args... args);
+
+  /// @brief Sets config name
+  /// @param name  A path to the config
+  void SetConfigName(const char* path);
 
 protected:
+  /// @brief Function to check, if a property is defined
+  /// @param property  A property to be tested
+  /// @param name      A name of property (used for logging)
+  /// @note  Throws an exception, if property is undefined
+  template<typename T>
+  void CheckProperty(T&& property, const char* name) const;
+
   /// @brief Applies properties on the histogram created with MakeHisto funciton
   /// @param pHist  Pointer to histogram
   virtual void SetHistoProperties(TH1* /*pHits*/);
@@ -117,14 +151,36 @@ protected:
   /// @param pOutFile Pointer to output ROOT file
   void WriteToFile(TFile* pOutFile) const;
 
+
   TString fsRootFolderName = "";  ///< Name of root folder
+  TString fsConfigName     = "";  ///< Name of configuration file
   TString fsPrefix         = "";  ///< Unique prefix for all writeable root
 
   EStoringMode fStoringMode             = EStoringMode::kSUBDIR;  ///< Objects storing mode
   std::shared_ptr<ObjList_t> fpvObjList = nullptr;                ///< List of registered ROOT objects
+
+  YAML::Node fConfigNode {};  ///< Configuration node
 };
 
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<typename T>
+void CbmQaIO::CheckProperty(T&& property, const char* name) const
+{
+  bool bPropertyUndefined = false;
+  if constexpr (std::is_signed_v<T>) { bPropertyUndefined = property < 0; }
+  else if constexpr (std::is_floating_point_v<T>) {
+    bPropertyUndefined = std::isnan(property);
+  }
+
+  if (bPropertyUndefined) {
+    std::stringstream msg;
+    msg << "Property " << name << " is undefined in the configuration file";
+    throw std::runtime_error(msg.str());
+  }
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<typename T, typename... Args>
@@ -191,7 +247,112 @@ T* CbmQaIO::MakeEfficiency(TString nameBase, Args... args)
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<typename T, typename... Args>
-T* CbmQaIO::MakeHisto(TString nameBase, Args... args)
+T* CbmQaIO::MakeHisto(TString nameBase, Args... args) 
+{
+  return CbmQaIO::MakeQaObject<T>(nameBase, args...);
+}
+
+
+T* CbmQaIO::MakeHistoConfig(const char* nameBase, const char* title, Args... args)
+{
+  TString sObjName = nameBase;
+  auto iLastSepPos = static_cast<int>(sObjName.Last(';'));
+  TString sTagName = sObjName(iLastSepPos + 1, sObjName.Length() - iLastSepPos);
+  sObjName         = sObjName(0, iLastSepPos);
+
+  bool bUseConfig = false;
+  // Check, if parameters are provided for this tag
+  if (fConfigNode) {
+    if (fConfigNode["histograms"]) {
+      if (fConfigNode["histograms"][sTagName.Data()]) { bUseConfig = true; }
+    }
+  }
+
+  if (bUseConfig) {
+    const auto& tagNode = fConfigNode["histograms"][sTagName.Data()];
+
+    int nBinsX                   = -1;
+    double minX                  = std::numeric_limits<double>::signaling_NaN();
+    double maxX                  = std::numeric_limits<double>::signaling_NaN();
+    [[maybe_unused]] int nBinsY  = -1;
+    [[maybe_unused]] double minY = std::numeric_limits<double>::signaling_NaN();
+    [[maybe_unused]] double maxY = std::numeric_limits<double>::signaling_NaN();
+    [[maybe_unused]] int nBinsZ  = -1;
+    [[maybe_unused]] double minZ = std::numeric_limits<double>::signaling_NaN();
+    [[maybe_unused]] double maxZ = std::numeric_limits<double>::signaling_NaN();
+
+    if (tagNode["x"]) {
+      nBinsX = tagNode["x"]["nbins"].as<int>();
+      minX   = tagNode["x"]["min"].as<double>();
+      maxX   = tagNode["x"]["max"].as<double>();
+    }
+    if (tagNode["y"]) {
+      nBinsY = tagNode["y"]["nbins"].as<int>();
+      minY   = tagNode["y"]["min"].as<double>();
+      maxY   = tagNode["y"]["max"].as<double>();
+    }
+    if (tagNode["z"]) {
+      nBinsZ = tagNode["z"]["nbins"].as<int>();
+      minZ   = tagNode["z"]["min"].as<double>();
+      maxZ   = tagNode["z"]["max"].as<double>();
+    }
+
+    if constexpr (std::is_base_of_v<TProfile2D, T>) {
+      CheckProperty(nBinsX, Form("qa/histograms/%s/x/nbins", sTagName.Data()));
+      CheckProperty(minX, Form("qa/histograms/%s/x/min", sTagName.Data()));
+      CheckProperty(maxX, Form("qa/histograms/%s/x/max", sTagName.Data()));
+      CheckProperty(nBinsY, Form("qa/histograms/%s/y/nbins", sTagName.Data()));
+      CheckProperty(minY, Form("qa/histograms/%s/y/min", sTagName.Data()));
+      CheckProperty(maxY, Form("qa/histograms/%s/y/max", sTagName.Data()));
+      CheckProperty(minZ, Form("qa/histograms/%s/z/min", sTagName.Data()));
+      CheckProperty(maxZ, Form("qa/histograms/%s/z/max", sTagName.Data()));
+      return MakeHisto<T>(sObjName.Data(), title, nBinsX, minX, maxX, nBinsY, minY, maxY, minZ, maxZ);
+    }
+    else if constexpr (std::is_base_of_v<TProfile, T>) {
+      CheckProperty(nBinsX, Form("qa/histograms/%s/x/nbins", sTagName.Data()));
+      CheckProperty(minX, Form("qa/histograms/%s/x/min", sTagName.Data()));
+      CheckProperty(maxX, Form("qa/histograms/%s/x/max", sTagName.Data()));
+      CheckProperty(minY, Form("qa/histograms/%s/y/min", sTagName.Data()));
+      CheckProperty(maxY, Form("qa/histograms/%s/y/max", sTagName.Data()));
+      return MakeHisto<T>(sObjName.Data(), title, nBinsX, minX, maxX, minY, maxY);
+    }
+    else if constexpr (std::is_base_of_v<TH3, T>) {
+      CheckProperty(nBinsX, Form("qa/histograms/%s/x/nbins", sTagName.Data()));
+      CheckProperty(minX, Form("qa/histograms/%s/x/min", sTagName.Data()));
+      CheckProperty(maxX, Form("qa/histograms/%s/x/max", sTagName.Data()));
+      CheckProperty(nBinsY, Form("qa/histograms/%s/y/nbins", sTagName.Data()));
+      CheckProperty(minY, Form("qa/histograms/%s/y/min", sTagName.Data()));
+      CheckProperty(maxY, Form("qa/histograms/%s/y/max", sTagName.Data()));
+      CheckProperty(nBinsZ, Form("qa/histograms/%s/z/nbins", sTagName.Data()));
+      CheckProperty(minZ, Form("qa/histograms/%s/z/min", sTagName.Data()));
+      CheckProperty(maxZ, Form("qa/histograms/%s/z/max", sTagName.Data()));
+      return MakeHisto<T>(sObjName.Data(), title, nBinsX, minX, maxX, nBinsY, minY, maxY, nBinsZ, minZ, maxZ);
+    }
+    else if constexpr (std::is_base_of_v<TH2, T>) {
+      CheckProperty(nBinsX, Form("qa/histograms/%s/x/nbins", sTagName.Data()));
+      CheckProperty(minX, Form("qa/histograms/%s/x/min", sTagName.Data()));
+      CheckProperty(maxX, Form("qa/histograms/%s/x/max", sTagName.Data()));
+      CheckProperty(nBinsY, Form("qa/histograms/%s/y/nbins", sTagName.Data()));
+      CheckProperty(minY, Form("qa/histograms/%s/y/min", sTagName.Data()));
+      CheckProperty(maxY, Form("qa/histograms/%s/y/max", sTagName.Data()));
+      return MakeHisto<T>(sObjName.Data(), title, nBinsX, minX, maxX, nBinsY, minY, maxY);
+    }
+    else if constexpr (std::is_base_of_v<TH1, T>) {
+      CheckProperty(nBinsX, Form("qa/histograms/%s/x/nbins", sTagName.Data()));
+      CheckProperty(minX, Form("qa/histograms/%s/x/min", sTagName.Data()));
+      CheckProperty(maxX, Form("qa/histograms/%s/x/max", sTagName.Data()));
+      return MakeHisto<T>(sObjName.Data(), title, nBinsX, minX, maxX);
+    }
+  }
+  else {
+    return MakeHisto<T>(sObjName.Data(), title, args...);
+  }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<typename T, typename... Args>
+T* CbmQaIO::MakeObject(const char* name, Args... args)
 {
   return MakeQaObject<T>(nameBase, args...);
 }
diff --git a/core/qa/CbmQaTask.cxx b/core/qa/CbmQaTask.cxx
index 2782247f6a..f2b3ffbd4f 100644
--- a/core/qa/CbmQaTask.cxx
+++ b/core/qa/CbmQaTask.cxx
@@ -80,22 +80,6 @@ InitStatus CbmQaTask::Init()
   LOG_IF(info, fVerbose > 0) << fName << ": initializing task ...";
   InitStatus res = kSUCCESS;
 
-  // ----- Open configuration file
-  YAML::Node config;
-  if (fsConfigName.Length()) {
-    LOG(info) << fName << ": reading configuration from file \"" << fsConfigName << "\"";
-    try {
-      config        = YAML::LoadFile(fsConfigName.Data())["qa"][fName.Data()];
-      fpCurrentNode = &config;
-    }
-    catch (const YAML::BadFile& exc) {
-      LOG(fatal) << fName << ": configuration file \"" << fsConfigName << "\" does not exist";
-    }
-    catch (const YAML::ParserException& exc) {
-      LOG(fatal) << fName << ": configuration file \"" << fsConfigName << "\" is formatted improperly";
-    }
-  }
-
   // ----- Clear map of the histograms (note)
   DeInitBase();
 
@@ -109,7 +93,6 @@ InitStatus CbmQaTask::Init()
 
   fNofEvents.SetVal(0);
 
-  fpCurrentNode = nullptr;  // De-init pointer to
   return res;
 }
 
diff --git a/core/qa/CbmQaTask.h b/core/qa/CbmQaTask.h
index e79ce19fca..494b2c3007 100644
--- a/core/qa/CbmQaTask.h
+++ b/core/qa/CbmQaTask.h
@@ -74,13 +74,7 @@ public:
   /// FairTask: Defines action of the task in the end of run
   void Finish();
 
-  /// @brief Sets task configuration file
-  /// @param filename  Name of file
-  ///
-  /// Sets name of YAML configuration file, which defines parameters needed for the task. The file is assumed
-  /// to contain root branch "qa/[task name]". A subbranch "histograms" contains a list of histograms with pre defined
-  /// parameters: title, number of bins and axis ranges.
-  void SetConfigName(const char* filename) { fsConfigName = filename; }
+  ClassDef(CbmQaTask, 0);
 
 protected:
   // *****************************************************
@@ -146,11 +140,6 @@ private:
   bool fbUseMC = false;  ///< Flag, if MC is used
 
   TParameter<int> fNofEvents {"nEvents", 0};  ///< Number of processed events
-
-  TString fsConfigName      = "";       ///< Name of YAML configuration file
-  YAML::Node* fpCurrentNode = nullptr;  ///< Pointer to current node of the configuration file
-
-  ClassDef(CbmQaTask, 0);
 };
 
 
diff --git a/macro/L1/configs/CMakeLists.txt b/macro/L1/configs/CMakeLists.txt
index 2d297127cd..d54f684160 100644
--- a/macro/L1/configs/CMakeLists.txt
+++ b/macro/L1/configs/CMakeLists.txt
@@ -1,4 +1,3 @@
 Install(FILES config_ideal_hits_mcbm.yaml
               DESTINATION share/cbmroot/macro/L1/configs
        )
-#Install(DIRECTORY modules DESTINATION share/cbmroot/macro/L1/configs)
diff --git a/macro/L1/configs/config_ideal_hits_mcbm.yaml b/macro/L1/configs/config_ideal_hits_mcbm.yaml
index 962016c556..81e896ff43 100644
--- a/macro/L1/configs/config_ideal_hits_mcbm.yaml
+++ b/macro/L1/configs/config_ideal_hits_mcbm.yaml
@@ -2,7 +2,7 @@
 #  SPDX-License-Identifier: GPL-3.0-only
 #  Authors: Sergei Zharko [committer] 
 # 
-## @file   CbmCaIdealHitProducerConfig.yaml
+## @file   config_ideal_hits_mcbm.yaml
 ## @brief  Configuration file for ideal hit producers
 ## @since  28.06.2023
 ## @author Sergei Zharko <s.zharko@gsi.de>
diff --git a/macro/mcbm/mcbm_qa.C b/macro/mcbm/mcbm_qa.C
index d4f4641b3e..64336d6abf 100644
--- a/macro/mcbm/mcbm_qa.C
+++ b/macro/mcbm/mcbm_qa.C
@@ -36,7 +36,7 @@
 #endif
 
 void mcbm_qa(Int_t nEvents = 0, TString dataset = "data/mcbm_beam_2020_03_test",
-             TString setupName = "mcbm_beam_2020_03", Bool_t bUseMC = kTRUE)
+             TString setupName = "mcbm_beam_2020_03", Bool_t bUseMC = kTRUE, const TString& config = "")
 {
 
   // ========================================================================
@@ -51,6 +51,8 @@ void mcbm_qa(Int_t nEvents = 0, TString dataset = "data/mcbm_beam_2020_03_test",
   int verbose    = 6;                              // verbose level
   TString myName = "mcbm_qa";                      // this macro's name for screen output
   TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  TString qaConfig = (config.Length() ? config : srcDir + "/macro/qa/configs/qa_tasks_config_mcbm.yaml");
+  // NOTE: SZh 28.07.2024: config can depend from the setup
   // ------------------------------------------------------------------------
 
   // -----   In- and output file names   ------------------------------------
@@ -221,6 +223,7 @@ void mcbm_qa(Int_t nEvents = 0, TString dataset = "data/mcbm_beam_2020_03_test",
     // CA Input QA
     auto* pCaInputTrd = new CbmCaInputQaTrd(verbose, bUseMC);
     pCaInputTrd->SetEfficiencyThrsh(0.5, 0, 100);
+    //pCaInputTrd->SetConfigName(qaConfig);
     run->AddTask(pCaInputTrd);
   }
   // ------------------------------------------------------------------------
diff --git a/macro/qa/CMakeLists.txt b/macro/qa/CMakeLists.txt
index 43258bdad5..dec6ce17ff 100644
--- a/macro/qa/CMakeLists.txt
+++ b/macro/qa/CMakeLists.txt
@@ -1,3 +1,5 @@
+add_subdirectory(configs)
+
 # =====   Generate the needed shell scripts   ================================
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/qa/qa_compare.C)
 
@@ -12,8 +14,8 @@ file(COPY ${CBMROOT_SOURCE_DIR}/macro/include/.rootrc
 # ============================================================================
 
 # Copy file-object map
-file(COPY ${CBMROOT_SOURCE_DIR}/macro/qa/objects.yaml
-	DESTINATION ${CBMROOT_BINARY_DIR}/macro/qa)
+file(COPY ${CBMROOT_SOURCE_DIR}/macro/qa/configs/objects.yaml
+	DESTINATION ${CBMROOT_BINARY_DIR}/macro/qa/configs)
 
 # =====   Define variables for tests   =======================================
 if(${CBM_TEST_MODEL} MATCHES Weekly)
@@ -91,7 +93,7 @@ foreach(setup IN LISTS cbm_setup)
 endforeach(setup IN LISTS cbm_setup)
 # ============================================================================
 
-Install(FILES ../run/.rootrc qa_compare.C objects.yaml
+Install(FILES ../run/.rootrc qa_compare.C
         DESTINATION share/cbmroot/macro/qa
        )
 #Install(CODE "FILE(MAKE_DIRECTORY \${CMAKE_INSTALL_PREFIX}/share/cbmroot/macro/run/data)")
diff --git a/macro/qa/objects.yaml b/macro/qa/objects.yaml
deleted file mode 100644
index fe4d1e6aa7..0000000000
--- a/macro/qa/objects.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-##################################################
-#                                                #
-#  File-object map for the QA-Checker framework  #
-#                                                #
-##################################################
-
-
-checker:
-  files:
-    - name: "%v/%d_qa.qa.root"
-      label: qa
-      objects:
-        - CbmCaInputQaSts/efficiencies/casts_reco_eff_vs_r_st0
-        - CbmCaInputQaSts/efficiencies/casts_reco_eff_vs_xy_st0
-        - CbmCaInputQaSts/histograms/casts_pull_t_st2
-        - CbmCaInputQaSts/histograms/casts_res_x_vs_x_st2        
diff --git a/macro/qa/qa_compare.C b/macro/qa/qa_compare.C
index ee32e588d9..d5cda2386a 100644
--- a/macro/qa/qa_compare.C
+++ b/macro/qa/qa_compare.C
@@ -21,7 +21,7 @@
 /// NOTE: Disable clang formatting to keep easy parameters overview
 /* clang-format off */
 int qa_compare( 
-                const char* configName         = "objects.yaml",
+                const char* configName         = "configs/objects.yaml",
                 const char* datasetName        = "s100e",
                 const char* oldVersionInputDir = "../run/data",          // NOTE: Files from external repository
                 const char* newVersionInputDir = "../run/data",          // NOTE: Files from preceding fixture
diff --git a/reco/L1/qa/CbmCaInputQaTrd.cxx b/reco/L1/qa/CbmCaInputQaTrd.cxx
index ae7dea1a22..e3a3a142da 100644
--- a/reco/L1/qa/CbmCaInputQaTrd.cxx
+++ b/reco/L1/qa/CbmCaInputQaTrd.cxx
@@ -130,7 +130,7 @@ bool CbmCaInputQaTrd::Check()
     pEffTable->SetColWidth(20);
 
     for (int iSt = 0; iSt < nSt; ++iSt) {
-      auto [eff, effEL, effEU] = fvpe_reco_eff_vs_r[iSt]->GetTotalEfficiency();
+      auto eff = fvpe_reco_eff_vs_r[iSt]->GetMean(2);
       pEffTable->SetCell(iSt, 0, iSt);
       pEffTable->SetCell(iSt, 1, eff);
       res = CheckRange("Hit finder efficiency in station " + std::to_string(iSt), eff, fEffThrsh, 1.000);
@@ -303,7 +303,7 @@ void CbmCaInputQaTrd::FillHistograms()
     LOG_IF(fatal, iSt < 0 || iSt >= nSt) << fName << ": index of station (" << iSt << ") is out of range "
                                          << "for hit with id = " << iH;
 
-    int hitType = pHit->GetClassType();  // TRD-1D, TRD-2D
+    //int hitType = pHit->GetClassType();  // TRD-1D, TRD-2D
 
     // Hit position
     double xHit = pHit->GetX();
@@ -327,14 +327,6 @@ void CbmCaInputQaTrd::FillHistograms()
     fvph_hit_dy[iSt]->Fill(dyHit);
     fvph_hit_dt[iSt]->Fill(dtHit);
 
-    fvph_hit_ypos_vs_xpos[nSt + hitType]->Fill(xHit, yHit);
-    fvph_hit_xpos_vs_zpos[nSt + hitType]->Fill(zHit, xHit);
-    fvph_hit_ypos_vs_zpos[nSt + hitType]->Fill(zHit, yHit);
-    fvph_hit_dx[nSt + hitType]->Fill(dxHit);
-    fvph_hit_dy[nSt + hitType]->Fill(dyHit);
-    fvph_hit_dt[nSt + hitType]->Fill(dtHit);
-
-
     // **********************
     // ** MC information QA
 
@@ -367,7 +359,6 @@ void CbmCaInputQaTrd::FillHistograms()
       }
 
       fvph_n_points_per_hit[iSt]->Fill(nMCpoints);
-      fvph_n_points_per_hit[nSt + hitType]->Fill(nMCpoints);
 
       if (nMCpoints != 1) { continue; }  // ??
 
@@ -430,6 +421,7 @@ void CbmCaInputQaTrd::FillHistograms()
       if (std::fabs(pMCPoint->GetPzOut()) < fMinMomentum) { continue; }  // CUT ON MINIMUM MOMENTUM
       //if (pMCo < cuts::kMinP) { continue; }  // Momentum threshold
 
+
       fvph_point_ypos_vs_xpos[iSt]->Fill(xMC, yMC);
       fvph_point_xpos_vs_zpos[iSt]->Fill(zMC, xMC);
       fvph_point_ypos_vs_zpos[iSt]->Fill(zMC, yMC);
@@ -451,28 +443,6 @@ void CbmCaInputQaTrd::FillHistograms()
       fvph_pull_x_vs_x[iSt]->Fill(xHit, xRes / dxHit);
       fvph_pull_y_vs_y[iSt]->Fill(yHit, yRes / dyHit);
       fvph_pull_t_vs_t[iSt]->Fill(tHit, tRes / dtHit);
-
-      fvph_point_ypos_vs_xpos[nSt + hitType]->Fill(xMC, yMC);
-      fvph_point_xpos_vs_zpos[nSt + hitType]->Fill(zMC, xMC);
-      fvph_point_ypos_vs_zpos[nSt + hitType]->Fill(zMC, yMC);
-
-      fvph_point_hit_delta_z[nSt + hitType]->Fill(shiftZ);
-
-      fvph_res_x[nSt + hitType]->Fill(xRes);
-      fvph_res_y[nSt + hitType]->Fill(yRes);
-      fvph_res_t[nSt + hitType]->Fill(tRes);
-
-      fvph_pull_x[nSt + hitType]->Fill(xRes / dxHit);
-      fvph_pull_y[nSt + hitType]->Fill(yRes / dyHit);
-      fvph_pull_t[nSt + hitType]->Fill(tRes / dtHit);
-
-      fvph_res_x_vs_x[nSt + hitType]->Fill(xHit, xRes);
-      fvph_res_y_vs_y[nSt + hitType]->Fill(yHit, yRes);
-      fvph_res_t_vs_t[nSt + hitType]->Fill(tHit, tRes);
-
-      fvph_pull_x_vs_x[nSt + hitType]->Fill(xHit, xRes / dxHit);
-      fvph_pull_y_vs_y[nSt + hitType]->Fill(yHit, yRes / dyHit);
-      fvph_pull_t_vs_t[nSt + hitType]->Fill(tHit, tRes / dtHit);
     }
   }  // loop over hits: end
 
@@ -500,11 +470,8 @@ void CbmCaInputQaTrd::FillHistograms()
         // Conditions under which point is accounted as reconstructed: point
         bool ifPointHasHits = (vNofHitsPerPoint[iE][iP] > 0);
 
-        fvpe_reco_eff_vs_xy[iSt]->Fill(ifPointHasHits, xMC, yMC);
-        fvpe_reco_eff_vs_xy[nSt]->Fill(ifPointHasHits, xMC, yMC);
-
-        fvpe_reco_eff_vs_r[iSt]->Fill(ifPointHasHits, rMC);
-        fvpe_reco_eff_vs_r[nSt]->Fill(ifPointHasHits, rMC);
+        fvpe_reco_eff_vs_xy[iSt]->Fill(xMC, yMC, ifPointHasHits);
+        fvpe_reco_eff_vs_r[iSt]->Fill(rMC, ifPointHasHits);
 
       }  // loop over MC-points: end
     }    // loop over MC-events: end
@@ -633,43 +600,6 @@ InitStatus CbmCaInputQaTrd::InitCanvases()
     phProj->DrawCopy();
   }
 
-
-  // ** Occupancy in XZ plane
-  MakeCanvas<CbmQaCanvas>("hit_xpos_vs_zpos", "", 600, 400);
-  fvph_hit_xpos_vs_zpos[nSt]->DrawCopy("colz", "");
-  for (int iSt = 0; iSt < nSt; ++iSt) {
-    // Station positions in detector IFS
-    double stZmin = fpDetInterface->GetZ(iSt) - 0.5 * fpDetInterface->GetThickness(iSt);
-    double stZmax = fpDetInterface->GetZ(iSt) + 0.5 * fpDetInterface->GetThickness(iSt);
-    double stHmin = -fpDetInterface->GetRmax(iSt);
-    double stHmax = +fpDetInterface->GetRmax(iSt);
-
-    auto* pBox = new TBox(stZmin, stHmin, stZmax, stHmax);
-    pBox->SetLineWidth(contWidth);
-    pBox->SetLineStyle(contStyle);
-    pBox->SetLineColor(contColor);
-    pBox->SetFillStyle(contFill);
-    pBox->Draw("SAME");
-  }
-
-  // ** Occupancy in YZ plane
-  MakeCanvas<CbmQaCanvas>("hit_ypos_vs_zpos", "", 600, 400);
-  fvph_hit_ypos_vs_zpos[nSt]->DrawCopy("colz", "");
-  for (int iSt = 0; iSt < nSt; ++iSt) {
-    // Station positions in detector IFS
-    double stZmin = fpDetInterface->GetZ(iSt) - 0.5 * fpDetInterface->GetThickness(iSt);
-    double stZmax = fpDetInterface->GetZ(iSt) + 0.5 * fpDetInterface->GetThickness(iSt);
-    double stHmin = -fpDetInterface->GetRmax(iSt);
-    double stHmax = +fpDetInterface->GetRmax(iSt);
-
-    auto* pBox = new TBox(stZmin, stHmin, stZmax, stHmax);
-    pBox->SetLineWidth(contWidth);
-    pBox->SetLineStyle(contStyle);
-    pBox->SetLineColor(contColor);
-    pBox->SetFillStyle(contFill);
-    pBox->Draw("SAME");
-  }
-
   // ************
   // ************
 
@@ -714,44 +644,6 @@ InitStatus CbmCaInputQaTrd::InitCanvases()
       pBox->Draw("SAME");
     }
 
-    // ** Occupancy in XZ plane
-    MakeCanvas<CbmQaCanvas>("point_xpos_vs_zpos", "", 600, 400);
-    fvph_point_xpos_vs_zpos[nSt]->SetStats(false);
-    fvph_point_xpos_vs_zpos[nSt]->DrawCopy("colz", "");
-    for (int iSt = 0; iSt < nSt; ++iSt) {
-      // Station positions in detector IFS
-      double stZmin = fpDetInterface->GetZ(iSt) - 0.5 * fpDetInterface->GetThickness(iSt);
-      double stZmax = fpDetInterface->GetZ(iSt) + 0.5 * fpDetInterface->GetThickness(iSt);
-      double stHmin = -fpDetInterface->GetRmax(iSt);
-      double stHmax = +fpDetInterface->GetRmax(iSt);
-
-      auto* pBox = new TBox(stZmin, stHmin, stZmax, stHmax);
-      pBox->SetLineWidth(contWidth);
-      pBox->SetLineStyle(contStyle);
-      pBox->SetLineColor(contColor);
-      pBox->SetFillStyle(contFill);
-      pBox->Draw("SAME");
-    }
-
-    // ** Occupancy in YZ plane
-    MakeCanvas<CbmQaCanvas>("point_ypos_vs_zpos", "", 600, 400);
-    fvph_point_ypos_vs_zpos[nSt]->SetStats(false);
-    fvph_point_ypos_vs_zpos[nSt]->DrawCopy("colz", "");
-    for (int iSt = 0; iSt < nSt; ++iSt) {
-      // Station positions in detector IFS
-      double stZmin = fpDetInterface->GetZ(iSt) - 0.5 * fpDetInterface->GetThickness(iSt);
-      double stZmax = fpDetInterface->GetZ(iSt) + 0.5 * fpDetInterface->GetThickness(iSt);
-      double stHmin = -fpDetInterface->GetRmax(iSt);
-      double stHmax = +fpDetInterface->GetRmax(iSt);
-
-      auto* pBox = new TBox(stZmin, stHmin, stZmax, stHmax);
-      pBox->SetLineWidth(contWidth);
-      pBox->SetLineStyle(contStyle);
-      pBox->SetLineColor(contColor);
-      pBox->SetFillStyle(contFill);
-      pBox->Draw("SAME");
-    }
-
     // **************
     // ** Residuals
 
@@ -816,7 +708,6 @@ InitStatus CbmCaInputQaTrd::InitCanvases()
     pc_reco_eff_vs_r->Divide2D(nSt);
     for (int iSt = 0; iSt < nSt; ++iSt) {
       pc_reco_eff_vs_r->cd(iSt + 1);
-      fvpe_reco_eff_vs_r[iSt]->SetMarkerStyle(20);
       fvpe_reco_eff_vs_r[iSt]->DrawCopy("AP", "");
     }
 
@@ -838,198 +729,164 @@ InitStatus CbmCaInputQaTrd::InitHistograms()
   int nSt = fpDetInterface->GetNtrackingStations();
 
   // ----- Histograms initialization
-  fvph_hit_ypos_vs_xpos.resize(nSt + 2, nullptr);
-  fvph_hit_ypos_vs_zpos.resize(nSt + 2, nullptr);
-  fvph_hit_xpos_vs_zpos.resize(nSt + 2, nullptr);
+  fvph_hit_ypos_vs_xpos.resize(nSt, nullptr);
+  fvph_hit_ypos_vs_zpos.resize(nSt, nullptr);
+  fvph_hit_xpos_vs_zpos.resize(nSt, nullptr);
 
   fvph_hit_station_delta_z.resize(nSt);
 
-  fvph_hit_dx.resize(nSt + 2, nullptr);
-  fvph_hit_dy.resize(nSt + 2, nullptr);
-  fvph_hit_dt.resize(nSt + 2, nullptr);
+  fvph_hit_dx.resize(nSt, nullptr);
+  fvph_hit_dy.resize(nSt, nullptr);
+  fvph_hit_dt.resize(nSt, nullptr);
 
-  for (int iSt = 0; iSt < nSt + 2; ++iSt) {
-    TString nsuff = "";  // Histogram name suffix
-    TString tsuff = "";  // Histogram title suffix
+  if (IsMCUsed()) {
+    fvph_n_points_per_hit.resize(nSt, nullptr);
+    fvph_point_ypos_vs_xpos.resize(nSt, nullptr);
+    fvph_point_xpos_vs_zpos.resize(nSt, nullptr);
+    fvph_point_ypos_vs_zpos.resize(nSt, nullptr);
+    fvph_point_hit_delta_z.resize(nSt, nullptr);
+    fvph_res_x.resize(nSt, nullptr);
+    fvph_res_y.resize(nSt, nullptr);
+    fvph_res_t.resize(nSt, nullptr);
+    fvph_pull_x.resize(nSt, nullptr);
+    fvph_pull_y.resize(nSt, nullptr);
+    fvph_pull_t.resize(nSt, nullptr);
+    fvph_res_x_vs_x.resize(nSt, nullptr);
+    fvph_res_y_vs_y.resize(nSt, nullptr);
+    fvph_res_t_vs_t.resize(nSt, nullptr);
+    fvph_pull_x_vs_x.resize(nSt, nullptr);
+    fvph_pull_y_vs_y.resize(nSt, nullptr);
+    fvph_pull_t_vs_t.resize(nSt, nullptr);
+    fvpe_reco_eff_vs_xy.resize(nSt, nullptr);
+    fvpe_reco_eff_vs_r.resize(nSt, nullptr);
+  }
 
-    // Select group: indexes 0 .. iSt - 1 stand for single TRD stations, index iSt == nSt is TRD-1D
-    // and iSt == nSt + 1 is TRD-2D
-    if (iSt < nSt) {
-      nsuff = Form("_st%d", iSt);
-      tsuff = Form(" in TRD station %d", iSt);
-    }
-    else if (iSt == nSt) {
-      nsuff = "_1D";
-      tsuff = " in TRD-1D";
-    }
-    else {
-      nsuff = "_2D";
-      tsuff = " in TRD-2D";
-    }
+  for (int iSt = 0; iSt < nSt; ++iSt) {
+    TString nsuff        = Form("_st%d", iSt);
+    TString tsuff        = Form(" in TRD station %d", iSt);
+    TString npref        = Form("station%d/", iSt);
+    TString xyBinningTag = Form("xy_station%d", iSt);
 
     TString sN = "";
     TString sT = "";
 
+    double xMax = fpDetInterface->GetXmax(iSt);
+    double yMax = fpDetInterface->GetYmax(iSt);
+    double xRes = 0.05;  // [cm]
+    double yRes = 0.20;  // [cm]
+    int nBinsX  = static_cast<int>(2 * xMax / xRes);
+    int nBinsY  = static_cast<int>(2 * yMax / yRes);
+
     // Hit occupancy
-    sN                         = (TString) "hit_ypos_vs_xpos" + nsuff;
+    sN                         = npref + "hit_ypos_vs_xpos" + nsuff + ";" + xyBinningTag;
     sT                         = (TString) "Hit occupancy in xy-Plane" + tsuff + ";x_{hit} [cm];y_{hit} [cm]";
-    fvph_hit_ypos_vs_xpos[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, kRHitX[0], kRHitX[1], kNbins, kRHitY[0], kRHitY[1]);
+    fvph_hit_ypos_vs_xpos[iSt] = MakeHistoConfig<TH2F>(sN, sT, nBinsX, -xMax, xMax, nBinsY, -yMax, yMax);
 
-    sN                         = (TString) "hit_xpos_vs_zpos" + nsuff;
+    sN                         = npref + "hit_xpos_vs_zpos" + nsuff;
     sT                         = (TString) "Hit occupancy in xz-Plane" + tsuff + ";z_{hit} [cm];x_{hit} [cm]";
-    fvph_hit_xpos_vs_zpos[iSt] = MakeHisto<TH2F>(sN, sT, kNbinsZ, kRHitZ[0], kRHitZ[1], kNbins, kRHitX[0], kRHitX[1]);
+    fvph_hit_xpos_vs_zpos[iSt] = MakeHisto<TH2F>(sN, sT, fNbinsZ, fvRHitZ[0], fvRHitZ[1], nBinsX, -xMax, xMax);
 
-    sN                         = (TString) "hit_ypos_vs_zpos" + nsuff;
+    sN                         = npref + "hit_ypos_vs_zpos" + nsuff;
     sT                         = (TString) "Hit occupancy in yz-plane" + tsuff + ";z_{hit} [cm];y_{hit} [cm]";
-    fvph_hit_ypos_vs_zpos[iSt] = MakeHisto<TH2F>(sN, sT, kNbinsZ, kRHitZ[0], kRHitZ[1], kNbins, kRHitY[0], kRHitY[1]);
+    fvph_hit_ypos_vs_zpos[iSt] = MakeHisto<TH2F>(sN, sT, fNbinsZ, fvRHitZ[0], fvRHitZ[1], nBinsY, -yMax, yMax);
 
     // Hit errors
-    sN               = (TString) "hit_dx" + nsuff;
+    sN               = npref + "hit_dx" + nsuff;
     sT               = (TString) "Hit position error along x-axis" + tsuff + ";dx_{hit} [cm]";
-    fvph_hit_dx[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRHitDx[0], kRHitDx[1]);
+    fvph_hit_dx[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRHitDx[0], fvRHitDx[1]);
 
-    sN               = (TString) "hit_dy" + nsuff;
+    sN               = npref + "hit_dy" + nsuff;
     sT               = (TString) "Hit position error along y-axis" + tsuff + ";dy_{hit} [cm]";
-    fvph_hit_dy[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRHitDy[0], kRHitDy[1]);
+    fvph_hit_dy[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRHitDy[0], fvRHitDy[1]);
 
-    sN               = (TString) "hit_dt" + nsuff;
+    sN               = npref + "hit_dt" + nsuff;
     sT               = (TString) "Hit time error" + tsuff + ";dt_{hit} [ns]";
-    fvph_hit_dt[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRHitDt[0], kRHitDt[1]);
+    fvph_hit_dt[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRHitDt[0], fvRHitDt[1]);
 
-    if (iSt >= nSt) { continue; }  // Following histograms are defined only for separate station
-
-    sN = (TString) "hit_station_delta_z" + nsuff;
+    sN = npref + "hit_station_delta_z" + nsuff;
     sT = (TString) "Different between hit and station z-positions" + tsuff + ";z_{hit} - z_{st} [cm]";
-    fvph_hit_station_delta_z[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, -5., 5);
-
-  }  // loop over station index: end
+    fvph_hit_station_delta_z[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, -5., 5);
 
-  // ----- Initialize histograms, which are use MC-information
-  if (IsMCUsed()) {
-    // Resize histogram vectors
-    fvph_n_points_per_hit.resize(nSt + 2, nullptr);
-    fvph_point_ypos_vs_xpos.resize(nSt + 2, nullptr);
-    fvph_point_xpos_vs_zpos.resize(nSt + 2, nullptr);
-    fvph_point_ypos_vs_zpos.resize(nSt + 2, nullptr);
-    fvph_point_hit_delta_z.resize(nSt + 2, nullptr);
-    fvph_res_x.resize(nSt + 2, nullptr);
-    fvph_res_y.resize(nSt + 2, nullptr);
-    fvph_res_t.resize(nSt + 2, nullptr);
-    fvph_pull_x.resize(nSt + 2, nullptr);
-    fvph_pull_y.resize(nSt + 2, nullptr);
-    fvph_pull_t.resize(nSt + 2, nullptr);
-    fvph_res_x_vs_x.resize(nSt + 2, nullptr);
-    fvph_res_y_vs_y.resize(nSt + 2, nullptr);
-    fvph_res_t_vs_t.resize(nSt + 2, nullptr);
-    fvph_pull_x_vs_x.resize(nSt + 2, nullptr);
-    fvph_pull_y_vs_y.resize(nSt + 2, nullptr);
-    fvph_pull_t_vs_t.resize(nSt + 2, nullptr);
-    fvpe_reco_eff_vs_xy.resize(nSt + 2, nullptr);
-    fvpe_reco_eff_vs_r.resize(nSt + 2, nullptr);
-
-    for (int iSt = 0; iSt < nSt + 2; ++iSt) {
-      TString nsuff = "";  // Histogram name suffix
-      TString tsuff = "";  // Histogram title suffix
-
-      // Select group: indexes 0 .. iSt - 1 stand for single TRD stations, index iSt == nSt is TRD-1D
-      // and iSt == nSt + 1 is TRD-2D
-      if (iSt < nSt) {
-        nsuff = Form("_st%d", iSt);
-        tsuff = Form(" in TRD station %d", iSt);
-      }
-      else if (iSt == nSt) {
-        nsuff = "_1D";
-        tsuff = " in TRD-1D";
-      }
-      else {
-        nsuff = "_2D";
-        tsuff = " in TRD-2D";
-      }
-
-      TString sN = "";
-      TString sT = "";
-
-      sN                         = (TString) "n_points_per_hit" + nsuff;
+    // ----- Initialize histograms, which are use MC-information
+    if (IsMCUsed()) {
+      sN                         = npref + "n_points_per_hit" + nsuff;
       sT                         = (TString) "Number of points per hit" + tsuff + ";N_{point}/hit";
       fvph_n_points_per_hit[iSt] = MakeHisto<TH1F>(sN, sT, 10, -0.5, 9.5);
 
       // Point occupancy
-      sN = (TString) "point_ypos_vs_xpos" + nsuff;
+      sN                           = npref + "point_ypos_vs_xpos" + nsuff + ";" + xyBinningTag;
       sT = (TString) "Point occupancy in XY plane" + tsuff + ";x_{MC} [cm];y_{MC} [cm]";
-      fvph_point_ypos_vs_xpos[iSt] =
-        MakeHisto<TH2F>(sN, sT, kNbins, kRHitX[0], kRHitX[1], kNbins, kRHitY[0], kRHitY[1]);
+      fvph_point_ypos_vs_xpos[iSt] = MakeHistoConfig<TH2F>(sN, sT, nBinsX, -xMax, xMax, nBinsY, -yMax, yMax);
 
-      sN = (TString) "point_xpos_vs_zpos" + nsuff;
+      sN                           = npref + "point_xpos_vs_zpos" + nsuff;
       sT = (TString) "Point Occupancy in XZ plane" + tsuff + ";z_{MC} [cm];x_{MC} [cm]";
-      fvph_point_xpos_vs_zpos[iSt] =
-        MakeHisto<TH2F>(sN, sT, kNbinsZ, kRHitZ[0], kRHitZ[1], kNbins, kRHitX[0], kRHitX[1]);
+      fvph_point_xpos_vs_zpos[iSt] = MakeHisto<TH2F>(sN, sT, fNbinsZ, fvRHitZ[0], fvRHitZ[1], nBinsX, -xMax, xMax);
 
-      sN = (TString) "point_ypos_vs_zpos" + nsuff;
+      sN                           = npref + "point_ypos_vs_zpos" + nsuff;
       sT = (TString) "Point Occupancy in YZ Plane" + tsuff + ";z_{MC} [cm];y_{MC} [cm]";
-      fvph_point_ypos_vs_zpos[iSt] =
-        MakeHisto<TH2F>(sN, sT, kNbinsZ, kRHitZ[0], kRHitZ[1], kNbins, kRHitY[0], kRHitY[1]);
+      fvph_point_ypos_vs_zpos[iSt] = MakeHisto<TH2F>(sN, sT, fNbinsZ, fvRHitZ[0], fvRHitZ[1], nBinsY, -yMax, yMax);
 
       // Difference between MC input z and hit z coordinates
-      sN = (TString) "point_hit_delta_z" + nsuff;
+      sN = npref + "point_hit_delta_z" + nsuff;
       sT = (TString) "Distance between point and hit along z axis" + tsuff + ";z_{reco} - z_{MC} [cm]";
-      fvph_point_hit_delta_z[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, -0.04, 0.04);
+      fvph_point_hit_delta_z[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, -0.04, 0.04);
 
-      sN              = (TString) "res_x" + nsuff;
+      sN              = npref + "res_x" + nsuff;
       sT              = (TString) "Residuals for x-coordinate" + tsuff + ";x_{reco} - x_{MC} [cm]";
-      fvph_res_x[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRResX[0], kRResX[1]);
+      fvph_res_x[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRResX[0], fvRResX[1]);
 
-      sN              = (TString) "res_y" + nsuff;
+      sN              = npref + "res_y" + nsuff;
       sT              = (TString) "Residuals for y-coordinate" + tsuff + ";y_{reco} - y_{MC} [cm]";
-      fvph_res_y[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRResY[0], kRResY[1]);
+      fvph_res_y[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRResY[0], fvRResY[1]);
 
-      sN              = (TString) "res_t" + nsuff;
+      sN              = npref + "res_t" + nsuff;
       sT              = (TString) "Residuals for time" + tsuff + ";t_{reco} - t_{MC} [ns]";
-      fvph_res_t[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRResT[0], kRResT[1]);
+      fvph_res_t[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRResT[0], fvRResT[1]);
 
-      sN               = (TString) "pull_x" + nsuff;
+      sN               = npref + "pull_x" + nsuff;
       sT               = (TString) "Pulls for x-coordinate" + tsuff + ";(x_{reco} - x_{MC}) / #sigma_{x}^{reco}";
-      fvph_pull_x[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRPullX[0], kRPullX[1]);
+      fvph_pull_x[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRPullX[0], fvRPullX[1]);
 
-      sN               = (TString) "pull_y" + nsuff;
+      sN               = npref + "pull_y" + nsuff;
       sT               = (TString) "Pulls for y-coordinate" + tsuff + ";(y_{reco} - y_{MC}) / #sigma_{y}^{reco}";
-      fvph_pull_y[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRPullY[0], kRPullY[1]);
+      fvph_pull_y[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRPullY[0], fvRPullY[1]);
 
-      sN               = (TString) "pull_t" + nsuff;
+      sN               = npref + "pull_t" + nsuff;
       sT               = (TString) "Pulls for time" + tsuff + ";(t_{reco} - t_{MC}) / #sigma_{t}^{reco}";
-      fvph_pull_t[iSt] = MakeHisto<TH1F>(sN, sT, kNbins, kRPullT[0], kRPullT[1]);
+      fvph_pull_t[iSt] = MakeHisto<TH1F>(sN, sT, fNbins, fvRPullT[0], fvRPullT[1]);
 
-      sN                   = (TString) "res_x_vs_x" + nsuff;
+      sN                   = npref + "res_x_vs_x" + nsuff;
       sT                   = (TString) "Residuals for x-coordinate" + tsuff + ";x_{reco} [cm];x_{reco} - x_{MC} [cm]";
-      fvph_res_x_vs_x[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, 0, 0, kNbins, kRResX[0], kRResX[1]);
+      fvph_res_x_vs_x[iSt] = MakeHisto<TH2F>(sN, sT, fNbins, 0, 0, fNbins, fvRResX[0], fvRResX[1]);
 
-      sN                   = (TString) "res_y_vs_y" + nsuff;
+      sN                   = npref + "res_y_vs_y" + nsuff;
       sT                   = (TString) "Residuals for y-coordinate" + tsuff + ";y_{reco} [cm];y_{reco} - y_{MC} [cm]";
-      fvph_res_y_vs_y[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, 0, 0, kNbins, kRResY[0], kRResY[1]);
+      fvph_res_y_vs_y[iSt] = MakeHisto<TH2F>(sN, sT, fNbins, 0, 0, fNbins, fvRResY[0], fvRResY[1]);
 
-      sN                   = (TString) "res_t_vs_t" + nsuff;
+      sN                   = npref + "res_t_vs_t" + nsuff;
       sT                   = (TString) "Residuals for time" + tsuff + "t_{reco} [ns];t_{reco} - t_{MC} [ns]";
-      fvph_res_t_vs_t[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, 0, 0, kNbins, kRResT[0], kRResT[1]);
+      fvph_res_t_vs_t[iSt] = MakeHisto<TH2F>(sN, sT, fNbins, 0, 0, fNbins, fvRResT[0], fvRResT[1]);
 
-      sN = (TString) "pull_x_vs_x" + nsuff;
+      sN = npref + "pull_x_vs_x" + nsuff;
       sT = (TString) "Pulls for x-coordinate" + tsuff + "x_{reco} [cm];(x_{reco} - x_{MC}) / #sigma_{x}^{reco}";
-      fvph_pull_x_vs_x[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, 0, 0, kNbins, kRPullX[0], kRPullX[1]);
+      fvph_pull_x_vs_x[iSt] = MakeHisto<TH2F>(sN, sT, fNbins, 0, 0, fNbins, fvRPullX[0], fvRPullX[1]);
 
-      sN = (TString) "pull_y_vs_y" + nsuff;
+      sN = npref + "pull_y_vs_y" + nsuff;
       sT = (TString) "Pulls for y-coordinate" + tsuff + ";y_{reco} [cm];(y_{reco} - y_{MC}) / #sigma_{y}^{reco}";
-      fvph_pull_y_vs_y[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, 0, 0, kNbins, kRPullY[0], kRPullY[1]);
+      fvph_pull_y_vs_y[iSt] = MakeHisto<TH2F>(sN, sT, fNbins, 0, 0, fNbins, fvRPullY[0], fvRPullY[1]);
 
-      sN = (TString) "pull_t_vs_t" + nsuff;
+      sN                    = npref + "pull_t_vs_t" + nsuff;
       sT = (TString) "Pulls for time" + tsuff + ";t_{reco} [ns];(t_{reco} - t_{MC}) / #sigma_{t}^{reco}";
-      fvph_pull_t_vs_t[iSt] = MakeHisto<TH2F>(sN, sT, kNbins, 0, 0, kNbins, kRPullT[0], kRPullT[1]);
-
+      fvph_pull_t_vs_t[iSt] = MakeHisto<TH2F>(sN, sT, fNbins, 0, 0, fNbins, fvRPullT[0], fvRPullT[1]);
 
-      sN                       = (TString) "reco_eff_vs_xy" + nsuff;
+      sN                       = npref + "reco_eff_vs_xy" + nsuff + ";" + xyBinningTag;
       sT                       = (TString) "Hit rec. efficiency" + tsuff + ";x_{MC} [cm];y_{MC} [cm];#epsilon";
-      fvpe_reco_eff_vs_xy[iSt] = MakeEfficiency<CbmQaEff>(sN, sT, 100, -50, 50, 100, -50, 50);
+      fvpe_reco_eff_vs_xy[iSt] =
+        MakeHistoConfig<TProfile2D>(sN, sT, fNbins, fvRHitX[0], fvRHitX[1], fNbins, fvRHitY[0], fvRHitY[1]);
 
-      sN                      = (TString) "reco_eff_vs_r" + nsuff;
+      sN                      = npref + "reco_eff_vs_r" + nsuff;
       sT                      = (TString) "Hit rec. efficiency" + tsuff + ";r_{MC} [cm];#epsilon";
-      fvpe_reco_eff_vs_r[iSt] = MakeEfficiency<CbmQaEff>(sN, sT, 100, 0, 100);
+      fvpe_reco_eff_vs_r[iSt] = MakeHisto<TProfile>(sN, sT, 100, 0, 100, 0., 1.);
     }
   }
   return kSUCCESS;
diff --git a/reco/L1/qa/CbmCaInputQaTrd.h b/reco/L1/qa/CbmCaInputQaTrd.h
index db714adbf8..70bd9e7f48 100644
--- a/reco/L1/qa/CbmCaInputQaTrd.h
+++ b/reco/L1/qa/CbmCaInputQaTrd.h
@@ -31,7 +31,8 @@ class CbmTrdTrackingInterface;
 class TClonesArray;
 class TH1F;
 class TH2F;
-class CbmQaEff;
+class TProfile;
+class TProfile2D;
 
 /// A QA-task class, which provides assurance of TRD hits and geometry
 class CbmCaInputQaTrd : public CbmQaTask, public CbmCaInputQaBase {
@@ -94,29 +95,27 @@ private:
   std::vector<char> fvTrdStationType;  ///< Station type: TRD-1D and TRD-2D
 
   // ** Histograms **
-  static constexpr double kEffRangeMin = 35.;  ///< Lower limit of hit distance for efficiency integration [cm]
-  static constexpr double kEffRangeMax = 70.;  ///< Upper limit of hit distance for efficiency integration [cm]
+  double fEffRangeMin = 35.;  ///< Lower limit of hit distance for efficiency integration [cm]
+  double fEffRangeMax = 70.;  ///< Upper limit of hit distance for efficiency integration [cm]
 
-  static constexpr double kRHitX[2] = {-100., 100};  ///< Range for hit x coordinate [cm]
-  static constexpr double kRHitY[2] = {-100., 100};  ///< Range for hit y coordinate [cm]
-  static constexpr double kRHitZ[2] = {30., 300.};   ///< Range for hit z coordinate [cm]
+  std::array<double, 2> fvRHitX = {-100., 100};  ///< Range for hit x coordinate [cm]
+  std::array<double, 2> fvRHitY = {-100., 100};  ///< Range for hit y coordinate [cm]
+  std::array<double, 2> fvRHitZ = {30., 300.};   ///< Range for hit z coordinate [cm]
 
-  static constexpr int kNbins  = 100;  ///< General number of bins
-  static constexpr int kNbinsZ = 800;  ///< Number of bins for z coordinate axis
+  int fNbins  = 100;  ///< General number of bins
+  int fNbinsZ = 800;  ///< Number of bins for z coordinate axis
 
-  static constexpr double kRHitDx[2] = {-.05, .005};  ///< Range for hit x coordinate [cm]
-  static constexpr double kRHitDy[2] = {-.05, .005};  ///< Range for hit y coordinate [cm]
-  static constexpr double kRHitDt[2] = {-10., 10.};   ///< Range for hit time [ns]
+  std::array<double, 2> fvRHitDx = {-.05, .005};  ///< Range for hit x coordinate [cm]
+  std::array<double, 2> fvRHitDy = {-.05, .005};  ///< Range for hit y coordinate [cm]
+  std::array<double, 2> fvRHitDt = {-10., 10.};   ///< Range for hit time [ns]
 
-  static constexpr double kRResX[2] = {-2., 2.};    ///< Range for residual of x coordinate [cm]
-  static constexpr double kRResY[2] = {-2., 2.};    ///< Range for residual of y coordinate [cm]
-  static constexpr double kRResT[2] = {-20., 20.};  ///< Range for residual of time [ns]
+  std::array<double, 2> fvRResX = {-2., 2.};    ///< Range for residual of x coordinate [cm]
+  std::array<double, 2> fvRResY = {-2., 2.};    ///< Range for residual of y coordinate [cm]
+  std::array<double, 2> fvRResT = {-20., 20.};  ///< Range for residual of time [ns]
 
-  static constexpr double kRPullX[2] = {-10., 10.};  ///< Range for pull of x coordinate
-  static constexpr double kRPullY[2] = {-10., 10.};  ///< Range for pull of y coordinate
-  static constexpr double kRPullT[2] = {-5., 5.};    ///< Range for pull of time
-
-  // NOTE: the last three elements of each vector stands for integral distribution over TRD-1D and TRD-2D
+  std::array<double, 2> fvRPullX = {-10., 10.};  ///< Range for pull of x coordinate
+  std::array<double, 2> fvRPullY = {-10., 10.};  ///< Range for pull of y coordinate
+  std::array<double, 2> fvRPullT = {-5., 5.};    ///< Range for pull of time
 
   // hit occupancy
   std::vector<TH2F*> fvph_hit_ypos_vs_xpos;  ///< hit ypos vs xpos in different stations
@@ -160,8 +159,8 @@ private:
   std::vector<TH2F*> fvph_pull_t_vs_t;  ///< pull for t coordinate in different stations
 
   // Hit efficiencies
-  std::vector<CbmQaEff*> fvpe_reco_eff_vs_xy;  ///< Efficiency of hit reconstruction vs. x and y coordinates of MC
-  std::vector<CbmQaEff*> fvpe_reco_eff_vs_r;   ///< Efficiency of hit reconstruction vs. distance from center
+  std::vector<TProfile2D*> fvpe_reco_eff_vs_xy;  ///< Efficiency of hit reconstruction vs. x and y coordinates of MC
+  std::vector<TProfile*> fvpe_reco_eff_vs_r;     ///< Efficiency of hit reconstruction vs. distance from center
 };
 
 #endif  // CbmCaInputQaTrd_h
-- 
GitLab