From 3bdd9fbe56191c0e708206310ff1052b989e0e19 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Wed, 9 Nov 2022 20:27:24 +0100 Subject: [PATCH] L1: estimated search windows are introduced to tracking --- macro/run/run_reco.C | 3 +- reco/L1/CMakeLists.txt | 2 + reco/L1/CbmL1.cxx | 25 +- reco/L1/CbmL1.h | 25 +- reco/L1/CbmL1MCTrack.cxx | 4 +- reco/L1/CbmL1MCTrack.h | 34 +-- reco/L1/CbmL1Performance.cxx | 89 ++++-- reco/L1/CbmL1ReadEvent.cxx | 5 +- reco/L1/L1Algo/L1Constants.h | 4 + reco/L1/L1Algo/L1InitManager.cxx | 42 +++ reco/L1/L1Algo/L1InitManager.h | 18 +- reco/L1/L1Algo/L1Parameters.cxx | 3 + reco/L1/L1Algo/L1Parameters.cxx.orig | 360 ++++++++++++++++++++++++ reco/L1/L1Algo/L1Parameters.h | 30 +- reco/L1/L1Algo/L1SearchWindow.cxx | 112 ++++++++ reco/L1/L1Algo/L1SearchWindow.h | 167 +++++++++++ reco/L1/L1LinkDef.h | 1 + reco/L1/catools/CaToolsWindowFinder.cxx | 84 ++++++ reco/L1/catools/CaToolsWindowFinder.h | 106 +++++++ 19 files changed, 1047 insertions(+), 67 deletions(-) create mode 100644 reco/L1/L1Algo/L1Parameters.cxx.orig create mode 100644 reco/L1/L1Algo/L1SearchWindow.cxx create mode 100644 reco/L1/L1Algo/L1SearchWindow.h create mode 100644 reco/L1/catools/CaToolsWindowFinder.cxx create mode 100644 reco/L1/catools/CaToolsWindowFinder.h diff --git a/macro/run/run_reco.C b/macro/run/run_reco.C index 5c3a90adc3..2ed01f00b1 100644 --- a/macro/run/run_reco.C +++ b/macro/run/run_reco.C @@ -383,7 +383,8 @@ void run_reco(TString input = "", Int_t nTimeSlices = -1, Int_t firstTimeSlice = auto l1 = (debugWithMC) ? new CbmL1("L1", 2, 3, 0) : new CbmL1("L1", 0); // L1 configuration file (optional) //l1->SetInputConfigName(TString(gSystem->Getenv("VMCWORKDIR")) + "/reco/L1/L1Algo/L1ConfigExample.yaml"); - if (debugWithMC) { l1->SetOutputMcTracksNtupleFilename("mcTracksNtuple"); } + // Define filename to save MC triplets + //if (debugWithMC) { l1->SetOutputMcTripletsTreeFilename("mcTripletsTree"); } // --- Material budget file names TString mvdGeoTag; diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt index b4e445b438..3f45f45072 100644 --- a/reco/L1/CMakeLists.txt +++ b/reco/L1/CMakeLists.txt @@ -71,6 +71,7 @@ set(SRCS catools/CaToolsMcDataManager.cxx catools/CaToolsPerformance.cxx catools/CaToolsDebugger.cxx + catools/CaToolsWindowFinder.cxx ParticleFinder/CbmL1PFFitter.cxx ParticleFinder/CbmL1PFMCParticle.cxx @@ -94,6 +95,7 @@ set(HEADERS CbmL1Vtx.h L1Algo/L1Def.h L1Algo/L1Vector.h + catools/CaToolsWindowFinder.h ) diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx index ca0d359f2e..2cc894d87b 100644 --- a/reco/L1/CbmL1.cxx +++ b/reco/L1/CbmL1.cxx @@ -825,6 +825,19 @@ InitStatus CbmL1::Init() //fInitManager.PushBackCAIteration(trackingIterAllSecJump); } + // ******************************* + // ** Initialize search windows ** + // ******************************* + + if (fsInputSearchWindowsFilename.size()) { + fInitManager.DevSetIsParSearchWUsed(); + fInitManager.ReadSearchWindows(fsInputSearchWindowsFilename); + } + else { + fInitManager.DevSetIsParSearchWUsed(false); + } + + // ********************** // ** Set special cuts ** // ********************** @@ -1181,7 +1194,7 @@ void CbmL1::Reconstruct(CbmEvent* event) EfficienciesPerformance(); HistoPerformance(); TrackFitPerformance(); - if (fsMcTracksOutputFilename.size()) { DumpMCTracksToNtuple(); } + if (fsMcTripletsOutputFilename.size()) { DumpMCTripletsToTree(); } // TimeHist(); /// WriteSIMDKFData(); } @@ -1230,11 +1243,11 @@ void CbmL1::Finish() outfile->Delete(); } - if (fpMcTracksOutFile) { - fpMcTracksOutFile->cd(); - fpMcTracksTree->Write(); - fpMcTracksOutFile->Close(); - fpMcTracksOutFile->Delete(); + if (fpMcTripletsOutFile) { + fpMcTripletsOutFile->cd(); + fpMcTripletsTree->Write(); + fpMcTripletsOutFile->Close(); + fpMcTripletsOutFile->Delete(); } gFile = currentFile; diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h index f3b5edc187..8219400432 100644 --- a/reco/L1/CbmL1.h +++ b/reco/L1/CbmL1.h @@ -263,14 +263,20 @@ public: /// \param filename Name of the input tracking configuration file void SetInputConfigName(const char* filename); + /// \brief Sets a name for the input search window file + /// If the filename is not defined, a default track finder with Kalman filter is used. Otherwise, an experimental + /// version of track finder with estimated hit search windows is utilised + /// \param filename Name of the input search window file + void SetInputSearchWindowFilename(const char* filename) { fsInputSearchWindowsFilename = filename; } + /// \brief Sets a name for the output configuration file /// \param filename Name of the input tracking configuration file void SetOutputConfigName(const char* filename) { fInitManager.SetOutputConfigName(std::string(filename)); } - /// \brief Sets output file for MC tracks ntuple - /// If the filename is empty string, ntuple is not filled + /// \brief Sets output file for MC triplets tree + /// If the filename is empty string, tree is not filled /// \param filename Name of the output file name - void SetOutputMcTracksNtupleFilename(const char* filename) { fsMcTracksOutputFilename = std::string(filename); } + void SetOutputMcTripletsTreeFilename(const char* filename) { fsMcTripletsOutputFilename = std::string(filename); } /// Sets flag: to correct input hits on MC or not /// \param flag: true - hits will be corrected on MC information @@ -424,9 +430,9 @@ private: /// Fills performance histograms void HistoPerformance(); - /// Writes MC tracks to ntuple + /// Writes MC triplets to tree /// \note Executed only if the filename for MC tracks ntuple output is defined - void DumpMCTracksToNtuple(); + void DumpMCTripletsToTree(); // ** STandAlone Package service-functions ** @@ -471,7 +477,8 @@ private: static void writedir2current(TObject* obj); // help procedure private: - std::string fInputDataFilename = ""; ///< File name to read/write input hits + std::string fInputDataFilename = ""; ///< File name to read/write input hits + std::string fsInputSearchWindowsFilename = ""; ///< File name to read search windows // *************************** // ** Member variables list ** @@ -660,9 +667,9 @@ private: static const int fNGhostHistos = 9; TH1F* fGhostHisto[fNGhostHistos] {nullptr}; - TFile* fpMcTracksOutFile = nullptr; ///< File to save MC-tracks ntuple - TNtuple* fpMcTracksTree = nullptr; ///< Ntuple to save MC-tracks - std::string fsMcTracksOutputFilename = ""; ///< Name of file to save MC-tracks ntuple + TFile* fpMcTripletsOutFile = nullptr; ///< File to save MC-triplets tree + TTree* fpMcTripletsTree = nullptr; ///< Tree to save MC-triplets + std::string fsMcTripletsOutputFilename = ""; ///< Name of file to save MC-triplets tree int fFindParticlesMode {0}; // 0 - don't run FindParticles // 1 - run, all MC particle is reco-able diff --git a/reco/L1/CbmL1MCTrack.cxx b/reco/L1/CbmL1MCTrack.cxx index 46e57059b3..00c6385bae 100644 --- a/reco/L1/CbmL1MCTrack.cxx +++ b/reco/L1/CbmL1MCTrack.cxx @@ -26,7 +26,8 @@ #include "L1Algo/L1Algo.h" #include "L1Algo/L1Hit.h" -CbmL1MCTrack::CbmL1MCTrack(double mass_, double q_, TVector3 vr, TLorentzVector vp, int _ID, int _mother_ID, int _pdg) +CbmL1MCTrack::CbmL1MCTrack(double mass_, double q_, TVector3 vr, TLorentzVector vp, int _ID, int _mother_ID, int _pdg, + unsigned int _process_ID) : mass(mass_) , q(q_) , p(vp.P()) @@ -39,6 +40,7 @@ CbmL1MCTrack::CbmL1MCTrack(double mass_, double q_, TVector3 vr, TLorentzVector , ID(_ID) , mother_ID(_mother_ID) , pdg(_pdg) + , process_ID(_process_ID) { } diff --git a/reco/L1/CbmL1MCTrack.h b/reco/L1/CbmL1MCTrack.h index 59c820b832..007b07bbd3 100644 --- a/reco/L1/CbmL1MCTrack.h +++ b/reco/L1/CbmL1MCTrack.h @@ -38,7 +38,8 @@ public: CbmL1MCTrack(int _ID) : ID(_ID) {}; - CbmL1MCTrack(double mass, double q, TVector3 vr, TLorentzVector vp, int ID, int mother_ID, int pdg); + CbmL1MCTrack(double mass, double q, TVector3 vr, TLorentzVector vp, int ID, int mother_ID, int pdg, + unsigned int procID); // CbmL1MCTrack(TmpMCPoints &mcPoint, TVector3 vr, TLorentzVector vp, int ID, int mother_ID); bool IsPrimary() const { return mother_ID < 0; } @@ -72,21 +73,22 @@ private: void CalculateIsReconstructable(); public: - double mass = 0.; - double q = 0.; - double p = 0.; - double x = 0.; - double y = 0.; - double z = 0.; - double px = 0.; - double py = 0.; - double pz = 0.; - double time = 0.; - int ID = -1; - int iFile = -1; - int iEvent = -1; - int mother_ID = -1; - int pdg = -1; + double mass = 0.; + double q = 0.; + double p = 0.; + double x = 0.; + double y = 0.; + double z = 0.; + double px = 0.; + double py = 0.; + double pz = 0.; + double time = 0.; + int ID = -1; + int iFile = -1; + int iEvent = -1; + int mother_ID = -1; + int pdg = -1; + unsigned int process_ID = (unsigned int) -1; bool isSignal {0}; L1Vector<int> Points {"CbmL1MCTrack::Points"}; // indices of pints in CbmL1::fvMCPoints L1Vector<int> Hits {"CbmL1MCTrack::Hits"}; // indices of hits in algo->vHits or L1::vHits diff --git a/reco/L1/CbmL1Performance.cxx b/reco/L1/CbmL1Performance.cxx index 3bfd392054..99d15a41f4 100644 --- a/reco/L1/CbmL1Performance.cxx +++ b/reco/L1/CbmL1Performance.cxx @@ -2251,9 +2251,9 @@ void CbmL1::InputPerformance() // --------------------------------------------------------------------------------------------------------------------- // -void CbmL1::DumpMCTracksToNtuple() +void CbmL1::DumpMCTripletsToTree() { - if (!fpMcTracksTree) { + if (!fpMcTripletsTree) { auto* currentDir = gDirectory; auto* currentFile = gFile; @@ -2262,16 +2262,16 @@ void CbmL1::DumpMCTracksToNtuple() boost::filesystem::path p = (FairRunAna::Instance()->GetUserOutputFileName()).Data(); std::string dir = p.parent_path().string(); if (dir.empty()) dir = "."; - std::string filename = dir + "/" + fsMcTracksOutputFilename + "." + p.filename().string(); + std::string filename = dir + "/" + fsMcTripletsOutputFilename + "." + p.filename().string(); std::cout << "\033[1;31mSAVING A TREE: " << filename << "\033[0m\n"; - fpMcTracksOutFile = new TFile(filename.c_str(), "RECREATE"); - fpMcTracksOutFile->cd(); - fpMcTracksTree = new TNtuple("t", "McTracks", "motherId:pdg:p:q:zv:s:x0:y0:z0:x1:y1:z1:x2:y2:z2"); - // motherID - id of mother particle (< 0, if primary) + fpMcTripletsOutFile = new TFile(filename.c_str(), "RECREATE"); + fpMcTripletsOutFile->cd(); + fpMcTripletsTree = new TTree("t", "MC Triplets"); + // motherId - id of mother particle (< 0, if primary) // pdg - PDG code of particle - // p - absolute value of track momentum [GeV/c] - // q - charge of track [e] + // processId - id of the process (ROOT::TMCProcessID) + // pq - absolute value of track momentum [GeV/c], divided by charge [e] // zv - z-component of track vertex [cm] // s - global index of station // x0, y0, z0 - position of the left MC point in a triplet [cm] @@ -2282,6 +2282,43 @@ void CbmL1::DumpMCTracksToNtuple() gDirectory = currentDir; } + // Variables for tree branches + int brMotherId = -1; ///< mother ID of track + int brPdg = -1; ///< PDG code of track + unsigned int brProcId = (unsigned int) -1; ///< process ID (see ROOT::TMCProcessID) + float brP = 0.f; ///< abs. momentum of track [GeV/c] + int brQ = 0; ///< charge of track [e] + float brVertexZ = 0.f; ///< z-component of the MC track vertex [cm] + int brStation = -1; ///< global index of the left MC point station + + float brX0 = 0.f; ///< x-component of the left MC point in a triplet [cm] + float brY0 = 0.f; ///< y-component of the left MC point in a triplet [cm] + float brZ0 = 0.f; ///< z-component of the left MC point in a triplet [cm] + float brX1 = 0.f; ///< x-component of the middle MC point in a triplet [cm] + float brY1 = 0.f; ///< y-component of the middle MC point in a triplet [cm] + float brZ1 = 0.f; ///< z-component of the middle MC point in a triplet [cm] + float brX2 = 0.f; ///< x-component of the right MC point in a triplet [cm] + float brY2 = 0.f; ///< y-component of the right MC point in a triplet [cm] + float brZ2 = 0.f; ///< z-component of the right MC point in a triplet [cm] + + // Register branches + fpMcTripletsTree->Branch("brMotherId", &brMotherId, "motherId/I"); + fpMcTripletsTree->Branch("brPdg", &brPdg, "pdg/I"); + fpMcTripletsTree->Branch("brProcId", &brProcId, "processId/i"); + fpMcTripletsTree->Branch("brP", &brP, "p/F"); + fpMcTripletsTree->Branch("brQ", &brQ, "q/I"); + fpMcTripletsTree->Branch("brVertexZ", &brVertexZ, "zv/F"); + fpMcTripletsTree->Branch("brStation", &brStation, "s/I"); + fpMcTripletsTree->Branch("brX0", &brX0, "x0/F"); + fpMcTripletsTree->Branch("brY0", &brY0, "y0/F"); + fpMcTripletsTree->Branch("brZ0", &brZ0, "z0/F"); + fpMcTripletsTree->Branch("brX1", &brX1, "x1/F"); + fpMcTripletsTree->Branch("brY1", &brY1, "y1/F"); + fpMcTripletsTree->Branch("brZ1", &brZ1, "z1/F"); + fpMcTripletsTree->Branch("brX2", &brX2, "x2/F"); + fpMcTripletsTree->Branch("brY2", &brY2, "y2/F"); + fpMcTripletsTree->Branch("brZ2", &brZ2, "z2/F"); + struct ReducedMcPoint { int s; ///< global active index of tracking station float x; ///< x-component of point position [cm] @@ -2306,21 +2343,25 @@ void CbmL1::DumpMCTracksToNtuple() // Condition to collect only triplets without gaps in stations // TODO: SZh 20.10.2022 Add cases for jump iterations if (vPoints[i + 1].s == vPoints[i].s + 1 && vPoints[i + 2].s == vPoints[i].s + 2) { - fpMcTracksTree->Fill(tr.mother_ID, ///< index of mother particle - tr.pdg, ///< PDG code - tr.p, ///< absolute value of track momentum [GeV/c] - tr.q, ///< charge of track [e] - tr.z, ///< z-position of track vertex [cm] - vPoints[i].s, ///< global index of active tracking station - vPoints[i].x, ///< x-component of the left MC point in a triplet [cm] - vPoints[i].y, ///< y-component of the left MC point in a triplet [cm] - vPoints[i].z, ///< z-component of the left MC point in a triplet [cm] - vPoints[i + 1].x, ///< x-component of the middle MC point in a triplet [cm] - vPoints[i + 1].y, ///< y-component of the middle MC point in a triplet [cm] - vPoints[i + 1].z, ///< z-component of the middle MC point in a triplet [cm] - vPoints[i + 2].x, ///< x-component of the right MC point in a triplet [cm] - vPoints[i + 2].y, ///< y-component of the right MC point in a triplet [cm] - vPoints[i + 2].z); ///< z-component of the right MC point in a triplet [cm] + // Fill MC-triplets tree + brMotherId = tr.mother_ID; + brPdg = tr.pdg; + brProcId = tr.process_ID; + brP = tr.p; + brQ = tr.q; + brVertexZ = tr.z; + brStation = vPoints[i].s; + brX0 = vPoints[i].x; + brY0 = vPoints[i].y; + brZ0 = vPoints[i].z; + brX1 = vPoints[i + 1].x; + brY1 = vPoints[i + 1].y; + brZ1 = vPoints[i + 1].z; + brX2 = vPoints[i + 2].x; + brY2 = vPoints[i + 2].y; + brZ2 = vPoints[i + 2].z; + + fpMcTripletsTree->Fill(); } } } diff --git a/reco/L1/CbmL1ReadEvent.cxx b/reco/L1/CbmL1ReadEvent.cxx index 5ac7aac611..c77594bf4d 100644 --- a/reco/L1/CbmL1ReadEvent.cxx +++ b/reco/L1/CbmL1ReadEvent.cxx @@ -1368,7 +1368,8 @@ void CbmL1::Fill_vMCTracks() TLorentzVector vp; MCTrack->GetStartVertex(vr); MCTrack->Get4Momentum(vp); - Int_t pdg = MCTrack->GetPdgCode(); + Int_t pdg = MCTrack->GetPdgCode(); + unsigned int processID = MCTrack->GetGeantProcessId(); Double_t q = 0, mass = 0.; if (pdg < 9999999 && ((TParticlePDG*) TDatabasePDG::Instance()->GetParticle(pdg))) { q = TDatabasePDG::Instance()->GetParticle(pdg)->Charge() / 3.0; @@ -1379,7 +1380,7 @@ void CbmL1::Fill_vMCTracks() //cout << "mc track " << iMCTrack << " pdg " << pdg << " z " << vr.Z() << endl; Int_t iTrack = fvMCTracks.size(); //or iMCTrack? - CbmL1MCTrack T(mass, q, vr, vp, iTrack, mother_ID, pdg); + CbmL1MCTrack T(mass, q, vr, vp, iTrack, mother_ID, pdg, processID); // CbmL1MCTrack T(mass, q, vr, vp, iMCTrack, mother_ID, pdg); T.time = MCTrack->GetStartT(); T.iFile = iFile; diff --git a/reco/L1/L1Algo/L1Constants.h b/reco/L1/L1Algo/L1Constants.h index 77d3a4c03c..6d8e3cbeed 100644 --- a/reco/L1/L1Algo/L1Constants.h +++ b/reco/L1/L1Algo/L1Constants.h @@ -37,6 +37,10 @@ namespace L1Constants constexpr int kMaxNthreads = 1u << kThreadBits; ///< Max number of threads, 2^6 = 64 constexpr int kMaxNtriplets = 1u << kTripletBits; ///< Max number of triplets, 2^20 = 1,048,576 + /// Max number of track groups + /// NOTE: For a "track group" definition see L1Parameters.h, GetSearchWindow function + constexpr int kMaxNtrackGroups = 4; + // TODO: Clarify the meaning of these coefficients constexpr int kCoeff = 64 / 4; ///< TODO: constexpr int kSingletPortionSize = 1024 / kCoeff; ///< portion of left hits diff --git a/reco/L1/L1Algo/L1InitManager.cxx b/reco/L1/L1Algo/L1InitManager.cxx index bd84d8effe..9da08993de 100644 --- a/reco/L1/L1Algo/L1InitManager.cxx +++ b/reco/L1/L1Algo/L1InitManager.cxx @@ -164,6 +164,8 @@ bool L1InitManager::FormParametersContainer() } } + if (!fParameters.fDevIsParSearchWUsed) { fInitController.SetFlag(EInitKey::kSearchWindows, true); } + // Check initialization this->CheckInit(); @@ -272,6 +274,46 @@ void L1InitManager::ReadParametersObject(const std::string& fileName) } } +// --------------------------------------------------------------------------------------------------------------------- +// +void L1InitManager::ReadSearchWindows(const std::string& fileName) +{ + // Open input binary file + std::ifstream ifs(fileName, std::ios::binary); + if (!ifs) { LOG(fatal) << "L1InitManager: search window file \"" << fileName << "\" was not found"; } + + try { + boost::archive::binary_iarchive ia(ifs); + int nWindows = -1; + ia >> nWindows; + std::stringstream errMsg; + for (int iW = 0; iW < nWindows; ++iW) { + L1SearchWindow swBuffer; + ia >> swBuffer; + int iStationID = swBuffer.GetStationID(); + int iTrackGrID = swBuffer.GetTrackGroupID(); + if (iStationID < 0 || iStationID > L1Constants::size::kMaxNstations) { + errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and " + << L1Constants::size::kMaxNstations << ")\n"; + } + if (iTrackGrID < 0 || iTrackGrID > L1Constants::size::kMaxNtrackGroups) { + errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and " + << L1Constants::size::kMaxNtrackGroups << ")\n"; + } + fParameters.fSearchWindows[iTrackGrID * L1Constants::size::kMaxNstations + iStationID] = swBuffer; + } + if (errMsg.str().size()) { + LOG(fatal) << "L1InitManager: some errors occurred while reading search windows: " << errMsg.str(); + } + } + catch (const std::exception&) { + LOG(fatal) << "L1InitManager: search windows file \"" << fileName + << "\" has incorrect data format or was corrupted"; + } + + fInitController.SetFlag(EInitKey::kSearchWindows, true); +} + // --------------------------------------------------------------------------------------------------------------------- // bool L1InitManager::SendParameters(L1Algo* pAlgo) diff --git a/reco/L1/L1Algo/L1InitManager.h b/reco/L1/L1Algo/L1InitManager.h index 35eeb04f17..796877548c 100644 --- a/reco/L1/L1Algo/L1InitManager.h +++ b/reco/L1/L1Algo/L1InitManager.h @@ -83,10 +83,11 @@ private: kStationsInfo, ///< 5) If all the planned stations were added to the manager kCAIterationsNumberCrosscheck, ///< 6) If the number of CA track finder is initialized kCAIterations, ///< 7) If the CA track finder iterations were initialized - kTrackingLevel, ///< 8) - kGhostSuppression, ///< 9) - kMomentumCutOff, ///< 10) - kEnd ///< 11) [technical] number of entries in the enumeration + kSearchWindows, ///< 8) If the hit search windows were initialized + kTrackingLevel, ///< 9) + kGhostSuppression, ///< 10) + kMomentumCutOff, ///< 11) + kEnd ///< 12) [technical] number of entries in the enumeration }; using L1DetectorIDIntMap_t = std::unordered_map<L1DetectorID, int, L1Utils::EnumClassHash>; @@ -193,6 +194,10 @@ public: /// \param fileName Name of input file void ReadParametersObject(const std::string& fileName); + /// Reads search windows from file + /// \param fileName Name of input file + void ReadSearchWindows(const std::string& fileName); + /// Sets a set of active tracking detector IDs void SetActiveDetectorIDs(const L1DetectorIDSet_t& detectorIDs); @@ -261,6 +266,11 @@ public: /// Flag to match triplets using Mc information void DevSetIsMatchTripletsViaMc(bool value = true) { fParameters.fDevIsMatchTripletsViaMc = value; } + /// Flag to use estimated hit search windows + /// true: estimated search windows will be used in track finder + /// false: Kalman filter will be used in track finder + void DevSetIsParSearchWUsed(bool value = true) { fParameters.fDevIsParSearchWUsed = value; } + private: // ********************* // ** Private methods ** diff --git a/reco/L1/L1Algo/L1Parameters.cxx b/reco/L1/L1Algo/L1Parameters.cxx index d2c190ee76..876a9bc5da 100644 --- a/reco/L1/L1Algo/L1Parameters.cxx +++ b/reco/L1/L1Algo/L1Parameters.cxx @@ -278,6 +278,9 @@ std::string L1Parameters::ToString(int verbosity, int indentLevel) const aStream << indent << indentChar << "Non-approx. field is used: " << fDevIsMatchDoubletsViaMc << '\n'; aStream << indent << indentChar << "Doublets vs. MC matching: " << fDevIsMatchDoubletsViaMc << '\n'; aStream << indent << indentChar << "Triplets vs. MC matching: " << fDevIsMatchTripletsViaMc << '\n'; + aStream << indent << indentChar << "Use hit search windows: " << fDevIsParSearchWUsed << '\n'; + // TODO: SZh 09.11.2022: Print search windows here + aStream << indent << "--------------------------------------------------------------------------------------------------\n"; return aStream.str(); diff --git a/reco/L1/L1Algo/L1Parameters.cxx.orig b/reco/L1/L1Algo/L1Parameters.cxx.orig new file mode 100644 index 0000000000..768656ee98 --- /dev/null +++ b/reco/L1/L1Algo/L1Parameters.cxx.orig @@ -0,0 +1,360 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +/// @file L1Parameters.cxx +/// @brief Parameter container for the L1Algo library +/// @since 10.02.2022 +/// @author S.Zharko <s.zharko@gsi.de> + +#include "L1Parameters.h" + +#include <FairLogger.h> + +#include <iomanip> + +//---------------------------------------------------------------------------------------------------------------------- +// +L1Parameters::L1Parameters() +{ + fActiveStationGlobalIDs.fill(-1); // by default, all stations are inactive, thus all the IDs must be -1 +} + +//---------------------------------------------------------------------------------------------------------------------- +// +<<<<<<< HEAD +L1Parameters::~L1Parameters() noexcept {} + +//---------------------------------------------------------------------------------------------------------------------- +// +L1Parameters::L1Parameters(const L1Parameters& other) noexcept + : fMaxDoubletsPerSinglet(other.fMaxDoubletsPerSinglet) + , fMaxTripletPerDoublets(other.fMaxTripletPerDoublets) + , fCAIterations(other.fCAIterations) + , fTargetPos(other.fTargetPos) + , fVertexFieldValue(other.fVertexFieldValue) + , fVertexFieldRegion(other.fVertexFieldRegion) + , fStations(other.fStations) + , fThickMap(other.fThickMap) + , fNstationsGeometryTotal(other.fNstationsGeometryTotal) + , fNstationsActiveTotal(other.fNstationsActiveTotal) + , fNstationsGeometry(other.fNstationsGeometry) + , fNstationsActive(other.fNstationsActive) + , fActiveStationGlobalIDs(other.fActiveStationGlobalIDs) + , fTrackingLevel(other.fTrackingLevel) + , fGhostSuppression(other.fGhostSuppression) + , fMomentumCutOff(other.fMomentumCutOff) + , fDevIsIgnoreHitSearchAreas(other.fDevIsIgnoreHitSearchAreas) + , fDevIsUseOfOriginalField(other.fDevIsUseOfOriginalField) + , fDevIsMatchDoubletsViaMc(other.fDevIsMatchDoubletsViaMc) + , fDevIsMatchTripletsViaMc(other.fDevIsMatchTripletsViaMc) +{ +} + +//---------------------------------------------------------------------------------------------------------------------- +// +L1Parameters& L1Parameters::operator=(const L1Parameters& other) noexcept +{ + if (this != &other) { L1Parameters(other).Swap(*this); } + return *this; +} + +//---------------------------------------------------------------------------------------------------------------------- +// +L1Parameters::L1Parameters(L1Parameters&& other) noexcept { this->Swap(other); } + +//---------------------------------------------------------------------------------------------------------------------- +// +L1Parameters& L1Parameters::operator=(L1Parameters&& other) noexcept +{ + if (this != &other) { + L1Parameters tmp(std::move(other)); + this->Swap(tmp); + } + return *this; +} + +//---------------------------------------------------------------------------------------------------------------------- +// +void L1Parameters::Swap(L1Parameters& other) noexcept +{ + std::swap(fMaxDoubletsPerSinglet, other.fMaxDoubletsPerSinglet); + std::swap(fMaxTripletPerDoublets, other.fMaxTripletPerDoublets); + std::swap(fCAIterations, other.fCAIterations); + std::swap(fTargetPos, other.fTargetPos); + std::swap(fVertexFieldValue, other.fVertexFieldValue); + std::swap(fVertexFieldRegion, other.fVertexFieldRegion); + std::swap(fStations, other.fStations); + std::swap(fThickMap, other.fThickMap); + std::swap(fNstationsGeometryTotal, other.fNstationsGeometryTotal); + std::swap(fNstationsActiveTotal, other.fNstationsActiveTotal); + std::swap(fNstationsGeometry, other.fNstationsGeometry); + std::swap(fNstationsActive, other.fNstationsActive); + std::swap(fActiveStationGlobalIDs, other.fActiveStationGlobalIDs); + std::swap(fTrackingLevel, other.fTrackingLevel); + std::swap(fGhostSuppression, other.fGhostSuppression); + std::swap(fMomentumCutOff, other.fMomentumCutOff); + std::swap(fDevIsIgnoreHitSearchAreas, other.fDevIsIgnoreHitSearchAreas); + std::swap(fDevIsUseOfOriginalField, other.fDevIsUseOfOriginalField); + std::swap(fDevIsMatchDoubletsViaMc, other.fDevIsMatchDoubletsViaMc); + std::swap(fDevIsMatchTripletsViaMc, other.fDevIsMatchTripletsViaMc); +} + +//---------------------------------------------------------------------------------------------------------------------- +// +======= +>>>>>>> L1: explicit implementation of copy and move constructors and assignment operators were replaced with default for L1Parameters and L1CAIteration classes +void L1Parameters::CheckConsistency() const +{ + LOG(info) << "Consistency test for L1 parameters object... "; + /* + * Arrays containing numbers of stations + * + * In the fNstationsActive and fNstationsGeometry array first L1Constants::size::kMaxNdetectors elements are the numbers of stations + * in particular detector subsystem. The last element in both arrays corresponds to the total number of stations (geometry or + * active). This fact applies restriction on the arrays: the last element must be equal to the sum of all previous elements. + * + */ + + if (std::accumulate(fNstationsGeometry.cbegin(), fNstationsGeometry.cend(), 0) != fNstationsGeometryTotal) { + throw std::logic_error("L1Parameters: invalid object condition: total number of stations provided by geometry " + "differs from the sum of the station numbers for individual detector subsystems"); + }; + + if (std::accumulate(fNstationsActive.cbegin(), fNstationsActive.cend(), 0) != fNstationsActiveTotal) { + throw std::logic_error("L1Parameters: invalid object condition: total number of stations active in tracking " + "differs from the sum of the station numbers for individual detector subsystems"); + }; + + /* + * Array of active station IDs + * + * In the array of active station IDs, + * (i) sum of elements, which are not equal -1, must be equal the number of stations, + * (ii) subsequence of all the elements, which are not equal -1, must be a gapless subset of integer numbers starting with 0 + */ + + auto filterInactiveStationIDs = [](int x) { return x != -1; }; + int nStationsCheck = + std::count_if(fActiveStationGlobalIDs.cbegin(), fActiveStationGlobalIDs.cend(), filterInactiveStationIDs); + if (nStationsCheck != fNstationsActiveTotal) { + std::stringstream msg; + msg << "L1Parameters: invalid object condition: array of active station IDs is not consistent " + << "with the total number of stations (" << nStationsCheck << " vs. " << fNstationsActiveTotal << ' ' + << "expected)"; + throw std::logic_error(msg.str()); + } + + // Check, if the subsequence of all the elements, which are not equal -1, must be a gapless subset of integer numbers + // starting from 0. If it is, the testValue in the end must be equal the number of non -1 elements + + std::vector<int> idsCheck( + nStationsCheck); // temporary vector containing a sequence of active station IDs without -1 elements + std::copy_if(fActiveStationGlobalIDs.cbegin(), fActiveStationGlobalIDs.cend(), idsCheck.begin(), + filterInactiveStationIDs); + bool isStationIDsOk = true; + for (int id = 0; id < nStationsCheck; ++id) { + isStationIDsOk = isStationIDsOk && idsCheck[id] == id; + } + if (!isStationIDsOk) { + std::stringstream msg; + msg << "L1Parameters: invalid object condition: array of active station IDs is not a gapless subset " + << "of integer numbers starting from 0:\n\t"; + for (auto id : fActiveStationGlobalIDs) { + msg << std::setw(3) << std::setfill(' ') << id << ' '; + } + throw std::logic_error(msg.str()); + } + + /* + * Check magnetic field flags of the stations + * + * In a current version of tracking there are three configurations possible to be proceeded: + * A. All the stations are inside magnetic field + * B. There is no magnetic field in a setup + * C. All the first stations are inside magnetic field, all the last stations are outside the field + * In all the cases the fieldStatus flags should be sorted containing all non-zero elements in the beginning + * (representing stations placed into magnetic field) and all zero elements in the end of z-axis. + */ + bool ifFieldStatusFlagsOk = std::is_sorted( + fStations.cbegin(), fStations.cbegin() + fNstationsActiveTotal, + [&](const L1Station& lhs, const L1Station& rhs) { return bool(lhs.fieldStatus) > bool(rhs.fieldStatus); }); + + if (!ifFieldStatusFlagsOk) { + std::stringstream msg; + msg << "L1Parameters: invalid object condition: L1 tracking is impossible for a given field configuration:\n"; + for (int iSt = 0; iSt < fNstationsActiveTotal; ++iSt) { + msg << "- station ID: " << iSt << ", field status: " << fStations[iSt].fieldStatus << '\n'; + } + throw std::logic_error(msg.str()); + } + + /* + * Check target position SIMD vector + */ + + L1Utils::CheckSimdVectorEquality(fTargetPos[0], "L1Parameters: target position x"); + L1Utils::CheckSimdVectorEquality(fTargetPos[1], "L1Parameters: target position y"); + L1Utils::CheckSimdVectorEquality(fTargetPos[2], "L1Parameters: target position z"); + + /* + * Check vertex field region and value objects at primary vertex + */ + + fVertexFieldValue.CheckConsistency(); + fVertexFieldRegion.CheckConsistency(); + + + /* + * Check if each station object is consistent itself, and if all of them are placed after the target + * NOTE: If a station was not set up, it is accounted inconsistent (uninitialized). In the array of stations there are uninitialized + * stations possible (with id > NstationsActiveTotal), thus one should NOT run the loop above over all the stations in array + * but only until *(fNstationsActive.cend() - 1) (== NstationsActiveTotal). + * TODO: Probably, we should introduce methods, which check the consistency of fully initialized objects such as L1Station, + * L1MaterialInfo, etc. (S.Zharko) + */ + + for (int iSt = 0; iSt < fNstationsActiveTotal; ++iSt) { + fStations[iSt].CheckConsistency(); + if (fStations[iSt].z[0] < fTargetPos[2][0]) { + std::stringstream msg; + msg << "L1Parameters: station with global ID = " << iSt << " is placed before target " + << "(z_st = " << fStations[iSt].z[0] << " [cm] < z_targ = " << fTargetPos[2][0] << " [cm])"; + throw std::logic_error(msg.str()); + } + } + + /* + * Check thickness maps + * NOTE: If a L1Material map was not set up, it is accounted inconsistent (uninitialized). In the array of thickness maps for each + * there are uninitialized elements possible (with id > NstationsActiveTotal), thus one should NOT run the loop above over + * all the stations in array but only until *(fNstationsActive.cend() - 1) (== NstationsActiveTotal). + */ + + for (int iSt = 0; iSt < fNstationsActiveTotal; ++iSt) { + fThickMap[iSt].CheckConsistency(); + } + + + /* + * Check iterations sequence + * 1. Number of iterations should be larger then zero + * 2. Each iteration should contain values within predefined limits + * 3. Number of iterations with TrackFromTriplets flag turned on no more then 1 + * 4. If the TrackFromTriplets iteration exists, it should be the last one in the sequence + */ + { + int nIterations = fCAIterations.size(); + if (!nIterations) { + std::stringstream msg; + msg << "L1Parameters: 0 track finder iterations were found. Please, define at least one iteration"; + throw std::logic_error(msg.str()); + } + + std::string names = ""; + for (const auto iter : fCAIterations) { + if (!iter.Check()) { names += iter.GetName() + " "; } + } + if (names.size()) { + std::stringstream msg; + msg << "L1Parameters: some parameters are out of range for the following iterations: " << names; + throw std::logic_error(msg.str()); + } + + nIterations = std::count_if(fCAIterations.begin(), fCAIterations.end(), + [=](const L1CAIteration& it) { return it.GetTrackFromTripletsFlag(); }); + if (nIterations > 1) { + std::stringstream msg; + msg << "L1Parameters: found " << nIterations << " iterations with GetTrackFromTripletsFlag() == true:\n"; + for (const auto& iter : fCAIterations) { + if (iter.GetTrackFromTripletsFlag()) { msg << '\t' << "- " << iter.GetName() << '\n'; } + } + msg << "Only the one iteration can have GetTrackFromTripletsFlag() == true, and this iteration should be "; + msg << "the last one"; + throw std::logic_error(msg.str()); + } + + if (nIterations == 1 && !(fCAIterations.end() - 1)->GetTrackFromTripletsFlag()) { + std::stringstream msg; + msg << "L1Parameters: iteration with GetTrackFromTripletsFlag() == true is not the last in a sequence. "; + msg << "The GetTrackFromTripletsFlag() value in the iterations sequence: \n"; + for (const auto& iter : fCAIterations) { + msg << '\t' << "- " << std::setw(15) << std::setfill(' ') << iter.GetName() << ' '; + msg << std::setw(6) << std::setfill(' ') << iter.GetTrackFromTripletsFlag() << '\n'; + } + throw std::logic_error(msg.str()); + } + } + + LOG(info) << "Consistency test for L1 parameters object... \033[1;32mpassed\033[0m"; +} + +//---------------------------------------------------------------------------------------------------------------------- +// +void L1Parameters::Print(int /*verbosityLevel*/) const +{ + LOG(info) << ToString(); +} + +//---------------------------------------------------------------------------------------------------------------------- +// +std::string L1Parameters::ToString(int verbosity, int indentLevel) const +{ + // FIXME: SZh: Fill it with other parameters + std::stringstream aStream {}; + constexpr char indentChar = '\t'; + std::string indent(indentLevel, indentChar); + aStream << '\n'; + aStream << indent << "--------------------------------------------------------------------------------\n"; + aStream << indent << " L1 parameters list\n"; + aStream << indent << "--------------------------------------------------------------------------------\n"; + aStream << indent << "COMPILE TIME CONSTANTS:\n"; + aStream << indent << indentChar << "Bits to code one station: " << L1Constants::size::kStationBits << '\n'; + aStream << indent << indentChar << "Bits to code one thread: " << L1Constants::size::kThreadBits << '\n'; + aStream << indent << indentChar << "Bits to code one triplet: " << L1Constants::size::kTripletBits << '\n'; + aStream << indent << indentChar << "Max number of stations: " << L1Constants::size::kMaxNstations << '\n'; + aStream << indent << indentChar << "Max number of threads: " << L1Constants::size::kMaxNthreads << '\n'; + aStream << indent << indentChar << "Max number of triplets: " << L1Constants::size::kMaxNtriplets << '\n'; + aStream << indent << "RUNTIME CONSTANTS:\n"; + aStream << indent << indentChar << "Max number of doublets per singlet: " << fMaxDoubletsPerSinglet << '\n'; + aStream << indent << indentChar << "Max number of triplets per doublet: " << fMaxTripletPerDoublets << '\n'; + aStream << indent << "CA TRACK FINDER ITERATIONS:\n"; + for (int idx = 0; idx < static_cast<int>(fCAIterations.size()); ++idx) { + aStream << idx << ") " << fCAIterations[idx].ToString(indentLevel + 1) << '\n'; + } + aStream << indent << "GEOMETRY:\n"; + + aStream << indent << indentChar << "TARGET:\n"; + aStream << indent << indentChar << indentChar << "Position:\n"; + for (int dim = 0; dim < 3 /*nDimensions*/; ++dim) { + aStream << indent << indentChar << indentChar << indentChar << char(120 + dim) << " = " << fTargetPos[dim][0] + << " cm\n"; + } + aStream << indent << indentChar << "NUMBER OF STATIONS:\n"; + aStream << indent << indentChar << indentChar << "Number of stations (Geometry): "; + for (int idx = 0; idx < int(fNstationsGeometry.size()); ++idx) { + aStream << std::setw(2) << std::setfill(' ') << fNstationsGeometry[idx] << ' '; + } + aStream << " | total = " << std::setw(2) << std::setfill(' ') << fNstationsGeometryTotal; + aStream << '\n'; + aStream << indent << indentChar << indentChar << "Number of stations (Active): "; + for (int idx = 0; idx < int(fNstationsActive.size()); ++idx) { + aStream << std::setw(2) << std::setfill(' ') << fNstationsActive[idx] << ' '; + } + aStream << " | total = " << std::setw(2) << std::setfill(' ') << fNstationsActiveTotal; + aStream << '\n'; + aStream << indent << indentChar << indentChar << "Active station indexes: "; + for (int idx = 0; idx < *(fNstationsActive.end() - 1); ++idx) { + aStream << std::setw(3) << std::setfill(' ') << fActiveStationGlobalIDs[idx] << ' '; + } + aStream << '\n'; + + aStream << indent << indentChar << "STATIONS:\n "; + for (int idx = 0; idx < *(fNstationsActive.end() - 1); ++idx) { + aStream << indent << indentChar << indentChar << fStations[idx].ToString(verbosity) << '\n'; + } + + aStream << indent << "FLAGS:\n"; + aStream << indent << "--------------------------------------------------------------------------------\n"; + return aStream.str(); +} diff --git a/reco/L1/L1Algo/L1Parameters.h b/reco/L1/L1Algo/L1Parameters.h index 4fa9318884..a86d09947c 100644 --- a/reco/L1/L1Algo/L1Parameters.h +++ b/reco/L1/L1Algo/L1Parameters.h @@ -18,6 +18,7 @@ #include "L1CAIteration.h" #include "L1Constants.h" #include "L1Material.h" +#include "L1SearchWindow.h" #include "L1Station.h" #include "L1Utils.h" #include "L1Vector.h" @@ -131,6 +132,17 @@ public: /// \param iStation Index of station in the active stations container const L1Station& GetStation(int iStation) const { return fStations[iStation]; } + /// Gets a search window for a selected station and track group + /// \note For a particular track finder iteration one can select a track group, which is defined by the minimal + /// momentum of tracks (fast tracks, all tracks), their vertex (primary or secondary tracks), or by particle + /// (electrons, muons, hadrons, etc.) + /// \param iStation Global index of active station + /// \param iTrackGr Index of a track group + const L1SearchWindow& GetSearchWindow(int iStation, int iTrackGr) const + { + return fSearchWindows[iTrackGr * L1Constants::size::kMaxNstations + iStation]; + } + /// Gets reference to the array of station thickness map const L1MaterialContainer_t& GetThicknessMaps() const { return fThickMap; } @@ -238,6 +250,13 @@ private: /// active index: 0 -1 1 2 -1 3 4 5 6 7 0 0 0 0 alignas(L1Constants::misc::kAlignment) std::array<int, L1Constants::size::kMaxNstations> fActiveStationGlobalIDs {}; + /// Map of search windows vs. active station global index and tracks group + /// The tracks group can be defined by minimum momentum (fast/all tracks), origin (primary/secondary) and particle type + /// (electron, muon, all). Other options also can be added + alignas(L1Constants::misc::kAlignment) + std::array<L1SearchWindow, L1Constants::size::kMaxNstations* L1Constants::size::kMaxNtrackGroups> fSearchWindows = + {}; + int fTrackingLevel = 0; ///< tracking level int fGhostSuppression = 0; ///< flag: if true, ghost tracks are suppressed float fMomentumCutOff = 0; ///< minimum momentum of tracks @@ -246,10 +265,12 @@ private: // ** Flags for development ** // *************************** - bool fDevIsIgnoreHitSearchAreas {false}; ///< Process all hits on the station ignoring hit search area - bool fDevIsUseOfOriginalField {false}; ///< Force use of original field - bool fDevIsMatchDoubletsViaMc {false}; ///< Flag to match doublets using MC information - bool fDevIsMatchTripletsViaMc {false}; ///< Flag to match triplets using Mc information + bool fDevIsIgnoreHitSearchAreas = false; ///< Process all hits on the station ignoring hit search area + bool fDevIsUseOfOriginalField = false; ///< Force use of original field + bool fDevIsMatchDoubletsViaMc = false; ///< Flag to match doublets using MC information + bool fDevIsMatchTripletsViaMc = false; ///< Flag to match triplets using MC information + bool fDevIsParSearchWUsed = false; ///< Flag: when true, the parametrized search windows are used in track + ///< finder; when false, the Kalman filter is used instead /// Serialization function friend class boost::serialization::access; @@ -273,6 +294,7 @@ private: ar& fNstationsGeometry; ar& fNstationsActive; ar& fActiveStationGlobalIDs; + ar& fSearchWindows; ar& fTrackingLevel; ar& fGhostSuppression; diff --git a/reco/L1/L1Algo/L1SearchWindow.cxx b/reco/L1/L1Algo/L1SearchWindow.cxx new file mode 100644 index 0000000000..c7418a58ef --- /dev/null +++ b/reco/L1/L1Algo/L1SearchWindow.cxx @@ -0,0 +1,112 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +#include "L1SearchWindow.h" + +#include <iomanip> +#include <sstream> + +// --------------------------------------------------------------------------------------------------------------------- +// +L1SearchWindow::L1SearchWindow(int stationID, int trackGrID) : fStationID(stationID), fTrackGroupID(trackGrID) +{ + assert(stationID > -1); + assert(trackGrID > -1); + + // Case for constant windows (TEMPORARY: we should add selection of different windows): + static_assert(kNpars == 1); +} + +// TODO: SZh 08.11.2022: Probably, we should have the assertions in the InitManager and remove them from here, since +// this class is supposed to be used inside the algorithm core +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDxMaxVsX0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDxMaxVsX0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDxMinVsX0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDxMinVsX0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDxMaxVsY0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDxMaxVsY0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDxMinVsY0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDxMinVsY0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDyMaxVsX0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDyMaxVsX0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDyMinVsX0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDyMinVsX0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDyMaxVsY0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDyMaxVsY0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetParamDyMinVsY0(int id, float val) +{ + assert(id > -1 && id < kNpars); + fvParams[kDyMinVsY0 * kNpars + id] = val; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string L1SearchWindow::ToString() const +{ + std::stringstream msg; + msg << "----- CA hits search window: \n"; + msg << "\tstation ID: " << fStationID << '\n'; + msg << "\ttracks group ID: " << fTracksGroupID << '\n'; + msg << "\tparameters:\n"; + msg << "\t\t" << std::setw(6) << std::setfill(' ') << "No." << ' '; + msg << std::setw(12) << std::setfill(' ') << "dx_max(x0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dx_min(x0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dx_max(y0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dx_min(y0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dy_max(x0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dy_min(x0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dy_max(y0)" << ' '; + msg << std::setw(12) << std::setfill(' ') << "dy_min(y0)" << '\n'; + for (int iPar = 0; iPar < kNpars; ++iPar) { + msg << "\t\t" << std::setw(6) << std::setfill(' ') << iPar << ' '; + for (int iDep = 0; iDep < kNdeps; ++iDep) { + msg << std::setw(12) << std::setfill(' ') << fvParams[iDep * kNpars + iPar] << ' '; + } + } + return msg.str(); +} diff --git a/reco/L1/L1Algo/L1SearchWindow.h b/reco/L1/L1Algo/L1SearchWindow.h new file mode 100644 index 0000000000..13dc50c0d9 --- /dev/null +++ b/reco/L1/L1Algo/L1SearchWindow.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +/// \file L1SearchWindow.h +/// \brief Provides parameterisation for hits searching window in the CA tracking (header) +/// \date 08.11.2022 +/// \author S.Zharko <s.zharko@gsi.de> + +#ifndef L1SearchWindow_h +#define L1SearchWindow_h 1 + +#include <boost/serialization/array.hpp> + +#include <array> +#include <string> + +/// TODO: SZh 8.11.2022: add selection of parameterisation + +/// \brief Class L1SearchWindow defines a parameterisation of hits search window for CA tracking algorithm +/// TODO: SZh 8.11.2022: add description +class L1SearchWindow { +public: + /// Constructor + /// \param stationID Global index of active station + /// \param trackGrID Track group ID + L1SearchWindow(int stationID, int trackGrID); + + /// Default constructor + L1SearchWindow() = default; + + /// Destructor + ~L1SearchWindow() = default; + + /// Copy constructor + L1SearchWindow(const L1SearchWindow& other) = default; + + /// Copy assignment operator + L1SearchWindow& operator=(const L1SearchWindow& other) = default; + + /// Move constructor + L1SearchWindow(L1SearchWindow&& other) = default; + + /// Move assignment operator + L1SearchWindow& operator=(L1SearchWindow&& other) = default; + + /// Parameterisation function for dx_max(x0) + float DxMaxVsX0(float /*x*/) const { return fvParams[kDxMaxVsX0 /*+ 0*/]; } + + /// Parameterisation function for dx_min(x0) + float DxMinVsX0(float /*x*/) const { return fvParams[kDxMinVsX0 /*+ 0*/]; } + + /// Parameterisation function for dx_max(y0) + float DxMaxVsY0(float /*x*/) const { return fvParams[kDxMaxVsY0 /*+ 0*/]; } + + /// Parameterisation function for dx_min(y0) + float DxMinVsY0(float /*x*/) const { return fvParams[kDxMinVsY0 /*+ 0*/]; } + + /// Parameterisation function for dy_max(x0) + float DyMaxVsX0(float /*x*/) const { return fvParams[kDyMaxVsX0 /*+ 0*/]; } + + /// Parameterisation function for dy_min(x0) + float DyMinVsX0(float /*x*/) const { return fvParams[kDyMinVsX0 /*+ 0*/]; } + + /// Parameterisation function for dy_max(y0) + float DyMaxVsY0(float /*y*/) const { return fvParams[kDyMaxVsY0 /*+ 0*/]; } + + /// Parameterisation function for dy_min(y0) + float DyMinVsY0(float /*y*/) const { return fvParams[kDyMinVsY0 /*+ 0*/]; } + + + /// Gets station id + int GetStationID() const { return fStationID; } + + /// Gets track group id + int GetTrackGroupID() const { return fTrackGroupID; } + + + /// TODO: SZh 08.11.2022: Implement variadic template function + /// TODO: SZh 08.11.2022: Try to reduce number of functions + /// Sets parameters for dx_max(x0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDxMaxVsX0(int id, float val); + + /// Sets parameters for dx_min(x0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDxMinVsX0(int id, float val); + + /// Sets parameters for dx_max(y0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDxMaxVsY0(int id, float val); + + /// Sets parameters for dx_min(y0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDxMinVsY0(int id, float val); + + /// Sets parameters for dy_max(x0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDyMaxVsX0(int id, float val); + + /// Sets parameters for dy_min(x0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDyMinVsX0(int id, float val); + + /// Sets parameters for dy_max(y0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDyMaxVsY0(int id, float val); + + /// Sets parameters for dy_min(y0) + /// \param id Parameter index + /// \param val Parameter value + void SetParamDyMinVsY0(int id, float val); + + /// String representation of the contents + std::string ToString() const; + +private: + static constexpr unsigned char kNpars = 1; ///< Max number of parameters for one dependency + static constexpr unsigned char kNdeps = 8; ///< Number of the dependencies + + /// Enumeration for dependencies stored + enum EDependency + { + kDxMaxVsX0, + kDxMinVsX0, + kDxMaxVsY0, + kDxMinVsY0, + kDyMaxVsX0, + kDyMinVsX0, + kDyMaxVsY0, + kDyMinVsY0 + }; + + /// Search window parameter array containing parameters from + /// - dx_max vs x0 - indexes [0 .. kNpars - 1] + /// - dx_min vs x0 - indexes [kNpars .. (2 * kNpars - 1)] + /// - dx_max vs y0 - indexes [2 * kNpars .. (3 * kNpars - 1)] + /// - dx_min vs y0 - indexes [3 * kNpars .. (4 * kNpars - 1)] + /// - dy_max vs y0 - indexes [4 * kNpars .. (5 * kNpars - 1)] + /// - dy_min vs y0 - indexes [5 * kNpars .. (6 * kNpars - 1)] + /// - dy_max vs y0 - indexes [6 * kNpars .. (7 * kNpars - 1)] + /// - dy_min vs y0 - indexes [7 * kNpars .. (8 * kNpars - 1)] + std::array<float, kNdeps* kNpars> fvParams = {0}; + + int fStationID = -1; ///< Global index of active tracking station + int fTrackGroupID = -1; ///< Index of tracks group + //std::string fsTag = ""; ///< Tag, containing information on the tracks group (TODO: can be omitted?) + + /// Serialization function + friend class boost::serialization::access; + template<class Archive> + void serialize(Archive& ar, const unsigned int) + { + ar& fvParams; + ar& fStationID; + ar& fTrackGroupID; + } +}; + +#endif // L1SearchWindow_h diff --git a/reco/L1/L1LinkDef.h b/reco/L1/L1LinkDef.h index 152819d5b8..7a1cccc9b4 100644 --- a/reco/L1/L1LinkDef.h +++ b/reco/L1/L1LinkDef.h @@ -30,5 +30,6 @@ #pragma link C++ class CbmTrackingInputQaSts + ; #pragma link C++ class CbmTrackerInputQaTrd + ; #pragma link C++ class CbmTrackerInputQaTof + ; +#pragma link C++ class ca::tools::WindowFinder + ; #endif diff --git a/reco/L1/catools/CaToolsWindowFinder.cxx b/reco/L1/catools/CaToolsWindowFinder.cxx new file mode 100644 index 0000000000..d663c7cc5b --- /dev/null +++ b/reco/L1/catools/CaToolsWindowFinder.cxx @@ -0,0 +1,84 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +/// \file CaToolsWindowFinder.cxx +/// \brief Framework for CA tracking hit-finder window estimation from MC (implementation) +/// \since 14.10.2022 +/// \author S.Zharko <s.zharko@gsi.de> + +#include "CaToolsWindowFinder.h" + +#include <Logger.h> + +#include "TChain.h" + +#include "L1Constants.h" + +using namespace ca::tools; +using namespace L1Constants::clrs; // for colored logs + +ClassImp(ca::tools::WindowFinder); + +// --------------------------------------------------------------------------------------------------------------------- +// +WindowFinder::WindowFinder() : fpMcTripletsTree(new TChain(kTreeName)) +{ + LOG(info) << kGNb << "Call" << kCLb << "WindowFinder constructor\n" << kCL; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::AddInputFile(const char* filename) +{ + assert(fpMcTripletsTree); + auto addingRes = fpMcTripletsTree->AddFile(filename); + if (addingRes != 1) { + LOG(error) << "WindowFinder::AddInputFile: File \"" << filename << "\" cannot be added to the MC triplets chain, " + << "some errors occurred\n"; + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::Process(EBuildingMode) { fpMcTripletsTree->Draw("zv"); } + + +// **************************** +// ** Setters implementation ** +// **************************** + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::SetBinning(int nBinsX, int nBinsY) +{ + assert(nBinsX > 0); + assert(nBinsY > 0); + fNbinsX = nBinsX; + fNbinsY = nBinsY; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::SetEpsilon(float eps) +{ + assert(eps > 0. && eps <= 1.); + fEps = eps; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::SetNslices(int nSlices) +{ + assert(nSlices > 0); + fNslices = nSlices; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::SetTarget(double x, double y, double z) +{ + fTargetPos[0] = x; + fTargetPos[1] = y; + fTargetPos[2] = z; +} diff --git a/reco/L1/catools/CaToolsWindowFinder.h b/reco/L1/catools/CaToolsWindowFinder.h new file mode 100644 index 0000000000..1ea7e53314 --- /dev/null +++ b/reco/L1/catools/CaToolsWindowFinder.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +/// \file CaToolsWindowFinder.h +/// \brief Framework for CA tracking hit-finder window estimation from MC (header) +/// \since 14.10.2022 +/// \author S.Zharko <s.zharko@gsi.de> + +#ifndef CaToolsWindowFinder_h +#define CaToolsWindowFinder_h 1 + +#include "TObject.h" + +// TODO: Replace tmp asserts with exceptions + +class TChain; + +namespace ca +{ + namespace tools + { + + /// Enumeration of parameterisations used to describe a search window + enum class EWindowForm + { + kConstant, + kLinear, + kParabolic, + kElliptic + }; + + /// Enumeration + enum class EBuildingMode + { + kDouplets, ///< Windows are built from doublets and a target + kTriplets ///< Windows are built from triplets without using target + }; + + /// TODO: ... write an instruction ... + class WindowFinder : public TObject { + public: + // TODO: TEMPORARY CONSTANT EXPRESSIONS (TO BE MOVED TO A SEPARATE HEADER) + static constexpr const char* kTreeName = "t"; ///< Name of the input MC triplets tree + + public: + /// Default constructor + WindowFinder(); + + virtual ~WindowFinder() = default; + + /// Copy and move are forbidden + WindowFinder(const WindowFinder&) = delete; + WindowFinder(WindowFinder&&) = delete; + WindowFinder& operator=(const WindowFinder&) = delete; + WindowFinder& operator=(WindowFinder&&) = delete; + + /// Adds an input file with a tree object of MC triplets + /// \note Multiple file input is possible + void AddInputFile(const char* filename); + + /// Process a tree (TEST) + void Process(EBuildingMode buildingMode); + + /// Sets binning of the dx (dy) distribution + /// \param nBinsX Number of bins for the x-axis + /// \param nBinsY Number of bins for the y-axis + void SetBinning(int nBinsX, int nBinsY); + + /// Sets a fraction of triplets (doublets), which can be omitted by the window + void SetEpsilon(float eps); + + /// Sets number of slices along the x-axis + /// If the number of slices larger then 1, the window bounds will be fitted with a function (...which TODO). + /// Otherwise, the bounds will be represented with constants (independent from x0 or y0) + void SetNslices(int nSlices); + + /// Sets components of the target center position + /// \param x Position x-component [cm] + /// \param y Position y-component [cm] + /// \param z Position z-component [cm] + void SetTarget(double x, double y, double z); + + + // ****************************** + // ** Member variables ** + // ****************************** + + private: + std::array<double, 3> fTargetPos = {0}; ///< Target position {x, y, z} [cm] + + // Window extraction settings + + int fNbinsX = 360; ///< Number of bins for the X axis of the distribution + int fNbinsY = 800; ///< Number of bins for the Y axis of the distribution + int fNslices = 1; ///< Number of slices along the X axis + float fEps = 0.001; ///< Fraction of triplets (doublets), which can be omitted + + TChain* fpMcTripletsTree = nullptr; ///< Chain of trees containing MC triplets, generated in CbmL1 Performance + + ClassDef(WindowFinder, 0); + }; + } // namespace tools +} // namespace ca + +#endif // CaToolsWindowsFinder_h -- GitLab