diff --git a/core/qa/CMakeLists.txt b/core/qa/CMakeLists.txt
index f59b755abec2cd102a6f2a42eea4916fd354ffae..f71105c8a624183d6d4f72d61b61c7eb287ab708 100644
--- a/core/qa/CMakeLists.txt
+++ b/core/qa/CMakeLists.txt
@@ -17,6 +17,7 @@ set(LINKDEF ${LIBRARY_NAME}LinkDef.h)
 set(PUBLIC_DEPENDENCIES
   FairRoot::Base
   FairLogger::FairLogger
+  external::yaml-cpp
   ROOT::Core
   ROOT::Gpad
   ROOT::Hist
diff --git a/core/qa/CbmQaTask.cxx b/core/qa/CbmQaTask.cxx
index a534f1758b23431830a0b34e19d833585f5d3f82..aed9e84f6c4983f09a51c88bab5822657fa67f06 100644
--- a/core/qa/CbmQaTask.cxx
+++ b/core/qa/CbmQaTask.cxx
@@ -65,9 +65,24 @@ void CbmQaTask::Finish()
 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();
 
@@ -80,12 +95,13 @@ InitStatus CbmQaTask::Init()
   fpFolderRoot->SetOwner(true);                            // When true, TFolder owns all added objects
   fpFolderRoot->Add(&fNofEvents);
 
-  // ----- Initialize histograms and canvases
+  // ----- Initialize histograms
   LOG_IF(info, fVerbose > 1) << fName << ": initializing histograms";
   res = std::max(res, InitHistograms());
 
   fNofEvents.SetVal(0);
 
+  fpCurrentNode = nullptr;  // De-init pointer to
   return res;
 }
 
@@ -111,57 +127,3 @@ void CbmQaTask::DeInitBase()
   // De-initialize particular QA-task implementation
   DeInit();
 }
-
-
-// ---------------------------------------------------------------------------------------------------------------------
-// NOTE: Example
-void CbmQaTask::SetHistoProperties(TH1* pHisto)
-{
-  constexpr double kHdefTextSize = 0.04;
-
-  pHisto->SetStats(kTRUE);
-  pHisto->Sumw2();
-
-  // Axis property settings
-  std::array<TAxis*, 3> vpAxes = {pHisto->GetXaxis(), pHisto->GetYaxis(), pHisto->GetZaxis()};
-  for (auto* pAxis : vpAxes) {
-    pAxis->SetTitleSize(kHdefTextSize);
-    pAxis->SetLabelSize(kHdefTextSize);
-  }
-  vpAxes[0]->SetNdivisions(504);
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmQaTask::InitDataBranches()
-{
-  LOG_IF(info, fVerbose > 1) << fName << ": data branches initialization function is not defined";
-  return kSUCCESS;
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmQaTask::InitHistograms()
-{
-  LOG_IF(info, fVerbose > 1) << fName << ": histogram initialization function is not defined";
-  return kSUCCESS;
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void CbmQaTask::FillHistograms()
-{
-  LOG_IF(info, fVerbose > 1) << fName << ": histogram filling function is not defined";
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmQaTask::InitCanvases()
-{
-  LOG_IF(info, fVerbose > 1) << fName << ": no initialization of canvases is provided";
-  return kSUCCESS;
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void CbmQaTask::DeInit() { LOG_IF(info, fVerbose > 1) << fName << ": no extra de-initialization is provided"; }
diff --git a/core/qa/CbmQaTask.h b/core/qa/CbmQaTask.h
index 61f876d7e9af887b9f5c8c73b6f648868e566a1a..143b7a7abde728c1c6256a08c8371652f72a048d 100644
--- a/core/qa/CbmQaTask.h
+++ b/core/qa/CbmQaTask.h
@@ -19,11 +19,20 @@
 #include "TEfficiency.h"
 #include "TFolder.h"
 #include "TH1.h"
+#include "TH2.h"
+#include "TH3.h"
 #include "TParameter.h"
+#include "TProfile.h"
+#include "TProfile2D.h"
+#include "TProfile3D.h"
 #include "TROOT.h"
 
 #include <algorithm>
+#include <regex>
 #include <string_view>
+#include <type_traits>
+
+#include <yaml-cpp/yaml.h>
 
 /// Class CbmQaTask is to be inherited with a particular QA-task. It provides mechanisms for storage and management
 /// of QA canvases and histograms management
@@ -63,6 +72,14 @@ 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:
@@ -74,22 +91,22 @@ protected:
   virtual bool Check() = 0;
 
   /// De-initialize the task
-  virtual void DeInit();
+  virtual void DeInit() {}
 
   /// Initializes data branches
-  virtual InitStatus InitDataBranches();
+  virtual InitStatus InitDataBranches() { return kSUCCESS; }
 
   /// Initializes histograms
-  virtual InitStatus InitHistograms();
+  virtual InitStatus InitHistograms() { return kSUCCESS; }
 
   /// Initializes canvases
-  virtual InitStatus InitCanvases();
+  virtual InitStatus InitCanvases() { return kSUCCESS; }
 
   /// Initializes event / time-slice
   virtual InitStatus InitTimeSlice() { return kSUCCESS; }
 
   /// Method to fill histograms per event or time-slice
-  virtual void FillHistograms();
+  virtual void FillHistograms() {}
 
   /// Creates, initializes and registers a canvas
   /// \tparam  T     Type of the canvas: TCanvas or CbmQaCanvas (\note T should not be a pointer)
@@ -112,22 +129,22 @@ protected:
   template<typename T, typename... Args>
   T* MakeHisto(const char* name, Args... args);
 
+  /// @brief Creates, initializes and registers a histogram, based on the configuration file
+  /// @tparam T    Type of the histogram (@note: should not be a pointer)
+  /// @param  name  Name of the histogram, stored in config
+  /// @param  id0   First index (optional)
+  /// @param  id1   Second index (optional)
+  /// @param  id2   Third index (optional)
+  /// @return  Pointer to the histogram object
+  template<typename T>
+  T* MakeHistoFromConfig(const char* name, int id0 = -1, int id1 = -1, int id2 = -1);
+
   /// 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(const char* name, Args... args);
 
-  /// Method to setup histogram properties (text sizes etc.)
-  /// \param  pHist  Pointer to a histogram to tune
-  virtual void SetHistoProperties(TH1* pHist);
-
-  /// Gets a reference to histograms map
-  ///const auto& GetHistoMap() const { return fmpHistList; }
-
-  /// Gets a reference to canvases map
-  ///const auto& GetCanvasMap() const { return fmpCanvList; }
-
   /// Get current event number
   int GetEventNumber() const { return fNofEvents.GetVal(); }
 
@@ -147,17 +164,9 @@ protected:
 
 
 private:
-  // **********************************************************
-  // ** Functions accessible inside the CbmQaTask class only **
-  // **********************************************************
-
-  /// De-initialize this task
+  /// @brief De-initializes this task
   void DeInitBase();
 
-  // ***********************
-  // ** Private variables **
-  // ***********************
-
   // I/O
   std::unique_ptr<TFolder> fpFolderRoot = nullptr;  ///< Root folder to store histograms and canvases
   TFolder* fpFolderHist                 = nullptr;  ///< Folder for raw histograms
@@ -169,6 +178,9 @@ 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
 };
 
 
@@ -256,14 +268,131 @@ T* CbmQaTask::MakeHisto(const char* nameBase, Args... args)
     delete pHist;
   }
 
-  // Create a new histogram or profile
   T* pHist = new T(name, args...);
 
   // Register histogram in the folder
   if (!fpFolderHist) { fpFolderHist = fpFolderRoot->AddFolder("histograms", "Histograms"); }
   fpFolderHist->Add(pHist);
 
-  SetHistoProperties(pHist);
+  return pHist;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<typename T>
+T* CbmQaTask::MakeHistoFromConfig(const char* nameBase, int id0, int id1, int id2)
+{
+  std::string name = std::string(fsPrefix.Data()) + "_" + nameBase;
+  if (id0 > -1) { name = std::regex_replace(name, std::regex("\\%0"), std::to_string(id0)); }
+  if (id1 > -1) { name = std::regex_replace(name, std::regex("\\%1"), std::to_string(id1)); }
+  if (id2 > -1) { name = std::regex_replace(name, std::regex("\\%2"), std::to_string(id2)); }
+
+  // Check, if the histogram with a given name was already created. If so, delete it
+  if (gROOT->FindObject(name.data())) {
+    LOG(warn) << fName << ": A histogram with name \"" << name << "\" was previously created and will be deleted now "
+              << "to avoid memory leaks";
+    T* pHist = (T*) gROOT->FindObject(name.data());
+    delete pHist;
+  }
+
+  T* pHist = nullptr;
+  // Create histogram
+  LOG_IF(fatal, !fpCurrentNode)
+    << fName << ": attempt to make a histogram (\"" << nameBase << "\") from configuration file, which was not "
+    << "defined. Please, provide configuration file with defined histogram list to the task via "
+    << "SetConfigName(filename) function.";
+  try {
+    const auto& node = (*fpCurrentNode)["histograms"][nameBase];
+    LOG_IF(fatal, !node) << fName << ": node for histogram \"" << nameBase
+                         << "\" was not defined in the configuration file";
+
+    std::string title = node["title"].as<std::string>("").data();
+    if (id0 > -1) { title = std::regex_replace(title, std::regex("\\%0"), std::to_string(id0)); }
+    if (id1 > -1) { title = std::regex_replace(title, std::regex("\\%1"), std::to_string(id1)); }
+    if (id2 > -1) { title = std::regex_replace(title, std::regex("\\%2"), std::to_string(id2)); }
+
+    // 1D-profiles
+    if constexpr (std::is_base_of_v<TProfile, T>) {
+      int nBinsX      = node["nbinsx"].as<int>();
+      double minX     = node["minx"].as<double>();
+      double maxX     = node["maxx"].as<double>();
+      double minY     = node["miny"].as<double>(0.);
+      double maxY     = node["maxy"].as<double>(0.);
+      std::string opt = node["opt"].as<std::string>("");
+      pHist           = new T(name.data(), title.data(), nBinsX, minX, maxX, minY, maxY, opt.data());
+    }
+    // 2D-profiles
+    else if constexpr (std::is_base_of_v<TProfile2D, T>) {
+      int nBinsX      = node["nbinsx"].as<int>();
+      double minX     = node["minx"].as<double>();
+      double maxX     = node["maxx"].as<double>();
+      int nBinsY      = node["nbinsy"].as<int>();
+      double minY     = node["miny"].as<double>();
+      double maxY     = node["maxy"].as<double>();
+      double minZ     = node["minz"].as<double>(0.);
+      double maxZ     = node["maxz"].as<double>(0.);
+      std::string opt = node["opt"].as<std::string>("");
+      pHist = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY, minZ, maxZ, opt.data());
+    }
+    // 3D-profiles
+    else if constexpr (std::is_base_of_v<TProfile3D, T>) {
+      int nBinsX      = node["nbinsx"].as<int>();
+      double minX     = node["minx"].as<double>();
+      double maxX     = node["maxx"].as<double>();
+      int nBinsY      = node["nbinsy"].as<int>();
+      double minY     = node["miny"].as<double>();
+      double maxY     = node["maxy"].as<double>();
+      int nBinsZ      = node["nbinsz"].as<int>();
+      double minZ     = node["minz"].as<double>();
+      double maxZ     = node["maxz"].as<double>();
+      std::string opt = node["opt"].as<std::string>("");
+      pHist = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY, minZ, maxZ, opt.data());
+    }
+    // 2D-histograms
+    else if constexpr (std::is_base_of_v<TH2, T>) {
+      int nBinsX  = node["nbinsx"].as<int>();
+      double minX = node["minx"].as<double>();
+      double maxX = node["maxx"].as<double>();
+      int nBinsY  = node["nbinsy"].as<int>();
+      double minY = node["miny"].as<double>();
+      double maxY = node["maxy"].as<double>();
+      pHist       = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY);
+    }
+    // 3D-histograms + derived
+    else if constexpr (std::is_base_of_v<TH3, T>) {
+      int nBinsX  = node["nbinsx"].as<int>();
+      double minX = node["minx"].as<double>();
+      double maxX = node["maxx"].as<double>();
+      int nBinsY  = node["nbinsy"].as<int>();
+      double minY = node["miny"].as<double>();
+      double maxY = node["maxy"].as<double>();
+      int nBinsZ  = node["nbinsz"].as<int>();
+      double minZ = node["minz"].as<double>();
+      double maxZ = node["maxz"].as<double>();
+      pHist       = new T(name.data(), title.data(), nBinsX, minX, maxX, nBinsY, minY, maxY, nBinsZ, minZ, maxZ);
+    }
+    // 1D-histograms + derived
+    else if constexpr (std::is_base_of_v<TH1, T>) {
+      int nBinsX  = node["nbinsx"].as<int>();
+      double minX = node["minx"].as<double>();
+      double maxX = node["maxx"].as<double>();
+      pHist       = new T(name.data(), title.data(), nBinsX, minX, maxX);
+    }
+    // Other types are restricted
+    //else {
+    //  static_assert(false, "CbmQaTask::MakeTable: unsupported type given as a template parameter");
+    //}
+  }
+  catch (const YAML::InvalidNode& exc) {
+    LOG(fatal) << fName << ": error while reading the histogram \"" << nameBase << "\" properties from "
+               << "configuration file \"" << fsConfigName << "\". Please, check the file formatting. \n Tip: probably, "
+               << "there ara mistakes in the obligatory property names, for example, \"nbinsX\" or \"nXBins\" is "
+               << "used instead of \"nbinsx\" etc.";
+  }
+
+  // Register histogram in the folder
+  if (!fpFolderHist) { fpFolderHist = fpFolderRoot->AddFolder("histograms", "Histograms"); }
+  fpFolderHist->Add(pHist);
 
   return pHist;
 }
diff --git a/macro/run/CMakeLists.txt b/macro/run/CMakeLists.txt
index f2965419df60ef7f15b59fe154155c09a9582271..c8846808a37c387d89f6f59384823eee4c792f82 100644
--- a/macro/run/CMakeLists.txt
+++ b/macro/run/CMakeLists.txt
@@ -15,6 +15,11 @@ file(COPY ${CBMROOT_SOURCE_DIR}/macro/include/.rootrc
 	DESTINATION ${CBMROOT_BINARY_DIR}/macro/run)
 # ============================================================================
 
+# =====   Copy configuration file for QA tasks to the build directory ========
+file(COPY ${CBMROOT_SOURCE_DIR}/macro/run/qa_config.cbm.yaml
+	DESTINATION ${CBMROOT_BINARY_DIR}/macro/run)
+# ============================================================================
+
 
 # =====   Define variables for tests   =======================================
 if(${CBM_TEST_MODEL} MATCHES Weekly)
@@ -223,7 +228,7 @@ foreach(setup IN LISTS cbm_setup)
   add_test(${testname} ${MACRODIR}/run_qa.sh
   	\"data/${sname}_coll\" \"data/${sname}_ts\"  \"data/${sname}_ts_eb_real\"
 	\"data/${sname}_coll\" \"data/${sname}_qa\" \"${setup}\" -1
-	\"data/${sname}_sign\" \"data/${sname}_beam\" )
+	\"data/${sname}_sign\" \"data/${sname}_beam\" \"qa_config.cbm.yaml\")
   set_tests_properties(${testname} PROPERTIES
   	TIMEOUT ${timeOutTime}
 	FAIL_REGULAR_EXPRESSION "segmentation violation"
@@ -481,7 +486,7 @@ EndIf() # If(DEFINED ENV{RAW_DATA_PATH} )
 #####################
 # ============================================================================
 
-Install(FILES .rootrc run_tra_file.C run_tra_beam.C run_digi.C run_reco.C run_unpack_online.C run_unpack_tsa.C
+Install(FILES .rootrc run_tra_file.C run_tra_beam.C run_digi.C run_reco.C run_unpack_online.C run_unpack_tsa.C qa_config.cbm.yaml
         DESTINATION share/cbmroot/macro/run
        )
 Install(PROGRAMS run_tests.sh
diff --git a/macro/run/qa_config.cbm.yaml b/macro/run/qa_config.cbm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6d23fa87225a98f1c8e9d22bd8235b746d144a8d
--- /dev/null
+++ b/macro/run/qa_config.cbm.yaml
@@ -0,0 +1,288 @@
+#
+#               -- Configuration for QA tasks --         
+#
+# Configuration file defines histogram properties for different QA 
+# tasks in Full-CBM setup.
+#
+# Properties of histograms:
+#
+# TH1:
+#   title   - title of histogram
+#   nbinsx  - number of bins in the X axis
+#   minx    - lower bound of the X axis
+#   maxx    - upper bound of the X axis
+#
+# TH2:
+#   title   - title of histogram
+#   nbinsx  - number of bins in the X axis
+#   minx    - lower bound of the X axis
+#   maxx    - upper bound of the X axis
+#   nbinsy  - number of bins in the Y axis
+#   miny    - lower bound of the Y axis
+#   maxy    - upper bound of the Y axis
+#
+# TH3:
+#   title   - title of histogram
+#   nbinsx  - number of bins in the X axis
+#   minx    - lower bound of the X axis
+#   maxx    - upper bound of the X axis
+#   nbinsy  - number of bins in the Y axis
+#   miny    - lower bound of the Y axis
+#   maxy    - upper bound of the Y axis
+#   nbinsz  - number of bins in the Z axis
+#   minz    - lower bound of the Z axis
+#   maxz    - upper bound of the Z axis
+#
+# TProfile:
+#   title   - title of the profile
+#   nbinsx  - number of bins in the X axis
+#   minx    - lower bound of the X axis
+#   maxx    - upper bound of the X axis
+#   miny    - lower bound of the Y axis (optional)
+#   maxy    - upper bound of the Y axis (optional)
+#   opt     - option (optional)
+#
+# TProfile2D:
+#   title   - title of the profile
+#   nbinsx  - number of bins in the X axis
+#   minx    - lower bound of the X axis
+#   maxx    - upper bound of the X axis
+#   nbinsy  - number of bins in the Y axis
+#   miny    - lower bound of the Y axis
+#   maxy    - upper bound of the Y axis
+#   minz    - lower bound of the Z axis (optional)
+#   maxz    - upper bound of the Z axis (optional)
+#   opt     - option (optional)
+
+qa:
+  CbmCaOutputQa:
+    histograms:
+      #
+      # Reconstructed tracks distributions
+      #
+      reco_p:
+        title:  "Momentum of reconstructed track;(p/q)_{reco} [GeV/ec]"
+        nbinsx: 150
+        minx:   0.
+        maxx:   15.
+      reco_pt:
+        title:  "Transverse momentum of reconstructed track;(p_{T}/q)_{reco} [GeV/ec]"
+        nbinsx: 100
+        minx:   0.
+        maxx:   10.
+      reco_phi:
+        title:  "Azimuthal angle of reconstructed track;#phi_{reco} [rad]"
+        nbinsx: 68
+        minx:   -3.2
+        maxx:   +3.2
+      reco_tx:
+        title:  "Slope along x-axis of reconstructed tracks;t_{x}"
+        nbinsx: 50
+        minx:   -2.
+        maxx:   +2.
+      reco_ty:
+        title:  "Slope along y-axis of reconstructed tracks;t_{y}" 
+        nbinsx: 50
+        minx:   -2.
+        maxx:   +2.
+      reco_fhitR:
+        title:  "Distance of the first hit from z-axis of reconstructed track;R [cm]" 
+        nbinsx: 50
+        minx:   0.
+        maxx:   150.
+      reco_nhits: 
+        title:  "Number of hits in a reconstructed track;N_{hits}"
+        nbinsx: 10
+        minx:   -0.5
+        maxx:   9.5
+      reco_fsta:
+        title:  "First station of reconstructed track;ID_{f.st.}"
+        nbinsx: 15
+        minx:   -0.5
+        maxx:   14.5
+      reco_purity: 
+        title:  "Purity of reconstructed track;purity [%]"
+        nbinsx: 15
+        minx:   -0.5
+        maxx:   14.5
+      reco_chi2_ndf:
+        title:  "Fit #chi^{2}/NDF of reconstructed track;(#chi^{2}/NDF)_{reco}"
+        nbinsx: 50
+        minx:   -0.5
+        maxx:   99.5
+      reco_prob:
+        title:  "Fit #chi^{2}/NDF of the rest tracks;(#chi^{2}/NDF)_{reco}"
+        nbinsx: 101
+        minx:   0.
+        maxx:   1.01
+      rest_chi2_ndf:
+        title:  "Fit probability of reconstructed track;Prob_{reco}"
+        nbinsx: 50
+        minx:   -0.5
+        maxx:   99.5
+      rest_prob:
+        title:  "Fit probability of the rest tracks;Prob_{reco}"
+        nbinsx: 101
+        minx:   0.
+        maxx:   1.01
+      #
+      # Ghost tracks distributions
+      #
+      ghost_p:
+        title: "Momentum of ghost track;(p/q)_{reco} [GeV/ec]"
+        nbinsx: 150
+        minx:   0.  # Gev/ec
+        maxx:   15. # Gev/ec
+      ghost_pt:
+        title:  "Transverse momentum of ghost track;(p_{T}/q)_{reco} [GeV/ec]"
+        nbinsx: 100
+        minx:   0.
+        maxx:   10.
+      ghost_phi:
+        title:  "Azimuthal angle of ghost track;#phi_{reco} [rad]"
+        nbinsx: 68
+        minx:   -3.2
+        maxx:   +3.2
+      ghost_tx:
+        title:  "Slope along x-axis of ghost tracks;t_{x}"
+        nbinsx: 50
+        minx:   -2.
+        maxx:   +2.
+      ghost_ty:
+        title:  "Slope along y-axis of ghost tracks;t_{y}" 
+        nbinsx: 50
+        minx:   -2.
+        maxx:   +2.
+      ghost_fhitR:
+        title:  "Distance of the first hit from z-axis of ghost track;R [cm]" 
+        nbinsx: 50
+        minx:   0.
+        maxx:   150.
+      ghost_nhits: 
+        title:  "Number of hits in a ghost track;N_{hits}"
+        nbinsx: 10
+        minx:   -0.5
+        maxx:   9.5
+      ghost_fsta:
+        title:  "First station of ghost track;ID_{f.st.}"
+        nbinsx: 15
+        minx:   -0.5
+        maxx:   14.5
+      ghost_purity: 
+        title:  "Purity of ghost track;purity [%]"
+        nbinsx: 15
+        minx:   -0.5
+        maxx:   14.5
+      ghost_chi2_ndf:
+        title:  "Fit #chi^{2}/NDF of ghost track;(#chi^{2}/NDF)_{reco}"
+        nbinsx: 50
+        minx:   -0.5
+        maxx:   99.5
+      ghost_prob:
+        title:  "Fit #chi^{2}/NDF of the ghost track;(#chi^{2}/NDF)_{reco}"
+        nbinsx: 101
+        minx:   0.
+        maxx:   1.01
+      ghost_nhits_vs_p:
+        title:  "Number of hits vs. momentum for ghost track;(p/q)_{reco} [GeV/ec];N_{hits}"
+        nbinsx: 150
+        minx:   0.
+        maxx:   15.
+        nbinsy: 10
+        miny:   -0.5
+        maxy:   9.5
+      ghost_fsta_vs_p:
+        title:  "First station vs. momentum for ghost track;(p/q)_{reco} [GeV/ec];ID_{f.st.}"
+        nbinsx: 150
+        minx:   0.
+        maxx:   15.
+        nbinsy: 15
+        miny:   -0.5
+        maxy:   14.5
+      ghost_lsta_vs_fsta:
+        title:  "Last station vs. first station for ghost track;ID_{first st.};ID_{last st.}"
+        nbinsx: 15
+        minx:   -0.5
+        maxx:   14.5
+        nbinsy: 15
+        miny:   -0.5
+        maxy:   14.5
+      #
+      #  -- Track residuals and pulls --
+      #
+      # Residuals and pulls at first station
+      #
+      fst_res_x:
+        titie:  "Residual of x in first track point;(x_{reco} - x_{MC})[cm]"
+        nbinsx: 160
+        minx:   -4.
+        maxx:   +4.
+      fst_res_y:
+        titie:  "Residual of y in first track point;(y_{reco} - y_{MC})[cm]"
+        nbinsx: 180
+        minx:   -45.
+        maxx:   +45.
+      fst_res_tx:
+        titie:  "Residual of t_{x} in first track point;(t^{reco}_{x} - t^{MC}_{x})"
+        nbinsx: 80
+        minx:   -4.
+        maxx:   +4.
+      fst_res_ty:
+        titie:  "Residual of t_{y} in first track point;(t^{reco}_{y} - t^{MC}_{y})"
+        nbinsx: 80
+        minx:   -4.
+        maxx:   +4.
+      fst_res_qp:
+        titie:  "Residual of q/p in first track point;((q/p)_{reco} - (q/p)_{MC}) [GeV/ec]"
+        nbinsx: 150
+        minx:   -15.
+        maxx:   +15.
+      fst_res_time:
+        titie:  "Residual of time in first track point;((t)_{reco} - (t)_{MC}) [ns]"
+        nbinsx: 100
+        minx:   -10.
+        maxx:   +10.
+      fst_res_v:
+        titie:  "Residual of velocity in first track point;(v_{reco} - v_{MC}) [c]"
+        nbinsx: 100
+        minx:   -10.
+        maxx:   +10.
+      fst_pull_x:
+        titie:  "Pull of x in first track point;(x_{reco} - x_{MC}) / #sigma_{x}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      fst_pull_y:
+        titie:  "Pull of y in first track point;(y_{reco} - y_{MC}) / #sigma_{y}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      fst_pull_tx:
+        titie:  "Pull of t_{x} in first track point;(t^{reco}_{x} - t^{MC}_{x}) / #sigma_{t_{x}}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      fst_pull_ty:
+        titie:  "Pull of t_{y} in first track point;(t^{reco}_{y} - t^{MC}_{y}) / #sigma_{t_{y}}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      fst_pull_qp:
+        titie:  "Pull of q/p in first track point;((q/p)_{reco} - (q/p)_{MC}) / #sigma_{q/p}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      fst_pull_time:
+        titie:  "Pull of time in first track point;((t)_{reco} - (t)_{MC}) / #sigma_{t}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      fst_pull_v:
+        titie:  "Pull of velocity in first track point;(v_{reco} - v_{MC}) / #sigma_{v}"
+        nbinsx: 120
+        minx:   -6.
+        maxx:   +6.
+      
+
+      
+
diff --git a/macro/run/run_qa.C b/macro/run/run_qa.C
index 5a2d18f6edf44b521ded5b1ff8b31b80b476c60f..bb9f10825399cf0bb53351f01f8195af83c09737 100644
--- a/macro/run/run_qa.C
+++ b/macro/run/run_qa.C
@@ -18,17 +18,13 @@
 
 // Includes needed for IDE
 #if !defined(__CLING__)
-#include "CbmCaInputQaMuch.h"
-#include "CbmCaInputQaSts.h"
-#include "CbmCaInputQaTof.h"
-#include "CbmCaInputQaTrd.h"
-#include "CbmCaOutputQa.h"
 #include "CbmDefs.h"
 #include "CbmMCDataManager.h"
 #include "CbmMuchDigitizerQa.h"
 #include "CbmMuchHitFinderQa.h"
 #include "CbmMuchTransportQa.h"
 #include "CbmSetup.h"
+#include "CbmStsFindTracksQa.h"
 
 #include <FairFileSource.h>
 #include <FairMonitor.h>
@@ -45,7 +41,7 @@
 void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "data/sis100_muon_jpsi_test",
             TString dataReco = "data/sis100_muon_jpsi_test", TString dataPar = "data/sis100_muon_jpsi_test",
             TString dataSink = "data/sis100_muon_jpsi_test", TString setup = "sis100_muon_jpsi", Int_t nEvents = -1,
-            TString dataTra2 = "", TString dataTra3 = "")
+            TString dataTra2 = "", TString dataTra3 = "", const char* configName = "./qa_config.fcbm.yaml")
 {
 
   gROOT->SetBatch(kTRUE);
@@ -58,9 +54,12 @@ void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "d
   fair::Logger::DefineVerbosity(
     "user1", fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity, fair::VerbositySpec::Info::file_line));
   FairLogger::GetLogger()->SetLogVerbosityLevel("user1");
+  FairLogger::GetLogger()->SetColoredLog(true);
   // ------------------------------------------------------------------------
 
   // -----   Environment   --------------------------------------------------
+  bool bUseMC    = true;  // MC flag: used or not
+  int verbose    = 3;
   TString myName = "run_qa";                       // this macro's name for screen output
   TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
   // ------------------------------------------------------------------------
@@ -78,8 +77,9 @@ void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "d
   // -----   Load the geometry setup   -------------------------------------
   std::cout << std::endl;
   std::cout << "-I- " << myName << ": Loading setup " << setup << std::endl;
-  CbmSetup* geo = CbmSetup::Instance();
+  auto* geo = CbmSetup::Instance();
   geo->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
@@ -96,6 +96,13 @@ void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "d
   bool bUseTrd  = geo->IsActive(ECbmModuleId::kTrd);
   bool bUseTof  = geo->IsActive(ECbmModuleId::kTof);
   bool bUsePsd  = geo->IsActive(ECbmModuleId::kPsd);
+  std::cout << "  MVD: " << (bUseMvd ? "ON" : "OFF") << '\n';
+  std::cout << "  STS: " << (bUseSts ? "ON" : "OFF") << '\n';
+  std::cout << "  RICH: " << (bUseRich ? "ON" : "OFF") << '\n';
+  std::cout << "  MUCH: " << (bUseMuch ? "ON" : "OFF") << '\n';
+  std::cout << "  TRD: " << (bUseTrd ? "ON" : "OFF") << '\n';
+  std::cout << "  TOF: " << (bUseTof ? "ON" : "OFF") << '\n';
+  std::cout << "  PSD: " << (bUsePsd ? "ON" : "OFF") << '\n';
   // ------------------------------------------------------------------------
 
   // -----   Parameter files as input to the runtime database   -------------
@@ -173,6 +180,7 @@ void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "d
   mcManager->AddFile(traFile);
   if (!dataTra2.IsNull()) mcManager->AddFile(tra2File);
   if (!dataTra3.IsNull()) mcManager->AddFile(tra3File);
+
   run->AddTask(mcManager);
   // ------------------------------------------------------------------------
 
@@ -189,6 +197,10 @@ void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "d
     CbmMuchHitFinderQa* muchHitFinderQa = new CbmMuchHitFinderQa();
     muchHitFinderQa->SetGeoFileName(muchParFile);
     run->AddTask(muchHitFinderQa);
+
+    auto* pCaInputQaMuch = new CbmCaInputQaMuch(verbose, bUseMC);
+    pCaInputQaMuch->SetEfficiencyThrsh(0.5, 0, 100);
+    run->AddTask(pCaInputQaMuch);
   }
 
   // ----- TRD QA  ---------------------------------
@@ -206,36 +218,43 @@ void run_qa(TString dataTra = "data/sis100_muon_jpsi_test", TString dataRaw = "d
     run->AddTask(trdHitProducerQa);
     run->AddTask(new CbmTrdCalibTracker());
     run->AddTask(new CbmTrackerInputQaTrd());  // Tracker requirements to TRD
+    auto* pCaInputQaTrd = new CbmCaInputQaTrd(verbose, bUseMC);
+    pCaInputQaTrd->SetEfficiencyThrsh(0.5, 0, 100);
+    run->AddTask(pCaInputQaTrd);
   }
   // ------------------------------------------------------------------------
 
   // ----- TOF QA  ---------------------------------
   if (CbmSetup::Instance()->IsActive(ECbmModuleId::kTof)) {
     //run->AddTask(new CbmTrackerInputQaTof());  // Tracker requirements to TOF
+    auto* pCaInputQaTof = new CbmCaInputQaTof(verbose, bUseMC);
+    pCaInputQaTof->SetEfficiencyThrsh(0.5, 0, 100);
+    run->AddTask(pCaInputQaTof);
   }
   // ------------------------------------------------------------------------
 
   // ----- STS QA  ---------------------------------
   if (CbmSetup::Instance()->IsActive(ECbmModuleId::kSts)) {
     //run->AddTask(new CbmStsDigitizeQa()); //opens lots of windows
-    //run->AddTask(new CbmStsFindTracksQa());
-    //run->AddTask(new CbmTrackingInputQaSts());
+    run->AddTask(new CbmStsFindTracksQa());
+    auto* pCaInputQaSts = new CbmCaInputQaSts(verbose, bUseMC);
+    pCaInputQaSts->SetEfficiencyThrsh(0.5, 0, 100);
+    run->AddTask(pCaInputQaSts);
   }
   // ------------------------------------------------------------------------
 
-  // ----- Event builder QA  ------------------------------------------------
+  // ----- Event builder QA  ---------------------------------
   CbmBuildEventsQa* evBuildQA = new CbmBuildEventsQa();
-  //run->AddTask(evBuildQA);
+  run->AddTask(evBuildQA);
   // ------------------------------------------------------------------------
 
   // ----- Tracking QA ------------------------------------------------------
-  int verbose       = 3;
-  bool isMCUsed     = true;
   TString caParFile = recFile;
   caParFile.ReplaceAll(".root", ".L1Parameters.dat");
 
-  auto* pCaOutputQa = new cbm::ca::OutputQa(verbose, isMCUsed);
+  auto* pCaOutputQa = new cbm::ca::OutputQa(verbose, bUseMC);
   pCaOutputQa->SetStsTrackingMode();
+  pCaOutputQa->SetConfigName(configName);
   pCaOutputQa->ReadParameters(caParFile.Data());
   pCaOutputQa->SetUseMvd(bUseMvd);
   pCaOutputQa->SetUseSts(bUseSts);
diff --git a/reco/L1/CbmCaMCModule.cxx b/reco/L1/CbmCaMCModule.cxx
index 126cc20bda252e963c7e4fe1645bd6cdb2f55663..3f56f34819c291638755e228493413d5d906e5c6 100644
--- a/reco/L1/CbmCaMCModule.cxx
+++ b/reco/L1/CbmCaMCModule.cxx
@@ -115,13 +115,6 @@ try {
 
   LOG(info) << "CA MC Module: initializing CA tracking Monte-Carlo module... \033[1;32mDone!\033[0m";
 
-  LOG(info) << "Detector subsystems used:";
-  LOG(info) << "\tMVD:  " << (fbUseMvd ? "ON" : "OFF");
-  LOG(info) << "\tSTS:  " << (fbUseSts ? "ON" : "OFF");
-  LOG(info) << "\tMuCh: " << (fbUseMuch ? "ON" : "OFF");
-  LOG(info) << "\tTRD:  " << (fbUseTrd ? "ON" : "OFF");
-  LOG(info) << "\tTOF:  " << (fbUseTof ? "ON" : "OFF");
-
   return true;
 }
 catch (const std::logic_error& error) {
@@ -134,9 +127,7 @@ catch (const std::logic_error& error) {
 //
 void CbmCaMCModule::InitEvent(CbmEvent* /*pEvent*/)
 {
-  std::cout << "\033[1;32mCALL CbmCAMCModule::InitEvent\033[0m\n";
-
-  // ------ Fill a set of file and event indexes
+  // Fill a set of file and event indexes
   fFileEventIDs.clear();
   if (fbLegacyEventMode) {
     int iFile  = FairRunAna::Instance()->GetEventHeader()->GetInputFileId();
@@ -152,18 +143,19 @@ void CbmCaMCModule::InitEvent(CbmEvent* /*pEvent*/)
     }
   }
 
-  // ------ Read data
+  // Read data
   fpMCData->Clear();
   this->ReadMCTracks();
   this->ReadMCPoints();
-  L1_SHOW(fpMCData->GetNofTracks());
-  L1_SHOW(fpMCData->GetNofPoints());
 
-  // ------ Prepare tracks: set point indexes and redefine indexes from external to internal containers
+  // Prepare tracks: set point indexes and redefine indexes from external to internal containers
   for (auto& aTrk : fpMCData->GetTrackContainer()) {
     aTrk.SortPointIndexes(
       [&](const int& iPl, const int& iPr) { return fpMCData->GetPoint(iPl).GetZ() < fpMCData->GetPoint(iPr).GetZ(); });
   }
+
+  // ------ Match reconstructed and MC data
+  this->MatchRecoAndMC();
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -172,16 +164,14 @@ void CbmCaMCModule::ProcessEvent(CbmEvent*) {}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void CbmCaMCModule::InitTrackInfo(const L1Vector<CbmL1HitDebugInfo>& vHits)
+void CbmCaMCModule::InitTrackInfo()
 {
-  LOG(info) << "\033[1;32m!!!! FLAG 1\033[0m";
   // ----- Initialize stations arrangement and hit indexes
-  fpMCData->InitTrackInfo(vHits);
+  fpMCData->InitTrackInfo(*fpvQaHits);
 
-  LOG(info) << "\033[1;32m!!!! FLAG 2\033[0m";
   // ----- Define reconstructable and additional flags
   for (auto& aTrk : fpMCData->GetTrackContainer()) {
-    bool isRec = true;  // is track reconstructable
+    bool isRec = true;  // the track can be reconstructed
 
     // Cut on momentum
     isRec &= aTrk.GetP() > CbmL1Constants::MinRecoMom;
@@ -213,7 +203,6 @@ void CbmCaMCModule::InitTrackInfo(const L1Vector<CbmL1HitDebugInfo>& vHits)
     aTrk.SetFlagReconstructable(isRec);
     aTrk.SetFlagAdditional(isAdd);
   }
-  LOG(info) << "\033[1;32m!!!! FLAG 3\033[0m";
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -227,32 +216,21 @@ void CbmCaMCModule::Finish() {}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void CbmCaMCModule::MatchPointsWithHits()
+void CbmCaMCModule::MatchRecoAndMC()
 {
-  // FIXME: Cleaning up makes it safer, but probably is not needed after old code removal
-  for (auto& hit : (*fpvHitIds)) {
-    hit.mcPointIds.clear();
-  }
-
-  int nHits = fpvHitIds->size();
-  for (int iH = 0; iH < nHits; ++iH) {
-    auto& hit = (*fpvHitIds)[iH];
-    int iP    = fpMCData->GetPointIndexOfHit(iH);
-    if (iP > -1) {
-      hit.mcPointIds.push_back_no_warning(iP);
-      fpMCData->GetPoint(iP).AddHitID(iH);
-    }
-  }  // loop over hit indexes: end
+  this->MatchPointsAndHits();
+  this->MatchRecoAndMCTracks();
+  this->InitTrackInfo();
 }
 
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<>
-int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kMvd>(int iHit) const
+int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kMvd>(int iHitExt) const
 {
   int iPoint = -1;
   if (fpMvdHitMatches) {
-    int iHitExt          = -(1 + iHit);  // TODO: SZh 28.08.2022: this should be replaced with iHitExt = hit.extIdex
     const auto* hitMatch = dynamic_cast<CbmMatch*>(fpMvdHitMatches->At(iHitExt));
     assert(hitMatch);
     if (hitMatch->GetNofLinks() > 0 && hitMatch->GetLink(0).GetIndex() < fvNofPointsUsed[int(L1DetectorID::kMvd)]) {
@@ -265,10 +243,10 @@ int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kMvd>(int iHit) const
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<>
-int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kSts>(int iHit) const
+int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kSts>(int iHitExt) const
 {
   int iPoint     = -1;
-  const auto* sh = dynamic_cast<CbmStsHit*>(fpStsHits->At(iHit));
+  const auto* sh = dynamic_cast<CbmStsHit*>(fpStsHits->At(iHitExt));
 
   // Match MC point
   if (fpStsClusterMatches) {
@@ -321,10 +299,10 @@ int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kSts>(int iHit) const
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<>
-int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kMuch>(int iHit) const
+int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kMuch>(int iHitExt) const
 {
   int iPoint               = -1;
-  const auto* hitMatchMuch = dynamic_cast<CbmMatch*>(fpMuchHitMatches->At(iHit));
+  const auto* hitMatchMuch = dynamic_cast<CbmMatch*>(fpMuchHitMatches->At(iHitExt));
   if (hitMatchMuch) {
     for (int iLink = 0; iLink < hitMatchMuch->GetNofLinks(); ++iLink) {
       if (hitMatchMuch->GetLink(iLink).GetIndex() < fvNofPointsUsed[int(L1DetectorID::kMuch)]) {
@@ -346,10 +324,10 @@ int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kMuch>(int iHit) const
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<>
-int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kTrd>(int iHit) const
+int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kTrd>(int iHitExt) const
 {
   int iPoint           = -1;
-  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fpTrdHitMatches->At(iHit));
+  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fpTrdHitMatches->At(iHitExt));
   if (hitMatch) {
     int iMC = -1;
     if (hitMatch->GetNofLinks() > 0) {
@@ -371,10 +349,10 @@ int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kTrd>(int iHit) const
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<>
-int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kTof>(int iHit) const
+int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kTof>(int iHitExt) const
 {
   int iPoint           = -1;
-  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fpTofHitMatches->At(iHit));
+  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fpTofHitMatches->At(iHitExt));
   if (hitMatch) {
     for (int iLink = 0; iLink < hitMatch->GetNofLinks(); ++iLink) {
       int iMc    = hitMatch->GetLink(iLink).GetIndex();
@@ -391,6 +369,55 @@ int CbmCaMCModule::MatchHitWithMc<L1DetectorID::kTof>(int iHit) const
   return iPoint;
 }
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmCaMCModule::MatchPointsAndHits()
+{
+  // Clear point indexes of each hit
+  // NOTE: at the moment only the best point is stored to the hit, but we keep the possibility for keeping many
+  //       points for possible future module extension.
+  for (auto& hit : (*fpvQaHits)) {
+    hit.mcPointIds.clear();
+  }
+
+  // Match hit with point for different detectors
+  auto DoMatch = [&](int iH, int iP) constexpr
+  {
+    if (iP > -1) {
+      auto& hit = (*fpvQaHits)[iH];
+      hit.mcPointIds.push_back_no_warning(iP);
+      fpMCData->GetPoint(iP).AddHitID(iH);
+    }
+  };
+
+  int iH = 0;
+  if (fbUseMvd) {
+    for (iH = (*fpvFstHitId)[int(L1DetectorID::kMvd)]; iH < (*fpvFstHitId)[int(L1DetectorID::kMvd) + 1]; ++iH) {
+      DoMatch(iH, MatchHitWithMc<L1DetectorID::kMvd>((*fpvQaHits)[iH].ExtIndex));
+    }
+  }
+  if (fbUseSts) {
+    for (iH = (*fpvFstHitId)[int(L1DetectorID::kSts)]; iH < (*fpvFstHitId)[int(L1DetectorID::kSts) + 1]; ++iH) {
+      DoMatch(iH, MatchHitWithMc<L1DetectorID::kSts>((*fpvQaHits)[iH].ExtIndex));
+    }
+  }
+  if (fbUseSts) {
+    for (iH = (*fpvFstHitId)[int(L1DetectorID::kMuch)]; iH < (*fpvFstHitId)[int(L1DetectorID::kMuch) + 1]; ++iH) {
+      DoMatch(iH, MatchHitWithMc<L1DetectorID::kMuch>((*fpvQaHits)[iH].ExtIndex));
+    }
+  }
+  if (fbUseTrd) {
+    for (iH = (*fpvFstHitId)[int(L1DetectorID::kTrd)]; iH < (*fpvFstHitId)[int(L1DetectorID::kTrd) + 1]; ++iH) {
+      DoMatch(iH, MatchHitWithMc<L1DetectorID::kTrd>((*fpvQaHits)[iH].ExtIndex));
+    }
+  }
+  if (fbUseTof) {
+    for (iH = (*fpvFstHitId)[int(L1DetectorID::kTof)]; iH < (*fpvFstHitId)[int(L1DetectorID::kTof) + 1]; ++iH) {
+      DoMatch(iH, MatchHitWithMc<L1DetectorID::kTof>((*fpvQaHits)[iH].ExtIndex));
+    }
+  }
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void CbmCaMCModule::MatchRecoAndMCTracks()
@@ -402,7 +429,7 @@ void CbmCaMCModule::MatchRecoAndMCTracks()
     auto& mNofHitsVsMCTrkID = trkRe.hitMap;
     mNofHitsVsMCTrkID.clear();
     for (int iH : trkRe.Hits) {
-      for (int iP : (*fpvHitIds)[iH].mcPointIds) {
+      for (int iP : (*fpvQaHits)[iH].mcPointIds) {
         assert(iP > -1);  // Should never be triggered
         int iTmc = fpMCData->GetPoint(iP).GetTrackId();
         if (mNofHitsVsMCTrkID.find(iTmc) == mNofHitsVsMCTrkID.end()) { mNofHitsVsMCTrkID[iTmc] = 1; }
@@ -472,20 +499,18 @@ void CbmCaMCModule::SetDetector(L1DetectorID detID, bool flag)
 //
 void CbmCaMCModule::CheckInit() const
 {
-  // ----- Check parameters
+  // Check parameters
   if (!fpParameters.get()) { throw std::logic_error("Tracking parameters object was not defined"); }
 
+  // Check output data containers
   if (!fpMCData) { throw std::logic_error("MC data object was not registered"); }
-
   if (!fpvRecoTracks) { throw std::logic_error("Reconstructed track container was not registered"); }
-
   if (!fpvHitIds) { throw std::logic_error("Hit index container was not registered"); }
-
-  if (!fpInputData) { throw std::logic_error("Input data object was not registered"); }
+  if (!fpvQaHits) { throw std::logic_error("QA hit container was not registered"); }
+  if (!fpvFstHitId) { throw std::logic_error("Array of first hit indexes in each detector was not registered"); }
 
   // Check event list
   if (!fbLegacyEventMode && !fpMCEventList) { throw std::logic_error("MC event list was not found"); }
-
   if (!fbLegacyEventMode && !fpTimeSlice) { throw std::logic_error("Time slice was not found"); }
 
   // Tracks branch
@@ -716,7 +741,7 @@ void CbmCaMCModule::ReadMCTracks()
       else {
         // This is a secondary track, mother ID should be recalculated for the internal array
         int motherId = fpMCData->FindInternalTrackIndex(extMotherId, iEvent, iFile);
-        assert(motherId > -1);
+        if (motherId == -1) { motherId = -3; }  // Mother is neutral particle, which is rejected
         aTrk.SetMotherId(motherId);
       }
 
diff --git a/reco/L1/CbmCaMCModule.h b/reco/L1/CbmCaMCModule.h
index 224fa600314c830755a22794ddb68e9bffc633a2..61efa6695f364d21096c262bbe5e5d9428cbf075 100644
--- a/reco/L1/CbmCaMCModule.h
+++ b/reco/L1/CbmCaMCModule.h
@@ -11,6 +11,7 @@
 #define CbmCaMCModule_h 1
 
 #include "CbmL1DetectorID.h"
+#include "CbmL1Hit.h"
 #include "CbmL1Track.h"
 #include "CbmLink.h"
 #include "CbmMCDataArray.h"
@@ -95,41 +96,28 @@ public:
   bool InitRun();
 
   /// @brief  Initializes MC track
-  /// @param  vHits  Vector of hit objects
   ///
   /// Initializes information about arrangement of points and hits of MC tracks within stations and the status
-  /// of track reconstructability, calculates max number of points and hits on a station, number of consecutive
-  /// stations containing a hit or point and number of stations and points with hits. Provides the determination
-  /// of track reconstructability status.
-  void InitTrackInfo(const L1Vector<CbmL1HitDebugInfo>& vHits);
+  /// of track ability to be reconstructed, calculates max number of points and hits on a station, number of
+  /// consecutive stations containing a hit or point and number of stations and points with hits.
+  void InitTrackInfo();
+
+  /// @brief Match reconstructed and MC data
+  ///
+  /// Runs matching of hits with points and reconstructed tracks with
+  void MatchRecoAndMC();
 
   /// @brief Processes event
   ///
   /// Fills histograms and tables, should be called after the tracking done
   void ProcessEvent(CbmEvent* pEvent);
 
-  /// @brief Matches hit with MC point
-  /// @tparam  DetId Detector ID
-  /// @param   iHit  External index of hit
-  /// @return        MC-point index in fvMCPoints array
-  ///
-  /// This method finds a match for a given hit or matches for hits clusters (in case of STS), finds the best
-  /// link in the match and returns the corresponding global ID of the MC points
-  template<L1DetectorID DetId>
-  int MatchHitWithMc(int iHit) const;
-
-  /// @brief Assigns MC point indexes to each hit and hit indexes to each MC point
-  void MatchPointsWithHits();
-
-  /// @brief Matches reconstructed tracks with MC tracks
-  ///
-  /// In the procedure, the maps of associated MC track indexes to corresponding number of hits are filled out and the
-  /// max purity is calculated for each reconstructed track in the TS/event. If the value of purity for a given MC track
-  /// is larger then a threshold, the corresponding track index is saved to the reconstructed track object, in the same
-  /// time the index of the reconstructed track object is saved to this MC track object. If purity for the MC track does
-  /// not pass the threshold, its index will not be accounted as a matched track, and the index of reconstructed track
-  /// will be added as an index of "touched" track.
-  void MatchRecoAndMCTracks();
+  /// @brief Sets first hit indexes container in different detectors
+  /// @param source Array of indexes
+  void RegisterFirstHitIndexes(const std::array<int, L1Constants::size::kMaxNdetectors + 1>& source)
+  {
+    fpvFstHitId = &source;
+  }
 
   /// @brief Sets used detector subsystems
   /// @param  detID  Id of detector
@@ -153,28 +141,23 @@ public:
 
   /// @brief Registers hit index container
   /// @param vHitIds  Reference to hit index container
-  void RegisterHitIndexContainer(L1Vector<CbmL1HitDebugInfo>& vHitIds) { fpvHitIds = &vHitIds; }
-
-  /// @brief Registers input data object
-  /// @param inputData  Instance of the input data object
-  void RegisterInputData(L1InputData& inputData) { fpInputData = &inputData; }
-
-  // /// @brief Registers debug hit container
-  // /// @param vDbgHits  Reference to debug hit container
-  // void RegisterHitDebugInfoContainer(L1Vector<CbmL1HitStore>& vDbgHits) { fpvDbgHits = &vDbgHits; }
+  void RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds) { fpvHitIds = &vHitIds; }
 
   /// @brief Registers CA parameters object
   /// @param pParameters  A shared pointer to the parameters object
   void RegisterParameters(std::shared_ptr<L1Parameters>& pParameters) { fpParameters = pParameters; }
 
+  /// @brief Registers debug hit container
+  /// @param vQaHits  Reference to debug hit container
+  void RegisterQaHitContainer(L1Vector<CbmL1HitDebugInfo>& vQaHits) { fpvQaHits = &vQaHits; }
 
 private:
   /// @brief Calculates global index of MC point
   /// @param  iPointLocal  Local index of MC point
   /// @param  detID        Detector ID
   ///
-  /// Calculates global index of MC point as a sum of a given local index and total provided number of points in previous
-  /// detector subsystem
+  /// The function calculates global index of MC point as a sum of a given local index and total provided number of
+  /// points in previous detector subsystem.
   int CalcGlobMCPointIndex(int iPointLocal, L1DetectorID detID) const
   {
     return iPointLocal + std::accumulate(fvNofPointsOrig.cbegin(), fvNofPointsOrig.cbegin() + int(detID), 0);
@@ -184,6 +167,31 @@ private:
   /// @note The function throws std::logic_error, if initialization is incomplete
   void CheckInit() const;
 
+  /// @brief Matches hit with MC point
+  /// @tparam  DetId Detector ID
+  /// @param   iHitExt  External index of hit
+  /// @return           MC-point index in fvMCPoints array
+  ///
+  /// This method finds a match for a given hit or matches for hits clusters (in case of STS), finds the best
+  /// link in the match and returns the corresponding global ID of the MC points.
+  template<L1DetectorID DetId>
+  int MatchHitWithMc(int iHitExt) const;
+
+  /// @brief Match MC points and reconstructed hits
+  ///
+  /// Writes indexes of MC points to each hit and indexes of hits to each MC point.
+  void MatchPointsAndHits();
+
+  /// @brief Matches reconstructed tracks with MC tracks
+  ///
+  /// In the procedure, the maps of associated MC track indexes to corresponding number of hits are filled out and the
+  /// max purity is calculated for each reconstructed track in the TS/event. If the value of purity for a given MC track
+  /// is larger then a threshold, the corresponding track index is saved to the reconstructed track object, in the same
+  /// time the index of the reconstructed track object is saved to this MC track object. If purity for the MC track does
+  /// not pass the threshold, its index will not be accounted as a matched track, and the index of reconstructed track
+  /// will be added as an index of "touched" track.
+  void MatchRecoAndMCTracks();
+
   /// @brief Reads MC tracks from external trees and saves them to MCDataObject
   void ReadMCTracks();
 
@@ -205,7 +213,6 @@ private:
   template<L1DetectorID DetID>
   bool FillMCPoint(int iExtId, int iEvent, int iFile, ca::tools::MCPoint& point);
 
-
   std::shared_ptr<L1Parameters> fpParameters = nullptr;  ///< Pointer to tracking parameters object
 
   // ------ Flags
@@ -234,8 +241,8 @@ private:
   CbmMCDataArray* fpTrdPoints  = nullptr;  ///< TRD MC-points input container
   CbmMCDataArray* fpTofPoints  = nullptr;  ///< TOF MC-points input container
 
-  std::array<int, L1Constants::size::kMaxNdetectors> fvNofPointsOrig = {};  ///< Number of points by detector provided
-  std::array<int, L1Constants::size::kMaxNdetectors> fvNofPointsUsed = {};  ///< Number of points used in performance
+  std::array<int, L1Constants::size::kMaxNdetectors> fvNofPointsOrig = {0};  ///< Number of points by detector provided
+  std::array<int, L1Constants::size::kMaxNdetectors> fvNofPointsUsed = {0};  ///< Number of points used in performance
 
   // Matches
   TClonesArray* fpMvdHitMatches  = nullptr;  ///< Array of MVD hit matches
@@ -250,13 +257,18 @@ private:
   // Matching information
   std::set<std::pair<int, int>> fFileEventIDs;  ///< Set of file and event indexes: first - iFile, second - iEvent
 
-  ca::tools::MCData* fpMCData = nullptr;  ///< MC-information in CA tracking internal format (tracks and points)
+  // MC data
+  ca::tools::MCData* fpMCData = nullptr;  ///< MC information (hits and tracks) instance
 
   // Reconstructed data
-  L1Vector<CbmL1Track>* fpvRecoTracks = nullptr;  ///< Pointer to reconstructed track container
-  L1Vector<CbmL1HitDebugInfo>* fpvHitIds       = nullptr;  ///< Pointer to hit index container
-  //L1Vector<CbmL1HitStore>* fpvDbgHits = nullptr;  ///< Pointer to debug hit container
-  L1InputData* fpInputData = nullptr;  ///< Pointer to input data object
+  L1Vector<CbmL1Track>* fpvRecoTracks    = nullptr;  ///< Pointer to reconstructed track container
+  L1Vector<CbmL1HitId>* fpvHitIds        = nullptr;  ///< Pointer to hit index container
+  L1Vector<CbmL1HitDebugInfo>* fpvQaHits = nullptr;  ///< Pointer to QA hit container
+
+  /// @brief Pointer to array of first hit indexes in the detector subsystem
+  ///
+  /// This array must be initialized in the run initialization function.
+  const std::array<int, L1Constants::size::kMaxNdetectors + 1>* fpvFstHitId = nullptr;
 };
 
 // **********************************************
diff --git a/reco/L1/CbmCaTimeSliceReader.cxx b/reco/L1/CbmCaTimeSliceReader.cxx
index 8c85c555b1103f71825db762bb45b2dad881efaa..1f55a04df68bee7ba2af52396b25e8661cedcfde 100644
--- a/reco/L1/CbmCaTimeSliceReader.cxx
+++ b/reco/L1/CbmCaTimeSliceReader.cxx
@@ -23,6 +23,7 @@
 using cbm::ca::TimeSliceReader;
 using L1Constants::clrs::kCL;   // clear log
 using L1Constants::clrs::kGNb;  // green bold log
+using L1Constants::clrs::kRDb;  // red bold log
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -41,6 +42,7 @@ void TimeSliceReader::Clear()
 
   // Input branches
   fpBrTimeSlice = nullptr;
+  fpParameters  = nullptr;
 
   fpBrMvdHits  = nullptr;
   fpBrStsHits  = nullptr;
@@ -56,15 +58,51 @@ void TimeSliceReader::Clear()
 
   // Pointers to output containers
   fpvHitIds       = nullptr;
-  fpvDbgHits      = nullptr;
+  fpvQaHits       = nullptr;
   fpIODataManager = nullptr;
   fpvTracks       = nullptr;
+
+  fNofHits     = 0;
+  fNofHitKeys  = 0;
+  fFirstHitKey = 0;
+
+  std::fill(fvHitFirstIndexDet.begin(), fvHitFirstIndexDet.end(), 0);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TimeSliceReader::InitRun()
+void TimeSliceReader::CheckInit() const
 {
+  // Check parameters
+  if (!fpParameters.get()) { throw std::logic_error("Tracking parameters object was not defined"); }
+  if (!fpvHitIds) { throw std::logic_error("Hit index container was not defined"); }
+
+  if (!fpBrTimeSlice) { throw std::logic_error("Time slice branch is unavailable"); }
+
+  if (fbUseMvd && !fpBrMvdHits) { throw std::logic_error("MVD hits branch is unavailable"); }
+  if (fbUseSts && !fpBrStsHits) { throw std::logic_error("STS hits branch is unavailable"); }
+  if (fbUseMuch && !fpBrMuchHits) { throw std::logic_error("MuCh hits branch is unavailable"); }
+  if (fbUseTrd && !fpBrTrdHits) { throw std::logic_error("TRD hits branch is unavailable"); }
+  if (fbUseTof && !fpBrTofHits) { throw std::logic_error("TOF hits branch is unavailable"); }
+
+  if (fpvTracks) {
+    if (ECbmTrackingMode::kSTS == fTrackingMode) {
+      if (!fpBrRecoTracks) { throw std::logic_error("StsTrack branch is unavailable"); }
+    }
+    else if (ECbmTrackingMode::kMCBM == fTrackingMode) {
+      if (!fpBrRecoTracks) { throw std::logic_error("GlobalTrack branch is unavailable"); }
+      if (fbUseSts && !fpBrStsTracks) { throw std::logic_error("StsTrack branch is unavailable"); }
+      if (fbUseMuch && !fpBrMuchTracks) { throw std::logic_error("MuchTrack branch is unavailable"); }
+      if (fbUseTrd && !fpBrRecoTracks) { throw std::logic_error("TrdTrack branch is unavailable"); }
+      if (fbUseTof && !fpBrRecoTracks) { throw std::logic_error("TofTrack branch is unavailable"); }
+    }
+  }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool TimeSliceReader::InitRun()
+try {
   LOG(info) << "TimeSliceReader: initializing run ... ";
 
   // Init tracking detector interfaces
@@ -80,70 +118,48 @@ void TimeSliceReader::InitRun()
   LOG_IF(fatal, !pFairManager) << "TimeSliceReader: FairRootManager was not defined";
 
   fpBrTimeSlice = dynamic_cast<CbmTimeSlice*>(pFairManager->GetObject("TimeSlice."));
-  LOG_IF(fatal, !fpBrTimeSlice) << "TimeSliceReader: time slice was not defined";
 
   // Init hit branches
-  if (fbUseMvd) {
-    fpBrMvdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MvdHit"));
-    LOG_IF(fatal, !fpBrMvdHits) << "TimeSliceReader: MVD hits were not found";
-  }
-
-  if (fbUseSts) {
-    fpBrStsHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsHit"));
-    LOG_IF(fatal, !fpBrStsHits) << "TimeSliceReader: STS hits were not found";
-  }
-
-  if (fbUseMuch) {
-    fpBrMuchHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchPixelHit"));
-    LOG_IF(fatal, !fpBrMuchHits) << "TimeSliceReader: MuCh hits were not found";
-  }
-
-  if (fbUseTrd) {
-    fpBrTrdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdHit"));
-    LOG_IF(fatal, !fpBrTrdHits) << "TimeSliceReader: TRD hits were not found";
-  }
-
-  if (fbUseTof) {
-    fpBrTofHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofHit"));
-    LOG_IF(fatal, !fpBrTofHits) << "TimeSliceReader: TOF hits were not found";
-  }
+  if (fbUseMvd) { fpBrMvdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MvdHit")); }
+  if (fbUseSts) { fpBrStsHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsHit")); }
+  if (fbUseMuch) { fpBrMuchHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchPixelHit")); }
+  if (fbUseTrd) { fpBrTrdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdHit")); }
+  if (fbUseTof) { fpBrTofHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofHit")); }
 
   // Init track branches
   if (fpvTracks) {
     switch (fTrackingMode) {
       case ECbmTrackingMode::kSTS:
         fpBrRecoTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack"));
-        LOG_IF(fatal, !fpBrRecoTracks) << "TimeSliceReader: StsTrack not found";
         break;
       case ECbmTrackingMode::kMCBM:
         fpBrRecoTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("GlobalTrack"));
-        LOG_IF(fatal, !fpBrRecoTracks) << "TimeSliceReader: GlobalTrack not found";
-        if (fbUseSts) {
-          fpBrStsTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack"));
-          LOG_IF(fatal, !fpBrStsTracks) << "TimeSliceReader: StsTrack not found";
-        }
-        if (fbUseMuch) {
-          fpBrMuchTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchTrack"));
-          LOG_IF(fatal, !fpBrMuchTracks) << "TimeSliceReader: MuchTrack not found";
-        }
-        if (fbUseTrd) {
-          fpBrTrdTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdTrack"));
-          LOG_IF(fatal, !fpBrTrdTracks) << "TimeSliceReader: TrdTrack not found";
-        }
-        if (fbUseTof) {
-          fpBrTofTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofTrack"));
-          LOG_IF(fatal, !fpBrTofTracks) << "TimeSliceReader: TofTrack not found";
-        }
+        if (fbUseSts) { fpBrStsTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack")); }
+        if (fbUseMuch) { fpBrMuchTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchTrack")); }
+        if (fbUseTrd) { fpBrTrdTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdTrack")); }
+        if (fbUseTof) { fpBrTofTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofTrack")); }
         break;
     }
   }
 
+  // Check initialization
+  this->CheckInit();
+
   LOG(info) << "TimeSliceReader: initializing run ... " << kGNb << "done" << kCL;
+  return true;
+}
+catch (const std::logic_error& error) {
+  LOG(info) << "TimeSliceReader: initializing run ... " << kRDb << "failed" << kCL << "\nReason: " << error.what();
+  return false;
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TimeSliceReader::InitTimeSlice() { LOG(info) << "TimeSliceReader: initializing time slice"; }
+void TimeSliceReader::InitTimeSlice()
+{
+  this->ReadHits();
+  this->ReadRecoTracks();
+}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -162,21 +178,58 @@ void TimeSliceReader::ReadHits()
   if (fbUseTof) { nHitsTot += fpBrTofHits->GetEntriesFast(); }
 
   // Resize the containers
-  fpvHitIds->clear();
-  fpvHitIds->reserve(nHitsTot);
-  fpvDbgHits->clear();
-  fpvDbgHits->reserve(nHitsTot);
-  fpIODataManager->ResetInputData();
-  fpIODataManager->ReserveNhits(nHitsTot);
+  if (fpvHitIds) {
+    fpvHitIds->clear();
+    fpvHitIds->reserve(nHitsTot);
+  }
+  if (fpvQaHits) {
+    fpvQaHits->clear();
+    fpvQaHits->reserve(nHitsTot);
+  }
+  if (fpIODataManager) {
+    fpIODataManager->ResetInputData();
+    fpIODataManager->ReserveNhits(nHitsTot);
+  }
+
+  std::fill(fvHitFirstIndexDet.begin(), fvHitFirstIndexDet.end(), 0);
+
+  // Save number of hits stored
+  std::array<int, L1Constants::size::kMaxNdetectors> vNofHits = {0};
 
   // Read hits for different detectors
-  if (fbUseMvd) { fNofHits += ReadHitsForDetector<L1DetectorID::kMvd>(fpBrMvdHits); }
-  if (fbUseSts) { fNofHits += ReadHitsForDetector<L1DetectorID::kSts>(fpBrStsHits); }
-  if (fbUseMuch) { fNofHits += ReadHitsForDetector<L1DetectorID::kMuch>(fpBrMuchHits); }
-  if (fbUseTrd) { fNofHits += ReadHitsForDetector<L1DetectorID::kTrd>(fpBrTrdHits); }
-  if (fbUseTof) { fNofHits += ReadHitsForDetector<L1DetectorID::kTof>(fpBrTofHits); }
+  if (fbUseMvd) { vNofHits[int(L1DetectorID::kMvd)] += ReadHitsForDetector<L1DetectorID::kMvd>(fpBrMvdHits); }
+  if (fbUseSts) { vNofHits[int(L1DetectorID::kSts)] += ReadHitsForDetector<L1DetectorID::kSts>(fpBrStsHits); }
+  if (fbUseMuch) { vNofHits[int(L1DetectorID::kMuch)] += ReadHitsForDetector<L1DetectorID::kMuch>(fpBrMuchHits); }
+  if (fbUseTrd) { vNofHits[int(L1DetectorID::kTrd)] += ReadHitsForDetector<L1DetectorID::kTrd>(fpBrTrdHits); }
+  if (fbUseTof) { vNofHits[int(L1DetectorID::kTof)] += ReadHitsForDetector<L1DetectorID::kTof>(fpBrTofHits); }
+
+  // Save first hit index for different detector subsystems
+  for (uint32_t iDet = 0; iDet < vNofHits.size(); ++iDet) {
+    fvHitFirstIndexDet[iDet + 1] = fvHitFirstIndexDet[iDet] + vNofHits[iDet];
+    fNofHits += vNofHits[iDet];
+  }
+
+  // Update maps of ext->int hit indexes
+  // NOTE: fvpHitIds must be initialized, if we want to read tracks from the file
+  if (fpvHitIds) {
+    auto UpdateHitIndexMap = [&](L1Vector<int> & vIds, L1DetectorID detID) constexpr
+    {
+      vIds.reset(vNofHits[int(detID)]);
+      for (int iH = fvHitFirstIndexDet[int(detID)]; iH < fvHitFirstIndexDet[int(detID) + 1]; ++iH) {
+        vIds[(*fpvHitIds)[iH].hitId] = iH;
+      }
+    };
+    if (fbUseMvd) { UpdateHitIndexMap(vHitMvdIds, L1DetectorID::kMvd); }
+    if (fbUseSts) { UpdateHitIndexMap(vHitStsIds, L1DetectorID::kSts); }
+    if (fbUseMuch) { UpdateHitIndexMap(vHitMuchIds, L1DetectorID::kMuch); }
+    if (fbUseTrd) { UpdateHitIndexMap(vHitTrdIds, L1DetectorID::kTrd); }
+    if (fbUseTof) { UpdateHitIndexMap(vHitTofIds, L1DetectorID::kTof); }
+  }
+  // Update number of hit keys in input data object
+  if (fpIODataManager) { fpIODataManager->SetNhitKeys(fNofHitKeys); }
 
-  fpIODataManager->SetNhitKeys(fNofHitKeys);
+  // Sort debug hits
+  if (fpvQaHits) { this->SortQaHits(); }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -210,10 +263,12 @@ void TimeSliceReader::ReadRecoTracks()
         track.Hits.clear();
         track.Hits.reserve(pInputTrack->GetNofHits());
         for (int iH = 0; iH < pInputTrack->GetNofMvdHits(); ++iH) {
-          track.Hits.push_back(-pInputTrack->GetMvdHitIndex(iH) - 1);  // !!!!
-        }                                                              // iH
+          int iHint = vHitMvdIds[pInputTrack->GetMvdHitIndex(iH)];
+          track.Hits.push_back(iHint);  // !!!!
+        }                               // iH
         for (int iH = 0; iH < pInputTrack->GetNofStsHits(); ++iH) {
-          track.Hits.push_back(pInputTrack->GetStsHitIndex(iH));
+          int iHint = vHitStsIds[pInputTrack->GetStsHitIndex(iH)];
+          track.Hits.push_back(iHint);
         }  // iH
       }    // iT
       break;
@@ -225,14 +280,6 @@ void TimeSliceReader::ReadRecoTracks()
   }
 }
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void TimeSliceReader::RegisterHitDebugInfoContainer(L1Vector<CbmL1HitDebugInfo>& vDbgHits) { fpvDbgHits = &vDbgHits; }
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void TimeSliceReader::RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds) { fpvHitIds = &vHitIds; }
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void TimeSliceReader::RegisterIODataManager(std::shared_ptr<L1IODataManager>& pIODataManager)
@@ -241,10 +288,6 @@ void TimeSliceReader::RegisterIODataManager(std::shared_ptr<L1IODataManager>& pI
   fpIODataManager = pIODataManager;
 }
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void TimeSliceReader::RegisterTracksContainer(L1Vector<CbmL1Track>& vTracks) { fpvTracks = &vTracks; }
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void TimeSliceReader::SetDetector(L1DetectorID detID, bool flag)
@@ -260,17 +303,42 @@ void TimeSliceReader::SetDetector(L1DetectorID detID, bool flag)
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TimeSliceReader::StoreHitRecord(const HitRecord& hitRecord)
+void TimeSliceReader::SortQaHits()
 {
-  int iHitGlob = static_cast<int>(fpIODataManager->GetNofHits());  // Current hit global index
+  int nStationsActive = fpParameters->GetNstationsActive();
+  L1Vector<CbmL1HitDebugInfo> vNewHits(fpvQaHits->size());
+  std::vector<int> vHitFirstIndexes(nStationsActive + 1, 0);
+  std::vector<int> vNofHitsStored(nStationsActive, 0);
+
+  // Count number of hits in each station (NOTE: we could use here boarders from the IO data manager, but we would keep
+  // these two procedures independent)
+  for (const auto& hit : (*fpvQaHits)) {
+    ++vHitFirstIndexes[hit.GetStationId() + 1];
+  }
+
+  for (int iSt = 0; iSt < nStationsActive; ++iSt) {
+    vHitFirstIndexes[iSt + 1] += vHitFirstIndexes[iSt];
+  }
+
+  for (const auto& hit : (*fpvQaHits)) {
+    int iSt                                                   = hit.GetStationId();
+    vNewHits[vHitFirstIndexes[iSt] + (vNofHitsStored[iSt]++)] = hit;
+  }
+
+  std::swap(vNewHits, (*fpvQaHits));
+}
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void TimeSliceReader::StoreHitRecord(const HitRecord& hitRecord)
+{
   // Save the algo hit
   if (fpIODataManager.get()) {
     L1Hit aHit;
     aHit.iSt = hitRecord.fStaId;
     aHit.f   = hitRecord.fStripF;
     aHit.b   = hitRecord.fStripB;
-    aHit.ID  = -1;
+    aHit.ID  = static_cast<int>(fpIODataManager->GetNofHits());
     aHit.z   = hitRecord.fZ;
     aHit.u   = hitRecord.fU;
     aHit.v   = hitRecord.fV;
@@ -285,7 +353,7 @@ void TimeSliceReader::StoreHitRecord(const HitRecord& hitRecord)
   if (fpvHitIds) { fpvHitIds->emplace_back(hitRecord.fDet, hitRecord.fExtId); }
 
   // Save debug information
-  if (fpvDbgHits) {
+  if (fpvQaHits) {
     CbmL1HitDebugInfo hitDbg;
     hitDbg.Det      = hitRecord.fDet;
     hitDbg.ExtIndex = hitRecord.fExtId;
@@ -296,6 +364,6 @@ void TimeSliceReader::StoreHitRecord(const HitRecord& hitRecord)
     hitDbg.dy       = hitRecord.fDy;
     hitDbg.dxy      = hitRecord.fDxy;
     hitDbg.time     = hitRecord.fT;
-    fpvDbgHits->push_back(hitDbg);
+    fpvQaHits->push_back(hitDbg);
   }
 }
diff --git a/reco/L1/CbmCaTimeSliceReader.h b/reco/L1/CbmCaTimeSliceReader.h
index 83a4e548e647b25e1fd4c48c67c78d811c8500a6..a92b7809a870f916473f940b56c4fe4a1f78bf23 100644
--- a/reco/L1/CbmCaTimeSliceReader.h
+++ b/reco/L1/CbmCaTimeSliceReader.h
@@ -37,34 +37,35 @@ class L1Parameters;
 
 namespace cbm::ca
 {
-  /// @brief A structure to store hits information from different detectors in a uniform manner
-  struct HitRecord {
-    double fX           = 0.;  ///< x component of hit position [cm]
-    double fY           = 0.;  ///< y component of hit position [cm]
-    double fDx          = 0.;  ///< error of x component of hit position [cm]
-    double fDy          = 0.;  ///< error of y component of hit position [cm]
-    double fDxy         = 0.;  ///< correlation between x and y components [cm]
-    double fU           = 0.;  ///< hit position in direction of front strips [cm]
-    double fV           = 0.;  ///< hit position in direction of back strips [cm]
-    double fDu          = 0.;  ///< hit position error in direction of front strips [cm]
-    double fDv          = 0.;  ///< hit position error in direction of back strips [cm]
-    double fZ           = 0.;  ///< z component of hit position [cm]
-    double fT           = 0.;  ///< time of hit [ns]
-    double fDt          = 0.;  ///< time error of hit [ns]
-    int64_t fDataStream = -1;  ///< Global index of detector module
-    int fExtId          = -1;  ///< external index of hit
-    int fStaId          = -1;  ///< index of active tracking station
-    int fStripF         = -1;  ///< index of front strip
-    int fStripB         = -1;  ///< index of back strip
-    int fDet            = -1;  ///< detector ID
-  };
-
   /// @brief A reader of time slice for CA tracker
   ///
   /// The class reads reconstructed hits and reconstructed tracks (optionally) and fills the CA tracking internal
   /// data structures.
   ///
   class TimeSliceReader {
+    /// @brief A structure to store hits information from different detectors in a uniform manner
+    ///
+    struct HitRecord {
+      double fX           = 0.;  ///< x component of hit position [cm]
+      double fY           = 0.;  ///< y component of hit position [cm]
+      double fDx          = 0.;  ///< error of x component of hit position [cm]
+      double fDy          = 0.;  ///< error of y component of hit position [cm]
+      double fDxy         = 0.;  ///< correlation between x and y components [cm]
+      double fU           = 0.;  ///< hit position in direction of front strips [cm]
+      double fV           = 0.;  ///< hit position in direction of back strips [cm]
+      double fDu          = 0.;  ///< hit position error in direction of front strips [cm]
+      double fDv          = 0.;  ///< hit position error in direction of back strips [cm]
+      double fZ           = 0.;  ///< z component of hit position [cm]
+      double fT           = 0.;  ///< time of hit [ns]
+      double fDt          = 0.;  ///< time error of hit [ns]
+      int64_t fDataStream = -1;  ///< Global index of detector module
+      int fExtId          = -1;  ///< external index of hit
+      int fStaId          = -1;  ///< index of active tracking station
+      int fStripF         = -1;  ///< index of front strip
+      int fStripB         = -1;  ///< index of back strip
+      int fDet            = -1;  ///< detector ID
+    };
+
   public:
     /// @brief Constructor from parameters
     /// @param mode  Tracking mode
@@ -88,14 +89,31 @@ namespace cbm::ca
     /// @brief Clears class content
     void Clear();
 
+    /// @brief Check class initialization
+    /// @note The function throws std::logic_error, if initialization is incomplete
+    void CheckInit() const;
+
+    /// @brief Gets reference to container of first hit indexes in a detector subsystem
+    /// @return Ref. to the container
+    const auto& GetHitFirstIndexDet() const { return fvHitFirstIndexDet; }
+
+    /// @brief Gets number of hits stored for a given detector
+    /// @param iDet  Detector ID
+    /// @return Number of hits
+    int GetNofHits(L1DetectorID iDet) const
+    {
+      return fvHitFirstIndexDet[int(iDet) + 1] - fvHitFirstIndexDet[int(iDet)];
+    }
+
     /// @brief Run initializer function
+    /// @return Success flag
     ///
     /// Initializes data branches and provides necessary checks in the beginning of the run
-    void InitRun();
+    bool InitRun();
 
     /// @brief Reads time slice
     ///
-    /// Reads hits from time slice
+    /// Reads hits and tracks (optionally) from time slice
     void InitTimeSlice();
 
     /// @brief Reads hits
@@ -105,20 +123,28 @@ namespace cbm::ca
     void ReadRecoTracks();
 
     /// @brief Registers hit debug info container
-    /// @param vDbgHits  Reference to debug hit container
-    void RegisterHitDebugInfoContainer(L1Vector<CbmL1HitDebugInfo>& vDbgHits);
+    /// @param vQaHits  Reference to Qa hit container
+    /// @note If no container is registered, all related routines are omitted
+    void RegisterQaHitContainer(L1Vector<CbmL1HitDebugInfo>& vQaHits) { fpvQaHits = &vQaHits; }
 
     /// @brief Registers hit index container
     /// @param vHitIds  Reference to hits indexes container
-    void RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds);
+    /// @note If no container is registered, all related routines are omitted
+    void RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds) { fpvHitIds = &vHitIds; }
+
+    /// @brief Registers CA parameters object
+    /// @param pParameters  A shared pointer to the parameters object
+    void RegisterParameters(std::shared_ptr<L1Parameters>& pParameters) { fpParameters = pParameters; }
 
     /// @brief Registers the CA IO data manager instance
     /// @param pIODataManager  Shared pointer to the IO data manager instance
+    /// @note If no container is registered, all related routines are omitted
     void RegisterIODataManager(std::shared_ptr<L1IODataManager>& ioDataManager);
 
     /// @brief Register the reconstructed tracks container
     /// @param vTracks  Reference to reconstructed tracks container
-    void RegisterTracksContainer(L1Vector<CbmL1Track>& vTracks);
+    /// @note If no container is registered, all related routines are omitted
+    void RegisterTracksContainer(L1Vector<CbmL1Track>& vTracks) { fpvTracks = &vTracks; }
 
     /// @brief Sets used detector subsystems
     /// @param  detID  Id of detector
@@ -135,7 +161,11 @@ namespace cbm::ca
     template<L1DetectorID DetID>
     int ReadHitsForDetector(const TClonesArray* pBrHits);
 
+    /// @brief Sorts QA hit objects by stations
+    void SortQaHits();
+
     /// @brief Saves hit to data structures
+    /// @param hitRecord  Filled hit record
     ///
     /// Stores recorded hit information into registered hit containers
     void StoreHitRecord(const HitRecord& hitRecord);
@@ -174,19 +204,31 @@ namespace cbm::ca
     TClonesArray* fpBrTrdTracks  = nullptr;  ///< Input branch for reconstructed TRD tracks ("TrdTrack")
     TClonesArray* fpBrTofTracks  = nullptr;  ///< Input branch for reconstructed TOF tracks ("TofTrack")
 
+
     // Pointers to output data containers
     L1Vector<CbmL1HitId>* fpvHitIds                  = nullptr;  ///< Pointer to array of hit index objects
-    L1Vector<CbmL1HitDebugInfo>* fpvDbgHits          = nullptr;  ///< Pointer to array of debug hits
+    L1Vector<CbmL1HitDebugInfo>* fpvQaHits           = nullptr;  ///< Pointer to array of debug hits
     L1Vector<CbmL1Track>* fpvTracks                  = nullptr;  ///< Pointer to array of reconstructed tracks
     std::shared_ptr<L1IODataManager> fpIODataManager = nullptr;  ///< Pointer to input data manager
+    std::shared_ptr<L1Parameters> fpParameters       = nullptr;  ///< Pointer to tracking parameters object
+
+    // Maps of hit indexes: ext -> int
+    L1Vector<int> vHitMvdIds {"CbmCaTimeSliceReader::vHitMvdIds"};
+    L1Vector<int> vHitStsIds {"CbmCaTimeSliceReader::vHitStsIds"};
+    L1Vector<int> vHitMuchIds {"CbmCaTimeSliceReader::vHitMuchIds"};
+    L1Vector<int> vHitTrdIds {"CbmCaTimeSliceReader::vHitTrdIds"};
+    L1Vector<int> vHitTofIds {"CbmCaTimeSliceReader::vHitTofIds"};
 
     // Additional
     ECbmTrackingMode fTrackingMode;  ///< Tracking mode
 
-    // Indexes
+    // Variables for storing cache
     int fNofHits     = 0;  ///< Stored number of hits
     int fNofHitKeys  = 0;  ///< Recorded number of hit keys
     int fFirstHitKey = 0;  ///< First index of hit key for the detector subsystem
+
+    std::array<int, L1Constants::size::kMaxNdetectors + 1> fvHitFirstIndexDet = {
+      0};  ///< First index of hit in detector
   };
 }  // namespace cbm::ca
 
@@ -206,7 +248,7 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
   fFirstHitKey = fNofHitKeys;
 
   for (int iH = 0; iH < nHitsTot; ++iH) {
-    cbm::ca::HitRecord hitRecord;  // Record of hits information
+    HitRecord hitRecord;  // Record of hits information
 
     CbmPixelHit* pPixelHit = nullptr;  // Pointer to hit object
     float phiF             = 0.;       // Stereo angle of front strips
@@ -269,12 +311,11 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
       if (ECbmTrackingMode::kMCBM == fTrackingMode && pTofHit->GetZ() > 400) { continue; }
     }
 
-    //int iStActive = fpParameters->GetStationIndexActive(iStGeom);
-    int iStActive = iStGeom;            // !!!! Initialize fParameters
+    int iStActive = fpParameters->GetStationIndexActive(iStGeom, DetID);
     if (iStActive == -1) { continue; }  // Cut off inactive stations
 
     // Fill out data common for all the detectors
-    hitRecord.fStaId      = iStGeom;
+    hitRecord.fStaId      = iStActive;
     hitRecord.fX          = pPixelHit->GetX();
     hitRecord.fY          = pPixelHit->GetY();
     hitRecord.fZ          = pPixelHit->GetZ();
@@ -287,12 +328,7 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
     hitRecord.fDataStream = (static_cast<int64_t>(hitRecord.fDet) << 60) | pPixelHit->GetAddress();
     hitRecord.fU          = hitRecord.fX * cos(phiF) + hitRecord.fY * sin(phiF);
     hitRecord.fV          = hitRecord.fX * cos(phiB) + hitRecord.fY * sin(phiB);
-
-    // Update hit external index
-    if constexpr (L1DetectorID::kMvd == DetID) { hitRecord.fExtId = -(1 + iH); }
-    else {
-      hitRecord.fExtId = iH;
-    }
+    hitRecord.fExtId      = iH;
 
     // Update number of hit keys
     if constexpr (L1DetectorID::kSts == DetID) {
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index f54e4cd40c9d28ff74411e2f7b6916eefb191345..c900f001af0ce51c7380ef8321b1955aa271ac8c 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -1156,8 +1156,11 @@ void CbmL1::DefineSTAPNames(const char* dirName)
   fSTAPDataPrefix.ReplaceAll(".root", "");
   fSTAPDataPrefix = fSTAPDataPrefix.Strip(TString::EStripType::kBoth, '.');
 
-  TString sDirName = TString(dirName).Length();
-  if (!sDirName.Length()) { fSTAPDataDir = pathToRecoOutput.parent_path().string(); }
+  TString sDirName = TString(dirName);
+  if (sDirName.Length() == 0) {
+    fSTAPDataDir = pathToRecoOutput.parent_path().string();
+    L1_SHOW(fSTAPDataDir);
+  }
   else if (bfs::exists(sDirName.Data()) && bfs::is_directory(sDirName.Data())) {
     fSTAPDataDir = sDirName;
   }
diff --git a/reco/L1/CbmL1Hit.h b/reco/L1/CbmL1Hit.h
index 3fabd44e628ced03f5ba365ba294eb174608296b..462548ffce1d66db0ee7ff9b4f2914d87a754692 100644
--- a/reco/L1/CbmL1Hit.h
+++ b/reco/L1/CbmL1Hit.h
@@ -11,9 +11,9 @@
 
 #include "L1Vector.h"
 
-/// TODO: SZh: Complete the rule of five
-/// TODO: SZh: Make variables private
-/// TODO; SZh: Move class to ca::tools (ca::tools::Hit)
+// TODO: SZh: Complete the rule of five
+// TODO: SZh: Make variables private
+// TODO: SZh: Move class to ca::tools (ca::tools::Hit)
 
 ///
 /// Identificator for cbm hits with their detector and index in cbm arrays
@@ -23,8 +23,8 @@ public:
   CbmL1HitId() = default;
   CbmL1HitId(int det, int index) : detId(det), hitId(index) {};
 
-  int detId {0};  ///< detector ID (mvd/sts/etc)
-  int hitId {0};  ///< index of hit in the TClonesArray array
+  int detId = -1;  ///< detector ID
+  int hitId = -1;  ///< index of hit in the TClonesArray array
 };
 
 
@@ -99,6 +99,7 @@ public:
     return msg.str();
   }
 
+  // TODO: SZh 2.03.2023: make the variables private
   int ExtIndex;                                                ///< index of hit in the external branch
   int iStation;                                                ///< index of station in active stations array
   double x;                                                    ///< x coordinate of position [cm]
diff --git a/reco/L1/catools/CaToolsMCData.cxx b/reco/L1/catools/CaToolsMCData.cxx
index 15ceb5263cc05b48666fee06918c81103fcc8b46..5a38d5b3354164dee76c7ad2c81fc6bd4fd49de6 100644
--- a/reco/L1/catools/CaToolsMCData.cxx
+++ b/reco/L1/catools/CaToolsMCData.cxx
@@ -26,7 +26,6 @@ MCData::MCData() {}
 MCData::MCData(const MCData& other)
   : fvPoints(other.fvPoints)
   , fvTracks(other.fvTracks)
-  , fvPointIndexOfHit(other.fvPointIndexOfHit)
   , fmPointLinkMap(other.fmPointLinkMap)
   , fmTrackLinkMap(other.fmTrackLinkMap)
 {
@@ -61,7 +60,6 @@ void MCData::Swap(MCData& other) noexcept
 {
   std::swap(fvPoints, other.fvPoints);
   std::swap(fvTracks, other.fvTracks);
-  std::swap(fvPointIndexOfHit, other.fvPointIndexOfHit);
   std::swap(fmPointLinkMap, other.fmPointLinkMap);
   std::swap(fmTrackLinkMap, other.fmTrackLinkMap);
 }
@@ -88,7 +86,6 @@ void MCData::Clear()
 {
   fvPoints.clear();
   fvTracks.clear();
-  fvPointIndexOfHit.clear();
   fmPointLinkMap.clear();
   fmTrackLinkMap.clear();
 }
@@ -126,20 +123,17 @@ std::string MCData::ToString(int verbose) const
   if (verbose > 1) {
     using std::setfill;
     using std::setw;
-    const int kNofTracksToPrint = 5;
-    msg << "\n Track sample (first 5 tracks):\n";
-    msg << setw(10) << setfill(' ') << "ID" << ' ' << setw(10) << setfill(' ') << "motherID" << ' ' << setw(10)
-        << setfill(' ') << "pdg" << ' ' << setw(10) << setfill(' ') << "zVTX [cm]" << ' ' << setw(10) << setfill(' ')
-        << "px [GeV/c]" << ' ' << setw(10) << setfill(' ') << "py [GeV/c]" << ' ' << setw(10) << setfill(' ')
-        << "pz [GeV/c]" << '\n';
+    constexpr int kNofTracksToPrint = 40;
+    constexpr int kNofPointsToPrint = 40;
+    msg << "\n Track sample (first " << kNofTracksToPrint << " tracks):";
+    msg << '\n' << setw(10) << setfill(' ') << fvTracks[0].ToString(verbose, true);  // header of the table
     for (int i = 0; i < kNofTracksToPrint; ++i) {
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetId() << ' ';
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetMotherId() << ' ';
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetPdgCode() << ' ';
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetStartZ() << ' ';
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetPx() << ' ';
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetPy() << ' ';
-      msg << setw(10) << setfill(' ') << fvTracks[i].GetPz() << '\n';
+      msg << '\n' << setw(10) << setfill(' ') << fvTracks[i].ToString(verbose);
+    }
+    msg << "\n Point sample (first " << kNofPointsToPrint << " points):";
+    msg << '\n' << setw(10) << setfill(' ') << fvPoints[0].ToString(verbose, true);  // header of the table
+    for (int i = 0; i < kNofPointsToPrint; ++i) {
+      msg << '\n' << setw(10) << setfill(' ') << fvPoints[i].ToString(verbose);
     }
   }
   return msg.str();
diff --git a/reco/L1/catools/CaToolsMCData.h b/reco/L1/catools/CaToolsMCData.h
index 48733204dc2d4c5072f38b18856f513b7097bac3..d0f6ec431d7c8fd01edd104d0865ae8ce81ae2fb 100644
--- a/reco/L1/catools/CaToolsMCData.h
+++ b/reco/L1/catools/CaToolsMCData.h
@@ -107,10 +107,6 @@ namespace ca::tools
     /// Gets a reference to the vector of points
     const auto& GetPointContainer() const { return fvPoints; }
 
-    /// Gets point index by global index of hit
-    /// \param  iHit  Index of hit
-    auto GetPointIndexOfHit(int iHit) const { return fvPointIndexOfHit[iHit]; }
-
     /// Gets a reference to MC track by its internal index
     const auto& GetTrack(int idx) const { return fvTracks[idx]; }
 
@@ -130,24 +126,12 @@ namespace ca::tools
     /// with hits.
     void InitTrackInfo(const L1Vector<CbmL1HitDebugInfo>& vHits);
 
-    /// Registers index of point for a given index of hit
-    /// \param  iHit    Index of hit
-    /// \param  iPoint  Index of point
-    void RegisterPointIndexForHit(int iHit, int iPoint)
-    {
-      assert(int(fvPointIndexOfHit.size()) > iHit);
-      fvPointIndexOfHit[iHit] = iPoint;
-    }
-
     /// Reserves memory for tracks to avoid extra allocations
     void ReserveNofTracks(int nTracks) { fvTracks.reserve(nTracks); }
 
     /// Reserves memory for points to avoid extra allocations
     void ReserveNofPoints(int nPoints) { fvPoints.reserve(nPoints); }
 
-    /// Reserves total number of used hits in the event
-    void ReserveNofHits(int nHits) { fvPointIndexOfHit.reserve(nHits); }
-
     /// Prints an example of tracks and points
     /// \param verbose  Verbose level:
     ///                 - #0: Nothing is printed
@@ -163,9 +147,6 @@ namespace ca::tools
     L1Vector<MCPoint> fvPoints = {"ca::tools::MCData::fvPoints"};  ///< Container of points
     L1Vector<MCTrack> fvTracks = {"ca::tools::MCData::fvTracks"};  ///< Container of tracks
 
-    /// Correspondence of MC point index to the global hit index
-    L1Vector<int> fvPointIndexOfHit = {"ca::tools::MCData::fvPointIndexOfHit"};
-
     std::unordered_map<LinkKey, int> fmPointLinkMap = {};  ///< MC point internal index vs. link
     std::unordered_map<LinkKey, int> fmTrackLinkMap = {};  ///< MC track internal index vs. link
   };
diff --git a/reco/L1/catools/CaToolsMCTrack.cxx b/reco/L1/catools/CaToolsMCTrack.cxx
index 0163c48c92cb9b384a17eabfc5695c1d6c5df33b..4aed3ac5807e61a6112770f8480fffd3a9043263 100644
--- a/reco/L1/catools/CaToolsMCTrack.cxx
+++ b/reco/L1/catools/CaToolsMCTrack.cxx
@@ -11,9 +11,12 @@
 
 #include "CbmL1Hit.h"
 
+#include <iomanip>
+#include <sstream>
+
 #include "CaToolsMCPoint.h"
 
-using namespace ca::tools;
+using ca::tools::MCTrack;
 
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -148,3 +151,69 @@ void MCTrack::SortPointIndexes(const std::function<bool(const int& lhs, const in
 {
   std::sort(fvPointIndexes.begin(), fvPointIndexes.end(), cmpFn);
 }
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+std::string MCTrack::ToString(int verbose, bool header) const
+{
+  using std::setfill;
+  using std::setw;
+  std::stringstream msg;
+  if (header) {
+    if (verbose > 0) {
+      msg << setw(8) << setfill(' ') << "ID" << ' ';
+      msg << setw(8) << setfill(' ') << "Mother" << ' ';
+      msg << setw(8) << setfill(' ') << "PDG" << ' ';
+      if (verbose > 1) {
+        msg << setw(8) << setfill(' ') << "N h." << ' ';
+        msg << setw(8) << setfill(' ') << "N p." << ' ';
+        msg << setw(8) << setfill(' ') << "N r.tr." << ' ';
+        if (verbose > 2) { msg << setw(8) << setfill(' ') << "N t.tr." << ' '; }
+        msg << setw(12) << setfill(' ') << "zVTX [cm]" << ' ';
+        msg << setw(12) << setfill(' ') << "t [ns]" << ' ';
+        msg << setw(12) << setfill(' ') << "p [GeV/c]" << ' ';
+      }
+      msg << setw(8) << setfill(' ') << "rec-able" << ' ';
+      msg << setw(8) << setfill(' ') << "rec-ed" << ' ';
+    }
+  }
+  else {
+    if (verbose > 0) {
+      msg << setw(8) << setfill(' ') << fId << ' ';
+      msg << setw(8) << setfill(' ') << fMotherId << ' ';
+      msg << setw(8) << setfill(' ') << fPdgCode << ' ';
+      if (verbose > 1) {
+        msg << setw(8) << setfill(' ') << GetNofHits() << ' ';
+        msg << setw(8) << setfill(' ') << GetNofPoints() << ' ';
+        msg << setw(8) << setfill(' ') << GetNofRecoTracks() << ' ';
+        if (verbose > 2) { msg << setw(8) << setfill(' ') << GetNofTouchTracks() << ' '; }
+        msg << setw(12) << setfill(' ') << GetStartZ() << ' ';
+        msg << setw(12) << setfill(' ') << GetStartT() << ' ';
+        msg << setw(12) << setfill(' ') << GetP() << ' ';
+      }
+      msg << setw(8) << setfill(' ') << IsReconstructable() << ' ';
+      msg << setw(8) << setfill(' ') << IsReconstructed() << ' ';
+      if (verbose > 1) {
+        msg << "\n\t- point indexes: ";
+        for (int index : fvPointIndexes) {
+          msg << index << ' ';
+        }
+        msg << "\n\t- hit indexes: ";
+        for (int index : fvHitIndexes) {
+          msg << index << ' ';
+        }
+        msg << "\n\t- reconstructed track indexes: ";
+        for (int index : fvRecoTrackIndexes) {
+          msg << index << ' ';
+        }
+        if (verbose > 2) {
+          msg << "\n\t- touch track indexes: ";
+          for (int index : fvTouchTrackIndexes) {
+            msg << index << ' ';
+          }
+        }
+      }
+    }
+  }
+  return msg.str();
+}
diff --git a/reco/L1/catools/CaToolsMCTrack.h b/reco/L1/catools/CaToolsMCTrack.h
index 602883d4748061bd01ee657042d37937a9f259a2..338ecaac1a861efa1b3d3844999654f1172c3130 100644
--- a/reco/L1/catools/CaToolsMCTrack.h
+++ b/reco/L1/catools/CaToolsMCTrack.h
@@ -10,6 +10,8 @@
 #ifndef CaToolsMCTrack_h
 #define CaToolsMCTrack_h 1
 
+#include "CbmL1Hit.h"
+
 #include "TMath.h"
 
 #include <functional>
@@ -310,6 +312,12 @@ namespace ca::tools
     /// \param  cmpFn  Functional object to compare mcPoints
     void SortPointIndexes(const std::function<bool(const int& lhs, const int& rhs)>& cmpFn);
 
+    /// @brief Provides string representation of a track
+    /// @param verbose  Verbosity level
+    /// @param header   Flag: to print header or data
+    /// @return String representation
+    std::string ToString(int verbose = 1, bool header = false) const;
+
   private:
     // ****************************
     // **     Data variables     **
diff --git a/reco/L1/catools/CaToolsQa.cxx b/reco/L1/catools/CaToolsQa.cxx
index 9bd471532625e9e7ca4711a7c473dd4237f7bce0..04fc6bd33012b046d3c25a3842248e18ca543efa 100644
--- a/reco/L1/catools/CaToolsQa.cxx
+++ b/reco/L1/catools/CaToolsQa.cxx
@@ -117,64 +117,65 @@ void Qa::FillHistograms()
   // ** Fill distributions for reconstructed tracks (including ghost ones) **
   // ************************************************************************
 
-  for (const auto& recoTrk : *fpvRecoTracks) {
-    // Reject tracks, which do not contain hits
-    if (recoTrk.GetNofHits() < 1) { continue; }
-
-    const auto& hitFst = (*fpvHits)[recoTrk.GetHitIndexes()[0]];                         // first hit of track
-    const auto& hitSnd = (*fpvHits)[recoTrk.GetHitIndexes()[1]];                         // second hit of track
-    const auto& hitLst = (*fpvHits)[recoTrk.GetHitIndexes()[recoTrk.GetNofHits() - 1]];  // last hit of track
-
-    fph_reco_p->Fill(recoTrk.GetP());
-    fph_reco_pt->Fill(recoTrk.GetPt());
-    fph_reco_phi->Fill(recoTrk.GetPhi());
-    fph_reco_nhits->Fill(recoTrk.GetNofHits());
-    fph_reco_fsta->Fill(hitFst.GetStationId());
-    fph_reco_purity->Fill(100 * recoTrk.GetMaxPurity());
-
-    if (recoTrk.GetNDF() > 0) {
-      if (recoTrk.IsGhost()) {
-        fph_ghost_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
-        fph_ghost_prob->Fill(recoTrk.GetProb());
-      }
-      else {
-        int iTmc          = recoTrk.GetMCTrackIndexes()[0];  // Index of first MC-track
-        const auto& mcTrk = fpMCData->GetTrack(iTmc);
-        // NOTE: reconstructed tracks usually have reference to only one MC-track
-        if (mcTrk.IsReconstructable()) {
-          fph_reco_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
-          fph_reco_prob->Fill(recoTrk.GetProb());
-        }
-        else {
-          fph_rest_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
-          fph_rest_prob->Fill(recoTrk.GetProb());
-        }
-      }
-    }  // recoTrk.GetNDF() > 0: end
-
-    if (recoTrk.IsGhost()) {
-      fph_ghost_purity->Fill(100 * recoTrk.GetMaxPurity());
-      fph_ghost_p->Fill(recoTrk.GetP());
-      fph_ghost_pt->Fill(recoTrk.GetPt());
-      fph_ghost_nhits->Fill(recoTrk.GetNofHits());
-      fph_ghost_fsta->Fill(hitFst.GetStationId());
-
-      // z-positions of the first and second hit stations
-      double z0 = fpParameters->GetStation(hitFst.GetStationId()).fZ[0];
-      double z1 = fpParameters->GetStation(hitSnd.GetStationId()).fZ[0];
-
-      if (fabs(z1 - z0) > 1.e-4) {  // test for z1 != z2
-        fph_ghost_tx->Fill((hitSnd.GetX() - hitFst.GetX()) / (z1 - z0));
-        fph_ghost_ty->Fill((hitSnd.GetY() - hitFst.GetY()) / (z1 - z0));
-      }
-
-      fph_ghost_nhits_vs_p->Fill(recoTrk.GetP(), recoTrk.GetNofHits());
-      fph_ghost_fsta_vs_p->Fill(recoTrk.GetP(), hitFst.GetStationId());
-      if (hitFst.GetStationId() <= hitLst.GetStationId()) {
-        fph_ghost_lsta_vs_fsta->Fill(hitFst.GetStationId(), hitLst.GetStationId());
-      }
-    }  // recoTrk.IsGhost(): end
-  }    // loop over recoTrk: end
+  //for (const auto& recoTrk : *fpvRecoTracks) {
+  //  // Reject tracks, which do not contain hits
+  //  if (recoTrk.GetNofHits() < 1) { continue; }
+
+  //  const auto& hitFst = (*fpvHits)[recoTrk.GetHitIndexes()[0]];                         // first hit of track
+  //  const auto& hitSnd = (*fpvHits)[recoTrk.GetHitIndexes()[1]];                         // second hit of track
+  //  const auto& hitLst = (*fpvHits)[recoTrk.GetHitIndexes()[recoTrk.GetNofHits() - 1]];  // last hit of track
+
+  //  fph_reco_p->Fill(recoTrk.GetP());
+  //  fph_reco_pt->Fill(recoTrk.GetPt());
+  //  fph_reco_phi->Fill(recoTrk.GetPhi());
+  //  fph_reco_nhits->Fill(recoTrk.GetNofHits());
+  //  //fph_reco_fsta->Fill(hitFst.GetStationId());
+  //  fph_reco_purity->Fill(100 * recoTrk.GetMaxPurity());
+
+  //  if (recoTrk.GetNDF() > 0) {
+  //    if (recoTrk.IsGhost()) {
+  //      fph_ghost_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
+  //      fph_ghost_prob->Fill(recoTrk.GetProb());
+  //    }
+  //    else {
+  //      int iTmc          = recoTrk.GetMCTrackIndexes()[0];  // Index of first MC-track
+  //      const auto& mcTrk = fpMCData->GetTrack(iTmc);
+  //      // NOTE: reconstructed tracks usually have reference to only one MC-track
+  //      if (mcTrk.IsReconstructable()) {
+  //        fph_reco_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
+  //        fph_reco_prob->Fill(recoTrk.GetProb());
+  //      }
+  //      else {
+  //        fph_rest_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
+  //        fph_rest_prob->Fill(recoTrk.GetProb());
+  //      }
+  //    }
+  //  }  // recoTrk.GetNDF() > 0: end
+
+  //  if (recoTrk.IsGhost()) {
+  //    fph_ghost_purity->Fill(100 * recoTrk.GetMaxPurity());
+  //    fph_ghost_p->Fill(recoTrk.GetP());
+  //    fph_ghost_pt->Fill(recoTrk.GetPt());
+  //    fph_ghost_nhits->Fill(recoTrk.GetNofHits());
+  //    fph_ghost_fsta->Fill(hitFst.GetStationId());
+  //    fph_ghost_fhitR->Fill(hitFst.GetDistFromBP());
+
+  //    // z-positions of the first and second hit stations
+  //    double z0 = fpParameters->GetStation(hitFst.GetStationId()).fZ[0];
+  //    double z1 = fpParameters->GetStation(hitSnd.GetStationId()).fZ[0];
+
+  //    if (fabs(z1 - z0) > 1.e-4) {  // test for z1 != z2
+  //      fph_ghost_tx->Fill((hitSnd.GetX() - hitFst.GetX()) / (z1 - z0));
+  //      fph_ghost_ty->Fill((hitSnd.GetY() - hitFst.GetY()) / (z1 - z0));
+  //    }
+
+  //    fph_ghost_nhits_vs_p->Fill(recoTrk.GetP(), recoTrk.GetNofHits());
+  //    fph_ghost_fsta_vs_p->Fill(recoTrk.GetP(), hitFst.GetStationId());
+  //    if (hitFst.GetStationId() <= hitLst.GetStationId()) {
+  //      fph_ghost_lsta_vs_fsta->Fill(hitFst.GetStationId(), hitLst.GetStationId());
+  //    }
+  //  }  // recoTrk.IsGhost(): end
+  //}  // loop over recoTrk: end
 
 
   // *************************************
diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx
index b8a7fd83cd164956a031703a617517f60db8563f..51080c550a51ecb2b1c0217e3b91d36d568f38a8 100644
--- a/reco/L1/qa/CbmCaOutputQa.cxx
+++ b/reco/L1/qa/CbmCaOutputQa.cxx
@@ -9,6 +9,7 @@
 
 #include "CbmCaOutputQa.h"
 
+#include "FairRootManager.h"
 #include "Logger.h"
 
 #include "L1InitManager.h"
@@ -27,16 +28,134 @@ void OutputQa::EnableDebugger(const char* filename)
   if (!fpDebugger.get()) { fpDebugger = std::make_shared<Debugger>(filename); }
 }
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void OutputQa::FillHistograms()
+{
+  // ************************************************************************
+  // ** Fill distributions for reconstructed tracks (including ghost ones) **
+  // ************************************************************************
+
+  for (const auto& recoTrk : fvRecoTracks) {
+    // Reject tracks, which do not contain hits
+    if (recoTrk.GetNofHits() < 1) { continue; }
+
+    const auto& hitFst = (fvHits)[recoTrk.GetHitIndexes()[0]];                         // first hit of track
+    const auto& hitSnd = (fvHits)[recoTrk.GetHitIndexes()[1]];                         // second hit of track
+    const auto& hitLst = (fvHits)[recoTrk.GetHitIndexes()[recoTrk.GetNofHits() - 1]];  // last hit of track
+
+    // ***************************************************
+    // ** Histograms, requiring reconstructed data only **
+    // ***************************************************
+    //
+    fph_reco_p->Fill(recoTrk.GetP());
+    fph_reco_pt->Fill(recoTrk.GetPt());
+    fph_reco_phi->Fill(recoTrk.GetPhi());
+    fph_reco_tx->Fill(recoTrk.GetTx());
+    fph_reco_ty->Fill(recoTrk.GetTy());
+    fph_reco_nhits->Fill(recoTrk.GetNofHits());
+    fph_reco_fsta->Fill(hitFst.GetStationId());
+    fph_reco_fhitR->Fill(hitFst.GetR());
+
+
+    // ******************************************
+    // ** Histograms, requiring MC information **
+    // ******************************************
+    //
+    if (IsMCUsed()) { fph_reco_purity->Fill(100 * recoTrk.GetMaxPurity()); }
+
+    if (recoTrk.GetNDF() > 0) {
+      if (IsMCUsed() && recoTrk.IsGhost()) {
+        fph_ghost_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
+        fph_ghost_prob->Fill(recoTrk.GetProb());
+      }
+      else {
+        int iTmc          = recoTrk.GetMCTrackIndexes()[0];  // Index of first MC-track
+        const auto& mcTrk = fMCData.GetTrack(iTmc);
+        // NOTE: reconstructed tracks usually have reference to only one MC-track
+        if (mcTrk.IsReconstructable()) {
+          fph_reco_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
+          fph_reco_prob->Fill(recoTrk.GetProb());
+        }
+        else {
+          fph_rest_chi2_ndf->Fill(recoTrk.GetChiSq() / recoTrk.GetNDF());
+          fph_rest_prob->Fill(recoTrk.GetProb());
+        }
+      }
+    }  // recoTrk.GetNDF() > 0: end
+
+    if (recoTrk.IsGhost()) {
+      fph_ghost_purity->Fill(100 * recoTrk.GetMaxPurity());
+      fph_ghost_p->Fill(recoTrk.GetP());
+      fph_ghost_pt->Fill(recoTrk.GetPt());
+      fph_ghost_phi->Fill(recoTrk.GetPhi());
+      fph_ghost_nhits->Fill(recoTrk.GetNofHits());
+      fph_ghost_fsta->Fill(hitFst.GetStationId());
+      fph_ghost_fhitR->Fill(hitFst.GetR());
+
+      // z-positions of the first and second hit stations
+      double z0 = fpParameters->GetStation(hitFst.GetStationId()).fZ[0];
+      double z1 = fpParameters->GetStation(hitSnd.GetStationId()).fZ[0];
+
+      if (fabs(z1 - z0) > 1.e-4) {  // test for z1 != z2
+        fph_ghost_tx->Fill((hitSnd.GetX() - hitFst.GetX()) / (z1 - z0));
+        fph_ghost_ty->Fill((hitSnd.GetY() - hitFst.GetY()) / (z1 - z0));
+      }
+
+      fph_ghost_nhits_vs_p->Fill(recoTrk.GetP(), recoTrk.GetNofHits());
+      fph_ghost_fsta_vs_p->Fill(recoTrk.GetP(), hitFst.GetStationId());
+      if (hitFst.GetStationId() <= hitLst.GetStationId()) {
+        fph_ghost_lsta_vs_fsta->Fill(hitFst.GetStationId(), hitLst.GetStationId());
+      }
+    }  // recoTrk.IsGhost(): end
+  }    // loop over recoTrk: end
+
+
+  // *************************************
+  // ** Fill distributions of MC-tracks **
+  // *************************************
+
+  //for (const auto& mcTrk: fpMCData->GetTrackContainer()) {
+  //
+  //}
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+InitStatus OutputQa::InitCanvases()
+{
+  // ***************************
+  // **  Track distributions
+
+
+  return kSUCCESS;
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 InitStatus OutputQa::InitDataBranches()
 {
+  // Turn off detectors, which hits are not presented in input tree
+  auto* fairManager = FairRootManager::Instance();
+  fbUseMvd          = fbUseMvd && fairManager->GetObject("MvdHit");
+  fbUseSts          = fbUseSts && fairManager->GetObject("StsHit");
+  fbUseMuch         = fbUseMuch && fairManager->GetObject("MuchPixelHit");
+  fbUseTrd          = fbUseTrd && fairManager->GetObject("TrdHit");
+  fbUseTof          = fbUseTof && fairManager->GetObject("TofHit");
+
+
+  LOG(info) << fName << ": Detector subsystems used:";
+  LOG(info) << "\tMVD:  " << (fbUseMvd ? "ON" : "OFF");
+  LOG(info) << "\tSTS:  " << (fbUseSts ? "ON" : "OFF");
+  LOG(info) << "\tMuCh: " << (fbUseMuch ? "ON" : "OFF");
+  LOG(info) << "\tTRD:  " << (fbUseTrd ? "ON" : "OFF");
+  LOG(info) << "\tTOF:  " << (fbUseTof ? "ON" : "OFF");
+
   LOG(info) << fName << ": Initializing data branches";
   LOG_IF(fatal, !fpParameters.get())
     << fName << ": CA parameters object is not defined. Please, provide initializer or read parameters from binary "
     << "via OutputQa::ReadParameters(filename) from the qa macro";
 
-
   // Initialize IO data manager
   if (!fpDataManager.get()) { fpDataManager = std::make_shared<L1IODataManager>(); }
 
@@ -48,12 +167,12 @@ InitStatus OutputQa::InitDataBranches()
   fpTSReader->SetDetector(L1DetectorID::kTrd, fbUseTrd);
   fpTSReader->SetDetector(L1DetectorID::kTof, fbUseTof);
 
-  fpTSReader->RegisterIODataManager(fpDataManager);
+  fpTSReader->RegisterParameters(fpParameters);
   fpTSReader->RegisterTracksContainer(fvRecoTracks);
-  fpTSReader->RegisterHitDebugInfoContainer(fvDbgHits);
-  //fpTSReader->RegisterHitIndexContainer(fvHitIds);
+  fpTSReader->RegisterQaHitContainer(fvHits);
+  fpTSReader->RegisterHitIndexContainer(fvHitIds);
 
-  fpTSReader->InitRun();
+  if (!fpTSReader->InitRun()) { return kFATAL; }
 
   // Initialize MC module
   if (IsMCUsed()) {
@@ -64,15 +183,70 @@ InitStatus OutputQa::InitDataBranches()
     fpMCModule->SetDetector(L1DetectorID::kTrd, fbUseTrd);
     fpMCModule->SetDetector(L1DetectorID::kTof, fbUseTof);
 
-    fpMCModule->RegisterInputData(fInputData);
     fpMCModule->RegisterMCData(fMCData);
     fpMCModule->RegisterRecoTrackContainer(fvRecoTracks);
     fpMCModule->RegisterHitIndexContainer(fvHitIds);
+    fpMCModule->RegisterQaHitContainer(fvHits);
     fpMCModule->RegisterParameters(fpParameters);
+    fpMCModule->RegisterFirstHitIndexes(fpTSReader->GetHitFirstIndexDet());
 
-    fpMCModule->InitRun();
+    if (!fpMCModule->InitRun()) { return kFATAL; }
   }
+  return kSUCCESS;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+InitStatus OutputQa::InitHistograms()
+{
+  fph_reco_p     = MakeHistoFromConfig<TH1F>("reco_p");
+  fph_reco_pt    = MakeHistoFromConfig<TH1F>("reco_pt");
+  fph_reco_phi   = MakeHistoFromConfig<TH1F>("reco_phi");
+  fph_reco_tx    = MakeHistoFromConfig<TH1F>("reco_tx");
+  fph_reco_ty    = MakeHistoFromConfig<TH1F>("reco_ty");
+  fph_reco_nhits = MakeHistoFromConfig<TH1F>("reco_nhits");
+  fph_reco_fsta  = MakeHistoFromConfig<TH1F>("reco_fsta");
+  fph_reco_fhitR = MakeHistoFromConfig<TH1F>("reco_fhitR");
+
+  if (IsMCUsed()) {
+    fph_reco_purity   = MakeHistoFromConfig<TH1F>("reco_purity");
+    fph_reco_chi2_ndf = MakeHistoFromConfig<TH1F>("reco_chi2_ndf");  // TODO: Can be filled without MC
+    fph_reco_prob     = MakeHistoFromConfig<TH1F>("reco_prob");      // TODO: Can be filled without MC
+    fph_rest_chi2_ndf = MakeHistoFromConfig<TH1F>("rest_chi2_ndf");
+    fph_rest_prob     = MakeHistoFromConfig<TH1F>("rest_prob");
+
+    fph_ghost_p            = MakeHistoFromConfig<TH1F>("ghost_p");
+    fph_ghost_pt           = MakeHistoFromConfig<TH1F>("ghost_pt");
+    fph_ghost_phi          = MakeHistoFromConfig<TH1F>("ghost_phi");
+    fph_ghost_nhits        = MakeHistoFromConfig<TH1F>("ghost_nhits");
+    fph_ghost_fsta         = MakeHistoFromConfig<TH1F>("ghost_fsta");
+    fph_ghost_purity       = MakeHistoFromConfig<TH1F>("ghost_purity");
+    fph_ghost_chi2_ndf     = MakeHistoFromConfig<TH1F>("ghost_chi2_ndf");
+    fph_ghost_prob         = MakeHistoFromConfig<TH1F>("ghost_prob");
+    fph_ghost_tx           = MakeHistoFromConfig<TH1F>("ghost_tx");
+    fph_ghost_ty           = MakeHistoFromConfig<TH1F>("ghost_ty");
+    fph_ghost_fhitR        = MakeHistoFromConfig<TH1F>("ghost_fhitR");
+    fph_ghost_nhits_vs_p   = MakeHistoFromConfig<TH2F>("ghost_nhits_vs_p");
+    fph_ghost_fsta_vs_p    = MakeHistoFromConfig<TH2F>("ghost_fsta_vs_p");
+    fph_ghost_lsta_vs_fsta = MakeHistoFromConfig<TH2F>("ghost_lsta_vs_fsta");
 
+    // Residuals and pools of track parameters
+    fph_fst_res_x    = MakeHistoFromConfig<TH1F>("fst_res_x");
+    fph_fst_res_y    = MakeHistoFromConfig<TH1F>("fst_res_y");
+    fph_fst_res_tx   = MakeHistoFromConfig<TH1F>("fst_res_tx");
+    fph_fst_res_ty   = MakeHistoFromConfig<TH1F>("fst_res_ty");
+    fph_fst_res_qp   = MakeHistoFromConfig<TH1F>("fst_res_qp");
+    fph_fst_res_time = MakeHistoFromConfig<TH1F>("fst_res_time");
+    fph_fst_res_v    = MakeHistoFromConfig<TH1F>("fst_res_v");
+
+    fph_fst_pull_x    = MakeHistoFromConfig<TH1F>("fst_pull_x");
+    fph_fst_pull_y    = MakeHistoFromConfig<TH1F>("fst_pull_y");
+    fph_fst_pull_tx   = MakeHistoFromConfig<TH1F>("fst_pull_tx");
+    fph_fst_pull_ty   = MakeHistoFromConfig<TH1F>("fst_pull_ty");
+    fph_fst_pull_qp   = MakeHistoFromConfig<TH1F>("fst_pull_qp");
+    fph_fst_pull_time = MakeHistoFromConfig<TH1F>("fst_pull_time");
+    fph_fst_pull_v    = MakeHistoFromConfig<TH1F>("fst_pull_v");
+  }
 
   return kSUCCESS;
 }
@@ -81,30 +255,25 @@ InitStatus OutputQa::InitDataBranches()
 //
 InitStatus OutputQa::InitTimeSlice()
 {
-  int nMCTracks   = -1;
-  int nMCPoints   = -1;
-  int nHits       = -1;
-  int nRecoTracks = -1;
-
-  // Read hits: fill fvHitIds, fvDbgHits and fpDataManager
-  fpTSReader->ReadHits();
-  fpDataManager->SendInputData(fInputData);
-
-  // Read reconstructed tracks
-  fpTSReader->ReadRecoTracks();
+  int nMCTracks   = 0;
+  int nMCPoints   = 0;
+  int nHits       = 0;
+  int nRecoTracks = 0;
 
-  nHits       = fInputData.GetNhits();
+  // Read reconstructed input
+  fpTSReader->InitTimeSlice();
+  nHits       = fvHits.size();
   nRecoTracks = fvRecoTracks.size();
 
   if (IsMCUsed()) {
     // Read MC information
     fpMCModule->InitEvent(nullptr);
-    nMCTracks = fMCData.GetNofTracks();
     nMCPoints = fMCData.GetNofPoints();
+    nMCTracks = fMCData.GetNofTracks();
   }
 
-  LOG(info) << fName << ": Event or time slice consists from " << nHits << " hits, " << nRecoTracks << " reco tracks, "
-            << nMCTracks << " MC tracks, " << nMCPoints << " MC points";
+  LOG_IF(info, fVerbose > 1) << fName << ": Data sample consists of " << nHits << " hits, " << nRecoTracks
+                             << " reco tracks, " << nMCTracks << " MC tracks, " << nMCPoints << " MC points";
 
   return kSUCCESS;
 }
@@ -119,5 +288,5 @@ void OutputQa::ReadParameters(const char* filename)
   manager.ReadParametersObject(filename);
   manager.SendParameters(*fpParameters);
 
-  LOG(info) << fpParameters->ToString(10);
+  LOG(info) << fpParameters->ToString(0);
 }
diff --git a/reco/L1/qa/CbmCaOutputQa.h b/reco/L1/qa/CbmCaOutputQa.h
index eafee38a1293c0344bc523dd8399ff875b4baa17..91b54aca2da5088aef4321509a01c9060a6a5ceb 100644
--- a/reco/L1/qa/CbmCaOutputQa.h
+++ b/reco/L1/qa/CbmCaOutputQa.h
@@ -13,6 +13,7 @@
 #include "CbmCaMCModule.h"
 #include "CbmCaTimeSliceReader.h"
 #include "CbmL1DetectorID.h"
+#include "CbmL1Hit.h"
 #include "CbmQaTask.h"
 
 #include "CaToolsDebugger.h"
@@ -79,20 +80,20 @@ namespace cbm::ca
     bool Check() { return true; }
 
     /// @brief Initializes canvases
-    InitStatus InitCanvases() { return kSUCCESS; }
+    InitStatus InitCanvases();
 
     /// @brief Initialises data branches in the beginning of the run
     InitStatus InitDataBranches();
 
     /// @brief Initializes histograms
-    InitStatus InitHistograms() { return kSUCCESS; }
+    InitStatus InitHistograms();
 
     /// @brief Initializes time slice
     /// @note  Is called in the FairTask::Exec function
     InitStatus InitTimeSlice();
 
-    /// @brief Fills histograms
-    void FillHistograms() {}
+    /// @brief Fills histograms from time slice or event
+    void FillHistograms();
 
     /// @brief De-initializes histograms
     void DeInit() {}
@@ -115,11 +116,60 @@ namespace cbm::ca
     std::shared_ptr<::ca::tools::Debugger> fpDebugger = nullptr;  ///< Debugger
     std::shared_ptr<L1Parameters> fpParameters        = nullptr;  ///< Tracking parameters object
 
-    L1Vector<CbmL1HitDebugInfo> fvHitIds {"CbmCaOutputQa::fvHitIds"};
-    L1Vector<CbmL1HitDebugInfo> fvDbgHits {"CbmCaOutputQa::fvDbgHits"};
+    L1Vector<CbmL1HitId> fvHitIds {"CbmCaOutputQa::fvHitIds"};
+    L1Vector<CbmL1HitDebugInfo> fvHits {"CbmCaOutputQa::fvHits"};
     L1Vector<CbmL1Track> fvRecoTracks {"CbmCaOutputQa::fvRecoTracks"};
-    L1InputData fInputData;       ///< Input hits to CA algo
     ::ca::tools::MCData fMCData;  ///< Input MC data (points and tracks)
+
+
+    // **  Pointers to histogram objects **
+    // Reconstructed tracks
+    TH1F* fph_reco_p        = nullptr;  ///< Total momentum over charge of reconstructed tracks
+    TH1F* fph_reco_pt       = nullptr;  ///< Transverse momentum over charge of reconstructed tracks
+    TH1F* fph_reco_phi      = nullptr;  ///< Azimuthal angle of reconstructed tracks
+    TH1F* fph_reco_tx       = nullptr;  ///< Slope along x-axis of reconstructed tracks
+    TH1F* fph_reco_ty       = nullptr;  ///< Slope along y-axis of reconstructed tracks
+    TH1F* fph_reco_fhitR    = nullptr;  ///< Distance of the first hit from z-axis for reconstructed tracks
+    TH1F* fph_reco_nhits    = nullptr;  ///< Hit number of reconstructed tracks
+    TH1F* fph_reco_fsta     = nullptr;  ///< First station index of reconstructed tracks
+    TH1F* fph_reco_purity   = nullptr;  ///< Purity of reconstructed tracks (\note purity requires MC information)
+    TH1F* fph_reco_chi2_ndf = nullptr;  ///< Fit chi2 over NDF of reconstructed tracks
+    TH1F* fph_reco_prob     = nullptr;  ///< Fit probability of reconstructed tracks
+    TH1F* fph_rest_chi2_ndf = nullptr;  ///< Fit chi2 over NDF of non-reconstructable tracks
+    TH1F* fph_rest_prob     = nullptr;  ///< Fit probability of non-reconstructable tracks
+
+    // Ghost tracks
+    TH1F* fph_ghost_p            = nullptr;  ///< Total momentum over charge of ghost tracks
+    TH1F* fph_ghost_pt           = nullptr;  ///< Transverse momentum over charge of ghost tracks
+    TH1F* fph_ghost_phi          = nullptr;  ///< Azimuthal angle of ghost tracks
+    TH1F* fph_ghost_nhits        = nullptr;  ///< Hit number of ghost tracks
+    TH1F* fph_ghost_fsta         = nullptr;  ///< First station index of ghost tracks
+    TH1F* fph_ghost_purity       = nullptr;  ///< Purity of ghost tracks
+    TH1F* fph_ghost_chi2_ndf     = nullptr;  ///< Fit chi2 over NDF of ghost tracks
+    TH1F* fph_ghost_prob         = nullptr;  ///< Fit probability of ghost tracks
+    TH1F* fph_ghost_tx           = nullptr;  ///< Slope along x-axis of ghost tracks
+    TH1F* fph_ghost_ty           = nullptr;  ///< Slope along y-axis of ghost tracks
+    TH1F* fph_ghost_fhitR        = nullptr;  ///< Distance of the first hit from z-axis for ghost tracks
+    TH2F* fph_ghost_nhits_vs_p   = nullptr;  ///< Hit number vs. total momentum over charge of ghost tracks
+    TH2F* fph_ghost_fsta_vs_p    = nullptr;  ///< First station index vs. total momentum over charge for ghost tracks
+    TH2F* fph_ghost_lsta_vs_fsta = nullptr;  ///< Last station index vs. first station index of ghost tracks
+
+    // Residuals and pulls at the first track point
+    TH1F* fph_fst_res_x    = nullptr;  ///< Residual of x at first track point [cm]
+    TH1F* fph_fst_res_y    = nullptr;  ///< Residual of y at first track point [cm]
+    TH1F* fph_fst_res_tx   = nullptr;  ///< Residual of tx at first track point
+    TH1F* fph_fst_res_ty   = nullptr;  ///< Residual of ty at first track point
+    TH1F* fph_fst_res_qp   = nullptr;  ///< Residual of q/p at first track point  [GeV/ec]
+    TH1F* fph_fst_res_time = nullptr;  ///< Residual of time at first track point [ns]
+    TH1F* fph_fst_res_v    = nullptr;  ///< Residual of velocity at first track point [c]
+
+    TH1F* fph_fst_pull_x    = nullptr;  ///< Pull of x at first track point [cm]
+    TH1F* fph_fst_pull_y    = nullptr;  ///< Pull of y at first track point [cm]
+    TH1F* fph_fst_pull_tx   = nullptr;  ///< Pull of tx at first track point
+    TH1F* fph_fst_pull_ty   = nullptr;  ///< Pull of ty at first track point
+    TH1F* fph_fst_pull_qp   = nullptr;  ///< Pull of q/p at first track point  [GeV/ec]
+    TH1F* fph_fst_pull_time = nullptr;  ///< Pull of time at first track point [ns]
+    TH1F* fph_fst_pull_v    = nullptr;  ///< Pull of velocity at first track point [c]
   };
 }  // namespace cbm::ca