From c8ace4dc9c65c5e9fa129c5b77c0745c8bf77c23 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Fri, 15 Jul 2022 21:03:38 +0200
Subject: [PATCH] L1: Updates for STS tracking input QA

---
 core/base/CbmTrackingDetectorInterfaceBase.h  |   5 +
 .../detectors/much/CbmMuchTrackingInterface.h |  12 +-
 core/detectors/sts/CbmStsTrackingInterface.h  |  10 +-
 core/detectors/tof/CbmTofTrackingInterface.h  |  13 +
 core/detectors/trd/CbmTrdTrackingInterface.h  |  10 +-
 core/qa/CbmQaHist.h                           |   2 +-
 mvd/CbmMvdTrackingInterface.h                 |  11 +-
 reco/L1/CMakeLists.txt                        |   2 -
 reco/L1/CbmL1ReadEvent.cxx                    |   4 +-
 reco/L1/L1LinkDef.h                           |   1 -
 reco/L1/qa/CbmTrackingInputQaBase.cxx         | 319 -------
 reco/L1/qa/CbmTrackingInputQaBase.h           | 195 -----
 reco/L1/qa/CbmTrackingInputQaSts.cxx          | 787 +++++++++++++++++-
 reco/L1/qa/CbmTrackingInputQaSts.h            | 234 +++++-
 14 files changed, 1031 insertions(+), 574 deletions(-)
 delete mode 100644 reco/L1/qa/CbmTrackingInputQaBase.cxx
 delete mode 100644 reco/L1/qa/CbmTrackingInputQaBase.h

diff --git a/core/base/CbmTrackingDetectorInterfaceBase.h b/core/base/CbmTrackingDetectorInterfaceBase.h
index dc9580829e..436c0a88b8 100644
--- a/core/base/CbmTrackingDetectorInterfaceBase.h
+++ b/core/base/CbmTrackingDetectorInterfaceBase.h
@@ -74,6 +74,11 @@ public:
   /// \return Local index of the tracking station
   virtual int GetTrackingStationIndex(const CbmPixelHit* hit) const = 0;
 
+  /// Gets a tracking station by the address of element
+  /// \param  address  Unique element address
+  /// \return Local index of the tracking station
+  virtual int GetTrackingStationIndex(int address) const = 0;
+
   /// Gets max size of a station along the X-axis
   /// \param  stationId  Tracking station ID in the setup (NOTE: must be in range [0..GetNstations()-1])
   /// \return Size of station along the X-axis [cm]
diff --git a/core/detectors/much/CbmMuchTrackingInterface.h b/core/detectors/much/CbmMuchTrackingInterface.h
index 0b637738a6..362288aeef 100644
--- a/core/detectors/much/CbmMuchTrackingInterface.h
+++ b/core/detectors/much/CbmMuchTrackingInterface.h
@@ -104,8 +104,16 @@ public:
   /// \return Local index of the tracking station
   int GetTrackingStationIndex(const CbmPixelHit* hit) const
   {
-    return CbmMuchGeoScheme::GetStationIndex(hit->GetAddress()) * 3
-           + CbmMuchGeoScheme::GetLayerIndex(hit->GetAddress());
+    return GetTrackingStationIndex(hit->GetAddress());
+  }
+
+  /// Gets a tracking station by the address of element
+  /// \param  address  Unique element address
+  /// \return Local index of the tracking station
+  int GetTrackingStationIndex(int address) const
+  {
+    return CbmMuchGeoScheme::GetStationIndex(address) * 3
+           + CbmMuchGeoScheme::GetLayerIndex(address);
   }
 
   /// Gets max size of a station along the X-axis
diff --git a/core/detectors/sts/CbmStsTrackingInterface.h b/core/detectors/sts/CbmStsTrackingInterface.h
index d3ffb73619..d279ba6d73 100644
--- a/core/detectors/sts/CbmStsTrackingInterface.h
+++ b/core/detectors/sts/CbmStsTrackingInterface.h
@@ -109,7 +109,15 @@ public:
   /// \return Local index of the tracking station
   int GetTrackingStationIndex(const CbmPixelHit* hit) const
   {
-    return CbmStsSetup::Instance()->GetStationNumber(hit->GetAddress());
+    return GetTrackingStationIndex(hit->GetAddress());
+  }
+
+  /// Gets a tracking station by the address of element
+  /// \param  address  Unique element address
+  /// \return Local index of the tracking station
+  int GetTrackingStationIndex(int address) const
+  {
+    return CbmStsSetup::Instance()->GetStationNumber(address);
   }
 
   /// Gets max size of a station along the X-axis
diff --git a/core/detectors/tof/CbmTofTrackingInterface.h b/core/detectors/tof/CbmTofTrackingInterface.h
index 2c3f2e222a..1a0fa5fdba 100644
--- a/core/detectors/tof/CbmTofTrackingInterface.h
+++ b/core/detectors/tof/CbmTofTrackingInterface.h
@@ -111,6 +111,19 @@ public:
     return iSt;
   }
 
+  /// Gets a tracking station by the address of element
+  /// \param  address  Unique element address
+  /// \return Local index of the tracking station
+  int GetTrackingStationIndex(int /*address*/) const
+  {
+    // int iSt = fDigiBdfPar->GetTrackingStation(CbmTofAddress::GetSmType(address),
+    //                                           CbmTofAddress::GetSmId(address),
+    //                                           CbmTofAddress::GetRpcId(address));
+    // NOTE: Implement, when the "mcbm_beam_2021_07_surveyed" parameters will be fixed
+
+    return -1; // iSt;
+  }
+
 
   /// Gets max size of a station along the X-axis
   /// \param  stationId  Tracking station ID in the setup (NOTE: must be in range [0..GetNstations()-1])
diff --git a/core/detectors/trd/CbmTrdTrackingInterface.h b/core/detectors/trd/CbmTrdTrackingInterface.h
index f193db4338..21108d9d0b 100644
--- a/core/detectors/trd/CbmTrdTrackingInterface.h
+++ b/core/detectors/trd/CbmTrdTrackingInterface.h
@@ -98,7 +98,15 @@ public:
   /// Gets a tracking station of a CbmPixelHit
   /// \param  hit  A pointer to CbmPixelHit
   /// \return Local index of the tracking station
-  int GetTrackingStationIndex(const CbmPixelHit* hit) const { return CbmTrdAddress::GetLayerId(hit->GetAddress()); }
+  int GetTrackingStationIndex(const CbmPixelHit* hit) const { return GetTrackingStationIndex(hit->GetAddress()); }
+
+  /// Gets a tracking station by the address
+  /// \param  address  Unique element address
+  /// \return Local index of the tracking station
+  int GetTrackingStationIndex(int address) const
+  {
+    return CbmTrdAddress::GetLayerId(address);
+  }
 
   /// Gets max size of a station along the X-axis
   /// \param  stationId  Tracking station ID in the setup (NOTE: must be in range [0..GetNstations()-1])
diff --git a/core/qa/CbmQaHist.h b/core/qa/CbmQaHist.h
index 860e9d1e8b..edb6f195ce 100644
--- a/core/qa/CbmQaHist.h
+++ b/core/qa/CbmQaHist.h
@@ -84,7 +84,7 @@ public:
       f->SetLineColor(kRed);
       f->SetLineWidth(3);
       TPaveStats* st = (TPaveStats*) this->FindObject("stats");
-      if (!st) { LOG(fatal) << "CbmQaHist: can not access histogram statistics"; }
+      if (!st) { LOG(fatal) << "CbmQaHist: can not access statistics of histogram with name \"" << this->GetName() << '\"'; }
       else {
         st->SetX1NDC(0.6);
         st->SetX2NDC(0.940);
diff --git a/mvd/CbmMvdTrackingInterface.h b/mvd/CbmMvdTrackingInterface.h
index b2df5b8418..01b845e3ed 100644
--- a/mvd/CbmMvdTrackingInterface.h
+++ b/mvd/CbmMvdTrackingInterface.h
@@ -12,6 +12,7 @@
 #ifndef CbmMvdTrackingInterface_h
 #define CbmMvdTrackingInterface_h 1
 
+#include "CbmMvdDetectorId.h"
 #include "CbmMvdDetector.h"
 #include "CbmMvdHit.h"
 #include "CbmMvdStationPar.h"
@@ -28,7 +29,7 @@
 /// Class CbmMvdTrackingInterface is a CbmL1 subtask, which provides necessary methods for L1 tracker
 /// to access the geometry and dataflow settings.
 ///
-class CbmMvdTrackingInterface : public FairTask, public CbmTrackingDetectorInterfaceBase {
+class CbmMvdTrackingInterface : public FairTask, public CbmTrackingDetectorInterfaceBase, public CbmMvdDetectorId {
 public:
   /// Default constructor
   CbmMvdTrackingInterface();
@@ -115,6 +116,14 @@ public:
     }();
     return hitMvd->GetStationNr();
   }
+  
+  /// Gets a tracking station by the address of element (detectorID in terms of MVD)
+  /// \param  detectorId  Unique element address (detectorID in terms of MVD)
+  /// \return Local index of the tracking station
+  int GetTrackingStationIndex(int detectorId) const
+  {
+    return StationNr(detectorId);
+  }
 
   /// Gets max size of a tracking station along the X-axis
   /// \param  stationId  Tracking station ID in the setup (NOTE: must be in range [0..GetNstations()-1])
diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt
index f21620c1f0..4f43b55df7 100644
--- a/reco/L1/CMakeLists.txt
+++ b/reco/L1/CMakeLists.txt
@@ -157,7 +157,6 @@ ParticleFinder/CbmL1PFFitter.cxx
 ParticleFinder/CbmL1PFMCParticle.cxx
 
 qa/CbmTrackerInputQaTrd.cxx
-qa/CbmTrackingInputQaBase.cxx
 qa/CbmTrackingInputQaSts.cxx
 )
 
@@ -191,7 +190,6 @@ OffLineInterface/CbmL1GlobalFindTracksEvents.h
 L1Algo/L1Def.h
 L1Algo/L1Vector.h
 qa/CbmTrackerInputQaTrd.h
-qa/CbmTrackingInputQaBase.h
 qa/CbmTrackingInputQaSts.h
 )
 
diff --git a/reco/L1/CbmL1ReadEvent.cxx b/reco/L1/CbmL1ReadEvent.cxx
index e74aedc781..45ea39e4cf 100644
--- a/reco/L1/CbmL1ReadEvent.cxx
+++ b/reco/L1/CbmL1ReadEvent.cxx
@@ -1482,8 +1482,8 @@ void CbmL1::HitMatch()
           static_cast<const CbmMatch*>(listStsClusterMatch->At(sh->GetBackClusterId()));
         CbmMatch stsHitMatch;
 
-        Float_t Sum_of_front = 0;
-        Float_t Sum_of_back  = 0;
+        Float_t Sum_of_front = 0; // total weight of all front links
+        Float_t Sum_of_back  = 0; // total weight of all back links
 
 
         for (Int_t iFrontLink = 0; iFrontLink < frontClusterMatch->GetNofLinks(); iFrontLink++) {
diff --git a/reco/L1/L1LinkDef.h b/reco/L1/L1LinkDef.h
index a4407477ec..7bb7c97cbf 100644
--- a/reco/L1/L1LinkDef.h
+++ b/reco/L1/L1LinkDef.h
@@ -29,7 +29,6 @@
 //#pragma link C++ class  CbmL1SttHit+;
 //#pragma link C++ class  CbmL1SttTrackFinder+;
 //#pragma link C++ class  CbmL1SttTrack+;
-#pragma link C++ class CbmTrackingInputQaBase + ;
 #pragma link C++ class CbmTrackingInputQaSts + ;
 #pragma link C++ class CbmTrackerInputQaTrd + ;
 
diff --git a/reco/L1/qa/CbmTrackingInputQaBase.cxx b/reco/L1/qa/CbmTrackingInputQaBase.cxx
deleted file mode 100644
index d0ffaf2475..0000000000
--- a/reco/L1/qa/CbmTrackingInputQaBase.cxx
+++ /dev/null
@@ -1,319 +0,0 @@
-/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
-
-/***************************************************************************************************
- * @file   CbmTrackingInputQaBase.cxx
- * @brief  Base class for the tracking input QA (definition)
- * @since  24.06.2022
- * @author S.Zharko <s.zharko@gsi.de>
- ***************************************************************************************************/
-
-#include "CbmTrackingInputQaBase.h"
-
-#include "CbmCluster.h"
-#include "CbmDigiManager.h"
-#include "CbmMCEventList.h"
-#include "CbmMatch.h"
-#include "CbmPixelHit.h"
-#include "CbmStsAddress.h"  // TODO: TMP for tests, must be removed!!!! (S.Zharko)
-#include "CbmTimeSlice.h"
-
-#include "FairLogger.h"
-
-#include "TClonesArray.h"
-
-#include <iostream>
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-CbmTrackingInputQaBase::CbmTrackingInputQaBase(const char* name, int verbose) : FairTask(name, verbose) {}
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-CbmTrackingInputQaBase::~CbmTrackingInputQaBase() {}
-
-ClassImp(CbmTrackingInputQaBase);
-
-//
-// --------------------------------------------------------------------------------------------------------------------
-//
-void CbmTrackingInputQaBase::Clear(Option_t*)
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::Clear(Option_t*)\n";
-}
-//
-// --------------------------------------------------------------------------------------------------------------------
-//
-void CbmTrackingInputQaBase::Exec(Option_t*)
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::Exec(Option_t*)\n";
-
-  // Run resolution Qa
-  ResolutionQa();
-
-  // Update number of events
-  fNevents.SetVal(fNevents.GetVal() + 1);
-}
-//
-// --------------------------------------------------------------------------------------------------------------------
-//
-void CbmTrackingInputQaBase::Finish() { std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::Finish()\n"; }
-//
-// --------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmTrackingInputQaBase::Init()
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::Init()\n";
-
-  // If detector is not present, fpDetectorInterface is nullptr
-  if (!fpDetectorInterface) { LOG(fatal) << "CbmTrackingInputQa: Tracking detector interface is undefined"; }
-
-  // Input data initialization
-  InitInputData();
-
-  // Base histograms initialization
-  InitBaseHistograms();
-
-  // Register histograms in output file
-  // TODO: Add subfolders for each subsystem like
-  fpOutFolder =
-    std::make_shared<TFolder>(TString("TrackingInputQa_") + fDetName, TString("TrackingInputQa_") + fDetName);
-  fpOutFolder->SetOwner(false);
-  fpOutFolderHists = fpOutFolder->AddFolder("rawHist", "Raw histograms");
-  gStyle->SetOptStat(0);
-
-  fNevents.SetVal(0);
-  fpOutFolderHists->Add(&fNevents);
-
-  // Register histograms in the output folder
-  for (auto* histo : fHistList) {
-    fpOutFolderHists->Add(histo);
-  }
-
-  // Geometry QA
-  GeometryQa();
-
-  return kSUCCESS;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmTrackingInputQaBase::InitInputData()
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::InitInputData()\n";
-
-  auto* manager = FairRootManager::Instance();
-  fpDigiManager = CbmDigiManager::Instance();
-  fpDigiManager->Init();  // NOTE: is initialized only once
-
-  // Reconstructed data initialization
-  fpTimeSlice = dynamic_cast<CbmTimeSlice*>(manager->GetObject("TimeSlice."));
-  if (!fpTimeSlice) {
-    LOG(error) << "Time slice was not found";
-    return kERROR;
-  }
-
-  fpHits = GetHitsInput();
-  if (!fpHits) {
-    LOG(error) << "Hits input array was not found for " << fDetTitle;
-    return kERROR;
-  }
-
-  fpClusters = GetClustersInput();
-  if (!fpClusters) {
-    LOG(error) << "Cluster input array was not found for " << fDetTitle;
-    return kERROR;
-  }
-
-  // MC data initialization
-  fpMcManager  = dynamic_cast<CbmMCDataManager*>(manager->GetObject("MCDataManager"));
-  fIsMcPresent = bool(fpMcManager);
-
-  if (fIsMcPresent) {
-    fpMcEventList = dynamic_cast<CbmMCEventList*>(manager->GetObject("MCEventList."));
-    fpMcTracks    = fpMcManager->InitBranch("MCTrack");
-    fpMcPoints    = GetMcPointsInput();
-    fpHitMatches  = GetHitMatchesInput();
-
-    if (!fpMcEventList) {
-      LOG(error) << "MCEventList data were not found";
-      return kERROR;
-    }
-
-    if (!fpMcTracks) {
-      LOG(error) << "MC tracks data were not found";
-      return kERROR;
-    }
-
-    if (!fpMcPoints) {
-      LOG(error) << "MC points data were not found for " << fDetTitle;
-      return kERROR;
-    }
-
-    if (!fpHitMatches) {
-      LOG(error) << "Hits match data were not found for " << fDetTitle;
-      return kERROR;
-    }
-
-    if (!fpDigiManager->IsMatchPresent(fDetId)) {
-      LOG(error) << "No digi matches were found for " << fDetTitle;
-      return kERROR;
-    }
-  }
-
-  return kSUCCESS;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmTrackingInputQaBase::InitBaseHistograms()
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::InitBaseHistograms()\n";
-
-  fHistResidualX.clear();
-  fHistResidualY.clear();
-  fHistResidualT.clear();
-
-  fHistPullX.clear();
-  fHistPullY.clear();
-  fHistPullT.clear();
-
-  fHistPointsPerHit.clear();
-  fHistHitsPerPoint.clear();
-
-  int nTrackingStations = fpDetectorInterface->GetNtrackingStations();
-
-  fHistResidualX.reserve(nTrackingStations);
-  fHistResidualY.reserve(nTrackingStations);
-  fHistResidualT.reserve(nTrackingStations);
-
-  fHistPullX.reserve(nTrackingStations);
-  fHistPullY.reserve(nTrackingStations);
-  fHistPullT.reserve(nTrackingStations);
-
-  fHistPointsPerHit.reserve(nTrackingStations);
-  fHistHitsPerPoint.reserve(nTrackingStations);
-
-  // Create histograms
-  TString histName  = "";
-  TString histTitle = "";
-  int nBins         = -1;
-  int rMin          = 0.;
-  int rMax          = 0.;
-  for (int iSt = 0; iSt < nTrackingStations; ++iSt) {
-    // Residuals
-    histName                    = fDetName + Form("_st%d_h1ResidualX", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Residual X; (X_{reco} - X_{MC}) [cm]", iSt);
-    std::tie(nBins, rMin, rMax) = fRangeResidualX;
-    fHistResidualX.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    histName                    = fDetName + Form("_st%d_h1ResidualY", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Residual Y; (Y_{reco} - Y_{MC}) [cm]", iSt);
-    std::tie(nBins, rMin, rMax) = fRangeResidualY;
-    fHistResidualY.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    histName                    = fDetName + Form("_st%d_h1ResidualT", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Residual T; (T_{reco} - T_{MC}) [cm]", iSt);
-    std::tie(nBins, rMin, rMax) = fRangeResidualT;
-    fHistResidualT.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    // Pulls
-    histName                    = fDetName + Form("_st%d_h1PullX", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Pull X; (X_{reco} - X_{MC}) / #sigmaX_{reco}", iSt);
-    std::tie(nBins, rMin, rMax) = fRangePullX;
-    fHistPullX.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    histName                    = fDetName + Form("_st%d_h1PullY", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Pull Y; (Y_{reco} - Y_{MC}) / #sigmaY_{reco}", iSt);
-    std::tie(nBins, rMin, rMax) = fRangePullY;
-    fHistPullY.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    histName                    = fDetName + Form("_st%d_h1PullT", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Pull T; (T_{reco} - T_{MC}) / #sigmaT_{reco}", iSt);
-    std::tie(nBins, rMin, rMax) = fRangePullT;
-    fHistPullT.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    // MC points per one hit
-    histName                    = fDetName + Form("_st%d_h1PointsPerHit", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: MC Points per Hit; N_{MC Points} per hit", iSt);
-    std::tie(nBins, rMin, rMax) = fRangePointsPerHit;
-    fHistPointsPerHit.emplace_back(histName, histTitle, nBins, rMin, rMax);
-
-    // Hits per one mc point
-    histName                    = fDetName + Form("_st%d_h1HitsPerPoint", iSt);
-    histTitle                   = fDetTitle + Form(" Station %d: Hit per MC points; N_{hits} per MC point", iSt);
-    std::tie(nBins, rMin, rMax) = fRangeHitsPerPoint;
-    fHistHitsPerPoint.emplace_back(histName, histTitle, nBins, rMin, rMax);
-  }
-
-  // Register histograms
-  for (int iSt = 0; iSt < nTrackingStations; ++iSt) {
-    RegisterHist(&fHistResidualX[iSt]);
-    RegisterHist(&fHistResidualY[iSt]);
-    RegisterHist(&fHistResidualT[iSt]);
-
-    RegisterHist(&fHistPullX[iSt]);
-    RegisterHist(&fHistPullY[iSt]);
-    RegisterHist(&fHistPullT[iSt]);
-
-    RegisterHist(&fHistPointsPerHit[iSt]);
-    RegisterHist(&fHistHitsPerPoint[iSt]);
-  }
-
-  return kSUCCESS;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-void CbmTrackingInputQaBase::Reset() { std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::Reset()\n"; }
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-void CbmTrackingInputQaBase::SetParContainers()
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::SetParContainers()\n";
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-InitStatus CbmTrackingInputQaBase::GeometryQa()
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::GeometryQa()\n";
-  return kSUCCESS;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-//
-void CbmTrackingInputQaBase::ResolutionQa()
-{
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaBase::ResolutionQa()\n";
-
-  // Resolution QA is impossible without MC information
-  if (!fIsMcPresent) { return; }
-
-  int nHits     = fpHits->GetEntriesFast();                     // Hits in the event/time slice
-  int nClusters = fpClusters->GetEntriesFast();                 // Clusters in the event/time slice
-  int nDigis    = fpDigiManager->GetNofDigis(fDetId);           // Number of digies
-  int nStations = fpDetectorInterface->GetNtrackingStations();  // Number of tracking stations
-
-  // *********************************************
-  // ** Loop over hits in this event/time slice **
-  // *********************************************
-
-  for (int iHit = 0; iHit < nHits; ++iHit) {
-    /// TODO: put it into a function from iHit
-
-    auto* hit = dynamic_cast<CbmPixelHit*>(fpHits->At(iHit));
-    if (!hit) { LOG(error) << "There is an empty hit at position " << iHit << " (" << fDetTitle << ")"; }
-
-    // Tracking station index
-    int iStation = fpDetectorInterface->GetTrackingStationIndex(hit);
-    if (iStation < 0 || iStation >= nStations) {
-      LOG(fatal) << "Wrong tracking station index was calculated by the tracking detector interface for " << fDetTitle
-                 << ": station index = " << iStation << " (expected in the range [0, " << nStations - 1 << "])";
-      return;
-    }
-
-  }  // Loop over hits in this event/time slice: END
-}
diff --git a/reco/L1/qa/CbmTrackingInputQaBase.h b/reco/L1/qa/CbmTrackingInputQaBase.h
deleted file mode 100644
index 76feaf7ba9..0000000000
--- a/reco/L1/qa/CbmTrackingInputQaBase.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
-
-/***************************************************************************************************
- * @file   CbmTrackingInputQaBase.h
- * @brief  Base class for the tracking input QA (declaration)
- * @since  24.06.2022
- * @author S.Zharko <s.zharko@gsi.de>
- ***************************************************************************************************/
-
-#ifndef CbmTrackingInputQaBase_h
-#define CbmTrackingInputQaBase_h 1
-
-#include "CbmMCDataManager.h"
-#include "CbmQaCanvas.h"
-#include "CbmQaHist.h"
-#include "CbmSetup.h"
-#include "CbmTrackingDetectorInterfaceBase.h"  // Communicate via tracking detector interface
-
-#include <FairTask.h>
-
-#include "TFolder.h"
-#include "TH1D.h"
-#include "TH1I.h"
-#include "TH2D.h"
-#include "TParameter.h"
-#include "TProfile.h"
-#include "TString.h"
-#include <tuple>
-
-#include <memory>
-#include <vector>
-
-class CbmDigiManager;
-class CbmMCEventList;
-class CbmMCDataArray;
-class CbmTimeSlice;
-class TClonesArray;
-class CbmCluster;
-class CbmMatch;
-
-/// Class CbmTrackingInputQaBase is an abstract FairTask inherited class, providing interface for a
-/// tracking detector QA including input geometry and data checks. One should inherit this class
-/// for a particular detector subsystem.
-///
-class CbmTrackingInputQaBase : public FairTask {
-public:
-  /// Constructor from the task name and verbosity level
-  CbmTrackingInputQaBase(const char* name = "CbmTrackingInputQaBase", int verbose = 1);
-
-  /// Destructor
-  virtual ~CbmTrackingInputQaBase();
-
-  /// Suppress copy and move
-  CbmTrackingInputQaBase(const CbmTrackingInputQaBase&) = delete;
-  CbmTrackingInputQaBase(CbmTrackingInputQaBase&&)      = delete;
-  CbmTrackingInputQaBase& operator=(const CbmTrackingInputQaBase&) = delete;
-  CbmTrackingInputQaBase& operator=(CbmTrackingInputQaBase&&) = delete;
-
-  /// TTask: Clears all data structures created by a previous execution of the task
-  /// \param option  Specify action for the TTask::Exec (not defined yet)
-  void Clear(Option_t* option = "");
-
-  /// Ttask: Executes the task (processes a timeslice)
-  /// \param option  Specify action for the TTask::Exec (not defined yet)
-  void Exec(Option_t* /*option*/);
-
-  /// FairTask: Action at hte end of the run
-  void Finish();
-
-  //TFolder& GetQa();
-
-  /// FairTask: Task initialization an the beginning of the run
-  InitStatus Init();
-
-  /// FairTask: Task reinitialization
-  InitStatus ReInit() { return Init(); }
-
-  /// FairTask: Set parameter containers (if any)
-  void SetParContainers();
-
-  /// Resets data fields
-  void Reset();
-
-  /// Gets pointer to hits array of a particular detector type
-  virtual TClonesArray* GetHitsInput() = 0;
-
-  /// Gets pointer to clusters array of a particular detector type
-  virtual TClonesArray* GetClustersInput() = 0;
-
-  /// Gets pointer to hit matches array for a particular detector type
-  virtual TClonesArray* GetHitMatchesInput() = 0;
-
-  /// Gets pointer to MC points for a particular detector type
-  virtual CbmMCDataArray* GetMcPointsInput() = 0;
-
-  ClassDef(CbmTrackingInputQaBase, 0);  // Base class for tracking input QA
-
-protected:
-  /// Registers histogram
-  void RegisterHist(TH1* histo)
-  {
-    fHistList.push_back(histo);
-    histo->SetDirectory(0);
-  }
-
-  /// Checks geometry
-  InitStatus GeometryQa();  // TODO: Final or not final? (S.Zharko)
-
-  /// Checks resolution
-  /// A general scheme of resolution checks is provided in this method. One should specify particular operations in the
-  /// derived classes for each particular detector....
-  void ResolutionQa();  // TODO: Final or not final? (S.Zharko)
-
-
-  // ***********
-  // ** Setup **
-  // ***********
-
-
-  CbmTrackingDetectorInterfaceBase* fpDetectorInterface {nullptr};  ///< Pointer to current tracking detector I/F
-  CbmTimeSlice* fpTimeSlice {nullptr};                              ///< Pointer to current time slice
-  CbmDigiManager* fpDigiManager {nullptr};                          ///< Pointer to digi manager
-
-  CbmMCEventList* fpMcEventList {nullptr};
-  CbmMCDataManager* fpMcManager {nullptr};
-
-  // **********
-  // ** Data **
-  // **********
-
-  TClonesArray* fpClusters {nullptr};
-  TClonesArray* fpHits {nullptr};
-  TClonesArray* fpHitMatches {nullptr};
-
-  CbmMCDataArray* fpMcTracks {nullptr};
-  CbmMCDataArray* fpMcPoints {nullptr};
-
-  // ********************************
-  // ** List of base QA histograms **
-  // ********************************
-
-  // NOTE: One can add extra detector specific histograms in the Init method of the derived class. In that case, the
-  //       histograms should be registered via RegisterHisto method
-
-  std::vector<CbmQaHist<TH1D>> fHistResidualX;  ///< Residual distributions for X vs index of a station
-  std::vector<CbmQaHist<TH1D>> fHistResidualY;  ///< Residual distributions for X vs index of a station
-  std::vector<CbmQaHist<TH1D>> fHistResidualT;  ///< Residual distributions for T vs index of a station
-
-  std::vector<CbmQaHist<TH1D>> fHistPullX;  ///< Pulls distribution for X vs. index of a station
-  std::vector<CbmQaHist<TH1D>> fHistPullY;  ///< Pulls distribution for Y vs. index of a station
-  std::vector<CbmQaHist<TH1D>> fHistPullT;  ///< Pulls distribution for T vs. index of a station
-
-  std::vector<CbmQaHist<TH1I>> fHistPointsPerHit;  ///< Distribution of MC points per one hit vs. index of a station
-  std::vector<CbmQaHist<TH1I>> fHistHitsPerPoint;  ///< Distribution of hits per one MC point vs. index of a station
-
-  // Histogram properties, can be modified in the constructor of a derived class
-  std::tuple<int, double, double> fRangeResidualX {100, -5., 5.};
-  std::tuple<int, double, double> fRangeResidualY {100, -10., 10.};
-  std::tuple<int, double, double> fRangeResidualT {100, -50., 50.};
-
-  std::tuple<int, double, double> fRangePullX {100, -5., 5.};
-  std::tuple<int, double, double> fRangePullY {100, -5., 5.};
-  std::tuple<int, double, double> fRangePullT {100, -5., 5.};
-
-  std::tuple<int, double, double> fRangePointsPerHit {10, -0.5, 9.5};
-  std::tuple<int, double, double> fRangeHitsPerPoint {10, -0.5, 9.5};
-
-  TParameter<long> fNevents {"nEvents", 0};  ///< Number of processed events
-
-  // ************
-  // ** Output **
-  // ************
-
-  std::shared_ptr<TFolder> fpOutFolder {nullptr};  ///< Output folder for this QA task
-  TFolder* fpOutFolderHists {nullptr};             ///< Subfolder for raw histograms
-
-  ECbmModuleId fDetId;     ///< ID of the detector subsystem
-  TString fDetName {""};   ///< Name of the detector subsystem, used for i/o (e.g., mvd, sts, much, trd1d, trd2d, tof)
-  TString fDetTitle {""};  ///< Title of the detector subsystem, used for logs (e.g., MVD, STS, MuCh, TRD-1D, ...)
-
-private:
-  /// Initializes base histograms
-  InitStatus InitBaseHistograms();
-
-  /// Initializes input data arrays
-  InitStatus InitInputData();
-
-  std::vector<TH1*> fHistList;  ///< List of the pointers to all histograms contained in the class
-
-  bool fIsMcPresent {false};
-};
-
-#endif  // CbmTrackingInputQaBase_h
diff --git a/reco/L1/qa/CbmTrackingInputQaSts.cxx b/reco/L1/qa/CbmTrackingInputQaSts.cxx
index b02229e00f..29a546ef9d 100644
--- a/reco/L1/qa/CbmTrackingInputQaSts.cxx
+++ b/reco/L1/qa/CbmTrackingInputQaSts.cxx
@@ -4,66 +4,799 @@
 
 /***************************************************************************************************
  * @file   CbmTrackingInputQaSts.cxx
- * @brief  Class for the tracking input QA for STS (definition)
- * @since  27.06.2022
+ * @brief  Base class for the tracking input QA (definition)
+ * @since  24.06.2022
  * @author S.Zharko <s.zharko@gsi.de>
  ***************************************************************************************************/
 
 #include "CbmTrackingInputQaSts.h"
 
-#include "CbmDigiManager.h"
 #include "CbmMCDataArray.h"
+#include "CbmStsCluster.h"
+#include "CbmDigiManager.h"
 #include "CbmMCEventList.h"
 #include "CbmMatch.h"
-#include "CbmSetup.h"
-#include "CbmStsCluster.h"
-#include "CbmStsDigi.h"
 #include "CbmStsHit.h"
-#include "CbmStsTrackingInterface.h"
+#include "CbmStsAddress.h"  // TODO: TMP for tests, must be removed!!!! (S.Zharko)
+#include "CbmTimeSlice.h"
+#include "CbmMCTrack.h"
+#include "CbmStsPoint.h"
+#include "CbmStsTrackingInterface.h"  // Communicate via tracking detector interface
+
+#include "FairLogger.h"
+
+#include "TClonesArray.h"
+#include "TParticlePDG.h"
+#include "TDatabasePDG.h"
+
+#include <iostream>
+#include <stdexcept>
 
 ClassImp(CbmTrackingInputQaSts);
 
-// --------------------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------------------------------------------------------
 //
-CbmTrackingInputQaSts::CbmTrackingInputQaSts(int verbose) : CbmTrackingInputQaBase("CbmTrackingInputQaSts", verbose)
+CbmTrackingInputQaSts::CbmTrackingInputQaSts(int verbosity) : FairTask("CbmTrackingInputQaSts", verbosity) 
 {
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaSts::CbmTrackingInputQaSts()\n";
+}
 
-  // Setup detector-specific parameters
-  fDetId              = ECbmModuleId::kSts;
-  fDetName            = "sts";
-  fDetTitle           = "STS";
-  fpDetectorInterface = CbmStsTrackingInterface::Instance();
+// ---------------------------------------------------------------------------------------------------------------------
+//
+CbmTrackingInputQaSts::~CbmTrackingInputQaSts()
+{
+  DeInit();
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool CbmTrackingInputQaSts::CheckDistributions()
+{
+  bool res = true;
+  
+  const int nStations = fpDetectorInterface->GetNtrackingStations();
+
+  // ** Check pulls **
+  //
+
+
+  // Function to compare pulls distributions RMS with 1
+  // TODO: Choose proper selection criteria (S.Zharko)
+  auto CheckPullsDistribution = [&](const TH1& pHist) {
+    // Checks sigma of distribution fit with unity
+    auto* pFitFunc = pHist.GetFunction("gaus");
+    if (!pFitFunc) {
+      throw std::runtime_error("STS tracking input QA: attempt to check sigma of unfitted pulls histogram");
+    }
+    auto vSigma = pFitFunc->GetParameter(2);
+    auto eSigma = pFitFunc->GetParError(2);
+
+    // Select 3 sigma interval
+    LOG(info) << "Checking histogram \"" << pHist.GetName() << "\": fit result = " << vSigma << " +/- " << eSigma; 
+    if (std::fabs(vSigma - 1.) < 3. * eSigma) {
+      return true;
+    }
+    else {
+      return false;
+    }
+    
+    //auto vRms = pHist.GetRMS();      // RMS value
+    //auto eRms = pHist.GetRMSError(); // RMS error
+    //std::cout << std::fabs(vRms - 1.) << '\n';
+    //if (eRms > vRms * fMaxPullsRmsDiff ) {
+    //  LOG(error) << "STS tracking input QA: the analysis of \"" << pHist.GetName() << "\" RMS is impossible due to "
+    //             << "lack of statistics\n";
+    //  // TODO: probably, here we can use fit? (S.Zharko)
+    //  return false;
+    //}
+    //if (std::fabs(vRms - 1.) < fMaxPullsRmsDiff) {
+    //  return true;
+    //}
+    //else {
+    //  LOG(info) << "STS tracking input QA: RMS check for pulls distribution failed (histogram: \"" << pHist.GetName() << "\"): "
+    //            << "RMS = " << vRms << " +/- " << eRms;
+    //  return false;
+    //}
+    return false;
+  };
+
+
+  for (int iSt = 0; iSt < nStations; ++iSt) {
+    res = CheckPullsDistribution(fHistPullX[iSt]) && res;
+    res = CheckPullsDistribution(fHistPullY[iSt]) && res;
+    res = CheckPullsDistribution(fHistPullT[iSt]) && res;
+  }
+
+  return res;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmTrackingInputQaSts::DeInit()
+{
+  fIsMcPresent = false;
+
+  fpDetectorInterface = nullptr;
+  fpTimeSlice         = nullptr;
+  fpDigiManager       = nullptr;
+
+  fpMcManager = nullptr;
+  fpMcTracks = nullptr;
+  fpMcPoints = nullptr;
+
+  fpMcEventList = nullptr;
+  fpClusters  = nullptr;
+  fpHits      = nullptr;
+  fpClusterMatches = nullptr;
+  fpHitMatches = nullptr;
+
+  fOutFolder.Clear();
+  fpOutFolderHists = nullptr;
+
+  fNevents.SetVal(0);
+
+  fHistResidualX.clear();
+  fHistResidualY.clear();
+  fHistResidualT.clear();
+
+  fHistPullX.clear();
+  fHistPullY.clear();
+  fHistPullT.clear();
+
+  fHistPointsPerHit.clear();
+  fHistHitsPerPoint.clear();
+
+  fHistEfficiencyXY.clear();
+  fHistEfficiencyR.clear();
 }
 
 // --------------------------------------------------------------------------------------------------------------------
 //
-CbmTrackingInputQaSts::~CbmTrackingInputQaSts() {}
+void CbmTrackingInputQaSts::Exec(Option_t*)
+{
+  // Run resolution Qa
+  ResolutionQa();
+
+  // Update number of events
+  fNevents.SetVal(fNevents.GetVal() + 1);
+}
 
 // --------------------------------------------------------------------------------------------------------------------
 //
+void CbmTrackingInputQaSts::Finish()
+{ 
+  // Add output to a sink
+  auto* pSink = FairRootManager::Instance()->GetSink();
+  if (pSink) {
+    pSink->WriteObject(&GetQa(), nullptr);
+  }
+
+  // Check accumulated distributions 
+  bool areResolutionsOk = CheckDistributions();
+
+  // TODO: Collect all the flags in one place and make a decission here (S.Zharko)
+
+  if (areResolutionsOk) {
+    LOG(info) << this->GetName() << ": \033[1;32mtask succeeded\033[0m"; 
+  } 
+  else {
+    LOG(info) << this->GetName() << ": \033[1;31mtask failed\033[0m"; 
+  }
+
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+InitStatus CbmTrackingInputQaSts::GeometryQa()
+{
+  // Test stations ordering: TODO - is it needed here? This test is done in L1
+  return kSUCCESS;
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+TFolder& CbmTrackingInputQaSts::GetQa()
+{
+  //gStyle->SetPaperSize(20, 20);
+  
+  // Loop over tracking stations
+  const int nStations = fpDetectorInterface->GetNtrackingStations();
+  for (int iSt = 0; iSt < nStations; ++iSt) {
+    // Fit histograms
+    fHistResidualX[iSt].Fit("gaus", "Q");
+    fHistResidualY[iSt].Fit("gaus", "Q");
+    fHistResidualT[iSt].Fit("gaus", "Q");
+    
+    fHistPullX[iSt].Fit("gaus", "Q");
+    fHistPullY[iSt].Fit("gaus", "Q");
+    fHistPullT[iSt].Fit("gaus", "Q");
+    
+    // Draw histograms
+    fCanvResidualX.cd(iSt + 1);
+    fHistResidualX[iSt].DrawCopy("", "");
+    fCanvResidualY.cd(iSt + 1);
+    fHistResidualY[iSt].DrawCopy("", "");
+    fCanvResidualT.cd(iSt + 1);
+    fHistResidualT[iSt].DrawCopy("", "");
+
+    fCanvPullX.cd(iSt + 1);
+    fHistPullX[iSt].DrawCopy("", "");
+    fCanvPullY.cd(iSt + 1);
+    fHistPullY[iSt].DrawCopy("", "");
+    fCanvPullT.cd(iSt + 1);
+    fHistPullT[iSt].DrawCopy("", "");
+
+    fCanvPointsPerHit.cd(iSt + 1);
+    fHistPointsPerHit[iSt].DrawCopy("", "");
+
+    fCanvHitsPerPoint.cd(iSt + 1);
+    fHistHitsPerPoint[iSt].DrawCopy("", "");
+
+    fCanvEfficiencyR.cd(iSt + 1);
+    fHistEfficiencyR[iSt].DrawCopy("", "");
+
+    fCanvEfficiencyXY.cd(iSt + 1);
+    fHistEfficiencyXY[iSt].DrawCopy("colz", "");
+  }// Loop over tracking stations: end
+  return fOutFolder;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
 InitStatus CbmTrackingInputQaSts::Init()
 {
-  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaSts::Init()\n";
-  // Check, if STS is in the setup
-  if (!CbmSetup::Instance()->IsActive(ECbmModuleId::kSts)) {
-    LOG(warn) << "STS is not active in the current setup";
-    return kSUCCESS;
+  // Reset data fields
+  DeInit();
+
+  // If detector is not present, fpDetectorInterface is nullptr
+  fpDetectorInterface = CbmStsTrackingInterface::Instance();
+  if (!fpDetectorInterface) { LOG(fatal) << "CbmTrackingInputQa: Tracking detector interface is undefined"; }
+
+  // Input data initialization
+  ReadAndCreateDataBranches();
+
+  // Histograms initialization
+  InitHistograms();
+
+  // Canvases initialization
+  InitCanvases();
+
+  // Register histograms in output file
+  // TODO: Add subfolders for each subsystem like
+  fOutFolder.SetOwner(false);
+  fpOutFolderHists = fOutFolder.AddFolder("rawHist", "Raw histograms");
+  gStyle->SetOptStat(0);
+
+  fNevents.SetVal(0); // redundant
+  fpOutFolderHists->Add(&fNevents);
+
+  // Register histograms in the output folder
+  for (auto* histo : fHistList) {
+    fpOutFolderHists->Add(histo);
   }
+  
+  // Do QA of geometry in the end of initialization
+  return GeometryQa();
+}
+
+
+// --------------------------------------------------------------------------------------------------------------------
+//
+InitStatus CbmTrackingInputQaSts::InitCanvases()
+{
+  // Reset canvases
+  fCanvResidualX.Clear();
+  fCanvResidualY.Clear();
+  fCanvResidualT.Clear();
+
+  fCanvPullX.Clear();
+  fCanvPullY.Clear();
+  fCanvPullT.Clear();
+
+  fCanvPointsPerHit.Clear();
+  fCanvHitsPerPoint.Clear();
+
+  fCanvEfficiencyR.Clear();
+  fCanvEfficiencyXY.Clear();
 
-  // Initialize base histograms
-  CbmTrackingInputQaBase::Init();
+  // Devide canvases into sections to store plots vs. station ID
+  fCanvResidualX.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  fCanvResidualY.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  fCanvResidualT.Divide2D(fpDetectorInterface->GetNtrackingStations());
 
-  // Additional STS-specific histograms can be initialized here
-  // ...
+  fCanvPullX.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  fCanvPullY.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  fCanvPullT.Divide2D(fpDetectorInterface->GetNtrackingStations());
 
+  fCanvPointsPerHit.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  fCanvHitsPerPoint.Divide2D(fpDetectorInterface->GetNtrackingStations());
+
+  fCanvEfficiencyR.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  fCanvEfficiencyXY.Divide2D(fpDetectorInterface->GetNtrackingStations());
+  
+  // Add the canvases to the output folder
+  fOutFolder.Add(&fCanvResidualX);
+  fOutFolder.Add(&fCanvResidualY);
+  fOutFolder.Add(&fCanvResidualT);
+
+  fOutFolder.Add(&fCanvPullX);
+  fOutFolder.Add(&fCanvPullY);
+  fOutFolder.Add(&fCanvPullT);
+
+  fOutFolder.Add(&fCanvPointsPerHit);
+  fOutFolder.Add(&fCanvHitsPerPoint);
+  
+  fOutFolder.Add(&fCanvEfficiencyR);
+  fOutFolder.Add(&fCanvEfficiencyXY);
+  
   return kSUCCESS;
 }
 
 // --------------------------------------------------------------------------------------------------------------------
 //
+InitStatus CbmTrackingInputQaSts::InitHistograms()
+{
+  gStyle->SetOptStat();
+  
+  fHistResidualX.clear();
+  fHistResidualY.clear();
+  fHistResidualT.clear();
 
+  fHistPullX.clear();
+  fHistPullY.clear();
+  fHistPullT.clear();
 
-// --------------------------------------------------------------------------------------------------------------------
+  fHistPointsPerHit.clear();
+  fHistHitsPerPoint.clear();
+  
+  fHistEfficiencyR.clear();
+  fHistEfficiencyXY.clear();
+
+  const int nStations = fpDetectorInterface->GetNtrackingStations();
+
+  fHistResidualX.reserve(nStations);
+  fHistResidualY.reserve(nStations);
+  fHistResidualT.reserve(nStations);
+
+  fHistPullX.reserve(nStations);
+  fHistPullY.reserve(nStations);
+  fHistPullT.reserve(nStations);
+
+  fHistPointsPerHit.reserve(nStations);
+  fHistHitsPerPoint.reserve(nStations);
+
+  fHistEfficiencyR.reserve(nStations);
+  fHistEfficiencyXY.reserve(nStations);
+
+  // Create histograms
+  TString histName  = "";
+  TString histTitle = "";
+  int nBins         = -1;
+  double rMin       = 0.;
+  double rMax       = 0.;
+  for (int iSt = 0; iSt < nStations; ++iSt) {
+    // Residuals
+    histName                    = Form("h1_sts_ResidualX_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Residual X; (X_{reco} - X_{MC}) [cm]", iSt);
+    std::tie(nBins, rMin, rMax) = fRangeResidualX;
+    fHistResidualX.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    histName                    = Form("h1_sts_ResidualY_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Residual Y; (Y_{reco} - Y_{MC}) [cm]", iSt);
+    std::tie(nBins, rMin, rMax) = fRangeResidualY;
+    fHistResidualY.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    histName                    = Form("h1_sts_ResidualT_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Residual T; (T_{reco} - T_{MC}) [ns]", iSt);
+    std::tie(nBins, rMin, rMax) = fRangeResidualT;
+    fHistResidualT.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    // Pulls
+    histName                    = Form("h1_sts_PullX_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Pull X; (X_{reco} - X_{MC}) / #sigmaX_{reco}", iSt);
+    std::tie(nBins, rMin, rMax) = fRangePullX;
+    fHistPullX.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    histName                    = Form("h1_sts_PullY_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Pull Y; (Y_{reco} - Y_{MC}) / #sigmaY_{reco}", iSt);
+    std::tie(nBins, rMin, rMax) = fRangePullY;
+    fHistPullY.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    histName                    = Form("h1_sts_PullT_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Pull T; (T_{reco} - T_{MC}) / #sigmaT_{reco}", iSt);
+    std::tie(nBins, rMin, rMax) = fRangePullT;
+    fHistPullT.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    // MC points per one hit
+    histName                    = Form("h1_sts_PointsPerHit_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: MC Points per Hit; N_{MC Points} per hit", iSt);
+    std::tie(nBins, rMin, rMax) = fRangePointsPerHit;
+    fHistPointsPerHit.emplace_back(histName, histTitle, nBins, rMin, rMax);
+
+    // Hits per one mc point
+    histName                    = Form("h1_sts_HitsPerPoint_st%d", iSt);
+    histTitle                   = Form("STS: Station %d: Hit per MC points; N_{hits} per MC point", iSt);
+    std::tie(nBins, rMin, rMax) = fRangeHitsPerPoint;
+    fHistHitsPerPoint.emplace_back(histName, histTitle, nBins, rMin, rMax);
+  
+    // Efficiencies
+    double xMax = fpDetectorInterface->GetXmax(iSt);  /// TODO: test ranges              
+    double yMax = fpDetectorInterface->GetYmax(iSt);  /// TODO: test ranges
+    
+    // Efficiency vs. distance of point from center
+    histName    = Form("pr1_sts_EfficiencyR_st%d", iSt);
+    histTitle   = Form("STS: Station %d: Efficiency R; R [cm]", iSt);
+    rMin        = 0.;
+    rMax        = sqrt(xMax * xMax + yMax * yMax);
+    nBins       = 100;
+    fHistEfficiencyR.emplace_back(histName, histTitle, nBins, rMin, rMax);
+    fHistEfficiencyR[iSt].SetOptStat(1110);
+
+    // Efficiency vs. x and y 
+    histName    = Form("pr1_sts_EfficiencyXY_st%d", iSt);
+    histTitle   = Form("STS: Station %d: Efficiency XY; X [cm]; Y [cm]", iSt);
+    nBins       = 50;
+    fHistEfficiencyXY.emplace_back(histName, histTitle, nBins, -xMax, xMax, nBins, -yMax, yMax);
+    fHistEfficiencyXY[iSt].SetOptStat(10);
+  }
+
+  // Register histograms
+  for (int iSt = 0; iSt < nStations; ++iSt) {
+    RegisterHist(&fHistResidualX[iSt]);
+    RegisterHist(&fHistResidualY[iSt]);
+    RegisterHist(&fHistResidualT[iSt]);
+
+    RegisterHist(&fHistPullX[iSt]);
+    RegisterHist(&fHistPullY[iSt]);
+    RegisterHist(&fHistPullT[iSt]);
+
+    RegisterHist(&fHistPointsPerHit[iSt]);
+    RegisterHist(&fHistHitsPerPoint[iSt]);
+
+    RegisterHist(&fHistEfficiencyXY[iSt]);
+    RegisterHist(&fHistEfficiencyR[iSt]);
+  }
+
+  return kSUCCESS;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+CbmMatch CbmTrackingInputQaSts::MatchHits(const CbmStsHit* pHit, int iHit)
+{
+  CbmMatch res;  // Matching result
+
+  // Front and back cluster indeces
+  const int iClusterF = pHit->GetFrontClusterId();
+  if (iClusterF < 0) {
+    LOG(error) << "STD: hit (id = " << iHit << ") has incorrect front cluster index: " << iClusterF;
+    throw std::runtime_error("STS tracking input QA: wrong front cluster index");
+  }
+  
+  const int iClusterB = pHit->GetBackClusterId();
+  if (iClusterB < 0) {
+    LOG(error) << "STD: hit (id = " << iHit << ") has incorrect back cluster index: " << iClusterF;
+    throw std::runtime_error("STS tracking input QA: wrong back cluster index");
+  }
+
+  // Front and back clusters of a hit
+  const auto* pClusterF = dynamic_cast<const CbmStsCluster*>(fpClusters->At(iClusterF));
+  if (!pClusterF) {
+    LOG(error) << "STD: front cluster does not exist for hit (id = " << iHit << ')';
+    throw std::runtime_error("STS tracking input QA: front cluster not found");
+  }
+
+  const auto* pClusterB = dynamic_cast<const CbmStsCluster*>(fpClusters->At(iClusterB));
+  if (!pClusterB) {
+    LOG(error) << "STD: back cluster does not exist for hit (id = " << iHit << ')';
+    throw std::runtime_error("STS tracking input QA: back cluster not found");
+  }
+  
+  const CbmMatch* pClusterMatchF = dynamic_cast<const CbmMatch*>(fpClusterMatches->At(iClusterF));
+  const CbmMatch* pClusterMatchB = dynamic_cast<const CbmMatch*>(fpClusterMatches->At(iClusterB));
+
+  // Check addresses
+  const int addressHit      = pHit->GetAddress();
+  const int addressClusterF = pClusterF->GetAddress();
+  const int addressClusterB = pClusterB->GetAddress();
+  if (addressHit != addressClusterF || addressHit != addressClusterB) {
+    LOG(error) << "STS hit (id = " << iHit << ") and its front and(or) back clusters has different addresses: "
+               << "hit address = " << addressHit << ", front cluster address = " << addressClusterF
+               << ", back cluster address = " << addressClusterB;
+    throw std::runtime_error("STS tracking input QA: inconsistent in hit and clusters addresses");
+  }
+
+  // CUSTOM MATCHING: we choose only those links, which are presented both in front and back clusters
+  // The same matching is used in L1 tracking
+  for (int iLinkF = 0; iLinkF < pClusterMatchF->GetNofLinks(); ++iLinkF) {
+    const auto& linkF = pClusterMatchF->GetLink(iLinkF);
+    for (int iLinkB = 0; iLinkB < pClusterMatchB->GetNofLinks(); ++iLinkB) {
+      const auto& linkB = pClusterMatchB->GetLink(iLinkB);
+      if (linkF == linkB) {
+        res.AddLink(linkF);
+        res.AddLink(linkB);
+      }
+    }
+  }
+
+  return res; // Rely on NRVO
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+double CbmTrackingInputQaSts::ParticleMass(int pdg)
+{
+  if (fabs(pdg) < 9999999 && ((TParticlePDG*) TDatabasePDG::Instance()->GetParticle(pdg))) {
+    return TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
+  }
+  
+  constexpr double kAmuToGev {0.93149410242};  // 1 amu in GeV/c2
+  
+  // Define masses of several light nuclei by hands
+  if (fabs(pdg) == 1000010020) { 
+    return kAmuToGev * 2.01410177812; // deutron
+  } 
+  else if (fabs(pdg) == 1000010030) { 
+    return kAmuToGev * 3.01604927790; // triton
+  } 
+  else if (fabs(pdg) == 1000020030) { 
+    return kAmuToGev * 3.01602932007; // He-3
+  } 
+  else if (fabs(pdg) == 1000020040) { 
+    return kAmuToGev * 4.00260325413; // He-4
+  }
+    
+  LOG(warn) << "\033[1;31m Found mass for pdg = " << pdg << " is undefined. "
+            << "Please, provide data for this particle\033[0m\n"; 
+
+  return 0.;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+InitStatus CbmTrackingInputQaSts::ReadAndCreateDataBranches()
+{
+  auto* pManager = FairRootManager::Instance();
+  if (!pManager) {
+    LOG(fatal) << "FairRootManager was not found";
+  }
+
+  fpDigiManager = CbmDigiManager::Instance();
+  fpDigiManager->Init();  // NOTE: is initialized only once
+
+  // ************************************************
+  // ** Reconstructed data branches initialization **
+  // ************************************************
+
+  fpTimeSlice = dynamic_cast<CbmTimeSlice*>(pManager->GetObject("TimeSlice."));
+  if (!fpTimeSlice) {
+    LOG(error) << "Time slice was not found";
+    return kERROR;
+  }
+
+  fpHits = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsHit"));;
+  if (!fpHits) {
+    LOG(error) << "Hits input array was not found for STS";
+    return kERROR;
+  }
+
+  fpClusters = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsCluster"));
+  if (!fpClusters) {
+    LOG(error) << "Cluster input array was not found for STS";
+    return kERROR;
+  }
+
+  // MC data initialization
+  fpMcManager  = dynamic_cast<CbmMCDataManager*>(pManager->GetObject("MCDataManager"));
+  fIsMcPresent = bool(fpMcManager);
+
+  if (fIsMcPresent) {
+    fpMcEventList    = dynamic_cast<CbmMCEventList*>(pManager->GetObject("MCEventList."));
+    fpMcTracks       = fpMcManager->InitBranch("MCTrack");
+    fpMcPoints       = fpMcManager->InitBranch("StsPoint");
+    fpHitMatches     = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsHitMatch"));
+    fpClusterMatches = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsClusterMatch"));
+
+    if (!fpMcEventList) {
+      LOG(error) << "MCEventList data were not found";
+      return kERROR;
+    }
+
+    if (!fpMcTracks) {
+      LOG(error) << "MC tracks data were not found";
+      return kERROR;
+    }
+
+    if (!fpMcPoints) {
+      LOG(error) << "MC points data were not found for STS";
+      return kERROR;
+    }
+
+    if (!fpHitMatches) {
+      LOG(error) << "Hits match data were not found for STS";
+      return kERROR;
+    }
+  }
+
+  return kSUCCESS;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmTrackingInputQaSts::ResolutionQa()
+{
+  // Resolution QA is impossible without MC information
+  if (!fIsMcPresent) { return; }
+  
+  const int nHits     = fpHits->GetEntriesFast();                     // Number of hits in event/ts
+  const int nStations = fpDetectorInterface->GetNtrackingStations();  // Number of stations in event/ts
+  const int nMcEvents = fpMcEventList->GetNofEvents();                // Number of MC events in event/ts
+  
+  std::vector<std::vector<int>> nHitsPerMcPoint; // Number of hits per one MC point in different MC events
+  nHitsPerMcPoint.resize(nMcEvents);
+  
+  // ** Loop over MC events within event/ts **
+  for (int iE = 0; iE < nMcEvents; ++iE) {
+    const int fileId  = fpMcEventList->GetFileIdByIndex(iE);
+    const int eventId = fpMcEventList->GetEventIdByIndex(iE);
+    const int nPoints = fpMcPoints->Size(fileId, eventId);
+    nHitsPerMcPoint[iE].resize(nPoints, 0);
+  } // Loop over MC events within event/ts: end
+
+
+  // ** Loop over hits within event/ts **
+  for (int iHit = 0; iHit < nHits; ++iHit) {
+    const auto* pHit = dynamic_cast<const CbmStsHit*>(fpHits->At(iHit));
+    if (!pHit) {
+      LOG(error) << "STS hit with index " << iHit << " does not exist in \"StsHit\" array";
+      throw std::runtime_error("STS tracking input QA: hit does not exist");
+    }
+ 
+    // Check station index of a hit
+    const int iStation = fpDetectorInterface->GetTrackingStationIndex(pHit);
+    if (iStation < 0 || iStation >= nStations) {
+      LOG(error) << "STS hit with index " << iHit << ": tracking station index = "
+                 << iStation << " is out of range [0, " << nStations << ']';
+      throw std::runtime_error("STS tracking input QA: hit has inconsistent station index");
+    }
+
+    // Get custom match for the hit
+    const CbmMatch hitMatch = MatchHits(pHit, iHit); // throws std::runtime_error
+
+    // Fill number of hits per one MC point vector and update the number of hits per a given MC point
+    int nMcPoints = 0;  // Number of non-noisy MC points per event
+    for (int iLink = 0; iLink < hitMatch.GetNofLinks(); ++iLink) {
+      const auto& link = hitMatch.GetLink(iLink);
+      if (link.GetIndex() >= 0) { // Select only non-noisy links (non-noisy digis)
+        ++nMcPoints;
+        const int iE = fpMcEventList->GetEventIndex(link);
+        if (iE < 0 || iE >= nMcEvents) {
+          LOG(error) << "STS: link points to a non-existing MC event (iHit = " << iHit << ')';
+          throw std::runtime_error("STS tracking input QA: link points to non-existing MC event");
+        }
+        if (link.GetIndex() >= int(nHitsPerMcPoint[iE].size())) {
+          LOG(error) << "STS: link points to a non-existing MC point (iHit = " << iHit << ')';
+          throw std::runtime_error("STS tracking input QA: link points to non-existing MC point");
+        }
+        nHitsPerMcPoint[iE][link.GetIndex()]++;
+      }
+    }
+
+    fHistPointsPerHit[iStation].Fill(nMcPoints);
+
+    // Select only hits with one MC point
+    if (nMcPoints != 1) { continue; }
+    
+    // Take the best link in the match
+    const auto& bestLink = hitMatch.GetMatchedLink();
+
+    // Skip noise 
+    if (bestLink.GetIndex() < 0) { continue; }
+
+    // Get MC point
+    const auto* pPoint = dynamic_cast<const CbmStsPoint*>(fpMcPoints->Get(bestLink));
+    if (!pPoint) {
+      LOG(error) << "STS: MC point does not exist (iHit = " << iHit << ')';
+      throw std::runtime_error("STS tracking input QA: MC point does not exist"); // NOTE: 
+    }
+
+    // TODO: Study the distributions of |pointZIn - stationZ|, |pointZout - stationZ| and |hitZ - stationZ|
+    //const double stationZ = fpDetectorInterface->GetZ(iStation);
+    
+    // ***********************************
+    // ** Calculate residuals and pools **
+    // ***********************************
+
+    // Get MC event time
+    double t0 = fpMcEventList->GetEventTime(bestLink);
+    if (t0 < 0) {
+      LOG(error) << "STS: MC event time is undefined (iHit = " << iHit << ')';
+      throw std::runtime_error("STS tracking input QA: the MC event time is undefined");
+    }
+  
+    // Get time, space position and momenta components for the MC point (values are taken for the "In" point)
+    double mcX = pPoint->GetXIn();       // [cm]
+    double mcY = pPoint->GetYIn();       // [cm]
+    double mcZ = pPoint->GetZIn();       // [cm]
+    double mcT = pPoint->GetTime() + t0; // [ns]
+    double mcPx = pPoint->GetPx();       // [GeV/c]
+    double mcPy = pPoint->GetPy();       // [GeV/c]
+    double mcPz = pPoint->GetPz();       // [GeV/c]
+
+    // Skip slow particles (TODO: why pZ, not p?
+    if (fabs(pPoint->GetPzOut()) < fMinMomentum) { continue; }
+
+    // Difference between z components of MC in point and the hit
+    double dz = pHit->GetZ() - mcZ; // [cm]
+
+    // Propagate MC-point x and y "In" coordinates to z-plane of the hit
+    mcX += dz * mcPx / mcPz;
+    mcY += dz * mcPy / mcPz;
+
+    // Propagete MC-point "In" time to z-plane of the hit
+    int pdgCode = pPoint->GetPid();
+    double mass = ParticleMass(pdgCode);
+    constexpr double speedOfLight {29.9792458}; // cm/ns
+    TVector3 mom;
+    
+    mcT += dz / (mcPz * speedOfLight) * sqrt(mass * mass + mom.Mag2());
+
+    double dx = pHit->GetX() - mcX;
+    double dy = pHit->GetY() - mcY;
+    double dt = pHit->GetTime() - mcT;
+    double rmsX = pHit->GetDx();
+    double rmsY = pHit->GetDy();
+    double rmsT = pHit->GetTimeError();
+
+    fHistResidualX[iStation].Fill(dx);
+    fHistResidualY[iStation].Fill(dy);
+    fHistResidualT[iStation].Fill(dt);
+
+    fHistPullX[iStation].Fill(dx / rmsX);
+    fHistPullY[iStation].Fill(dy / rmsY);
+    fHistPullT[iStation].Fill(dt / rmsT);  
+  }// Loop over hits within event/ts: end
+  
+  // *********************
+  // ** Fill efficiency **
+  // *********************
+
+  // ** Loop over MC events within event/ts **
+  for (int iE = 0; iE < nMcEvents; ++iE) {
+    const int fileId  = fpMcEventList->GetFileIdByIndex(iE);
+    const int eventId = fpMcEventList->GetEventIdByIndex(iE);
+    const int nPoints = fpMcPoints->Size(fileId, eventId);
+    
+    // ** Loop over MC points **
+    for (int iP = 0; iP < nPoints; ++iP) {
+      const auto* pPoint = dynamic_cast<CbmStsPoint*>(fpMcPoints->Get(fileId, eventId, iP));
+      if (!pPoint) {
+        LOG(error) << "MC point does not exist for iE = " << iE << ", iP = " << iP;
+        throw std::runtime_error("STS tracking input QA: MC point does not exist");
+      }
+      
+      int address  = pPoint->GetDetectorID();
+      int iStation = fpDetectorInterface->GetTrackingStationIndex(address);
+      if (iStation < 0 || iStation >= nStations) {
+        LOG(error) << "STS MC point with index " << iP << ": tracking station index = "
+                   << iStation << " is out of range [0, " << nStations << ']';
+        throw std::runtime_error("STS tracking input QA: MC point has inconsistent station index");
+      }
+      fHistHitsPerPoint[iStation].Fill(nHitsPerMcPoint[iE][iP]);
+      
+      double pointDistance = sqrt(pPoint->GetXIn() * pPoint->GetXIn() + pPoint->GetYIn() * pPoint->GetYIn()); // [cm]
+      fHistEfficiencyR[iStation].Fill(pointDistance, (nHitsPerMcPoint[iE][iP] > 0));
+      fHistEfficiencyXY[iStation].Fill(pPoint->GetXIn(), pPoint->GetYIn(), (nHitsPerMcPoint[iE][iP] > 0));
+    }
+
+  } // Loop over MC events within event/ts: end
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmTrackingInputQaSts::SetParContainers()
+{
+  std::cout << "\033[1;32mCALL:\033[0mCbmTrackingInputQaSts::SetParContainers()\n";
+}
 
-// --------------------------------------------------------------------------------------------------------------------
diff --git a/reco/L1/qa/CbmTrackingInputQaSts.h b/reco/L1/qa/CbmTrackingInputQaSts.h
index f866655a99..7a0b324baa 100644
--- a/reco/L1/qa/CbmTrackingInputQaSts.h
+++ b/reco/L1/qa/CbmTrackingInputQaSts.h
@@ -4,52 +4,242 @@
 
 /***************************************************************************************************
  * @file   CbmTrackingInputQaSts.h
- * @brief  Class for the tracking input QA for STS (declaration)
- * @since  27.06.2022
+ * @brief  Base class for the tracking input QA (declaration)
+ * @since  24.06.2022
  * @author S.Zharko <s.zharko@gsi.de>
  ***************************************************************************************************/
 
 #ifndef CbmTrackingInputQaSts_h
 #define CbmTrackingInputQaSts_h 1
 
-#include "CbmTrackingInputQaBase.h"
+#include "CbmMCDataManager.h"
+#include "CbmQaCanvas.h"
+#include "CbmQaHist.h"
+#include "CbmSetup.h"
+#include "CbmTrackingDetectorInterfaceBase.h"  // Communicate via tracking detector interface
 
-#include "FairRootManager.h"
+#include <FairTask.h>
 
-#include "TClonesArray.h"
+#include "TFolder.h"
+#include "TH1D.h"
+#include "TH1I.h"
+#include "TH2D.h"
+#include "TParameter.h"
+#include "TProfile.h"
+#include "TString.h"
+#include <tuple>
 
+#include <memory>
+#include <vector>
+
+class CbmDigiManager;
+class CbmMCEventList;
 class CbmMCDataArray;
-class CbmMatch;
+class CbmTimeSlice;
+class TClonesArray;
 class CbmCluster;
+class CbmMatch;
+class CbmStsHit;
 
-class CbmTrackingInputQaSts : public CbmTrackingInputQaBase {
+/// Class CbmTrackingInputQaSts is an abstract FairTask inherited class, providing interface for a
+/// tracking detector QA including input geometry and data checks. One should inherit this class
+/// for a particular detector subsystem.
+///
+class CbmTrackingInputQaSts : public FairTask {
 public:
-  CbmTrackingInputQaSts(int verbose = 1);
+  /// Constructor from the task name and verbosity level
+  CbmTrackingInputQaSts(int verbosity = 0);
+
+  /// Destructor
   ~CbmTrackingInputQaSts();
 
+  /// Suppress copy and move
+  CbmTrackingInputQaSts(const CbmTrackingInputQaSts&) = delete;
+  CbmTrackingInputQaSts(CbmTrackingInputQaSts&&)      = delete;
+  CbmTrackingInputQaSts& operator=(const CbmTrackingInputQaSts&) = delete;
+  CbmTrackingInputQaSts& operator=(CbmTrackingInputQaSts&&) = delete;
+  
+  /// TTask: Executes the task (processes a timeslice)
+  /// \param option  Specify action for the TTask::Exec (not defined yet)
+  void Exec(Option_t* /*option*/);
+
+  /// FairTask: Action at hte end of the run
+  void Finish();
+
+  /// Gets maximum allowed distance between z-components of hit/MC-point position and the station center [cm]
+  double GetMaxDistanceZ() const { return fMaxDistanceZ; }
+  
+  /// Gets maximum allowed difference between pulls distributions RMS and the expected RMS value of RMS = 1
+  double GetMaxPullsRmsDiff() const { return fMaxPullsRmsDiff; }
+  
+  /// Gets minimum particle momentum
+  double GetMinMomentum() const { return fMinMomentum; }
+  
+  /// Fits and draws histograms
+  TFolder& GetQa();
+  
+  /// FairTask: Task initialization an the beginning of the run
   InitStatus Init();
 
+  /// FairTask: Task reinitialization
+  InitStatus ReInit() { return Init(); }
 
-  /// Gets pointer to hits array of a particular detector type
-  TClonesArray* GetHitsInput() { return dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsHit")); }
+  /// Sets maximum allowed distance between z-components of hit/MC-point position and the station center [cm]
+  void SetMaxDistanceZ(double dist) { fMaxDistanceZ = dist; }
 
-  /// Gets pointer to clusters array of a particular detector type
-  TClonesArray* GetClustersInput()
-  {
-    return dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsCluster"));
-  }
+  /// Sets maximum allowed difference between pulls distributions RMS and the expected RMS value of RMS = 1
+  void SetMaxPullsRmsDiff(double rmsMaxDiff) { fMaxPullsRmsDiff = rmsMaxDiff; }
+
+  /// Sets minimum particle momentum
+  void SetMinMomentum(double pMin) { fMinMomentum = pMin; }
+
+  /// FairTask: Set parameter containers (if any)
+  void SetParContainers();
+
+  ClassDef(CbmTrackingInputQaSts, 0);  // Base class for tracking input QA
+
+private:
+  // ***************
+  // ** Functions **
+  // ***************
+  
+  /// Checks accumulated distributions
+  bool CheckDistributions();
+
+  /// Deinitialize data
+  void DeInit();
+
+  /// Fills distributions of residuals
+  bool FillHistosResiduals();
 
-  /// Gets pointer to hit matches array for a particular detector type
-  TClonesArray* GetHitMatchesInput()
+  /// Checks geometry
+  InitStatus GeometryQa();
+
+  /// Returns particle mass [GeV/c2] by its pdg code
+  static double ParticleMass(int pdg);
+
+  /// Initializes canvases
+  InitStatus InitCanvases();
+
+  /// Initializes base histograms
+  InitStatus InitHistograms();
+
+  /// Match hits with MC points and fills out the vector
+  /// \param  pHit  A pointer to the hit to be matched
+  /// \param  iHit  An index of the hit in the hits array
+  /// \return Match object
+  CbmMatch MatchHits(const CbmStsHit* pHit, int iHit);
+  
+  /// Initializes input data branches
+  InitStatus ReadAndCreateDataBranches();
+
+  /// Registers histogram
+  /// \param  pHisto  
+  void RegisterHist(TH1* pHisto)
   {
-    return dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("StsHitMatch"));
+    fHistList.push_back(pHisto);
+    pHisto->SetDirectory(0);
   }
 
-  /// Gets pointer to MC points for a particular detector type
-  CbmMCDataArray* GetMcPointsInput() { return fpMcManager->InitBranch("StsPoint"); }
+  /// Checks resolution
+  /// A general scheme of resolution checks is provided in this method. One should specify particular operations in the
+  /// derived classes for each particular detector....
+  void ResolutionQa();
+
+  // *****************
+  // ** Data fields **
+  // *****************
+
+  // ** Flags and cuts **
+  bool fIsMcPresent {false};  ///< Flag: true - all procedures involving MC will be processed, otherwice data will be processed only
+
+  bool fIsQaPassed {true};  ///< Flag: true - QA is successfull, false - Qa is failed 
+
+  /// Maximum allowed distance between z-components of hit/MC-point position and the station center [cm]
+  double fMaxDistanceZ {1.0};  
+
+  double fMinMomentum {0.01}; ///< Minimum value of particle momentum z component [GeV/c]
+  
+  double fMaxPullsRmsDiff {0.05};  ///< Maximum difference of the pulls RMS from unity
+  
+  // ** Input arrays **
+
+  CbmTrackingDetectorInterfaceBase* fpDetectorInterface {nullptr};  ///< Pointer to current tracking detector I/F
+  CbmTimeSlice* fpTimeSlice {nullptr};                              ///< Pointer to current time slice
+  CbmDigiManager* fpDigiManager {nullptr};                          ///< Pointer to digi manager
+
+  CbmMCEventList* fpMcEventList {nullptr};
+  CbmMCDataManager* fpMcManager {nullptr};
+
+  TClonesArray* fpClusters {nullptr};          ///< Clusters
+  TClonesArray* fpHits {nullptr};              ///< Hits
+  TClonesArray* fpClusterMatches {nullptr};    ///< Matches for clusters (used only in STS)
+  TClonesArray* fpHitMatches {nullptr};        ///< Matches for hits, provided with CbmMatchRecoToMC task
+
+  CbmMCDataArray* fpMcTracks {nullptr};
+  CbmMCDataArray* fpMcPoints {nullptr};
+
+
+  // ** Output folders **
+
+  TFolder  fOutFolder {"TrackingInputQaSts", "TrackingInputQaSts"}; ///< Output folder for this QA task
+  TFolder* fpOutFolderHists {nullptr};  ///< Subfolder for raw histograms
+
+  std::vector<TH1*> fHistList;  ///< List of the pointers to all histograms contained in the class
+
+  // ** Histograms **
+
+  TParameter<long> fNevents {"nEvents", 0};  ///< Number of processed events
+  
+  std::vector<CbmQaHist<TH1D>> fHistResidualX;  ///< Residual distributions for X vs index of a station
+  std::vector<CbmQaHist<TH1D>> fHistResidualY;  ///< Residual distributions for X vs index of a station
+  std::vector<CbmQaHist<TH1D>> fHistResidualT;  ///< Residual distributions for T vs index of a station
+
+  std::vector<CbmQaHist<TH1D>> fHistPullX;  ///< Pulls distribution for X vs. index of a station
+  std::vector<CbmQaHist<TH1D>> fHistPullY;  ///< Pulls distribution for Y vs. index of a station
+  std::vector<CbmQaHist<TH1D>> fHistPullT;  ///< Pulls distribution for T vs. index of a station
+
+  std::vector<CbmQaHist<TH1D>> fHistPointsPerHit;  ///< Distribution of MC points per one hit vs. index of a station
+  std::vector<CbmQaHist<TH1D>> fHistHitsPerPoint;  ///< Distribution of hits per one MC point vs. index of a station
+
+  // TODO: There is a class TEfficiency in the ROOT, probably it's a good idea to use it here (S.Zharko)
+  std::vector<CbmQaHist<TProfile2D>> fHistEfficiencyXY;  ///< 
+  std::vector<CbmQaHist<TProfile>>   fHistEfficiencyR;   ///<
+
+  static constexpr std::tuple<int, double, double> fRangeResidualX {100, -0.01, 0.01}; 
+  static constexpr std::tuple<int, double, double> fRangeResidualY {100, -0.03, 0.03};
+  static constexpr std::tuple<int, double, double> fRangeResidualT {100, -25., 25.};
+
+  static constexpr std::tuple<int, double, double> fRangePullX {100, -5., 5.};
+  static constexpr std::tuple<int, double, double> fRangePullY {100, -5., 5.};
+  static constexpr std::tuple<int, double, double> fRangePullT {100, -5., 5.};
+
+  static constexpr std::tuple<int, double, double> fRangePointsPerHit {10, -0.5, 9.5};
+  static constexpr std::tuple<int, double, double> fRangeHitsPerPoint {10, -0.5, 9.5};
+
+
+  // ** Canvases **
+
+  CbmQaCanvas fCanvResidualX {"c_sts_residualX", "STS X Residual distributions", 1500, 1000 };
+  CbmQaCanvas fCanvResidualY {"c_sts_residualY", "STS Y Residual distributions", 1500, 1000 };
+  CbmQaCanvas fCanvResidualT {"c_sts_residualT", "STS T Residual distributions", 1500, 1000 };
+
+  CbmQaCanvas fCanvPullX {"c_sts_pullX", "STS X Pull distributions", 1500, 1000};
+  CbmQaCanvas fCanvPullY {"c_sts_pullY", "STS Y Pull distributions", 1500, 1000};
+  CbmQaCanvas fCanvPullT {"c_sts_pullT", "STS T Pull distributions", 1500, 1000};
+
+  CbmQaCanvas fCanvPointsPerHit {"c_sts_PointsPerHit", "STS MC Points per Hit", 1500, 1000};
+  CbmQaCanvas fCanvHitsPerPoint {"c_sts_HitsPerPoint", "STS Hits per MC Point", 1500, 1000};
+  
+  CbmQaCanvas fCanvEfficiencyR {"c_sts_EfficiencyR", "STS Efficiency vs. R", 1500, 1000};
+  CbmQaCanvas fCanvEfficiencyXY {"c_sts_EfficiencyXY", "STS Efficiency vs. X and Y", 1500, 1000};
+
+
+  // ************
+  // ** Output **
+  // ************
 
 
-  ClassDef(CbmTrackingInputQaSts, 0);
 };
 
-#endif  // CbmTrackingInputQaSts_h
+#endif
-- 
GitLab