diff --git a/core/qa/CbmQaTask.cxx b/core/qa/CbmQaTask.cxx index 78ce9c0386afae4cdb57a19d029dcaf779d0934d..a534f1758b23431830a0b34e19d833585f5d3f82 100644 --- a/core/qa/CbmQaTask.cxx +++ b/core/qa/CbmQaTask.cxx @@ -37,7 +37,8 @@ void CbmQaTask::Exec(Option_t* /*option*/) { fNofEvents.SetVal(fNofEvents.GetVal() + 1); LOG_IF(info, fVerbose > 1) << fName << ": event " << fNofEvents.GetVal(); - FillHistograms(); + this->InitTimeSlice(); + this->FillHistograms(); } // --------------------------------------------------------------------------------------------------------------------- diff --git a/core/qa/CbmQaTask.h b/core/qa/CbmQaTask.h index 2415e28a41b7d274595abb28ca6de2547b213d0c..61f876d7e9af887b9f5c8c73b6f648868e566a1a 100644 --- a/core/qa/CbmQaTask.h +++ b/core/qa/CbmQaTask.h @@ -85,6 +85,9 @@ protected: /// Initializes canvases virtual InitStatus InitCanvases(); + /// Initializes event / time-slice + virtual InitStatus InitTimeSlice() { return kSUCCESS; } + /// Method to fill histograms per event or time-slice virtual void FillHistograms(); diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt index 52aa3bb0775addc455bcd47cc01e175a23d426f0..ddad3866d316bef46926039ad3d1c441724d7e98 100644 --- a/reco/L1/CMakeLists.txt +++ b/reco/L1/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRCS CbmL1Performance.cxx CbmL1ReadEvent.cxx CbmCaMCModule.cxx + CbmCaTimeSliceReader.cxx L1Algo/L1Station.cxx L1Algo/L1Fit.cxx L1Algo/L1MCEvent.cxx @@ -86,6 +87,7 @@ set(SRCS qa/CbmCaInputQaMuch.cxx qa/CbmCaInputQaTrd.cxx qa/CbmCaInputQaTof.cxx + qa/CbmCaOutputQa.cxx qa/CbmTofInteraction.cxx # Tests ) diff --git a/reco/L1/CbmCaTimeSliceReader.cxx b/reco/L1/CbmCaTimeSliceReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e4f7fa6b592e68cbbf14e436704458c0cef609ca --- /dev/null +++ b/reco/L1/CbmCaTimeSliceReader.cxx @@ -0,0 +1,312 @@ +/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file CbmCaTimeSliceReader.cxx +/// @brief Time-slice/event reader for CA tracker in CBM (implementation) +/// @since 24.02.2023 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#include "CbmCaTimeSliceReader.h" + +#include "CbmGlobalTrack.h" +#include "CbmKFMath.h" // for CopyTrackParam2TC +#include "CbmStsTrack.h" + +#include "FairRootManager.h" +#include "Logger.h" + +#include "L1Constants.h" +#include "L1InputData.h" +#include "L1Parameters.h" + +using cbm::ca::TimeSliceReader; +using L1Constants::clrs::kCL; // clear log +using L1Constants::clrs::kGNb; // green bold log + +// --------------------------------------------------------------------------------------------------------------------- +// +TimeSliceReader::TimeSliceReader(ECbmTrackingMode mode) : fTrackingMode(mode) {} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::Clear() +{ + // Detector used + fbUseMvd = false; + fbUseSts = false; + fbUseMuch = false; + fbUseTrd = false; + fbUseTof = false; + + // Input branches + fpBrTimeSlice = nullptr; + + fpBrMvdHits = nullptr; + fpBrStsHits = nullptr; + fpBrMuchHits = nullptr; + fpBrTrdHits = nullptr; + fpBrTofHits = nullptr; + + fpBrRecoTracks = nullptr; + fpBrStsTracks = nullptr; + fpBrMuchTracks = nullptr; + fpBrTrdTracks = nullptr; + fpBrTofTracks = nullptr; + + // Pointers to output containers + fpvHitIds = nullptr; + fpvDbgHits = nullptr; + fpIODataManager = nullptr; + fpvTracks = nullptr; + + // Other + fpParameters = nullptr; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::InitRun() +{ + LOG(info) << "TimeSliceReader: initializing run ... "; + + // Init tracking detector interfaces + fpMvdInterface = CbmMvdTrackingInterface::Instance(); + fpStsInterface = CbmStsTrackingInterface::Instance(); + fpMuchInterface = CbmMuchTrackingInterface::Instance(); + fpTrdInterface = CbmTrdTrackingInterface::Instance(); + fpTofInterface = CbmTofTrackingInterface::Instance(); + + // ** Init data branches ** + + auto* pFairManager = FairRootManager::Instance(); + LOG_IF(fatal, !pFairManager) << "TimeSliceReader: FairRootManager was not defined"; + + fpBrTimeSlice = dynamic_cast<CbmTimeSlice*>(pFairManager->GetObject("TimeSlice.")); + LOG_IF(fatal, !fpBrTimeSlice) << "TimeSliceReader: time slice was not defined"; + + // Init hit branches + if (fbUseMvd) { + fpBrMvdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MvdHit")); + LOG_IF(fatal, !fpBrMvdHits) << "TimeSliceReader: MVD hits were not found"; + } + + if (fbUseSts) { + fpBrStsHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsHit")); + LOG_IF(fatal, !fpBrStsHits) << "TimeSliceReader: STS hits were not found"; + } + + if (fbUseMuch) { + fpBrMuchHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchPixelHit")); + LOG_IF(fatal, !fpBrMuchHits) << "TimeSliceReader: MuCh hits were not found"; + } + + if (fbUseTrd) { + fpBrTrdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdHit")); + LOG_IF(fatal, !fpBrTrdHits) << "TimeSliceReader: TRD hits were not found"; + } + + if (fbUseTof) { + fpBrTofHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofHit")); + LOG_IF(fatal, !fpBrTofHits) << "TimeSliceReader: TOF hits were not found"; + } + + // Init track branches + if (fpvTracks) { + switch (fTrackingMode) { + case ECbmTrackingMode::kSTS: + fpBrRecoTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack")); + LOG_IF(fatal, !fpBrRecoTracks) << "TimeSliceReader: StsTrack not found"; + break; + case ECbmTrackingMode::kMCBM: + fpBrRecoTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("GlobalTrack")); + LOG_IF(fatal, !fpBrRecoTracks) << "TimeSliceReader: GlobalTrack not found"; + if (fbUseSts) { + fpBrStsTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack")); + LOG_IF(fatal, !fpBrStsTracks) << "TimeSliceReader: StsTrack not found"; + } + if (fbUseMuch) { + fpBrMuchTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchTrack")); + LOG_IF(fatal, !fpBrMuchTracks) << "TimeSliceReader: MuchTrack not found"; + } + if (fbUseTrd) { + fpBrTrdTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdTrack")); + LOG_IF(fatal, !fpBrTrdTracks) << "TimeSliceReader: TrdTrack not found"; + } + if (fbUseTof) { + fpBrTofTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofTrack")); + LOG_IF(fatal, !fpBrTofTracks) << "TimeSliceReader: TofTrack not found"; + } + break; + } + } + + LOG(info) << "TimeSliceReader: initializing run ... " << kGNb << "done" << kCL; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::InitTimeSlice() { LOG(info) << "TimeSliceReader: initializing time slice"; } + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::ReadHits() +{ + fNofHits = 0; + fNofHitKeys = 0; + fFirstHitKey = 0; + + // Get total number of hits + int nHitsTot = 0; + if (fbUseMvd) { nHitsTot += fpBrMvdHits->GetEntriesFast(); } + if (fbUseSts) { nHitsTot += fpBrStsHits->GetEntriesFast(); } + if (fbUseMuch) { nHitsTot += fpBrMuchHits->GetEntriesFast(); } + if (fbUseTrd) { nHitsTot += fpBrTrdHits->GetEntriesFast(); } + if (fbUseTof) { nHitsTot += fpBrTofHits->GetEntriesFast(); } + + // Resize the containers + fpvHitIds->clear(); + fpvHitIds->reserve(nHitsTot); + fpvDbgHits->clear(); + fpvDbgHits->reserve(nHitsTot); + fpIODataManager->ResetInputData(); + fpIODataManager->ReserveNhits(nHitsTot); + + // Read hits for different detectors + if (fbUseMvd) { fNofHits += ReadHitsForDetector<L1DetectorID::kMvd>(fpBrMvdHits); } + if (fbUseSts) { fNofHits += ReadHitsForDetector<L1DetectorID::kSts>(fpBrStsHits); } + if (fbUseMuch) { fNofHits += ReadHitsForDetector<L1DetectorID::kMuch>(fpBrMuchHits); } + if (fbUseTrd) { fNofHits += ReadHitsForDetector<L1DetectorID::kTrd>(fpBrTrdHits); } + if (fbUseTof) { fNofHits += ReadHitsForDetector<L1DetectorID::kTof>(fpBrTofHits); } + + fpIODataManager->SetNhitKeys(fNofHitKeys); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::ReadRecoTracks() +{ + if (!fpvTracks) { + LOG(warn) << "TimeSliceReader: reconstructed tracks should not be read in this regime"; + return; + } + + assert(fpBrRecoTracks); + int nTracks = fpBrRecoTracks->GetEntriesFast(); + fpvTracks->reset(nTracks); + switch (fTrackingMode) { + case ECbmTrackingMode::kSTS: + // Fill tracks from StsTrack branch + for (int iT = 0; iT < nTracks; ++iT) { + auto* pInputTrack = static_cast<CbmStsTrack*>(fpBrRecoTracks->At(iT)); + auto& track = (*fpvTracks)[iT]; + CbmKFMath::CopyTrackParam2TC(pInputTrack->GetParamFirst(), track.T, track.C); + CbmKFMath::CopyTrackParam2TC(pInputTrack->GetParamLast(), track.TLast, track.CLast); + track.chi2 = pInputTrack->GetChiSq(); + track.NDF = pInputTrack->GetNDF(); + track.Tpv[6] = pInputTrack->GetStartTime(); + track.Cpv[20] = pInputTrack->GetStartTimeError(); + track.T[6] = pInputTrack->GetFirstHitTime(); + track.C[20] = pInputTrack->GetFirstHitTimeError(); + track.TLast[6] = pInputTrack->GetLastHitTime(); + track.CLast[20] = pInputTrack->GetLastHitTimeError(); + track.Hits.clear(); + track.Hits.reserve(pInputTrack->GetNofHits()); + for (int iH = 0; iH < pInputTrack->GetNofMvdHits(); ++iH) { + track.Hits.push_back(-pInputTrack->GetMvdHitIndex(iH) - 1); // !!!! + } // iH + for (int iH = 0; iH < pInputTrack->GetNofStsHits(); ++iH) { + track.Hits.push_back(pInputTrack->GetStsHitIndex(iH)); + } // iH + } // iT + break; + + case ECbmTrackingMode::kMCBM: + LOG(fatal) << "Sorry, mCBM mode has not been implemented yet. Stay tuned :)"; + // TODO: fill Global track here + break; + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::RegisterHitDebugInfoContainer(L1Vector<CbmL1HitDebugInfo>& vDbgHits) { fpvDbgHits = &vDbgHits; } + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds) { fpvHitIds = &vHitIds; } + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::RegisterIODataManager(std::shared_ptr<L1IODataManager>& pIODataManager) +{ + LOG_IF(fatal, !pIODataManager.get()) << "TimeSliceReader: passed null pointer as a L1IODataManager instance"; + fpIODataManager = pIODataManager; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::RegisterTracksContainer(L1Vector<CbmL1Track>& vTracks) { fpvTracks = &vTracks; } + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::SetDetector(L1DetectorID detID, bool flag) +{ + switch (detID) { + case L1DetectorID::kMvd: fbUseMvd = flag; break; + case L1DetectorID::kSts: fbUseSts = flag; break; + case L1DetectorID::kMuch: fbUseMuch = flag; break; + case L1DetectorID::kTrd: fbUseTrd = flag; break; + case L1DetectorID::kTof: fbUseTof = flag; break; + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::SetParameters(const L1Parameters* pParameters) +{ + LOG_IF(fatal, !pParameters) << "TimeSliceReader: passed null pointer as L1IODataManager instance"; + fpParameters = pParameters; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TimeSliceReader::StoreHitRecord(const HitRecord& hitRecord) +{ + int iHitGlob = static_cast<int>(fpIODataManager->GetNofHits()); // Current hit global index + + // Save the algo hit + if (fpIODataManager.get()) { + L1Hit aHit; + aHit.iSt = hitRecord.fStaId; + aHit.f = hitRecord.fStripF; + aHit.b = hitRecord.fStripB; + aHit.ID = -1; + aHit.z = hitRecord.fZ; + aHit.u = hitRecord.fU; + aHit.v = hitRecord.fV; + aHit.t = hitRecord.fT; + aHit.dt2 = hitRecord.fDt * hitRecord.fDt; + aHit.du2 = hitRecord.fDu * hitRecord.fDu; + aHit.dv2 = hitRecord.fDv * hitRecord.fDv; + fpIODataManager->PushBackHit(aHit, hitRecord.fDataStream); + } + + // Save hit ID information + if (fpvHitIds) { fpvHitIds->emplace_back(hitRecord.fDet, hitRecord.fExtId); } + + // Save debug information + if (fpvDbgHits) { + CbmL1HitDebugInfo hitDbg; + hitDbg.Det = hitRecord.fDet; + hitDbg.ExtIndex = hitRecord.fExtId; + hitDbg.iStation = hitRecord.fStaId; + hitDbg.x = hitRecord.fX; + hitDbg.y = hitRecord.fY; + hitDbg.dx = hitRecord.fDx; + hitDbg.dy = hitRecord.fDy; + hitDbg.dxy = hitRecord.fDxy; + hitDbg.time = hitRecord.fT; + fpvDbgHits->push_back(hitDbg); + } +} diff --git a/reco/L1/CbmCaTimeSliceReader.h b/reco/L1/CbmCaTimeSliceReader.h new file mode 100644 index 0000000000000000000000000000000000000000..92ff3c3644a7b8dbda287380d79f44ccde082f82 --- /dev/null +++ b/reco/L1/CbmCaTimeSliceReader.h @@ -0,0 +1,323 @@ +/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file CbmCaTimeSliceReader.h +/// @brief Time-slice/event reader for CA tracker in CBM (header) +/// @since 24.02.2023 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#ifndef CbmCaTimeSliceReader_h +#define CbmCaTimeSliceReader_h 1 + +#include "CbmL1.h" // TMP: for CbmL1HitStore +#include "CbmL1DetectorID.h" +#include "CbmL1Hit.h" +#include "CbmL1Track.h" +#include "CbmMuchPixelHit.h" +#include "CbmMuchTrackingInterface.h" +#include "CbmMvdHit.h" +#include "CbmMvdTrackingInterface.h" +#include "CbmPixelHit.h" +#include "CbmStsHit.h" +#include "CbmStsTrackingInterface.h" +#include "CbmTofHit.h" +#include "CbmTofTrackingInterface.h" +#include "CbmTrdHit.h" +#include "CbmTrdTrackingInterface.h" + +#include "TClonesArray.h" + +#include "L1Vector.h" + + +class CbmTimeSlice; +class L1IODataManager; +class L1Parameters; + +namespace cbm::ca +{ + /// @brief A structure to store hits information from different detectors in a uniform manner + struct HitRecord { + double fX = 0.; ///< x component of hit position [cm] + double fY = 0.; ///< y component of hit position [cm] + double fDx = 0.; ///< error of x component of hit position [cm] + double fDy = 0.; ///< error of y component of hit position [cm] + double fDxy = 0.; ///< correlation between x and y components [cm] + double fU = 0.; ///< hit position in direction of front strips [cm] + double fV = 0.; ///< hit position in direction of back strips [cm] + double fDu = 0.; ///< hit position error in direction of front strips [cm] + double fDv = 0.; ///< hit position error in direction of back strips [cm] + double fZ = 0.; ///< z component of hit position [cm] + double fT = 0.; ///< time of hit [ns] + double fDt = 0.; ///< time error of hit [ns] + int64_t fDataStream = -1; ///< Global index of detector module + int fExtId = -1; ///< external index of hit + int fStaId = -1; ///< index of active tracking station + int fStripF = -1; ///< index of front strip + int fStripB = -1; ///< index of back strip + int fDet = -1; ///< detector ID + }; + + /// @brief A reader of time slice for CA tracker + /// + /// The class reads reconstructed hits and reconstructed tracks (optionally) and fills the CA tracking internal + /// data structures. + /// + class TimeSliceReader { + public: + /// @brief Constructor from parameters + /// @param mode Tracking mode + TimeSliceReader(ECbmTrackingMode mode); + + /// @brief Destructor + ~TimeSliceReader() = default; + + /// @brief Copy constructor + TimeSliceReader(const TimeSliceReader&) = delete; + + /// @brief Move constructor + TimeSliceReader(TimeSliceReader&&) = delete; + + /// @brief Copy assignment operator + TimeSliceReader& operator=(const TimeSliceReader&) = delete; + + /// @brief Move assignment operator + TimeSliceReader& operator=(TimeSliceReader&&) = delete; + + /// @brief Clears class content + void Clear(); + + /// @brief Run initializer function + /// + /// Initializes data branches and provides necessary checks in the beginning of the run + void InitRun(); + + /// @brief Reads time slice + /// + /// Reads hits from time slice + void InitTimeSlice(); + + /// @brief Reads hits + void ReadHits(); + + /// @brief Reads reconstructed tracks + void ReadRecoTracks(); + + /// @brief Registers hit debug info container + /// @param vDbgHits Reference to debug hit container + void RegisterHitDebugInfoContainer(L1Vector<CbmL1HitDebugInfo>& vDbgHits); + + /// @brief Registers hit index container + /// @param vHitIds Reference to hits indexes container + void RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds); + + /// @brief Registers the CA IO data manager instance + /// @param pIODataManager Shared pointer to the IO data manager instance + void RegisterIODataManager(std::shared_ptr<L1IODataManager>& ioDataManager); + + /// @brief Register the reconstructed tracks container + /// @param vTracks Reference to reconstructed tracks container + void RegisterTracksContainer(L1Vector<CbmL1Track>& vTracks); + + /// @brief Sets used detector subsystems + /// @param detID Id of detector + /// @param flag Flag: true - detector is used + /// @note Should be called before this->Init() + void SetDetector(L1DetectorID detID, bool flag = true); + + /// @brief Sets the instance of parameters object + /// @param pParameters Pointer to the parameters instance + void SetParameters(const L1Parameters* pParameters); + + + private: + /// @brief Reads hits for a given detector subsystem + /// @tparam Detector ID + /// @param pBrHits Pointer to input hit branch + /// @return Number of stored hits + /// @note The function modifies fNofHitKey and fFirstHitKey counters + template<L1DetectorID DetID> + int ReadHitsForDetector(const TClonesArray* pBrHits); + + /// @brief Saves hit to data structures + /// + /// Stores recorded hit information into registered hit containers + void StoreHitRecord(const HitRecord& hitRecord); + + // Flags for detector subsystems being used + bool fbUseMvd = false; ///< is MVD used + bool fbUseSts = false; ///< is STS used + bool fbUseMuch = false; ///< is MuCh used + bool fbUseTrd = false; ///< is TRD used + bool fbUseTof = false; ///< is TOF used + bool fbReadTracks = true; ///< flag to read reconstructed tracks from reco.root + + // Pointers to the tracking detector interfaces + CbmTrackingDetectorInterfaceBase* fpMvdInterface = nullptr; + CbmTrackingDetectorInterfaceBase* fpStsInterface = nullptr; + CbmTrackingDetectorInterfaceBase* fpMuchInterface = nullptr; + CbmTrackingDetectorInterfaceBase* fpTrdInterface = nullptr; + CbmTrackingDetectorInterfaceBase* fpTofInterface = nullptr; + + // Input data branches + CbmTimeSlice* fpBrTimeSlice = nullptr; ///< Pointer to the TS object + + TClonesArray* fpBrMvdHits = nullptr; ///< Input branch for MVD hits ("MvdHit") + TClonesArray* fpBrStsHits = nullptr; ///< Input branch for STS hits ("StsHit") + TClonesArray* fpBrMuchHits = nullptr; ///< Input branch for MuCh hits ("MuchPixelHit") + TClonesArray* fpBrTrdHits = nullptr; ///< Input branch for TRD hits ("TrdHit") + TClonesArray* fpBrTofHits = nullptr; ///< Input branch for TOF hits ("TofHit") + + // Branches for reconstructed tracks. The input at the moment (as for 27.02.2023) depends on the selected + // tracking mode. For simulations in CBM, the CA tracking is used only in STS + MVD detectors. In this case + // the reconstructed tracks are saved to the "StsTrack" branch as CbmStsTrack objects. For mCBM, the tracks from + // CA are saved as global tracks, and the local ones are used to keep indexes of hits in different subsystems + TClonesArray* fpBrRecoTracks = nullptr; ///< Input branch for reconstructed tracks ("GlobalTrack", "StsTrack") + TClonesArray* fpBrStsTracks = nullptr; ///< Input branch for reconstructed STS tracks ("StsTrack") + TClonesArray* fpBrMuchTracks = nullptr; ///< Input branch for reconstructed MuCh tracks ("MuchTrack") + TClonesArray* fpBrTrdTracks = nullptr; ///< Input branch for reconstructed TRD tracks ("TrdTrack") + TClonesArray* fpBrTofTracks = nullptr; ///< Input branch for reconstructed TOF tracks ("TofTrack") + + // Pointers to output data containers + L1Vector<CbmL1HitId>* fpvHitIds = nullptr; ///< Pointer to array of hit index objects + L1Vector<CbmL1HitDebugInfo>* fpvDbgHits = nullptr; ///< Pointer to array of debug hits + L1Vector<CbmL1Track>* fpvTracks = nullptr; ///< Pointer to array of reconstructed tracks + std::shared_ptr<L1IODataManager> fpIODataManager = nullptr; ///< Pointer to input data manager + + + // Additional + const L1Parameters* fpParameters = nullptr; ///< Pointer to the defined parameters instance + ECbmTrackingMode fTrackingMode; ///< Tracking mode + + // Indexes + int fNofHits = 0; ///< Stored number of hits + int fNofHitKeys = 0; ///< Recorded number of hit keys + int fFirstHitKey = 0; ///< First index of hit key for the detector subsystem + }; +} // namespace cbm::ca + + +// ************************************************** +// ** Inline and template function implementations ** +// ************************************************** + +// --------------------------------------------------------------------------------------------------------------------- +// +template<L1DetectorID DetID> +int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits) +{ + int nHitsTot = pBrHits->GetEntriesFast(); // total number of hits stored in a branch + int nHitsStored = 0; // number of hits stored + + fFirstHitKey = fNofHitKeys; + + for (int iH = 0; iH < nHitsTot; ++iH) { + cbm::ca::HitRecord hitRecord; // Record of hits information + + CbmPixelHit* pPixelHit = nullptr; // Pointer to hit object + float phiF = 0.; // Stereo angle of front strips + float phiB = 0.; // Stereo angle of back strips + int iStGeom = -1; // Geometry station number + + // Fill out detector specific data + if constexpr (L1DetectorID::kMvd == DetID) { + CbmMvdHit* pMvdHit = static_cast<CbmMvdHit*>(pBrHits->At(iH)); + iStGeom = fpMvdInterface->GetTrackingStationIndex(pMvdHit->GetStationNr()); + phiF = fpMvdInterface->GetStripsStereoAngleFront(iStGeom); + phiB = fpMvdInterface->GetStripsStereoAngleBack(iStGeom); + pPixelHit = static_cast<CbmPixelHit*>(pMvdHit); + hitRecord.fDu = pMvdHit->GetDx(); + hitRecord.fDv = pMvdHit->GetDy(); + } + else if constexpr (L1DetectorID::kSts == DetID) { + CbmStsHit* pStsHit = static_cast<CbmStsHit*>(pBrHits->At(iH)); + iStGeom = fpStsInterface->GetTrackingStationIndex(pStsHit->GetAddress()); + phiF = fpStsInterface->GetStripsStereoAngleFront(iStGeom); + phiB = fpStsInterface->GetStripsStereoAngleBack(iStGeom); + pPixelHit = static_cast<CbmPixelHit*>(pStsHit); + hitRecord.fStripF = fFirstHitKey + pStsHit->GetFrontClusterId(); + hitRecord.fStripB = fFirstHitKey + pStsHit->GetBackClusterId(); + hitRecord.fDu = pStsHit->GetDu(); + hitRecord.fDv = pStsHit->GetDv(); + } + else if constexpr (L1DetectorID::kMuch == DetID) { + CbmMuchPixelHit* pMuchHit = static_cast<CbmMuchPixelHit*>(pBrHits->At(iH)); + iStGeom = fpMuchInterface->GetTrackingStationIndex(pMuchHit->GetAddress()); + phiF = fpMuchInterface->GetStripsStereoAngleFront(iStGeom); + phiB = fpMuchInterface->GetStripsStereoAngleBack(iStGeom); + pPixelHit = static_cast<CbmPixelHit*>(pMuchHit); + hitRecord.fDu = pMuchHit->GetDx(); + hitRecord.fDv = pMuchHit->GetDy(); + } + else if constexpr (L1DetectorID::kTrd == DetID) { + CbmTrdHit* pTrdHit = static_cast<CbmTrdHit*>(pBrHits->At(iH)); + iStGeom = fpTrdInterface->GetTrackingStationIndex(pTrdHit->GetAddress()); + phiF = fpTrdInterface->GetStripsStereoAngleFront(iStGeom); + phiB = fpTrdInterface->GetStripsStereoAngleBack(iStGeom); + pPixelHit = static_cast<CbmPixelHit*>(pTrdHit); + hitRecord.fDu = pTrdHit->GetDx(); + hitRecord.fDv = pTrdHit->GetDy(); + } + else if constexpr (L1DetectorID::kTof == DetID) { + CbmTofHit* pTofHit = static_cast<CbmTofHit*>(pBrHits->At(iH)); + iStGeom = fpTofInterface->GetTrackingStationIndex(pTofHit->GetAddress()); + phiF = fpTofInterface->GetStripsStereoAngleFront(iStGeom); + phiB = fpTofInterface->GetStripsStereoAngleBack(iStGeom); + pPixelHit = static_cast<CbmPixelHit*>(pTofHit); + hitRecord.fDu = pTofHit->GetDx(); + hitRecord.fDv = pTofHit->GetDy(); + + // *** Additional cuts for TOF *** + // Skip T0 hits + if (5 == CbmTofAddress::GetSmType(pTofHit->GetAddress())) { continue; } + + // FIXME: Figure it out, if this cut is still needed (introduced a year ago for mCBM) + if (ECbmTrackingMode::kMCBM == fTrackingMode && pTofHit->GetZ() > 400) { continue; } + } + + //int iStActive = fpParameters->GetStationIndexActive(iStGeom); + int iStActive = iStGeom; // !!!! Initialize fParameters + if (iStActive == -1) { continue; } // Cut off inactive stations + + // Fill out data common for all the detectors + hitRecord.fStaId = iStGeom; + hitRecord.fX = pPixelHit->GetX(); + hitRecord.fY = pPixelHit->GetY(); + hitRecord.fZ = pPixelHit->GetZ(); + hitRecord.fDx = pPixelHit->GetDx(); + hitRecord.fDy = pPixelHit->GetDy(); + hitRecord.fDxy = pPixelHit->GetDxy(); + hitRecord.fT = pPixelHit->GetTime(); + hitRecord.fDt = pPixelHit->GetTimeError(); + hitRecord.fDet = static_cast<int>(DetID); + hitRecord.fDataStream = (static_cast<int64_t>(hitRecord.fDet) << 60) | pPixelHit->GetAddress(); + hitRecord.fU = hitRecord.fX * cos(phiF) + hitRecord.fY * sin(phiF); + hitRecord.fV = hitRecord.fX * cos(phiB) + hitRecord.fY * sin(phiB); + + // Update hit external index + if constexpr (L1DetectorID::kMvd == DetID) { hitRecord.fExtId = -(1 + iH); } + else { + hitRecord.fExtId = iH; + } + + // Update number of hit keys + if constexpr (L1DetectorID::kSts == DetID) { + if (fNofHitKeys <= hitRecord.fStripF) { fNofHitKeys += hitRecord.fStripF; } + if (fNofHitKeys <= hitRecord.fStripB) { fNofHitKeys += hitRecord.fStripB; } + } + else { + hitRecord.fStripF = fFirstHitKey + iH; + hitRecord.fStripB = hitRecord.fStripF; + if (fNofHitKeys <= hitRecord.fStripF) { fNofHitKeys += hitRecord.fStripF; } + } + + // Save hit to data structures + this->StoreHitRecord(hitRecord); + ++nHitsStored; + } // iH + return nHitsStored; +} + + +#endif // CbmCaTimeSliceReader_h diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx index 0be8e167f99e0a5b8a749b7cb04ac37e6fef96fe..0efebbde0145ace8e6884a28123895b66da59187 100644 --- a/reco/L1/CbmL1.cxx +++ b/reco/L1/CbmL1.cxx @@ -90,7 +90,6 @@ CbmL1::CbmL1() : CbmL1("L1") {} CbmL1::CbmL1(const char* name, Int_t verbose, Int_t performance, int dataMode, const TString& dataDir, int findParticleMode) : FairTask(name, verbose) - , fIODataManager(L1IODataManager(gAlgo.GetParameters())) , fPerformance(performance) , fSTAPDataMode(dataMode) , fFindParticlesMode(findParticleMode) @@ -103,6 +102,8 @@ CbmL1::CbmL1(const char* name, Int_t verbose, Int_t performance, int dataMode, c default: LOG(info) << "CbmL1: tracking will be run without external data R/W"; break; } + fpIODataManager = std::make_shared<L1IODataManager>(); + if (1 == fSTAPDataMode || 2 == fSTAPDataMode) { this->DefineSTAPNames(dataDir); } if (!CbmTrackingDetectorInterfaceInit::Instance()) { @@ -867,6 +868,7 @@ InitStatus CbmL1::Init() fNStations = fpAlgo->GetParameters()->GetNstationsActive(); LOG(info) << fpAlgo->GetParameters()->ToString(0); + fpIODataManager->SetNofActiveStations(fNStations); LOG(info) << "----- Numbers of stations active in tracking -----"; LOG(info) << " MVD: " << fNMvdStations; @@ -1202,7 +1204,7 @@ void CbmL1::WriteSTAPAlgoInputData(int iJob) // must be called after ReadEvent + TString::Format(kSTAPAlgoIDataSuffix.data(), iJob); // Write file - fIODataManager.WriteInputData(filename.Data()); + fpIODataManager->WriteInputData(filename.Data()); } // --------------------------------------------------------------------------------------------------------------------- @@ -1228,7 +1230,7 @@ void CbmL1::ReadSTAPAlgoInputData(int iJob) + TString::Format(kSTAPAlgoIDataSuffix.data(), iJob); // Read file - fIODataManager.ReadInputData(filename.Data()); + fpIODataManager->ReadInputData(filename.Data()); } // --------------------------------------------------------------------------------------------------------------------- diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h index db0ee01adc5195c64236b64276c79b349fcb63e1..a5d550da97d4ee05b47e1c84a17ebad602964b2b 100644 --- a/reco/L1/CbmL1.h +++ b/reco/L1/CbmL1.h @@ -445,8 +445,8 @@ private: // *************************** - L1InitManager fInitManager; ///< Tracking parameters data manager - L1IODataManager fIODataManager; ///< Input-output data manager + L1InitManager fInitManager; ///< Tracking parameters data manager + std::shared_ptr<L1IODataManager> fpIODataManager = nullptr; ///< Input-output data manager //std::unique_ptr<CbmCaMCModule> fpMCModule = nullptr; ///< MC-module for tracking diff --git a/reco/L1/CbmL1DetectorID.h b/reco/L1/CbmL1DetectorID.h index 6bffea7026eb95166b225f8b28b44914a3df189f..c63df00909f01f3c7b0155b648273e51aa1cb49c 100644 --- a/reco/L1/CbmL1DetectorID.h +++ b/reco/L1/CbmL1DetectorID.h @@ -23,4 +23,12 @@ enum class L1DetectorID kTof }; +/// @brief Enumeration for different tracking running modes +enum class ECbmTrackingMode +{ + kSTS, ///< Local tracking in CBM (STS + MVD), results stored to the StsTrack branch + kMCBM ///< Global tracking in mCBM (STS, MuCh, TRD, TOF), results stored to GlobalTrack branch +}; + + #endif // CbmL1DetectorID_h diff --git a/reco/L1/CbmL1ReadEvent.cxx b/reco/L1/CbmL1ReadEvent.cxx index 3a96dd7dbbdebcfea76db50b63d636c28742f148..5655a3fdc36435a572adeceaa85d0ab6ffc46999 100644 --- a/reco/L1/CbmL1ReadEvent.cxx +++ b/reco/L1/CbmL1ReadEvent.cxx @@ -851,7 +851,7 @@ void CbmL1::ReadEvent(CbmEvent* event) th.dx = h->GetDx(); th.dy = h->GetDy(); - th.dxy = 0; + th.dxy = 0; /// FIXME: ??? th.du = h->GetDx(); th.dv = h->GetDy(); @@ -1056,7 +1056,7 @@ void CbmL1::ReadEvent(CbmEvent* event) if (0x00202806 == h->GetAddress() || 0x00002806 == h->GetAddress()) continue; // TODO: Why? (S.Zharko) - if (5 == CbmTofAddress::GetSmType(h->GetAddress())) continue; + if (5 == CbmTofAddress::GetSmType(h->GetAddress())) continue; // Skip T0 hits from TOF int sttof = CbmTofTrackingInterface::Instance()->GetTrackingStationIndex(h); @@ -1150,9 +1150,9 @@ void CbmL1::ReadEvent(CbmEvent* event) fvHitDebugInfo.reserve(nHits); fvHitPointIndexes.reserve(nHits); - fIODataManager.ResetInputData(); - fIODataManager.ReserveNhits(nHits); - fIODataManager.SetNhitKeys(NStrips); + fpIODataManager->ResetInputData(); + fpIODataManager->ReserveNhits(nHits); + fpIODataManager->SetNhitKeys(NStrips); // ----- Fill for (int iHit = 0; iHit < nHits; ++iHit) { @@ -1191,12 +1191,12 @@ void CbmL1::ReadEvent(CbmEvent* event) // TODO: Here one should fill in the fvExternalHits[iHit].mcPointIds - fIODataManager.PushBackHit(h, th.fDataStream); + fpIODataManager->PushBackHit(h, th.fDataStream); fvHitDebugInfo.push_back(s); fvHitPointIndexes.push_back(th.iMC); } - if (fPerformance) { HitMatch(); } /// OLD + if (fPerformance) { HitMatch(); } /// OLD if (fVerbose >= 2) cout << "ReadEvent: mvd and sts are saved." << endl; @@ -1204,7 +1204,7 @@ void CbmL1::ReadEvent(CbmEvent* event) if (1 == fSTAPDataMode) { WriteSTAPAlgoInputData(nCalls); } if (2 == fSTAPDataMode) { ReadSTAPAlgoInputData(nCalls); } // TODO: SZh: If we read data from file, we don't need to collect them above. This should be addressed - fIODataManager.SendInputData(fpAlgo); + fpIODataManager->SendInputData(fpAlgo); if (fPerformance) { if (fVerbose >= 10) cout << "HitMatch is done." << endl; diff --git a/reco/L1/L1Algo/L1Algo.h b/reco/L1/L1Algo/L1Algo.h index 3c89d2cf89815f2f251402e1c4e97d092cef0678..2500a4425738567fe36ec26af22759a1959c8761 100644 --- a/reco/L1/L1Algo/L1Algo.h +++ b/reco/L1/L1Algo/L1Algo.h @@ -348,6 +348,7 @@ public: void DrawRecoTracksTime(const L1Vector<CbmL1Track>& tracks); #endif + /// TODO: Move to L1 enum TrackingMode { kSts, diff --git a/reco/L1/L1Algo/L1IODataManager.cxx b/reco/L1/L1Algo/L1IODataManager.cxx index dbe5a6a95d9ec192ef373f120cec7efaa13833b9..73d9a572b900ff3af7c2b5d08fc528b3034ced90 100644 --- a/reco/L1/L1Algo/L1IODataManager.cxx +++ b/reco/L1/L1Algo/L1IODataManager.cxx @@ -16,9 +16,6 @@ #include "L1Algo.h" -// --------------------------------------------------------------------------------------------------------------------- -// -L1IODataManager::L1IODataManager(const L1Parameters* pParameters) : fpParameters(pParameters) {} // --------------------------------------------------------------------------------------------------------------------- // diff --git a/reco/L1/L1Algo/L1IODataManager.h b/reco/L1/L1Algo/L1IODataManager.h index 05c2c3f131c2fdc5ba1a53808ceb57f237ab8854..166972ecbe678a7e84910ac5146fbcf0cee19d7a 100644 --- a/reco/L1/L1Algo/L1IODataManager.h +++ b/reco/L1/L1Algo/L1IODataManager.h @@ -13,7 +13,6 @@ #include "L1Constants.h" #include "L1InputData.h" -class L1Parameters; class L1Algo; //class L1OutputData; @@ -28,11 +27,7 @@ public: // ** Constructors and destructor ** /// Default constructor - L1IODataManager() = delete; - - /// Constructor - /// \param fpParameters Pointer to the L1 tracking algorithm parameters instance - L1IODataManager(const L1Parameters* pParameters); + L1IODataManager() = default; /// Destructor ~L1IODataManager() = default; @@ -49,6 +44,10 @@ public: /// Move assignment operator L1IODataManager& operator=(L1IODataManager&& other) = delete; + /// @brief Gets number of hits stored + /// @return Number of hits + int GetNofHits() { return fInputData.fHits.size(); } + /// Reads input data object from boost-serialized binary file /// \param fileName Name of input file void ReadInputData(const std::string& fileName); @@ -78,6 +77,10 @@ public: /// \param nKeys Number of hit keys void SetNhitKeys(int nKeys) { fInputData.fNhitKeys = nKeys; } + /// @brief Sets number of active stations + /// @param nStations Number of stations + void SetNofActiveStations(int nStations) { fNofActiveStations = nStations; } + /// Sends (moves) input data to the destination reference /// \param pAlgo Pointer to the L1 tracking algorithm main class /// \return Success flag @@ -110,9 +113,8 @@ private: L1InputData fInputData {}; ///< Object of input data - const L1Parameters* fpParameters {nullptr}; ///< Pointer to the tracking parameters object - int64_t fLastStreamId {-1}; ///< data stream Id of the last hit added + int fNofActiveStations = -1; ///< Number of active stations }; diff --git a/reco/L1/L1LinkDef.h b/reco/L1/L1LinkDef.h index 3681e47ae71d0ac7aa593d1ea6a966f5ce92c09b..6097328d6e5cc3b8afea9cd1f18a3ef8d9b3466f 100644 --- a/reco/L1/L1LinkDef.h +++ b/reco/L1/L1LinkDef.h @@ -34,6 +34,7 @@ #pragma link C++ class CbmCaInputQaSts + ; #pragma link C++ class CbmCaInputQaTrd + ; #pragma link C++ class CbmCaInputQaTof + ; +#pragma link C++ class cbm::ca::OutputQa + ; #pragma link C++ class ca::tools::WindowFinder + ; #endif diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2f6713f24d23994653380230f880a389493427ec --- /dev/null +++ b/reco/L1/qa/CbmCaOutputQa.cxx @@ -0,0 +1,65 @@ +/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file CbmCaOutputQa.cxx +/// @brief Tracking output QA-task (implementation) +/// @since 24.02.2023 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#include "CbmCaOutputQa.h" + +#include "Logger.h" + +using ca::tools::Debugger; +using cbm::ca::OutputQa; + +// --------------------------------------------------------------------------------------------------------------------- +// +OutputQa::OutputQa(int verbose, bool isMCUsed) : CbmQaTask("CbmCaOutputQa", "caout", verbose, isMCUsed) {} + +// --------------------------------------------------------------------------------------------------------------------- +// +void OutputQa::EnableDebugger(const char* filename) +{ + if (!fpDebugger.get()) { fpDebugger = std::make_shared<Debugger>(filename); } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +InitStatus OutputQa::InitDataBranches() +{ + LOG(info) << fName << ": Initializing data branches"; + + if (!fpTSReader.get()) { fpTSReader = std::make_unique<TimeSliceReader>(fTrackingMode); } + + if (!fpDataManager.get()) { fpDataManager = std::make_shared<L1IODataManager>(); } + + // Initialize time slice reader instance + fpTSReader->SetDetector(L1DetectorID::kMvd, fbUseMvd); + fpTSReader->SetDetector(L1DetectorID::kSts, fbUseSts); + fpTSReader->SetDetector(L1DetectorID::kMuch, fbUseMuch); + fpTSReader->SetDetector(L1DetectorID::kTrd, fbUseTrd); + fpTSReader->SetDetector(L1DetectorID::kTof, fbUseTof); + + fpTSReader->RegisterIODataManager(fpDataManager); + fpTSReader->RegisterTracksContainer(fvRecoTracks); + fpTSReader->RegisterHitDebugInfoContainer(fvDbgHits); + fpTSReader->RegisterHitIndexContainer(fvHitIds); + + fpTSReader->InitRun(); + return kSUCCESS; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +InitStatus OutputQa::InitTimeSlice() +{ + // Read hits + fpTSReader->ReadHits(); + + // Read reconstructed tracks + fpTSReader->ReadRecoTracks(); + + return kSUCCESS; +} diff --git a/reco/L1/qa/CbmCaOutputQa.h b/reco/L1/qa/CbmCaOutputQa.h new file mode 100644 index 0000000000000000000000000000000000000000..6a0c6f01b321b91eacf49869b62a6af199f5bfa3 --- /dev/null +++ b/reco/L1/qa/CbmCaOutputQa.h @@ -0,0 +1,111 @@ +/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file CbmCaOutputQa.h +/// @brief Tracking output QA-task (header) +/// @since 24.02.2023 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#ifndef CbmCaOutputQa_h +#define CbmCaOutputQa_h 1 + +#include "CbmCaTimeSliceReader.h" +#include "CbmL1DetectorID.h" +#include "CbmQaTask.h" + +#include "CaToolsDebugger.h" + +namespace cbm::ca +{ + /// @brief QA-task for CA tracking output results + /// + class OutputQa : public CbmQaTask { + public: + /// @brief Constructor from parameters + /// @param verbose Verbosity level + /// @param isMCUsed Flag, if MC information is available for this task + OutputQa(int verbose, bool isMCUsed); + + /// @brief Sets MVD use flag + /// @param flag Boolean flag: true - detector subsystem is used, false - detector subsystem is ignored + void SetUseMvd(bool flag = true) { fbUseMvd = flag; } + + /// @brief Sets STS use flag + /// @param flag Boolean flag: true - detector subsystem is used, false - detector subsystem is ignored + void SetUseSts(bool flag = true) { fbUseSts = flag; } + + /// @brief Sets MuCh use flag + /// @param flag Boolean flag: true - detector subsystem is used, false - detector subsystem is ignored + void SetUseMuch(bool flag = true) { fbUseMuch = flag; } + + /// @brief Sets TRD use flag + /// @param flag Boolean flag: true - detector subsystem is used, false - detector subsystem is ignored + void SetUseTrd(bool flag = true) { fbUseTrd = flag; } + + /// @brief Sets TOF use flag + /// @param flag Boolean flag: true - detector subsystem is used, false - detector subsystem is ignored + void SetUseTof(bool flag = true) { fbUseTof = flag; } + + /// @brief Sets STS tracking mode + void SetStsTrackingMode() { fTrackingMode = ECbmTrackingMode::kSTS; } + + /// @brief Sets mCBM global tracking mode + void SetMcbmTrackingMode() { fTrackingMode = ECbmTrackingMode::kMCBM; } + + /// @brief Enables debugger + /// @param filename Name of output ROOT file + /// + /// Creates a debugger and enables its usage inside a QA task + void EnableDebugger(const char* filename); + + + ClassDef(OutputQa, 0); + + protected: + /// @brief Checks results of the QA and returns a success flag + /// @return true QA is passed + /// @return false QA is failed + bool Check() { return true; } + + /// @brief Initializes canvases + InitStatus InitCanvases() { return kSUCCESS; } + + /// @brief Initialises data branches in the beginning of the run + InitStatus InitDataBranches(); + + /// @brief Initializes histograms + InitStatus InitHistograms() { return kSUCCESS; } + + /// @brief Initializes time slice + /// @note Is called in the FairTask::Exec function + InitStatus InitTimeSlice(); + + /// @brief Fills histograms + void FillHistograms() {} + + /// @brief De-initializes histograms + void DeInit() {} + + private: + // Flags for detector subsystems being used + bool fbUseMvd = false; ///< is MVD used + bool fbUseSts = false; ///< is STS used + bool fbUseMuch = false; ///< is MuCh used + bool fbUseTrd = false; ///< is TRD used + bool fbUseTof = false; ///< is TOF used + + ECbmTrackingMode fTrackingMode = ECbmTrackingMode::kSTS; ///< Tracking mode + + std::unique_ptr<TimeSliceReader> fpTSReader = nullptr; ///< Reader of the time slice + std::shared_ptr<L1IODataManager> fpDataManager = nullptr; ///< Data manager + std::shared_ptr<::ca::tools::Debugger> fpDebugger = nullptr; ///< Debugger + + L1Vector<CbmL1HitId> fvHitIds {"CbmCaOutputQa::fvHitIds"}; + L1Vector<CbmL1HitDebugInfo> fvDbgHits {"CbmCaOutputQa::fvDbgHits"}; + L1Vector<CbmL1Track> fvRecoTracks {"CbmCaOutputQa::fvRecoTracks"}; + }; +} // namespace cbm::ca + + +#endif // CbmCaOutputQa_h