From 8ea81a6d00318b1359faa4e2c4e6988a9798a616 Mon Sep 17 00:00:00 2001
From: sgorbuno <se.gorbunov@gsi.de>
Date: Wed, 10 Mar 2021 13:53:36 +0000
Subject: [PATCH] make the QA tasks work with timeslices

---
 core/detectors/much/CbmMuchPointInfo.h        |  16 +-
 macro/run/run_qa.C                            |  20 +-
 reco/detectors/much/qa/CbmMuchHitFinderQa.cxx | 121 +--
 reco/detectors/much/qa/CbmMuchHitFinderQa.h   |  24 +-
 reco/detectors/sts/CMakeLists.txt             |   4 +
 reco/detectors/sts/CbmStsFindTracksQa.cxx     | 726 +++++++++---------
 reco/detectors/sts/CbmStsFindTracksQa.h       | 176 +++--
 sim/detectors/much/qa/CbmMuchDigitizerQa.cxx  | 234 +++---
 sim/detectors/much/qa/CbmMuchDigitizerQa.h    |  32 +-
 sim/detectors/much/qa/CbmMuchTransportQa.cxx  | 122 +--
 sim/detectors/much/qa/CbmMuchTransportQa.h    |  14 +-
 11 files changed, 833 insertions(+), 656 deletions(-)

diff --git a/core/detectors/much/CbmMuchPointInfo.h b/core/detectors/much/CbmMuchPointInfo.h
index 0d38fa7009..83d2a23b5e 100644
--- a/core/detectors/much/CbmMuchPointInfo.h
+++ b/core/detectors/much/CbmMuchPointInfo.h
@@ -31,14 +31,14 @@ public:
   }
   void Print(Option_t* = "") const;
 
-  Double_t GetKine() { return fKine; }
-  Double_t GetLength() { return fLength; }
-  Int_t GetPdgCode() { return fPdgCode; }
-  Int_t GetMotherPdg() { return fMotherPdg; }
-  Int_t GetCharge() { return fCharge; }
-  Int_t GetStationId() { return fStationId; }
-  Double_t GetArea() { return fS; }
-  Int_t GetNPads() { return fNPads; }
+  Double_t GetKine() const { return fKine; }
+  Double_t GetLength() const { return fLength; }
+  Int_t GetPdgCode() const { return fPdgCode; }
+  Int_t GetMotherPdg() const { return fMotherPdg; }
+  Int_t GetCharge() const { return fCharge; }
+  Int_t GetStationId() const { return fStationId; }
+  Double_t GetArea() const { return fS; }
+  Int_t GetNPads() const { return fNPads; }
 
 private:
   Double_t fKine;
diff --git a/macro/run/run_qa.C b/macro/run/run_qa.C
index d0104352c3..86bfae43e8 100644
--- a/macro/run/run_qa.C
+++ b/macro/run/run_qa.C
@@ -33,9 +33,8 @@
 #include <TStopwatch.h>
 #endif
 
-void run_qa(Int_t nEvents   = 0,
-            TString dataset = "data/sis100_muon_jpsi_test",
-            TString setup   = "sis100_muon_jpsi") {
+void run_qa(TString dataset = "data/sis100_muon_jpsi_test", TString setup = "sis100_muon_jpsi", Int_t nEvents = -1)
+{
 
   // ========================================================================
   //          Adjust this part according to your requirements
@@ -51,10 +50,10 @@ void run_qa(Int_t nEvents   = 0,
   // ------------------------------------------------------------------------
 
   // -----   In- and output file names   ------------------------------------
-  TString rawFile  = dataset + ".event.raw.root";
+  TString rawFile  = dataset + ".raw.root";
   TString traFile  = dataset + ".tra.root";
   TString parFile  = dataset + ".par.root";
-  TString recFile  = dataset + ".rec.root";
+  TString recFile  = dataset + ".reco.root";
   TString sinkFile = dataset + ".qa.root";
   // ------------------------------------------------------------------------
 
@@ -140,18 +139,25 @@ void run_qa(Int_t nEvents   = 0,
   FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monitorFile);
   // ------------------------------------------------------------------------
 
-  // -----   MCDataManager (legacy mode)  -----------------------------------
-  CbmMCDataManager* mcManager = new CbmMCDataManager("MCDataManager", 1);
+  // -----   MCDataManager  -----------------------------------
+  CbmMCDataManager* mcManager = new CbmMCDataManager("MCDataManager", 0);
   mcManager->AddFile(traFile);
   run->AddTask(mcManager);
   // ------------------------------------------------------------------------
 
+  // ----- Match reco to MC ------
+  CbmMatchRecoToMC* matchTask = new CbmMatchRecoToMC();
+  run->AddTask(matchTask);
+
   // ----- MUCH QA  ---------------------------------
   if (CbmSetup::Instance()->IsActive(ECbmModuleId::kMuch)) {
     run->AddTask(new CbmMuchTransportQa());
     run->AddTask(new CbmMuchDigitizerQa());
     run->AddTask(new CbmMuchHitFinderQa());
   }
+
+  // ----- STS QA  ---------------------------------
+  if (CbmSetup::Instance()->IsActive(ECbmModuleId::kSts)) { run->AddTask(new CbmStsFindTracksQa()); }
   // ------------------------------------------------------------------------
 
   // -----  Parameter database   --------------------------------------------
diff --git a/reco/detectors/much/qa/CbmMuchHitFinderQa.cxx b/reco/detectors/much/qa/CbmMuchHitFinderQa.cxx
index ebe7f84917..ca3e59c9fe 100644
--- a/reco/detectors/much/qa/CbmMuchHitFinderQa.cxx
+++ b/reco/detectors/much/qa/CbmMuchHitFinderQa.cxx
@@ -11,6 +11,8 @@
 #include "CbmDefs.h"
 #include "CbmDigiManager.h"
 #include "CbmLink.h"
+#include "CbmMCDataArray.h"
+#include "CbmMCDataManager.h"
 #include "CbmMCTrack.h"
 #include "CbmMatch.h"
 #include "CbmMuchAddress.h"
@@ -21,6 +23,7 @@
 #include "CbmMuchPixelHit.h"
 #include "CbmMuchPoint.h"
 #include "CbmQaCanvas.h"
+#include "CbmTimeSlice.h"
 
 #include "FairRootManager.h"
 #include <FairSink.h>
@@ -46,9 +49,10 @@
 #include <algorithm>
 #include <iostream>
 #include <map>
-#include <stdio.h>
 #include <vector>
 
+#include <stdio.h>
+
 using std::cout;
 using std::endl;
 using std::map;
@@ -129,10 +133,19 @@ void CbmMuchHitFinderQa::DeInit() {
 
 // -------------------------------------------------------------------------
 InitStatus CbmMuchHitFinderQa::Init() {
+
   DeInit();
-  FairRootManager* fManager = FairRootManager::Instance();
-  fMCTracks                 = (TClonesArray*) fManager->GetObject("MCTrack");
-  fPoints                   = (TClonesArray*) fManager->GetObject("MuchPoint");
+
+  fManager   = FairRootManager::Instance();
+  fMcManager = dynamic_cast<CbmMCDataManager*>(fManager->GetObject("MCDataManager"));
+
+  fTimeSlice = (CbmTimeSlice*) fManager->GetObject("TimeSlice.");
+
+  if (fMcManager) {
+    fMCTracks = fMcManager->InitBranch("MCTrack");
+    fPoints   = fMcManager->InitBranch("MuchPoint");
+  }
+
   fHits     = (TClonesArray*) fManager->GetObject("MuchPixelHit");
   fClusters = (TClonesArray*) fManager->GetObject("MuchCluster");
   // Reading Much Digis from CbmMuchDigiManager which are stored as vector
@@ -142,7 +155,7 @@ InitStatus CbmMuchHitFinderQa::Init() {
   TFile* oldFile     = gFile;
   TDirectory* oldDir = gDirectory;
 
-  TFile* f            = new TFile(fGeoFileName, "R");
+  TFile* f = new TFile(fGeoFileName, "R");
 
   /// Restore old global file and folder pointer to avoid messing with FairRoot
   gFile      = oldFile;
@@ -310,7 +323,8 @@ void CbmMuchHitFinderQa::Exec(Option_t*) {
 
 // -------------------------------------------------------------------------
 void CbmMuchHitFinderQa::FinishTask() {
-  printf("FinishTask\n");
+
+  if (fVerbose > 0) { printf(" CbmMuchHitFinderQa FinishTask\n"); }
 
   gStyle->SetPaperSize(20, 20);
 
@@ -320,11 +334,6 @@ void CbmMuchHitFinderQa::FinishTask() {
     fhHitsPerCluster[i]->Scale(1. / fNevents.GetVal());
   }
 
-  if (fVerbose > 1) {
-    printf("===================================\n");
-    printf("PullsQa:\n");
-  }
-
   std::vector<TH1D*> vResHistos;
   vResHistos.push_back(fhPullX);
   vResHistos.push_back(fhPullY);
@@ -337,18 +346,23 @@ void CbmMuchHitFinderQa::FinishTask() {
     TH1D* histo = vResHistos[i];
     histo->Sumw2();
     histo->Fit("gaus", "Q");
-    histo->GetFunction("gaus")->SetLineWidth(3);
-    histo->GetFunction("gaus")->SetLineColor(kRed);
+    auto f = histo->GetFunction("gaus");
+    if (f) {
+      f->SetLineWidth(3);
+      f->SetLineColor(kRed);
+    }
     // histo->SetStats(kTRUE);
   }
 
-  printf("===================================\n");
-  printf("StatisticsQa:\n");
-  printf("Total number of points: %i\n", fPointsTotal.GetVal());
-  printf("Points overcounted: %i\n", fPointsOverCounted.GetVal());
-  printf("Points undercounted: %i\n", fPointsUnderCounted.GetVal());
-  printf("Signal points: %i\n", fSignalPoints.GetVal());
-  printf("Signal hits: %i\n", fSignalHits.GetVal());
+  if (fVerbose > 0) {
+    printf("===================================\n");
+    printf("StatisticsQa:\n");
+    printf("Total number of points: %i\n", fPointsTotal.GetVal());
+    printf("Points overcounted: %i\n", fPointsOverCounted.GetVal());
+    printf("Points undercounted: %i\n", fPointsUnderCounted.GetVal());
+    printf("Signal points: %i\n", fSignalPoints.GetVal());
+    printf("Signal hits: %i\n", fSignalHits.GetVal());
+  }
 
   DrawCanvases();
 
@@ -505,7 +519,7 @@ void CbmMuchHitFinderQa::StatisticsQa() {
 // -------------------------------------------------------------------------
 void CbmMuchHitFinderQa::PullsQa() {
   Bool_t verbose = (fVerbose > 2);
-  // Filling residuals and pools for hits at the first layer
+  // Filling residuals and pulls for hits at the first layer
   for (Int_t i = 0; i < fHits->GetEntriesFast(); i++) {
     CbmMuchPixelHit* hit = (CbmMuchPixelHit*) fHits->At(i);
     // Select hits from the first station only
@@ -539,7 +553,7 @@ void CbmMuchHitFinderQa::PullsQa() {
     // Select hits with clusters formed by only one MC Point
     CbmMuchCluster* cluster = (CbmMuchCluster*) fClusters->At(clusterId);
     Bool_t point_unique     = 1;
-    Int_t pointId           = -1;
+    CbmLink link;
 
     for (Int_t digiId = 0; digiId < cluster->GetNofDigis(); digiId++) {
       Int_t index = cluster->GetDigi(digiId);
@@ -572,7 +586,7 @@ void CbmMuchHitFinderQa::PullsQa() {
         point_unique = 0;
         break;
       }
-      Int_t currentPointId = match->GetLink(0).GetIndex();
+      CbmLink currentLink = match->GetLink(0);
 
       CbmMuchModuleGem* module =
         (CbmMuchModuleGem*) fGeoScheme->GetModuleByDetId(digi->GetAddress());
@@ -581,11 +595,11 @@ void CbmMuchHitFinderQa::PullsQa() {
         return;
       }
       if (digiId == 0) {
-        pointId = currentPointId;
+        link = currentLink;
         continue;
       }
       // Not unique if mcPoint references differ for different digis
-      if (currentPointId != pointId) {
+      if (!(currentLink == link)) {
         point_unique = 0;
         break;
       }
@@ -597,8 +611,8 @@ void CbmMuchHitFinderQa::PullsQa() {
       continue;
     }
 
-    if (verbose) printf(" pointId=%i", pointId);
-    CbmMuchPoint* point = (CbmMuchPoint*) fPoints->At(pointId);
+    if (verbose) { printf(" file %i event %i pointId %i", link.GetFile(), link.GetEntry(), link.GetIndex()); }
+    CbmMuchPoint* point = (CbmMuchPoint*) fPoints->Get(link);
 
     Double_t xMC = 0.5 * (point->GetXIn() + point->GetXOut());
     Double_t yMC = 0.5 * (point->GetYIn() + point->GetYOut());
@@ -614,11 +628,11 @@ void CbmMuchHitFinderQa::PullsQa() {
     //    cout<<" Rec Hit time "<<tRC<<endl;
 
     if (dx < 1.e-10) {
-      printf("Anomalously small dx\n");
+      LOG(error) << "Anomalously small dx";
       continue;
     }
     if (dy < 1.e-10) {
-      printf("Anomalously small dy\n");
+      LOG(error) << "Anomalously small dy";
       continue;
     }
     fhPullX->Fill((xRC - xMC) / dx);
@@ -636,15 +650,26 @@ void CbmMuchHitFinderQa::PullsQa() {
 
 // -------------------------------------------------------------------------
 void CbmMuchHitFinderQa::ClusterDeconvQa() {
-  Int_t nPoints   = fPoints->GetEntriesFast();
-  Int_t nClusters = fClusters->GetEntriesFast();
-  vector<Int_t> pIndices;
-  vector<Int_t>::iterator it;
 
-  for (Int_t iPoint = 0; iPoint < nPoints; ++iPoint) {
-    if (IsSignalPoint(iPoint)) fSignalPoints.SetVal(fSignalPoints.GetVal() + 1);
+  Int_t nClusters = fClusters->GetEntriesFast();
+  vector<CbmLink> vPoints;
+
+  {
+    const CbmMatch& match = fTimeSlice->GetMatch();
+    for (int iLink = 0; iLink < match.GetNofLinks(); iLink++) {
+      CbmLink link    = match.GetLink(iLink);
+      int nMuchPoints = fPoints->Size(link);
+      for (Int_t iPoint = 0; iPoint < nMuchPoints; iPoint++) {
+        link.SetIndex(iPoint);
+        link.SetWeight(0.);
+        if (IsSignalPoint(link)) { fSignalPoints.SetVal(fSignalPoints.GetVal() + 1); }
+        vPoints.push_back(link);
+      }
+    }
   }
 
+  std::sort(vPoints.begin(), vPoints.end());
+
   for (Int_t iCluster = 0; iCluster < nClusters; ++iCluster) {
     CbmMuchCluster* cluster = (CbmMuchCluster*) fClusters->At(iCluster);
     if (!cluster) {
@@ -663,29 +688,27 @@ void CbmMuchHitFinderQa::ClusterDeconvQa() {
         return;
       }
       for (Int_t ip = 0; ip < match->GetNofLinks(); ++ip) {
-        Int_t iPoint = match->GetLink(ip).GetIndex();
-        it           = find(pIndices.begin(), pIndices.end(), iPoint);
-        if (it != pIndices.end()) continue;
-        pIndices.push_back(iPoint);
-        if (IsSignalPoint(iPoint)) fSignalHits.SetVal(fSignalHits.GetVal() + 1);
+        CbmLink pointLink = match->GetLink(ip);
+        auto it           = find(vPoints.begin(), vPoints.end(), pointLink);
+        assert(it != vPoints.end());
+        if (it->GetWeight() > 0.) continue;
+        it->SetWeight(1.);
+        if (IsSignalPoint(pointLink)) { fSignalHits.SetVal(fSignalHits.GetVal() + 1); }
       }
     }
   }
 }
 // -------------------------------------------------------------------------
 
-Bool_t CbmMuchHitFinderQa::IsSignalPoint(Int_t iPoint) {
-  Int_t nPoints       = fPoints->GetEntriesFast();
-  Int_t nTracks       = fMCTracks->GetEntriesFast();
-  CbmMuchPoint* point = (iPoint < 0 || iPoint > nPoints - 1)
-                          ? NULL
-                          : (CbmMuchPoint*) fPoints->At(iPoint);
+Bool_t CbmMuchHitFinderQa::IsSignalPoint(CbmLink pointLink)
+{
+
+  CbmMuchPoint* point = (CbmMuchPoint*) fPoints->Get(pointLink);
   if (!point) return kFALSE;
   Int_t iTrack      = point->GetTrackID();
-  CbmMCTrack* track = (iTrack < 0 || iTrack > nTracks - 1)
-                        ? NULL
-                        : (CbmMCTrack*) fMCTracks->At(iTrack);
+  CbmMCTrack* track = (CbmMCTrack*) fMCTracks->Get(pointLink.GetFile(), pointLink.GetEntry(), iTrack);
   if (!track) return kFALSE;
+
   if (iTrack != 0 && iTrack != 1)
     return kFALSE;  // Signal tracks must be fist ones
   // Verify if it is a signal muon
diff --git a/reco/detectors/much/qa/CbmMuchHitFinderQa.h b/reco/detectors/much/qa/CbmMuchHitFinderQa.h
index a61a438f11..1225734fc1 100644
--- a/reco/detectors/much/qa/CbmMuchHitFinderQa.h
+++ b/reco/detectors/much/qa/CbmMuchHitFinderQa.h
@@ -7,6 +7,8 @@
 #ifndef CbmMuchHitFinderQa_H
 #define CbmMuchHitFinderQa_H
 
+#include "CbmLink.h"
+
 #include "FairTask.h"
 
 #include "TParameter.h"
@@ -24,6 +26,9 @@ class TClonesArray;
 class TH1D;
 class TH1I;
 class TMemberInspector;
+class CbmMCDataArray;
+class CbmMCDataManager;
+class CbmTimeSlice;
 
 class CbmMuchHitFinderQa : public FairTask {
 
@@ -56,12 +61,20 @@ private:
   void DeInit();
   void DrawCanvases();
 
+  // setup
+  FairRootManager* fManager    = nullptr;  //!
+  CbmMCDataManager* fMcManager = nullptr;  //!
+  CbmTimeSlice* fTimeSlice     = nullptr;  //!
+
+  //
   CbmMuchGeoScheme* fGeoScheme;
   TString fGeoFileName;
   TString fFileName;
-  Int_t fVerbose               = 0;
-  Int_t fFlag                  = 0;
-  TClonesArray* fPoints        = nullptr;
+  Int_t fVerbose = 0;
+  Int_t fFlag    = 0;
+
+  CbmMCDataArray* fMCTracks    = nullptr;
+  CbmMCDataArray* fPoints      = nullptr;
   CbmDigiManager* fDigiManager = nullptr;
 
   TFolder fOutFolder;   /// output folder with histos and canvases
@@ -69,7 +82,6 @@ private:
 
   TClonesArray* fClusters = nullptr;
   TClonesArray* fHits     = nullptr;
-  TClonesArray* fMCTracks = nullptr;
 
   Int_t fNstations = 0;
 
@@ -101,12 +113,12 @@ private:
   TParameter<int> fPointsOverCounted;
 
   /** Defines whether the point with the given index is signal point. **/
-  Bool_t IsSignalPoint(Int_t iPoint);
+  Bool_t IsSignalPoint(CbmLink pointLink);
 
   CbmMuchHitFinderQa(const CbmMuchHitFinderQa&);
   CbmMuchHitFinderQa& operator=(const CbmMuchHitFinderQa&);
 
-  ClassDef(CbmMuchHitFinderQa, 1)
+  ClassDef(CbmMuchHitFinderQa, 0)
 };
 
 #endif
diff --git a/reco/detectors/sts/CMakeLists.txt b/reco/detectors/sts/CMakeLists.txt
index 732f085c0b..7a22abb28b 100644
--- a/reco/detectors/sts/CMakeLists.txt
+++ b/reco/detectors/sts/CMakeLists.txt
@@ -41,6 +41,10 @@ ${CBMDATA_DIR}
 ${CBMDATA_DIR}/base
 ${CBMDATA_DIR}/global
 ${CBMDATA_DIR}/sts
+${CBMDATA_DIR}/mvd
+
+# MVD
+${CBMROOT_SOURCE_DIR}/mvd
 
 # STS
 ${CBMDETECTORBASE_DIR}/sts
diff --git a/reco/detectors/sts/CbmStsFindTracksQa.cxx b/reco/detectors/sts/CbmStsFindTracksQa.cxx
index 038969aeea..afba76850f 100644
--- a/reco/detectors/sts/CbmStsFindTracksQa.cxx
+++ b/reco/detectors/sts/CbmStsFindTracksQa.cxx
@@ -21,16 +21,21 @@
 #include "FairRun.h"
 
 // Includes from CbmRoot
-#include "CbmEvent.h"
 #include "CbmMCDataArray.h"
 #include "CbmMCDataManager.h"
 #include "CbmMCTrack.h"
+#include "CbmMvdDetector.h"
+#include "CbmMvdHit.h"
+#include "CbmMvdPoint.h"
+#include "CbmMvdStationPar.h"
 #include "CbmStsHit.h"
 #include "CbmStsPoint.h"
 #include "CbmStsSetup.h"
 #include "CbmStsTrack.h"
+#include "CbmTimeSlice.h"
 #include "CbmTrackMatchNew.h"
 
+#include "FairRunAna.h"
 
 using std::fixed;
 using std::right;
@@ -39,125 +44,18 @@ using std::setw;
 
 
 // -----   Default constructor   -------------------------------------------
-CbmStsFindTracksQa::CbmStsFindTracksQa(Int_t iVerbose)
-  : FairTask("STSFindTracksQA", iVerbose)
-  , fHitMap()
-  , fMatchMap()
-  , fQualiMap()
-  , fEvents()
-  , fMCTracks(NULL)
-  , fStsPoints(NULL)
-  , fStsHits(NULL)
-  , fStsHitMatch(NULL)
-  , fStsTracks(NULL)
-  , fMatches(NULL)
-  , fLegacy(kFALSE)
-  , fTargetPos(0., 0., 0.)
-  , fSetup(NULL)
-  , fNStations(0)
-  , fMinStations(3)
-  , fQuota(0.7)
-  , fhMomAccAll(new TH1F())
-  , fhMomRecAll(new TH1F())
-  , fhMomEffAll(new TH1F())
-  , fhMomAccPrim(new TH1F())
-  , fhMomRecPrim(new TH1F())
-  , fhMomEffPrim(new TH1F())
-  , fhMomAccSec(new TH1F())
-  , fhMomRecSec(new TH1F())
-  , fhMomEffSec(new TH1F())
-  , fhNpAccAll(new TH1F())
-  , fhNpRecAll(new TH1F())
-  , fhNpEffAll(new TH1F())
-  , fhNpAccPrim(new TH1F())
-  , fhNpRecPrim(new TH1F())
-  , fhNpEffPrim(new TH1F())
-  , fhNpAccSec(new TH1F())
-  , fhNpRecSec(new TH1F())
-  , fhNpEffSec(new TH1F())
-  , fhZAccSec(new TH1F())
-  , fhZRecSec(new TH1F())
-  , fhZEffSec(new TH1F())
-  , fhNhClones(new TH1F())
-  , fhNhGhosts(new TH1F())
-  , fHistoList(new TList())
-  , fNAccAll(0)
-  , fNAccPrim(0)
-  , fNAccRef(0)
-  , fNAccSec(0)
-  , fNRecAll(0)
-  , fNRecPrim(0)
-  , fNRecRef(0)
-  , fNRecSec(0)
-  , fNGhosts(0)
-  , fNClones(0)
-  , fNEvents(0)
-  , fNEventsFailed(0)
-  , fTime(0.)
-  , fTimer() {}
+CbmStsFindTracksQa::CbmStsFindTracksQa(Int_t iVerbose) : FairTask("STSFindTracksQA", iVerbose) {}
 
 // -------------------------------------------------------------------------
 
 
 // -----   Standard constructor   ------------------------------------------
-CbmStsFindTracksQa::CbmStsFindTracksQa(Int_t minStations,
-                                       Double_t quota,
-                                       Int_t iVerbose)
+CbmStsFindTracksQa::CbmStsFindTracksQa(Int_t minStations, Double_t quota, Int_t iVerbose)
   : FairTask("STSFindTracksQA", iVerbose)
-  , fHitMap()
-  , fMatchMap()
-  , fQualiMap()
-  , fEvents(NULL)
-  , fMCTracks(NULL)
-  , fStsPoints(NULL)
-  , fStsHits(NULL)
-  , fStsHitMatch(NULL)
-  , fStsTracks(NULL)
-  , fMatches(NULL)
-  , fLegacy(kFALSE)
-  , fTargetPos(0., 0., 0.)
-  , fSetup(NULL)
-  , fNStations(0)
   , fMinStations(minStations)
   , fQuota(quota)
-  , fhMomAccAll(new TH1F())
-  , fhMomRecAll(new TH1F())
-  , fhMomEffAll(new TH1F())
-  , fhMomAccPrim(new TH1F())
-  , fhMomRecPrim(new TH1F())
-  , fhMomEffPrim(new TH1F())
-  , fhMomAccSec(new TH1F())
-  , fhMomRecSec(new TH1F())
-  , fhMomEffSec(new TH1F())
-  , fhNpAccAll(new TH1F())
-  , fhNpRecAll(new TH1F())
-  , fhNpEffAll(new TH1F())
-  , fhNpAccPrim(new TH1F())
-  , fhNpRecPrim(new TH1F())
-  , fhNpEffPrim(new TH1F())
-  , fhNpAccSec(new TH1F())
-  , fhNpRecSec(new TH1F())
-  , fhNpEffSec(new TH1F())
-  , fhZAccSec(new TH1F())
-  , fhZRecSec(new TH1F())
-  , fhZEffSec(new TH1F())
-  , fhNhClones(new TH1F())
-  , fhNhGhosts(new TH1F())
-  , fHistoList(new TList())
-  , fNAccAll(0)
-  , fNAccPrim(0)
-  , fNAccRef(0)
-  , fNAccSec(0)
-  , fNRecAll(0)
-  , fNRecPrim(0)
-  , fNRecRef(0)
-  , fNRecSec(0)
-  , fNGhosts(0)
-  , fNClones(0)
-  , fNEvents(0)
-  , fNEventsFailed(0)
-  , fTime(0.)
-  , fTimer() {}
+{
+}
 // -------------------------------------------------------------------------
 
 
@@ -173,174 +71,82 @@ CbmStsFindTracksQa::~CbmStsFindTracksQa() {
 // -----   Task execution   ------------------------------------------------
 void CbmStsFindTracksQa::Exec(Option_t* /*opt*/) {
 
-  // If there is an event branch: do the event loop
-  if (fEvents) {
-    Int_t nEvents = fEvents->GetEntriesFast();
-    LOG(debug) << GetName() << ": found time slice with " << nEvents
-               << " events.";
-
-    for (Int_t iEvent = 0; iEvent < nEvents; iEvent++) {
-      CbmEvent* event = dynamic_cast<CbmEvent*>(fEvents->At(iEvent));
-      assert(event);
-      ProcessEvent(event);
-    }
-  }
-
-  // If there is no event branch, process the entire tree
-  else {
-    ProcessEvent();
-  }
-}
-// -------------------------------------------------------------------------
-
-
-// -----   Public method SetParContainers   --------------------------------
-void CbmStsFindTracksQa::SetParContainers() {}
-// -------------------------------------------------------------------------
-
-
-// -----   Public method Init   --------------------------------------------
-InitStatus CbmStsFindTracksQa::Init() {
-
-  LOG(info) << "\n\n====================================================";
-  LOG(info) << GetName() << ": Initialising...";
-
-  // Get RootManager
-  FairRootManager* ioman = FairRootManager::Instance();
-  assert(ioman);
-
-  // Get STS setup
-  fSetup = CbmStsSetup::Instance();
-
-  // Get MCDataManager
-  CbmMCDataManager* mcManager =
-    dynamic_cast<CbmMCDataManager*>(ioman->GetObject("MCDataManager"));
-  assert(mcManager);
-
-  // Get MCTrack array
-  fMCTracks = mcManager->InitBranch("MCTrack");
-  assert(fMCTracks);
-
-  // Get StsPoint array
-  fStsPoints = mcManager->InitBranch("StsPoint");
-  assert(fStsPoints);
-
-  // Get Event array
-  fEvents = dynamic_cast<TClonesArray*>(ioman->GetObject("CbmEvent"));
-
-  // Get StsHit array
-  fStsHits = (TClonesArray*) ioman->GetObject("StsHit");
-  assert(fStsHits);
-
-  // Get StsHitMatch array
-  fStsHitMatch = (TClonesArray*) ioman->GetObject("StsHitMatch");
-  assert(fStsHitMatch);
-
-  // Get StsTrack array
-  fStsTracks = (TClonesArray*) ioman->GetObject("StsTrack");
-  assert(fStsTracks);
-
-  // Get StsTrackMatch array
-  fMatches = (TClonesArray*) ioman->GetObject("StsTrackMatch");
-  assert(fMatches);
-
-
-  // Get the geometry of target and STS
-  InitStatus geoStatus = GetGeometry();
-  if (geoStatus != kSUCCESS) {
-    LOG(error) << GetName() << "::Init: Error in reading geometry!";
-    return geoStatus;
-  }
-
-  // Create histograms
-  CreateHistos();
-  Reset();
-
-  // Output
-  LOG(info) << "   Number of STS stations : " << fNStations;
-  LOG(info) << "   Target position ( " << fTargetPos.X() << ", "
-            << fTargetPos.Y() << ", " << fTargetPos.Z() << ") cm";
-  LOG(info) << "   Minimum number of STS stations   : " << fMinStations;
-  LOG(info) << "   Matching quota               : " << fQuota;
-  LOG(info) << "====================================================";
-
-  return geoStatus;
-}
-// -------------------------------------------------------------------------
-
-
-// -----   Public method ReInit   ------------------------------------------
-InitStatus CbmStsFindTracksQa::ReInit() {
-
-  LOG(info) << "\n\n====================================================";
-  LOG(info) << GetName() << ": Re-initialising...";
-
-  // Get the geometry of target and STS
-  InitStatus geoStatus = GetGeometry();
-  if (geoStatus != kSUCCESS) {
-    LOG(error) << GetName() << "::Init: Error in reading geometry!";
-    return geoStatus;
-  }
-
-  // --- Screen log
-  LOG(info) << "   Number of STS stations : " << fNStations;
-  LOG(info) << "   Target position ( " << fTargetPos.X() << ", "
-            << fTargetPos.Y() << ", " << fTargetPos.Z() << ") cm";
-  LOG(info) << "   Minimum number of STS stations   : " << fMinStations;
-  LOG(info) << "   Matching quota               : " << fQuota;
-  LOG(info) << "====================================================";
-
-  return geoStatus;
-}
-// -------------------------------------------------------------------------
-
-
-// -----   Public method Exec   --------------------------------------------
-void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
-
-  // --- Event number. Note that the FairRun counting start with 1.
-  Int_t eventNumber =
-    (event ? event->GetNumber()
-           : FairRun::Instance()->GetEventHeader()->GetMCEntryNumber() - 1);
-
-  LOG(debug) << GetName() << ": Process event " << eventNumber;
+  LOG(debug) << GetName() << ": Process event ";
 
   // Timer
   fTimer.Start();
 
   // Eventwise counters
   //  Int_t nMCTracks = 0;
-  Int_t nTracks  = 0;
-  Int_t nGhosts  = 0;
-  Int_t nClones  = 0;
-  Int_t nAll     = 0;
-  Int_t nAcc     = 0;
-  Int_t nRecAll  = 0;
-  Int_t nPrim    = 0;
-  Int_t nRecPrim = 0;
-  Int_t nRef     = 0;
-  Int_t nRecRef  = 0;
-  Int_t nSec     = 0;
-  Int_t nRecSec  = 0;
+  Int_t nTracks     = 0;
+  Int_t nGhosts     = 0;
+  Int_t nClones     = 0;
+  Int_t nAll        = 0;
+  Int_t nAcc        = 0;
+  Int_t nRecAll     = 0;
+  Int_t nPrim       = 0;
+  Int_t nRecPrim    = 0;
+  Int_t nRef        = 0;
+  Int_t nRecRef     = 0;
+  Int_t nRefLong    = 0;
+  Int_t nRecRefLong = 0;
+  Int_t nSec        = 0;
+  Int_t nRecSec     = 0;
   TVector3 momentum;
   TVector3 vertex;
 
+  // check consistency
+  assert(fStsTracks->GetEntriesFast() == fStsTrackMatches->GetEntriesFast());
+
+  {
+    fMcTrackInfoMap.clear();
+    std::vector<CbmLink> events = fTimeSlice->GetMatch().GetLinks();
+    std::sort(events.begin(), events.end());
+    McTrackInfo info;
+    for (uint iLink = 0; iLink < events.size(); iLink++) {
+      CbmLink link    = events[iLink];
+      Int_t nMCTracks = fMCTracks->Size(link);
+      for (Int_t iTr = 0; iTr < nMCTracks; iTr++) {
+        link.SetIndex(iTr);
+        fMcTrackInfoMap.insert({link, info});
+      }
+    }
+  }
+
   // Fill hit and track maps
-  FillHitMap(event);
-  FillMatchMap(event, nTracks, nGhosts, nClones);
+  FillHitMap();
+  FillMatchMap(nTracks, nGhosts, nClones);
+
+  int nMcTracks = fMcTrackInfoMap.size();
 
   // Loop over MCTracks
-  Int_t nMcTracks = fMCTracks->Size(0, eventNumber);
-  for (Int_t mcTrackId = 0; mcTrackId < nMcTracks; mcTrackId++) {
-    CbmMCTrack* mcTrack =
-      dynamic_cast<CbmMCTrack*>(fMCTracks->Get(0, eventNumber, mcTrackId));
+  int iMcTrack = 0;
+  for (auto itTrack = fMcTrackInfoMap.begin(); itTrack != fMcTrackInfoMap.end(); ++itTrack, ++iMcTrack) {
+    const CbmLink& link = itTrack->first;
+    McTrackInfo& info   = itTrack->second;
+    CbmMCTrack* mcTrack = dynamic_cast<CbmMCTrack*>(fMCTracks->Get(link));
     assert(mcTrack);
 
     // Continue only for reconstructible tracks
     nAll++;
-    if (fHitMap.find(mcTrackId) == fHitMap.end()) continue;  // No hits
-    Int_t nStations = fHitMap[mcTrackId].size();
+    Int_t nStations = info.fHitMap.size();
     if (nStations < fMinStations) continue;  // Too few stations
+
+    int nContStations = 0;  // Number of continious stations
+    {
+      int istaprev = -1;
+      int len      = 0;
+      for (auto itSta = info.fHitMap.begin(); itSta != info.fHitMap.end(); itSta++) {
+        if (len == 0 || itSta->first == istaprev + 1) { len++; }
+        else {
+          len = 1;
+        }
+        if (nContStations < len) { nContStations = len; }
+        istaprev = itSta->first;
+      }
+    }
+    if (nContStations < fMinStations) continue;  // Too few stations
+
     nAcc++;
 
     // Check origin of MCTrack
@@ -363,6 +169,12 @@ void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
       nRef++;
     }
 
+    Bool_t isRefLong = kFALSE;
+    if (isRef && nContStations >= fStsNstations) {
+      isRefLong = kTRUE;
+      nRefLong++;
+    }
+
     // Fill histograms for reconstructible tracks
     fhMomAccAll->Fill(mom);
     fhNpAccAll->Fill(Double_t(nStations));
@@ -376,29 +188,26 @@ void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
     }
 
     // Get matched StsTrack
-    Int_t trackId  = -1;
-    Double_t quali = 0.;
+    Int_t trackId  = info.fStsTrackMatch;
+    Double_t quali = info.fQuali;
     //    Bool_t   isRec    = kFALSE;
-    if (fMatchMap.find(mcTrackId) != fMatchMap.end()) {
-      trackId = fMatchMap[mcTrackId];
+    if (trackId >= 0) {
       //      isRec = kTRUE;
       CbmStsTrack* stsTrack = (CbmStsTrack*) fStsTracks->At(trackId);
       assert(stsTrack);
-      quali = fQualiMap[mcTrackId];
       assert(quali >= fQuota);
-      CbmTrackMatchNew* match = (CbmTrackMatchNew*) fMatches->At(trackId);
+      CbmTrackMatchNew* match = (CbmTrackMatchNew*) fStsTrackMatches->At(trackId);
       assert(match);
       Int_t nTrue  = match->GetNofTrueHits();
       Int_t nWrong = match->GetNofWrongHits();
       //Int_t nFake  = match->GetNofFakeHits();
       Int_t nFake    = 0;
-      Int_t nAllHits = stsTrack->GetNofStsHits();
+      Int_t nAllHits = stsTrack->GetNofStsHits() + stsTrack->GetNofMvdHits();
+      if (!fIsMvdActive) { assert(stsTrack->GetNofMvdHits() == 0); }
       assert(nTrue + nWrong + nFake == nAllHits);
-
       // Verbose output
-      LOG(debug1) << GetName() << ": MCTrack " << mcTrackId << ", stations "
-                  << nStations << ", hits " << nAllHits << ", true hits "
-                  << nTrue;
+      LOG(debug1) << GetName() << ": MCTrack " << iMcTrack << ", stations " << nStations << ", hits " << nAllHits
+                  << ", true hits " << nTrue;
 
       // Fill histograms for reconstructed tracks
       nRecAll++;
@@ -408,24 +217,25 @@ void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
         nRecPrim++;
         fhMomRecPrim->Fill(mom);
         fhNpRecPrim->Fill(Double_t(nAllHits));
-        if (isRef) nRecRef++;
       } else {
         nRecSec++;
         fhMomRecSec->Fill(mom);
         fhNpRecSec->Fill(Double_t(nAllHits));
         fhZRecSec->Fill(vertex.Z());
       }
+      if (isRef) nRecRef++;
+      if (isRefLong) nRecRefLong++;
 
     }  // Match found in map?
 
   }  // Loop over MCTracks
 
-
   // Calculate efficiencies
-  Double_t effAll  = Double_t(nRecAll) / Double_t(nAcc);
-  Double_t effPrim = Double_t(nRecPrim) / Double_t(nPrim);
-  Double_t effRef  = Double_t(nRecRef) / Double_t(nRef);
-  Double_t effSec  = Double_t(nRecSec) / Double_t(nSec);
+  Double_t effAll     = Double_t(nRecAll) / Double_t(nAcc);
+  Double_t effPrim    = Double_t(nRecPrim) / Double_t(nPrim);
+  Double_t effRef     = Double_t(nRecRef) / Double_t(nRef);
+  Double_t effRefLong = Double_t(nRecRefLong) / Double_t(nRefLong);
+  Double_t effSec     = Double_t(nRecSec) / Double_t(nSec);
 
   fTimer.Stop();
 
@@ -446,6 +256,8 @@ void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
     LOG(debug) << "Reference  : reconstructible: " << nRef
                << ", reconstructed: " << nRecRef << ", efficiency "
                << effRef * 100. << "%";
+    LOG(debug) << "Reference long : reconstructible: " << nRefLong << ", reconstructed: " << nRecRefLong
+               << ", efficiency " << effRefLong * 100. << "%";
     LOG(debug) << "Non-vertex : reconstructible: " << nSec
                << ", reconstructed: " << nRecSec << ", efficiency "
                << effSec * 100. << "%";
@@ -457,13 +269,16 @@ void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
 
 
   // Increase counters
+  fNAll += nAll;
   fNAccAll += nAcc;
   fNAccPrim += nPrim;
   fNAccRef += nRef;
+  fNAccRefLong += nRefLong;
   fNAccSec += nSec;
   fNRecAll += nRecAll;
   fNRecPrim += nRecPrim;
   fNRecRef += nRecRef;
+  fNRecRefLong += nRecRefLong;
   fNRecSec += nRecSec;
   fNGhosts += nGhosts;
   fNClones += nClones;
@@ -473,6 +288,136 @@ void CbmStsFindTracksQa::ProcessEvent(CbmEvent* event) {
 // -------------------------------------------------------------------------
 
 
+// -----   Public method SetParContainers   --------------------------------
+void CbmStsFindTracksQa::SetParContainers() {}
+// -------------------------------------------------------------------------
+
+
+// -----   Public method Init   --------------------------------------------
+InitStatus CbmStsFindTracksQa::Init()
+{
+
+  LOG(info) << "\n\n====================================================";
+  LOG(info) << GetName() << ": Initialising...";
+
+  // Get STS setup
+  fStsSetup = CbmStsSetup::Instance();
+  assert(fStsSetup);
+  if (!fStsSetup->IsInit()) { fStsSetup->Init(); }
+
+  fManager = FairRootManager::Instance();
+  assert(fManager);
+
+  fMcManager = dynamic_cast<CbmMCDataManager*>(fManager->GetObject("MCDataManager"));
+
+  assert(fMcManager);
+
+  fTimeSlice = static_cast<CbmTimeSlice*>(fManager->GetObject("TimeSlice."));
+
+  if (fTimeSlice == nullptr) { LOG(fatal) << "CbmStsFindTracksQa: No time slice object"; }
+
+  if (fMcManager) {
+    fMCTracks  = fMcManager->InitBranch("MCTrack");
+    fStsPoints = fMcManager->InitBranch("StsPoint");
+  }
+
+  assert(fMCTracks);
+  assert(fStsPoints);
+
+  // Get the geometry
+  InitStatus geoStatus = GetGeometry();
+  if (geoStatus != kSUCCESS) {
+    LOG(error) << GetName() << "::Init: Error in reading geometry!";
+    return geoStatus;
+  }
+
+  // MVD
+
+  fMvdPoints   = fMcManager->InitBranch("MvdPoint");
+  fMvdCluster  = (TClonesArray*) (fManager->GetObject("MvdCluster"));
+  fMvdHits     = (TClonesArray*) (fManager->GetObject("MvdHit"));
+  fMvdHitMatch = (TClonesArray*) fManager->GetObject("MvdHitMatch");
+
+  // Currently in the time-based mode MVD is present but not reconstructed
+  // TODO: remove the check once the reconstruction works
+  if (fIsMvdActive && !fMvdHits) {
+    LOG(warning) << "CbmStsFindTracksQa: MVD hits are missing, MVD will not be "
+                    "included to the STS track match";
+    fIsMvdActive = false;
+  }
+
+  if (fIsMvdActive) {
+    assert(fMvdPoints);
+    assert(fMvdCluster);
+    assert(fMvdHits);
+    assert(fMvdHitMatch);
+  }
+
+  // STS
+
+  // Get StsHit array
+  fStsHits = (TClonesArray*) fManager->GetObject("StsHit");
+  assert(fStsHits);
+
+  // Get StsHitMatch array
+  fStsHitMatch = (TClonesArray*) fManager->GetObject("StsHitMatch");
+  assert(fStsHitMatch);
+
+  // Get StsHitMatch array
+  fStsClusterMatch = (TClonesArray*) fManager->GetObject("StsClusterMatch");
+  assert(fStsClusterMatch);
+
+  // Get StsTrack array
+  fStsTracks = (TClonesArray*) fManager->GetObject("StsTrack");
+  assert(fStsTracks);
+
+  // Get StsTrackMatch array
+  fStsTrackMatches = (TClonesArray*) fManager->GetObject("StsTrackMatch");
+  assert(fStsTrackMatches);
+
+
+  // Create histograms
+  CreateHistos();
+  Reset();
+
+  // Output
+  LOG(info) << "   Number of STS stations : " << fStsNstations;
+  LOG(info) << "   Target position ( " << fTargetPos.X() << ", " << fTargetPos.Y() << ", " << fTargetPos.Z() << ") cm";
+  LOG(info) << "   Minimum number of STS stations   : " << fMinStations;
+  LOG(info) << "   Matching quota               : " << fQuota;
+  LOG(info) << "====================================================";
+
+  return geoStatus;
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Public method ReInit   ------------------------------------------
+InitStatus CbmStsFindTracksQa::ReInit()
+{
+
+  LOG(info) << "\n\n====================================================";
+  LOG(info) << GetName() << ": Re-initialising...";
+
+  // Get the geometry of target and STS
+  InitStatus geoStatus = GetGeometry();
+  if (geoStatus != kSUCCESS) {
+    LOG(error) << GetName() << "::Init: Error in reading geometry!";
+    return geoStatus;
+  }
+
+  // --- Screen log
+  LOG(info) << "   Number of STS stations : " << fStsNstations;
+  LOG(info) << "   Target position ( " << fTargetPos.X() << ", " << fTargetPos.Y() << ", " << fTargetPos.Z() << ") cm";
+  LOG(info) << "   Minimum number of STS stations   : " << fMinStations;
+  LOG(info) << "   Matching quota               : " << fQuota;
+  LOG(info) << "====================================================";
+
+  return geoStatus;
+}
+// -------------------------------------------------------------------------
+
+
 // -----   Private method Finish   -----------------------------------------
 void CbmStsFindTracksQa::Finish() {
 
@@ -495,9 +440,10 @@ void CbmStsFindTracksQa::Finish() {
   Double_t effAll     = Double_t(fNRecAll) / Double_t(fNAccAll);
   Double_t effPrim    = Double_t(fNRecPrim) / Double_t(fNAccPrim);
   Double_t effRef     = Double_t(fNRecRef) / Double_t(fNAccRef);
+  Double_t effRefLong = Double_t(fNRecRefLong) / Double_t(fNAccRefLong);
   Double_t effSec     = Double_t(fNRecSec) / Double_t(fNAccSec);
-  Double_t rateGhosts = Double_t(fNGhosts) / Double_t(fNEvents);
-  Double_t rateClones = Double_t(fNClones) / Double_t(fNEvents);
+  Double_t rateGhosts = Double_t(fNGhosts) / Double_t(fNRecAll);
+  Double_t rateClones = Double_t(fNClones) / Double_t(fNRecAll);
 
   // Run summary to screen
   std::cout << std::endl;
@@ -510,34 +456,53 @@ void CbmStsFindTracksQa::Finish() {
             << fNRecPrim << "/" << fNAccPrim << ")";
   LOG(info) << "Eff. reference tracks : " << effRef * 100 << " % (" << fNRecRef
             << "/" << fNAccRef << ")";
+  LOG(info) << "Eff. reference long tracks : " << effRefLong * 100 << " % (" << fNRecRefLong << "/" << fNAccRefLong
+            << ")";
   LOG(info) << "Eff. secondary tracks : " << effSec * 100 << " % (" << fNRecSec
             << "/" << fNAccSec << ")";
-  LOG(info) << "Ghost rate            : " << rateGhosts << " per event";
-  LOG(info) << "Clone rate            : " << rateClones << " per event";
+  LOG(info) << "Ghost rate            : " << rateGhosts * 100 << " % (" << fNGhosts << "/" << fNRecAll << ")";
+  LOG(info) << "Clone rate            : " << rateClones * 100 << " % (" << fNClones << "/" << fNRecAll << ")";
+  LOG(info) << "mc tracks/event " << fNAll / fNEvents << " accepted " << fNRecAll / fNEvents;
   LOG(info) << "Time per event        : " << setprecision(6)
             << fTime / Double_t(fNEvents) << " s";
+
+  if (fMvdNstations > 0 && !fIsMvdActive) {
+    LOG(warning) << "CbmStsFindTracksQa: MVD hits are missing, MVD is not "
+                    "included to the STS track match";
+  }
+
   LOG(info) << "=====================================";
 
   // Write histos to output
+  /*
   gDirectory->mkdir("STSFindTracksQA");
   gDirectory->cd("STSFindTracksQA");
   TIter next(fHistoList);
   while (TH1* histo = ((TH1*) next()))
     histo->Write();
   gDirectory->cd("..");
+*/
+  FairSink* sink = FairRootManager::Instance()->GetSink();
+  sink->WriteObject(&fOutFolder, nullptr);
 }
 // -------------------------------------------------------------------------
 
 
 // -----   Private method GetGeometry   ------------------------------------
 InitStatus CbmStsFindTracksQa::GetGeometry() {
-
   // Get target geometry
   GetTargetPosition();
-
-  fNStations = CbmStsSetup::Instance()->GetNofStations();
-
-
+  fMvdNstations = 0;
+  {
+    CbmMvdDetector* mvdDetector = CbmMvdDetector::Instance();
+    if (mvdDetector) {
+      CbmMvdStationPar* mvdStationPar = mvdDetector->GetParameterFile();
+      assert(mvdStationPar);
+      fMvdNstations = mvdStationPar->GetStationCount();
+    }
+  }
+  fIsMvdActive  = (fMvdNstations > 0);
+  fStsNstations = CbmStsSetup::Instance()->GetNofStations();
   return kSUCCESS;
 }
 // -------------------------------------------------------------------------
@@ -601,6 +566,8 @@ void CbmStsFindTracksQa::GetTargetPosition() {
 // -----   Private method CreateHistos   -----------------------------------
 void CbmStsFindTracksQa::CreateHistos() {
 
+  fOutFolder.Clear();
+
   // Histogram list
   fHistoList = new TList();
 
@@ -692,6 +659,11 @@ void CbmStsFindTracksQa::CreateHistos() {
     new TH1F("hNhGhosts", "number of hits for ghosts", nBinsNp, minNp, maxNp);
   fHistoList->Add(fhNhClones);
   fHistoList->Add(fhNhGhosts);
+
+  TIter next(fHistoList);
+  while (TH1* histo = ((TH1*) next())) {
+    fOutFolder.Add(histo);
+  }
 }
 // -------------------------------------------------------------------------
 
@@ -703,118 +675,144 @@ void CbmStsFindTracksQa::Reset() {
   while (TH1* histo = ((TH1*) next()))
     histo->Reset();
 
-  fNAccAll = fNAccPrim = fNAccRef = fNAccSec = 0;
-  fNRecAll = fNRecPrim = fNRecRef = fNRecSec = 0;
+  fNAccAll = fNAccPrim = fNAccRef = fNAccRefLong = fNAccSec = 0;
+  fNRecAll = fNRecPrim = fNRecRef = fNRecRefLong = fNRecSec = 0;
   fNGhosts = fNClones = fNEvents = 0;
 }
 // -------------------------------------------------------------------------
 
 
 // -----   Private method FillHitMap   -------------------------------------
-void CbmStsFindTracksQa::FillHitMap(CbmEvent* event) {
-
-  // --- Event number. Note that the FairRun counting starts with 1.
-  Int_t eventNumber =
-    (event ? event->GetNumber()
-           : FairRun::Instance()->GetEventHeader()->GetMCEntryNumber() - 1);
+void CbmStsFindTracksQa::FillHitMap()
+{
 
   // --- Fill hit map ( mcTrack -> ( station -> number of hits ) )
-  fHitMap.clear();
-  Int_t nHits = (event ? event->GetNofData(ECbmDataType::kStsHit)
-                       : fStsHits->GetEntriesFast());
-  for (Int_t iHit = 0; iHit < nHits; iHit++) {
-    Int_t hitIndex =
-      (event ? event->GetIndex(ECbmDataType::kStsHit, iHit) : iHit);
-    CbmStsHit* hit     = (CbmStsHit*) fStsHits->At(hitIndex);
-    CbmMatch* hitMatch = (CbmMatch*) fStsHitMatch->At(hitIndex);
-    Int_t pointIndex   = hitMatch->GetMatchedLink().GetIndex();
-    assert(pointIndex >= 0);
-    CbmStsPoint* stsPoint =
-      dynamic_cast<CbmStsPoint*>(fStsPoints->Get(0, eventNumber, pointIndex));
-    assert(stsPoint);
-    Int_t mcTrackIndex = stsPoint->GetTrackID();
-    Int_t station      = fSetup->GetStationNumber(hit->GetAddress());
-    fHitMap[mcTrackIndex][station]++;
+
+  // pocess MVD hits
+
+  if (fIsMvdActive) {
+    assert(fMvdHits);
+    assert(fMvdHitMatch);
+    assert(fMvdPoints);
+    for (Int_t iHit = 0; iHit < fMvdHits->GetEntriesFast(); iHit++) {
+      CbmMvdHit* hit = (CbmMvdHit*) fMvdHits->At(iHit);
+      assert(hit);
+      Int_t station = hit->GetStationNr();
+      assert(station >= 0 && station < fMvdNstations);
+      const CbmMatch* match = (const CbmMatch*) fMvdHitMatch->At(iHit);
+      assert(match);
+      if (match->GetNofLinks() <= 0) continue;
+      CbmLink link    = match->GetMatchedLink();
+      CbmMvdPoint* pt = (CbmMvdPoint*) fMvdPoints->Get(link);
+      assert(pt);
+      link.SetIndex(pt->GetTrackID());
+      McTrackInfo& info = getMcTrackInfo(link);
+      info.fHitMap[station]++;
+    }
+  }
+
+  // pocess STS hits
+
+  for (Int_t iHit = 0; iHit < fStsHits->GetEntriesFast(); iHit++) {
+    CbmStsHit* hit = (CbmStsHit*) fStsHits->At(iHit);
+    assert(hit);
+
+    Int_t station = fStsSetup->GetStationNumber(hit->GetAddress());
+
+    // carefully check the hit match by looking at the strips from both sides
+
+    const CbmMatch* frontMatch = dynamic_cast<const CbmMatch*>(fStsClusterMatch->At(hit->GetFrontClusterId()));
+    assert(frontMatch);
+    if (frontMatch->GetNofLinks() <= 0) continue;
+
+    const CbmMatch* backMatch = dynamic_cast<const CbmMatch*>(fStsClusterMatch->At(hit->GetBackClusterId()));
+    assert(backMatch);
+    if (backMatch->GetNofLinks() <= 0) continue;
+
+    if (frontMatch->GetMatchedLink() == backMatch->GetMatchedLink()) {
+      CbmLink link    = frontMatch->GetMatchedLink();
+      CbmStsPoint* pt = (CbmStsPoint*) fStsPoints->Get(link);
+      assert(pt);
+      link.SetIndex(pt->GetTrackID());
+      McTrackInfo& info = getMcTrackInfo(link);
+      info.fHitMap[fMvdNstations + station]++;
+    }
   }
-  LOG(debug) << GetName() << ": Filled hit map from " << nHits
-             << " STS hits for " << fHitMap.size() << " MCTracks.";
+  LOG(debug) << GetName() << ": Filled hit map from " << fStsHits->GetEntriesFast() << " STS hits";
 }
 // -------------------------------------------------------------------------
 
 
 // ------   Private method FillMatchMap   ----------------------------------
-void CbmStsFindTracksQa::FillMatchMap(CbmEvent* event,
-                                      Int_t& nRec,
-                                      Int_t& nGhosts,
-                                      Int_t& nClones) {
+void CbmStsFindTracksQa::FillMatchMap(Int_t& nRec, Int_t& nGhosts, Int_t& nClones)
+{
 
   // Clear matching maps
-  fMatchMap.clear();
-  fQualiMap.clear();
+  for (auto it = fMcTrackInfoMap.begin(); it != fMcTrackInfoMap.end(); ++it) {
+    McTrackInfo& info      = it->second;
+    info.fStsTrackMatch    = -1;
+    info.fQuali            = 0.;
+    info.fMatchedNHitsAll  = 0;
+    info.fMatchedNHitsTrue = 0;
+  }
 
   // Loop over StsTracks. Check matched MCtrack and fill maps.
-  nGhosts       = 0;
-  nClones       = 0;
-  Int_t nTracks = (event ? event->GetNofData(ECbmDataType::kStsTrack)
-                         : fStsTracks->GetEntriesFast());
+  nGhosts = 0;
+  nClones = 0;
 
+  Int_t nTracks = fStsTracks->GetEntriesFast();
   for (Int_t iTrack = 0; iTrack < nTracks; iTrack++) {
 
     // --- StsTrack
-    Int_t trackIndex =
-      (event ? event->GetIndex(ECbmDataType::kStsTrack, iTrack) : iTrack);
-    CbmStsTrack* stsTrack = (CbmStsTrack*) fStsTracks->At(trackIndex);
+    CbmStsTrack* stsTrack = (CbmStsTrack*) fStsTracks->At(iTrack);
     assert(stsTrack);
     Int_t nHits = stsTrack->GetNofStsHits();
 
     // --- TrackMatch
-    CbmTrackMatchNew* match = (CbmTrackMatchNew*) fMatches->At(trackIndex);
+
+    assert(iTrack >= 0 && iTrack < fStsTrackMatches->GetEntriesFast());
+    CbmTrackMatchNew* match = (CbmTrackMatchNew*) fStsTrackMatches->At(iTrack);
     assert(match);
     Int_t nTrue = match->GetNofTrueHits();
 
-    // --- Matched MCTrack
-    Int_t mcTrackId = -1;
-    if (nTrue > 0) mcTrackId = match->GetMatchedLink().GetIndex();
-    if (mcTrackId < 0) {
+    // Check matching criterion (quota)
+    Double_t quali = Double_t(nTrue) / Double_t(nHits);
+
+    // Quality isn't good, it's a ghost
+
+    if (quali < fQuota) {
       fhNhGhosts->Fill(nHits);
       nGhosts++;
       continue;
     }
 
-    // Check matching criterion (quota)
-    Double_t quali = Double_t(nTrue) / Double_t(nHits);
-    if (quali >= fQuota) {
-
-      // No previous match for this MCTrack
-      if (fMatchMap.find(mcTrackId) == fMatchMap.end()) {
-        fMatchMap[mcTrackId] = iTrack;
-        fQualiMap[mcTrackId] = quali;
-      }  //? no previous match
-
-      // Previous match; take the better one
-      else {
-        if (fQualiMap[mcTrackId] < quali) {
-          CbmStsTrack* oldTrack =
-            (CbmStsTrack*) fStsTracks->At(fMatchMap[mcTrackId]);
-          fhNhClones->Fill(Double_t(oldTrack->GetNofStsHits()));
-          fMatchMap[mcTrackId] = iTrack;
-          fQualiMap[mcTrackId] = quali;
-        }  //? new track matches better to MCTrack
-
-        else
-          fhNhClones->Fill(nHits);
-        nClones++;
-      }  //? previous match found
-
-    }  //? true match ratio > quota
-
-    // If not matched, it's a ghost
-    else {
-      fhNhGhosts->Fill(nHits);
-      nGhosts++;
+    // Quality is good
+
+    // --- Matched MCTrack
+    assert(match->GetNofLinks() > 0);
+    const CbmLink& link = match->GetMatchedLink();
+    assert(link.GetIndex() >= 0);
+    McTrackInfo& info = getMcTrackInfo(link);
+
+    // previous match is better, this track is a clone
+    if ((quali < info.fQuali) || ((quali == info.fQuali) && (nTrue < info.fMatchedNHitsTrue))) {
+      fhNhClones->Fill(nHits);
+      nClones++;
+      continue;
     }
 
+    // this track is better than the old one
+    if (info.fMatchedNHitsAll > 0) {
+      fhNhClones->Fill(info.fMatchedNHitsAll);
+      nClones++;
+    }
+    info.fStsTrackMatch    = iTrack;
+    info.fQuali            = quali;
+    info.fMatchedNHitsAll  = nHits;
+    info.fMatchedNHitsTrue = nTrue;
+
   }  // Loop over StsTracks
+
   nRec = nTracks;
   LOG(debug) << GetName() << ": Filled match map for " << nRec
              << " STS tracks. Ghosts " << nGhosts << " Clones " << nClones;
diff --git a/reco/detectors/sts/CbmStsFindTracksQa.h b/reco/detectors/sts/CbmStsFindTracksQa.h
index db97586766..ea191d28db 100644
--- a/reco/detectors/sts/CbmStsFindTracksQa.h
+++ b/reco/detectors/sts/CbmStsFindTracksQa.h
@@ -10,19 +10,21 @@
  ** Quality check task for CbmStsFindTracks
  **/
 
-
 #ifndef CBMSTSTRACKFINDERQA_H
 #define CBMSTSTRACKFINDERQA_H 1
 
+#include "CbmLink.h"
+
 #include "FairTask.h"
+
 #include "TStopwatch.h"
 #include "TVector3.h"
 
 class TH1F;
-class CbmEvent;
 class CbmMCDataArray;
 class CbmStsSetup;
-
+class CbmMCDataManager;
+class CbmTimeSlice;
 
 class CbmStsFindTracksQa : public FairTask {
 
@@ -30,7 +32,6 @@ public:
   /** Default constructor **/
   CbmStsFindTracksQa(Int_t iVerbose = 1);
 
-
   /** Standard constructor 
   *@param minHits     Minimal number of StsHits for considered MCTracks
   *@param quota       True/all hits for track to be considered reconstructed
@@ -38,27 +39,21 @@ public:
   **/
   CbmStsFindTracksQa(Int_t minHits, Double_t quota, Int_t iVerbose);
 
-
   /** Destructor **/
   virtual ~CbmStsFindTracksQa();
 
-
   /** Set parameter containers **/
   virtual void SetParContainers();
 
-
   /** Initialisation **/
   virtual InitStatus Init();
 
-
   /** Reinitialisation **/
   virtual InitStatus ReInit();
 
-
   /** Execution **/
   virtual void Exec(Option_t* opt);
 
-
 private:
   /** Finish **/
   virtual void Finish();
@@ -66,31 +61,27 @@ private:
   /** Read the geometry parameters **/
   InitStatus GetGeometry();
 
-
   /** Get the target node from the geometry **/
   void GetTargetPosition();
 
-
   /** Create histograms **/
   void CreateHistos();
 
-
   /** Reset histograms and counters **/
   void Reset();
 
+  // collect id's of MC events participating to the data
+  void CollectMcEvents(TClonesArray* Matches);
 
   /** Fill a map from MCTrack index to number of corresponding StsHits **/
-  void FillHitMap(CbmEvent* event);
-
+  void FillHitMap();
 
   /** Fill a map from MCTrack index to matched StsTrack index
    *@param nRec  Number of reconstructed tracks (return)
    *@param nGhosts  Number of ghost tracks (return)
    *@param nClones  Number of clone tracks (return)
    **/
-  void
-  FillMatchMap(CbmEvent* event, Int_t& nRec, Int_t& nGhosts, Int_t& nClones);
-
+  void FillMatchMap(Int_t& nRec, Int_t& nGhosts, Int_t& nClones);
 
   /** Divide histograms (reco/all) with correct error for the efficiency
    *@param histo1  reconstructed tracks
@@ -99,83 +90,130 @@ private:
    **/
   void DivideHistos(TH1* histo1, TH1* histo2, TH1* histo3);
 
+  struct McTrackInfo {
+    std::map<Int_t, Int_t> fHitMap = {};  /// Mvd / Sts station -> number of attached hits
+    Int_t fStsTrackMatch           = -1;  /// matched StsTrack index
+    Double_t fQuali                = 0.;  /// percentage of matched hits
+    Int_t fMatchedNHitsAll         = 0;   /// number of matched hits
+    Int_t fMatchedNHitsTrue        = 0;   /// number of matched hits
+  };
+
+  McTrackInfo& getMcTrackInfo(const CbmLink& link)
+  {
+    assert(fMcTrackInfoMap.find(link) != fMcTrackInfoMap.end());
+    return fMcTrackInfoMap[link];
+  }
+
+  std::map<CbmLink, McTrackInfo> fMcTrackInfoMap = {};  //! map track link -> track info
+
+  /// Setup
+  FairRootManager* fManager    = nullptr;  //!
+  CbmMCDataManager* fMcManager = nullptr;  //!
+  CbmTimeSlice* fTimeSlice     = nullptr;  //!
+
+  /// MC tracks
+  CbmMCDataArray* fMCTracks = nullptr;  //! MCtrack
+
+  /// Mvd
+  Bool_t fIsMvdActive        = kTRUE;  // is the Mvd module active
+  Int_t fMvdNstations        = 0;
+  CbmMCDataArray* fMvdPoints = nullptr;  //!
+  TClonesArray* fMvdCluster  = nullptr;  //!
+  TClonesArray* fMvdHits     = nullptr;  //!
+  TClonesArray* fMvdHitMatch = nullptr;  //!
+
+  /// STS
+  CbmStsSetup* fStsSetup         = nullptr;  // STS setup interface
+  Int_t fStsNstations            = 0;        // Number of STS stations
+  CbmMCDataArray* fStsPoints     = nullptr;  //! StsPoints
+  TClonesArray* fStsHits         = nullptr;  //! StsHits
+  TClonesArray* fStsHitMatch     = nullptr;  //! StsHitMatch
+  TClonesArray* fStsClusterMatch = nullptr;  //!StsClusterMatch
+  TClonesArray* fStsTracks       = nullptr;  //! StsTrack
+  TClonesArray* fStsTrackMatches = nullptr;  //! StsTrackMatch
 
-  /** Process one event
-   ** @param event  Pointer to event object
-   **
-   ** If a NULL pointer is given, the entire input array is processed
-   ** (legacy mode)
-   */
-  void ProcessEvent(CbmEvent* event = NULL);
-
-
-  /** Map from MCTrack index to number of attached StsHits in each station **/
-  std::map<Int_t, std::map<Int_t, Int_t>> fHitMap;
+  /** Geometry parameters **/
+  TVector3 fTargetPos = {0., 0., 0.};  // Target centre position
 
+  /** Task parameters **/
 
-  /** Map from MCTrack index to matched StsTrack index **/
-  std::map<Int_t, Int_t> fMatchMap;
+  Int_t fMinStations = 4;  // Minimal number of stations with hits for considered MCTrack
 
+  Double_t fQuota = 0.7;  // True/all hits for track to be considered reconstructed
 
-  /** Map from MCTrack index to percentage of matched hits **/
-  std::map<Int_t, Double_t> fQualiMap;
+  TFolder fOutFolder = {"CbmStsFindTracksQa", "CbmStsFindTracksQa"};  /// output folder with histos and canvases
 
+  /** Histograms **/
 
-  /** Pointers to data arrays **/
-  TClonesArray* fEvents;       //! Event
-  CbmMCDataArray* fMCTracks;   //! MCtrack
-  CbmMCDataArray* fStsPoints;  //! StsPoints
-  TClonesArray* fStsHits;      //! StsHits
-  TClonesArray* fStsHitMatch;  //! StsHitMatch
-  TClonesArray* fStsTracks;    //! StsTrack
-  TClonesArray* fMatches;      //! StsTrackMatch
+  // eff. vs. p, all
+  TH1F* fhMomAccAll = nullptr;
+  TH1F* fhMomRecAll = nullptr;
+  TH1F* fhMomEffAll = nullptr;
 
-  /** Flag for legacy mode (event-by-event w/o event objects) **/
-  Bool_t fLegacy;
+  // eff. vs. p, vertex
+  TH1F* fhMomAccPrim = nullptr;
+  TH1F* fhMomRecPrim = nullptr;
+  TH1F* fhMomEffPrim = nullptr;
 
+  // eff. vs. p, non-vertex
+  TH1F* fhMomAccSec = nullptr;
+  TH1F* fhMomRecSec = nullptr;
+  TH1F* fhMomEffSec = nullptr;
 
-  /** Geometry parameters **/
-  TVector3 fTargetPos;  // Target centre position
-  CbmStsSetup* fSetup;  // STS setup interface
-  Int_t fNStations;     // Number of STS stations
+  // eff. vs. np, all
+  TH1F* fhNpAccAll = nullptr;
+  TH1F* fhNpRecAll = nullptr;
+  TH1F* fhNpEffAll = nullptr;
 
+  // eff. vs. np, vertex
+  TH1F* fhNpAccPrim = nullptr;
+  TH1F* fhNpRecPrim = nullptr;
+  TH1F* fhNpEffPrim = nullptr;
 
-  /** Task parameters **/
-  Int_t
-    fMinStations;  // Minimal number of stations with hits for considered MCTrack
-  Double_t fQuota;  // True/all hits for track to be considered reconstructed
+  // eff. vs. np, non-vertex
+  TH1F* fhNpAccSec = nullptr;
+  TH1F* fhNpRecSec = nullptr;
+  TH1F* fhNpEffSec = nullptr;
 
+  // eff. vs. z, non-vertex
+  TH1F* fhZAccSec = nullptr;
+  TH1F* fhZRecSec = nullptr;
+  TH1F* fhZEffSec = nullptr;
 
-  /** Histograms **/
-  TH1F *fhMomAccAll, *fhMomRecAll, *fhMomEffAll;     // eff. vs. p, all
-  TH1F *fhMomAccPrim, *fhMomRecPrim, *fhMomEffPrim;  // eff. vs. p, vertex
-  TH1F *fhMomAccSec, *fhMomRecSec, *fhMomEffSec;     // eff. vs. p, non-vertex
-  TH1F *fhNpAccAll, *fhNpRecAll, *fhNpEffAll;        // eff. vs. np, all
-  TH1F *fhNpAccPrim, *fhNpRecPrim, *fhNpEffPrim;     // eff. vs. np, vertex
-  TH1F *fhNpAccSec, *fhNpRecSec, *fhNpEffSec;        // eff. vs. np, non-vertex
-  TH1F *fhZAccSec, *fhZRecSec, *fhZEffSec;           // eff. vs. z, non-vertex
-  TH1F *fhNhClones, *fhNhGhosts;  // # hits of clones and ghosts
+  // # hits of clones and ghosts
+  TH1F* fhNhClones = nullptr;
+  TH1F* fhNhGhosts = nullptr;
 
 
   /** List of histograms **/
-  TList* fHistoList;
+  TList* fHistoList = nullptr;
 
 
   /** Counters **/
-  Int_t fNAccAll, fNAccPrim, fNAccRef, fNAccSec;
-  Int_t fNRecAll, fNRecPrim, fNRecRef, fNRecSec;
-  Int_t fNGhosts, fNClones;
-  Int_t fNEvents;       /** Number of events with success **/
-  Int_t fNEventsFailed; /** Number of events with failure **/
-  Double_t fTime;       /** Total real time used for good events **/
+  Int_t fNAll          = 0;
+  Int_t fNAccAll       = 0;
+  Int_t fNAccPrim      = 0;
+  Int_t fNAccRef       = 0;
+  Int_t fNAccRefLong   = 0;
+  Int_t fNAccSec       = 0;
+  Int_t fNRecAll       = 0;
+  Int_t fNRecPrim      = 0;
+  Int_t fNRecRef       = 0;
+  Int_t fNRecRefLong   = 0;
+  Int_t fNRecSec       = 0;
+  Int_t fNGhosts       = 0;
+  Int_t fNClones       = 0;
+  Int_t fNEvents       = 0;  /** Number of events with success **/
+  Int_t fNEventsFailed = 0;  /** Number of events with failure **/
+  Double_t fTime       = 0.; /** Total real time used for good events **/
 
   /** Timer **/
-  TStopwatch fTimer;
+  TStopwatch fTimer = {};
 
   CbmStsFindTracksQa(const CbmStsFindTracksQa&);
   CbmStsFindTracksQa operator=(const CbmStsFindTracksQa&);
 
-  ClassDef(CbmStsFindTracksQa, 2);
+  ClassDef(CbmStsFindTracksQa, 0);
 };
 
 
diff --git a/sim/detectors/much/qa/CbmMuchDigitizerQa.cxx b/sim/detectors/much/qa/CbmMuchDigitizerQa.cxx
index 967038b0c4..ad0e463620 100644
--- a/sim/detectors/much/qa/CbmMuchDigitizerQa.cxx
+++ b/sim/detectors/much/qa/CbmMuchDigitizerQa.cxx
@@ -8,8 +8,11 @@
 /// \date   21.10.2020
 
 #include "CbmMuchDigitizerQa.h"
+
 #include "CbmDigiManager.h"
 #include "CbmLink.h"
+#include "CbmMCDataArray.h"
+#include "CbmMCDataManager.h"
 #include "CbmMCTrack.h"
 #include "CbmMatch.h"
 #include "CbmMuchAddress.h"
@@ -23,6 +26,13 @@
 #include "CbmMuchRecoDefs.h"
 #include "CbmMuchStation.h"
 #include "CbmQaCanvas.h"
+#include "CbmTimeSlice.h"
+
+#include <FairRootManager.h>
+#include <FairSink.h>
+#include <FairTask.h>
+#include <Logger.h>
+
 #include "TClonesArray.h"
 #include "TDatabasePDG.h"
 #include "TF1.h"
@@ -32,21 +42,19 @@
 #include "TParameter.h"
 #include "TString.h"
 #include "TStyle.h"
-#include <FairRootManager.h>
-#include <FairSink.h>
-#include <FairTask.h>
-#include <Logger.h>
 #include <TAxis.h>
 #include <TCanvas.h>
 #include <TDirectory.h>
 #include <TMath.h>
 #include <TParticlePDG.h>
 #include <TVector2.h>
+
 #include <iostream>
 #include <limits>
-#include <math.h>
 #include <vector>
 
+#include <math.h>
+
 using std::endl;
 using std::vector;
 
@@ -84,8 +92,7 @@ void CbmMuchDigitizerQa::DeInit() {
   fDigiMatches = nullptr;
   fMCTracks    = nullptr;
   fOutFolder.Clear();
-
-  SafeDelete(fPointInfos);
+  fMcPointInfoMap.clear();
 
   for (uint i = 0; i < fvUsPadsFiredR.size(); i++) {
     SafeDelete(fvUsPadsFiredR[i]);
@@ -151,10 +158,10 @@ void CbmMuchDigitizerQa::DeInit() {
 // -------------------------------------------------------------------------
 InitStatus CbmMuchDigitizerQa::Init() {
   DeInit();
-  fPointInfos              = new TClonesArray("CbmMuchPointInfo", 10);
+  fMcPointInfoMap.clear();
   TDirectory* oldDirectory = gDirectory;
 
-  FairRootManager* fManager = FairRootManager::Instance();
+  fManager = FairRootManager::Instance();
   if (!fManager) {
     LOG(fatal) << "Can not find FairRootManager";
     return kFATAL;
@@ -176,8 +183,21 @@ InitStatus CbmMuchDigitizerQa::Init() {
   }
   fDigiManager->Init();
 
-  fMCTracks = (TClonesArray*) fManager->GetObject("MCTrack");
-  fPoints   = (TClonesArray*) fManager->GetObject("MuchPoint");
+  fMCTracks = nullptr;
+  fPoints   = nullptr;
+
+  fMcManager = dynamic_cast<CbmMCDataManager*>(fManager->GetObject("MCDataManager"));
+
+  fTimeSlice = (CbmTimeSlice*) fManager->GetObject("TimeSlice.");
+  if (!fTimeSlice) { LOG(error) << GetName() << ": No time slice found"; }
+
+  if (fMcManager) {
+    // Get MCTrack array
+    fMCTracks = fMcManager->InitBranch("MCTrack");
+
+    // Get StsPoint array
+    fPoints = fMcManager->InitBranch("MuchPoint");
+  }
 
   if (fMCTracks && fPoints
       && fDigiManager->IsMatchPresent(ECbmModuleId::kMuch)) {
@@ -635,12 +655,14 @@ void CbmMuchDigitizerQa::Exec(Option_t*) {
 
   ProcessMCPoints();
   FillChargePerPoint();
+
   FillDigitizerPerformancePlots();
 
   if (fVerbose > 1) {
     PrintFrontLayerPoints();
     PrintFrontLayerDigis();
   }
+
   gDirectory = oldDirectory;
   return;
 }
@@ -740,7 +762,7 @@ void CbmMuchDigitizerQa::OccupancyQa() {
 // -------------------------------------------------------------------------
 int CbmMuchDigitizerQa::ProcessMCPoints() {
 
-  if (!fMCTracks || !fPoints) {
+  if (!fMCTracks || !fPoints || !fTimeSlice) {
     LOG(debug)
       << " CbmMuchDigitizerQa::DigitizerQa(): Found no MC data. Skipping.";
     return 0;
@@ -748,68 +770,75 @@ int CbmMuchDigitizerQa::ProcessMCPoints() {
   TVector3 vIn;   // in  position of the track
   TVector3 vOut;  // out position of the track
   TVector3 p;     // track momentum
-  fPointInfos->Clear();
 
-  for (Int_t i = 0; i < fPoints->GetEntriesFast(); i++) {
-    CbmMuchPoint* point = (CbmMuchPoint*) fPoints->At(i);
-    if (!point) {
-      LOG(error) << " Much MC point " << i << " out of "
-                 << fPoints->GetEntriesFast() << " doesn't exist";
-      return -1;
-    }
+  fMcPointInfoMap.clear();
 
-    Int_t stId = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
+  std::vector<CbmLink> events = fTimeSlice->GetMatch().GetLinks();
+  std::sort(events.begin(), events.end());
 
-    if (stId < 0 || stId > fNstations) {
-      LOG(error) << " Much MC point station " << stId << " is out of the range";
-      return -1;
-    }
+  for (uint iLink = 0; iLink < events.size(); iLink++) {
+    CbmLink link    = events[iLink];
+    int nMuchPoints = fPoints->Size(link);
+    int nMcTracks   = fMCTracks->Size(link);
+    for (Int_t ip = 0; ip < nMuchPoints; ip++) {
+      link.SetIndex(ip);
+      CbmMuchPoint* point = (CbmMuchPoint*) fPoints->Get(link);
+      if (!point) {
+        LOG(error) << " Much MC point " << ip << " out of " << nMuchPoints << " doesn't exist";
+        return -1;
+      }
 
-    // Check if the point corresponds to a certain  MC Track
-    Int_t trackId = point->GetTrackID();
-    if (trackId < 0 || trackId >= fMCTracks->GetEntriesFast()) {
-      LOG(error) << " Much MC point track Id " << trackId
-                 << " is out of the range";
-      return -1;
-    }
+      Int_t stId = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
 
-    CbmMCTrack* mcTrack = (CbmMCTrack*) fMCTracks->At(trackId);
-    if (!mcTrack) {
-      LOG(error) << " MC track" << trackId << " is not found";
-      return -1;
-    }
+      if (stId < 0 || stId > fNstations) {
+        LOG(error) << " Much MC point station " << stId << " is out of the range";
+        return -1;
+      }
 
-    Int_t pdgCode          = mcTrack->GetPdgCode();
-    TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(pdgCode);
-
-    point->PositionIn(vIn);
-    point->PositionOut(vOut);
-    point->Momentum(p);
-    Double_t length = (vOut - vIn).Mag();  // Track length
-    Double_t kine   = 0;                   // Kinetic energy
-    if (particle) {
-      Double_t mass = particle->Mass();
-      kine          = sqrt(p.Mag2() + mass * mass) - mass;
-    }
+      // Check if the point corresponds to a certain  MC Track
+      Int_t trackId = point->GetTrackID();
+      if (trackId < 0 || trackId >= nMcTracks) {
+        LOG(error) << " Much MC point track Id " << trackId << " is out of the range";
+        return -1;
+      }
 
-    // Get mother pdg code
-    Int_t motherPdg = 0;
-    Int_t motherId  = mcTrack->GetMotherId();
-    if (motherId >= fMCTracks->GetEntriesFast()) {
-      LOG(error) << " MC track mother Id" << trackId << " is out of the range";
-      return -1;
-    }
-    if (motherId >= 0) {
-      CbmMCTrack* motherTrack = (CbmMCTrack*) fMCTracks->At(motherId);
-      if (!motherTrack) {
+      CbmMCTrack* mcTrack = (CbmMCTrack*) fMCTracks->Get(link.GetFile(), link.GetEntry(), trackId);
+      if (!mcTrack) {
         LOG(error) << " MC track" << trackId << " is not found";
         return -1;
       }
-      motherPdg = motherTrack->GetPdgCode();
-    }
-    new ((*fPointInfos)[i])
-      CbmMuchPointInfo(pdgCode, motherPdg, kine, length, stId);
-  }
+
+      Int_t pdgCode          = mcTrack->GetPdgCode();
+      TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(pdgCode);
+
+      point->PositionIn(vIn);
+      point->PositionOut(vOut);
+      point->Momentum(p);
+      Double_t length = (vOut - vIn).Mag();  // Track length
+      Double_t kine   = 0;                   // Kinetic energy
+      if (particle) {
+        Double_t mass = particle->Mass();
+        kine          = sqrt(p.Mag2() + mass * mass) - mass;
+      }
+
+      // Get mother pdg code
+      Int_t motherPdg = 0;
+      Int_t motherId  = mcTrack->GetMotherId();
+      if (motherId >= nMcTracks) {
+        LOG(error) << " MC track mother Id" << trackId << " is out of the range";
+        return -1;
+      }
+      if (motherId >= 0) {
+        CbmMCTrack* motherTrack = (CbmMCTrack*) fMCTracks->Get(link.GetFile(), link.GetEntry(), motherId);
+        if (!motherTrack) {
+          LOG(error) << " MC track" << trackId << " is not found";
+          return -1;
+        }
+        motherPdg = motherTrack->GetPdgCode();
+      }
+      fMcPointInfoMap.insert({link, CbmMuchPointInfo(pdgCode, motherPdg, kine, length, stId)});
+    }  // points
+  }    // events
   return 0;
 }
 
@@ -822,18 +851,21 @@ void CbmMuchDigitizerQa::FillChargePerPoint() {
     return;
   }
   for (Int_t i = 0; i < fDigiManager->GetNofDigis(ECbmModuleId::kMuch); i++) {
-    CbmMuchDigi* digi = (CbmMuchDigi*) fDigiManager->Get<CbmMuchDigi>(i);
-    CbmMatch* match =
-      (CbmMatch*) fDigiManager->GetMatch(ECbmModuleId::kMuch, i);
+    CbmMuchDigi* digi     = (CbmMuchDigi*) fDigiManager->Get<CbmMuchDigi>(i);
+    const CbmMatch* match = fDigiManager->GetMatch(ECbmModuleId::kMuch, i);
+    if (!match) {
+      LOG(error) << "digi has no match";
+      return;
+    }
     const CbmMuchPad* pad = GetPad(digi->GetAddress());
     Double_t area         = pad->GetDx() * pad->GetDy();
     Int_t nofLinks        = match->GetNofLinks();
     for (Int_t pt = 0; pt < nofLinks; pt++) {
-      Int_t pointId          = match->GetLink(pt).GetIndex();
-      Int_t charge           = match->GetLink(pt).GetWeight();
-      CbmMuchPointInfo* info = (CbmMuchPointInfo*) fPointInfos->At(pointId);
-      info->AddCharge(charge);
-      info->AddArea(area);
+      const CbmLink& link    = match->GetLink(pt);
+      Int_t charge           = link.GetWeight();
+      CbmMuchPointInfo& info = getPointInfo(link);
+      info.AddCharge(charge);
+      info.AddArea(area);
     }
   }
 }
@@ -847,16 +879,17 @@ void CbmMuchDigitizerQa::FillDigitizerPerformancePlots() {
     return;
   }
   Bool_t verbose = (fVerbose > 2);
-  for (Int_t i = 0; i < fPointInfos->GetEntriesFast(); i++) {
-    CbmMuchPointInfo* info = (CbmMuchPointInfo*) fPointInfos->At(i);
+  int iPoint     = 0;
+  for (auto it = fMcPointInfoMap.begin(); it != fMcPointInfoMap.end(); it++, ++iPoint) {
+    const CbmMuchPointInfo& info = it->second;
     if (verbose) {
-      printf("%i", i);
-      info->Print();
+      printf("%i", iPoint);
+      info.Print();
     }
-    Double_t length = info->GetLength();
-    Double_t kine   = 1000 * (info->GetKine());
-    Double_t charge = info->GetCharge();
-    Int_t pdg       = info->GetPdgCode();
+    Double_t length = info.GetLength();
+    Double_t kine   = 1000 * (info.GetKine());
+    Double_t charge = info.GetCharge();
+    Int_t pdg       = info.GetPdgCode();
     if (charge <= 0) continue;
 
     if (pdg == 22 ||  // photons
@@ -871,13 +904,13 @@ void CbmMuchDigitizerQa::FillDigitizerPerformancePlots() {
     Double_t log_charge = TMath::Log10(charge);
     charge              = charge / 1.e+4;  // measure charge in 10^4 electrons
 
-    Int_t nPads   = info->GetNPads();
-    Double_t area = info->GetArea() / nPads;
+    Int_t nPads   = info.GetNPads();
+    Double_t area = info.GetArea() / nPads;
     // printf("%f %i\n",TMath::Log2(area),nPads);
     //fhNpadsVsS->Fill(TMath::Log2(area), nPads);
     fhNpadsVsS->Fill(area, nPads);
     fhTrackCharge->Fill(charge);
-    fvTrackCharge[info->GetStationId()]->Fill(charge);
+    fvTrackCharge[info.GetStationId()]->Fill(charge);
     fhTrackChargeLog->Fill(log_charge);
     fhTrackChargeVsTrackEnergyLog->Fill(log_kine, charge);
     fhTrackChargeVsTrackLength->Fill(length, charge);
@@ -1004,21 +1037,26 @@ void CbmMuchDigitizerQa::DrawLengthCanvases() {
 // -------------------------------------------------------------------------
 void CbmMuchDigitizerQa::PrintFrontLayerPoints() {
 
-  if (!fMCTracks || !fPoints) { return; }
-
-  for (int i = 0; i < fPoints->GetEntriesFast(); i++) {
-    CbmMuchPoint* point = (CbmMuchPoint*) fPoints->At(i);
-    Int_t stId = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
-    if (stId != 0) continue;
-    Int_t layerId = CbmMuchAddress::GetLayerIndex(point->GetDetectorID());
-    if (layerId != 0) continue;
-    printf("point %4i xin=%6.2f yin=%6.2f xout=%6.2f yout=%6.2f zin=%6.2f\n",
-           i,
-           point->GetXIn(),
-           point->GetYIn(),
-           point->GetXOut(),
-           point->GetYOut(),
-           point->GetZIn());
+  if (!fMCTracks || !fTimeSlice) { return; }
+
+  const CbmMatch& match = fTimeSlice->GetMatch();
+  for (int iLink = 0; iLink < match.GetNofLinks(); iLink++) {
+    CbmLink link    = match.GetLink(iLink);
+    int nMuchPoints = fPoints->Size(link);
+    for (Int_t ip = 0; ip < nMuchPoints; ip++) {
+      link.SetIndex(ip);
+      CbmMuchPoint* point = (CbmMuchPoint*) fPoints->Get(link);
+      if (!point) {
+        LOG(error) << " Much MC point " << ip << " out of " << nMuchPoints << " doesn't exist";
+        return;
+      }
+      Int_t stId = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
+      if (stId != 0) continue;
+      Int_t layerId = CbmMuchAddress::GetLayerIndex(point->GetDetectorID());
+      if (layerId != 0) continue;
+      printf("point %4i xin=%6.2f yin=%6.2f xout=%6.2f yout=%6.2f zin=%6.2f\n", ip, point->GetXIn(), point->GetYIn(),
+             point->GetXOut(), point->GetYOut(), point->GetZIn());
+    }
   }
 }
 
diff --git a/sim/detectors/much/qa/CbmMuchDigitizerQa.h b/sim/detectors/much/qa/CbmMuchDigitizerQa.h
index 1ef0a78cd1..75b80d3f86 100644
--- a/sim/detectors/much/qa/CbmMuchDigitizerQa.h
+++ b/sim/detectors/much/qa/CbmMuchDigitizerQa.h
@@ -9,12 +9,17 @@
 #ifndef CbmMuchDigitizerQa_H
 #define CbmMuchDigitizerQa_H
 
+#include "CbmLink.h"
+#include "CbmMuchPointInfo.h"
+
 #include "FairTask.h"
+
+#include "TFolder.h"
 #include "TParameter.h"
-#include <Rtypes.h>
-#include <RtypesCore.h>
-#include <TFolder.h>
+
+#include <map>
 #include <vector>
+
 class TBuffer;
 class TClass;
 class TClonesArray;
@@ -28,6 +33,9 @@ class TH1F;
 class TH2F;
 class TVector2;
 class CbmMuchPad;
+class CbmMCDataArray;
+class CbmMCDataManager;
+class CbmTimeSlice;
 
 /// QA for the MUCH detector after a "digitization" step of the simulation.
 /// The class reimplements corresponding QA checks from old CbmMuchHitFinderQa class
@@ -85,17 +93,29 @@ private:
 
   TFolder* histFolder;  /// folder wich contains histogramms
 
+  // setup
+  FairRootManager* fManager    = nullptr;
+  CbmMCDataManager* fMcManager = nullptr;
+  CbmTimeSlice* fTimeSlice     = nullptr;
+
   // geometry
   CbmMuchGeoScheme* fGeoScheme = nullptr;
   Int_t fNstations             = 0;
   CbmDigiManager* fDigiManager = nullptr;
 
   // containers
-  TClonesArray* fPoints      = nullptr;
+  CbmMCDataArray* fPoints    = nullptr;
+  CbmMCDataArray* fMCTracks  = nullptr;
   TClonesArray* fDigis       = nullptr;
   TClonesArray* fDigiMatches = nullptr;
-  TClonesArray* fMCTracks    = nullptr;
-  TClonesArray* fPointInfos  = nullptr;  /// temporary additional information
+
+  std::map<CbmLink, CbmMuchPointInfo> fMcPointInfoMap = {};  //! map point link -> point info
+
+  CbmMuchPointInfo& getPointInfo(const CbmLink& link)
+  {
+    assert(fMcPointInfoMap.find(link) != fMcPointInfoMap.end());
+    return fMcPointInfoMap[link];
+  }
 
   TFolder fOutFolder;        /// output folder with histos and canvases
   TParameter<int> fNevents;  /// number of processed events
diff --git a/sim/detectors/much/qa/CbmMuchTransportQa.cxx b/sim/detectors/much/qa/CbmMuchTransportQa.cxx
index 032bdd84f8..6a17b4ba83 100644
--- a/sim/detectors/much/qa/CbmMuchTransportQa.cxx
+++ b/sim/detectors/much/qa/CbmMuchTransportQa.cxx
@@ -8,6 +8,9 @@
 /// \date   21.10.2020
 
 #include "CbmMuchTransportQa.h"
+
+#include "CbmMCDataArray.h"
+#include "CbmMCDataManager.h"
 #include "CbmMCTrack.h"
 #include "CbmMuchAddress.h"
 #include "CbmMuchGeoScheme.h"
@@ -15,22 +18,26 @@
 #include "CbmMuchStation.h"
 #include "CbmQaCanvas.h"
 #include "CbmQaPie.h"
+#include "CbmTimeSlice.h"
+
+#include <FairRootManager.h>
+#include <FairSink.h>
+#include <FairTask.h>
+#include <Logger.h>
+
 #include "TClonesArray.h"
 #include "TDatabasePDG.h"
 #include "TH1.h"
 #include "TH2.h"
 #include "TLegend.h"
 #include "TStyle.h"
-#include <FairRootManager.h>
-#include <FairSink.h>
-#include <FairTask.h>
-#include <Logger.h>
 #include <TAxis.h>
 #include <TDirectory.h>
 #include <TMath.h>
 #include <TParameter.h>
 #include <TString.h>
 #include <TVector3.h>
+
 #include <vector>
 
 #define BINS_STA fNstations, 0, fNstations
@@ -118,16 +125,29 @@ InitStatus CbmMuchTransportQa::Init() {
   DeInit();
 
   TDirectory* oldDirectory = gDirectory;
-  FairRootManager* manager = FairRootManager::Instance();
-  fMcTracks                = (TClonesArray*) manager->GetObject("MCTrack");
-  fPoints                  = (TClonesArray*) manager->GetObject("MuchPoint");
-  fNstations               = CbmMuchGeoScheme::Instance()->GetNStations();
-  histFolder               = fOutFolder.AddFolder("hist", "Histogramms");
+  fManager                 = FairRootManager::Instance();
 
-  if (!manager) {
+  if (!fManager) {
     LOG(error) << "No FairRootManager found";
     return kERROR;
   }
+
+  fMcManager = dynamic_cast<CbmMCDataManager*>(fManager->GetObject("MCDataManager"));
+
+  fTimeSlice = (CbmTimeSlice*) fManager->GetObject("TimeSlice.");
+  if (!fTimeSlice) { LOG(error) << GetName() << ": No time slice found"; }
+
+  if (fMcManager) {
+    // Get MCTrack array
+    fMcTracks = fMcManager->InitBranch("MCTrack");
+
+    // Get StsPoint array
+    fPoints = fMcManager->InitBranch("MuchPoint");
+  }
+
+  fNstations = CbmMuchGeoScheme::Instance()->GetNStations();
+  histFolder = fOutFolder.AddFolder("hist", "Histogramms");
+
   if (!fMcTracks) {
     LOG(error) << "No MC tracks found";
     return kERROR;
@@ -357,45 +377,53 @@ void CbmMuchTransportQa::Exec(Option_t*) {
 
   fNevents.SetVal(fNevents.GetVal() + 1);
   LOG(debug) << "Event: " << fNevents.GetVal();
-  // bitmask tells which stations were crossed by mc track
-  std::vector<UInt_t> trackStaCross(fMcTracks->GetEntriesFast(), 0);
-
-  for (Int_t i = 0; i < fPoints->GetEntriesFast(); i++) {
-
-    CbmMuchPoint* point = (CbmMuchPoint*) fPoints->At(i);
-    Int_t stId    = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
-    UInt_t stMask = (1 << stId);
-    Int_t trackId = point->GetTrackID();
-    if (!point) {
-      LOG(fatal) << "Much point " << i << " doesn't exist";
-      break;
-    }  // Check if the point corresponds to a certain  MC Track
-    if (trackId < 0 || trackId >= fMcTracks->GetEntriesFast()) {
-      LOG(fatal) << "Much point " << i << ": trackId " << trackId
-                 << " doesn't belong to [0," << fMcTracks->GetEntriesFast() - 1
-                 << "]";
-      break;
-    }
-
-    CbmMCTrack* mcTrack = (CbmMCTrack*) fMcTracks->At(trackId);
-    if (!mcTrack) {
-      LOG(fatal) << "MC track " << trackId << " doesn't exist";
-      break;
-    }
-
-    Int_t motherId = mcTrack->GetMotherId();
-    Int_t pdgCode  = mcTrack->GetPdgCode();
-    if (pdgCode == 22 ||  // photons
-        pdgCode == 2112)  // neutrons
-    {
-      continue;
-    }
 
-    if (!(trackStaCross[trackId] & stMask)) {
-      FillCountingHistos(stId, motherId, pdgCode);
+  const CbmMatch& sliceMatch = fTimeSlice->GetMatch();
+
+  for (int iLink = 0; iLink < sliceMatch.GetNofLinks(); iLink++) {
+    const CbmLink& eventLink = sliceMatch.GetLink(iLink);
+    int nMuchPoints          = fPoints->Size(eventLink);
+    int nMcTracks            = fMcTracks->Size(eventLink);
+
+    // bitmask tells which stations were crossed by mc track
+    std::vector<UInt_t> trackStaCross(nMcTracks, 0);
+
+    for (Int_t ip = 0; ip < nMuchPoints; ip++) {
+      CbmLink pointLink = eventLink;
+      pointLink.SetIndex(ip);
+      CbmMuchPoint* point = (CbmMuchPoint*) fPoints->Get(pointLink);
+      Int_t stId          = CbmMuchAddress::GetStationIndex(point->GetDetectorID());
+      UInt_t stMask       = (1 << stId);
+      Int_t trackId       = point->GetTrackID();
+      if (!point) {
+        LOG(fatal) << "Much point " << ip << " doesn't exist";
+        break;
+      }  // Check if the point corresponds to a certain  MC Track
+      if (trackId < 0 || trackId >= nMcTracks) {
+        LOG(fatal) << "Much point " << ip << ": trackId " << trackId << " doesn't belong to [0," << nMcTracks - 1
+                   << "]";
+        break;
+      }
+      CbmLink trackLink = eventLink;
+      trackLink.SetIndex(trackId);
+      CbmMCTrack* mcTrack = (CbmMCTrack*) fMcTracks->Get(trackLink);
+      if (!mcTrack) {
+        LOG(fatal) << "MC track " << trackId << " doesn't exist";
+        break;
+      }
+
+      Int_t motherId = mcTrack->GetMotherId();
+      Int_t pdgCode  = mcTrack->GetPdgCode();
+      if (pdgCode == 22 ||  // photons
+          pdgCode == 2112)  // neutrons
+      {
+        continue;
+      }
+
+      if (!(trackStaCross[trackId] & stMask)) { FillCountingHistos(stId, motherId, pdgCode); }
+      trackStaCross[trackId] |= stMask;
+      Fill2dSpatialDistributionHistos(point, stId);
     }
-    trackStaCross[trackId] |= stMask;
-    Fill2dSpatialDistributionHistos(point, stId);
   }
 }
 
diff --git a/sim/detectors/much/qa/CbmMuchTransportQa.h b/sim/detectors/much/qa/CbmMuchTransportQa.h
index 73cc74e190..6dcd28c9a1 100644
--- a/sim/detectors/much/qa/CbmMuchTransportQa.h
+++ b/sim/detectors/much/qa/CbmMuchTransportQa.h
@@ -16,6 +16,10 @@
 #include <RtypesCore.h>
 #include <TFolder.h>
 #include <vector>
+
+class CbmMCDataArray;
+class CbmMCDataManager;
+class CbmTimeSlice;
 class CbmMuchPoint;
 class CbmQaCanvas;
 class TBuffer;
@@ -73,9 +77,15 @@ private:
   /// geometry
   Int_t fNstations = 0;
 
+  // setup
+  FairRootManager* fManager    = nullptr;
+  CbmMCDataManager* fMcManager = nullptr;
+  CbmTimeSlice* fTimeSlice     = nullptr;
+
   /// containers
-  TClonesArray* fPoints   = nullptr;
-  TClonesArray* fMcTracks = nullptr;
+  CbmMCDataArray* fPoints   = nullptr;
+  CbmMCDataArray* fMcTracks = nullptr;
+
   ///
 
   TFolder* histFolder;       /// subfolder for histograms
-- 
GitLab