diff --git a/macro/L1/search_window.C b/macro/L1/search_window.C new file mode 100644 index 0000000000000000000000000000000000000000..767f01340ab9865e97484e57daaa164720cca138 --- /dev/null +++ b/macro/L1/search_window.C @@ -0,0 +1,83 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +/// \file search_window.C +/// \brief A macro to run a hit-search window estimator for the CA tracking +/// \since 8.11.2022 +/// \author S.Zharko <s.zharko@gsi.de> + +/// Splits a string to a vector of substrings using a char token +/// \param origString Original string +/// \param token Char token +std::vector<TString> SplitString(const char* aString, char token = ':'); + +// Instruction +// +// 1. Creation of MC-triplets tree input +// In a reconstruction macro, please, run CbmL1::SetOutputMcTripletsTreeFilename("<prefix>"), where <prefix> is a pre- +// fix for an output file. NOTE: this feature will not work with the "debugWithMC" flag switched off +// +// 2. Initialization of search windows file to CA tracking +// The file contains an array of serialized L1SearchWindow objects. The file can be generated +// for a given set of station IDs, MC-triplet trees and a sequence of track finder iteration using +// this macro. The L1SearchWindow objects are optional. They are initialized as far as a corresponding input file +// is provided. To do so, please, add this function into your reconstruction macro +//l1->SetInputSearchWindowFilename(TString(gSystem->Getenv("VMCWORKDIR")) + "/macro/L1/SearchWindows.dat"); + + +/// Estimates search windows +void search_window( + const char* yamlConfigFile = "", ///< Name of yaml configuration file containing track finder iterations + const char* inputTreeFile = "", ///< Name of ROOT input file with MC triplets + const char* swOutputFile = "", ///< Name of L1SearchWindow objects output + const char* logOutputName = "" ///< Name of pdf log +) +{ + // ----- Create a window finder object + ca::tools::WindowFinder wf; + + // ----- Initialize window finder parameters + wf.SetOutputName(swOutputFile); + wf.ReadTrackingIterationsFromYAML(yamlConfigFile); + + // Set global indexes of active tracking stations by which the search windows will be estimated + std::vector<int> vStationIDs = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + wf.SetStationIndexes(vStationIDs); + + // Set target (NOTE: for now x and y of the target should be 0.) + wf.SetTarget(0., 0., -44.); + + // Additional cut + //TCut extraCut = "abs(pdg) == 211"; // Select pions only + //wf.SetExtraCut(extraCut); + + // ----- Define input trees with MC triplets + auto vsInputTreeFilenames = SplitString(inputTreeFile); + for (const auto& inputTreeFilename : vsInputTreeFilenames) { + wf.AddInputFile(inputTreeFilename); + } + + // ----- Run the windows estimator + wf.Process(); + + // ----- Save a log to pdf files + wf.DumpCanvasesToPdf(logOutputName); +} + + +// ********************* +// ** Implementations ** +// ********************* + +std::vector<TString> SplitString(const char* aString, char token) +{ + TString sOrigin = TString(aString); + TObjArray* strings = sOrigin.Tokenize(TString(token)); + + std::vector<TString> res; + for (int i = 0; i < strings->GetEntries(); ++i) { + res.push_back(((TObjString*) strings->At(i))->String()); + } + return res; +} diff --git a/macro/run/run_reco.C b/macro/run/run_reco.C index 2ed01f00b1f084253e5ade68e3449b5219a9d821..997d408d42e4ebfab33fcae82e49dbc132bffc4a 100644 --- a/macro/run/run_reco.C +++ b/macro/run/run_reco.C @@ -381,10 +381,11 @@ void run_reco(TString input = "", Int_t nTimeSlices = -1, Int_t firstTimeSlice = // L1 tracking auto l1 = (debugWithMC) ? new CbmL1("L1", 2, 3, 0) : new CbmL1("L1", 0); + // L1 configuration file (optional) + // At the moment, the YAML configuration file defines different parameters for a sequence of track finder + // iterations. The same file should be used in ca::tools::WindowFinder class for hit search window estimation //l1->SetInputConfigName(TString(gSystem->Getenv("VMCWORKDIR")) + "/reco/L1/L1Algo/L1ConfigExample.yaml"); - // 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 3f45f45072de8e994cad5493970df75023897523..a9e5be41c11c0552a33cb44231c58da9c2ab4dd8 100644 --- a/reco/L1/CMakeLists.txt +++ b/reco/L1/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRCS L1Algo/L1IODataManager.cxx L1Algo/L1CloneMerger.cxx L1Algo/L1ConfigRW.cxx + L1Algo/L1SearchWindow.cxx L1Algo/utils/L1AlgoDraw.cxx L1Algo/utils/L1AlgoEfficiencyPerformance.cxx L1Algo/utils/L1AlgoPulls.cxx @@ -72,6 +73,7 @@ set(SRCS catools/CaToolsPerformance.cxx catools/CaToolsDebugger.cxx catools/CaToolsWindowFinder.cxx + catools/CaToolsWFExpression.cxx ParticleFinder/CbmL1PFFitter.cxx ParticleFinder/CbmL1PFMCParticle.cxx diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx index 2cc894d87bac89bc709f5e784835c049721da45b..a12cd94ff93f0850cd7a244b583977a9ebc4df6e 100644 --- a/reco/L1/CbmL1.cxx +++ b/reco/L1/CbmL1.cxx @@ -632,14 +632,14 @@ InitStatus CbmL1::Init() auto trackingIterFastPrim = L1CAIteration(trIterDefault, "FastPrimIter"); trackingIterFastPrim.SetMinNhitsStation0(3); trackingIterFastPrim.SetPickGather(3.0f); - trackingIterFastPrim.SetMaxInvMom(1.0 / 0.5); + trackingIterFastPrim.SetMaxQp(1.0 / 0.5); trackingIterFastPrim.SetMaxDZ(0); trackingIterFastPrim.SetTargetPosSigmaXY(1, 1); trackingIterFastPrim.SetPrimaryFlag(true); auto trackingIterAllPrim = L1CAIteration(trIterDefault, "AllPrimIter"); trackingIterAllPrim.SetMinNhitsStation0(3); - trackingIterAllPrim.SetMaxInvMom(1.0 / 0.05); + trackingIterAllPrim.SetMaxQp(1.0 / 0.05); trackingIterAllPrim.SetTargetPosSigmaXY(1, 1); trackingIterAllPrim.SetPrimaryFlag(true); @@ -647,7 +647,7 @@ InitStatus CbmL1::Init() trackingIterFastPrim2.SetTripletChi2Cut(21.1075f); trackingIterFastPrim2.SetTripletFinalChi2Cut(21.1075f); trackingIterFastPrim2.SetPickGather(3.0f); - trackingIterFastPrim2.SetMaxInvMom(1.0 / 0.5); + trackingIterFastPrim2.SetMaxQp(1.0 / 0.5); trackingIterFastPrim2.SetMaxDZ(0); trackingIterFastPrim2.SetTargetPosSigmaXY(5, 5); trackingIterFastPrim2.SetPrimaryFlag(true); @@ -655,7 +655,7 @@ InitStatus CbmL1::Init() auto trackingIterAllSec = L1CAIteration(trIterDefault, "AllSecIter"); trackingIterAllSec.SetTripletChi2Cut(18.7560f); // = 6.252 * 3; // prob = 0.1 trackingIterAllSec.SetTripletFinalChi2Cut(18.7560f); - trackingIterAllSec.SetMaxInvMom(1.0 / 0.1); + trackingIterAllSec.SetMaxQp(1.0 / 0.1); trackingIterAllSec.SetTargetPosSigmaXY(10, 10); trackingIterAllSec.SetMaxSlopePV(1.5); trackingIterAllSec.SetPrimaryFlag(false); @@ -664,7 +664,7 @@ InitStatus CbmL1::Init() trackingIterFastPrimJump.SetTripletChi2Cut(21.1075f); // prob = 0.01 trackingIterFastPrimJump.SetTripletFinalChi2Cut(21.1075f); trackingIterFastPrimJump.SetPickGather(3.0f); - trackingIterFastPrimJump.SetMaxInvMom(1.0 / 0.5); + trackingIterFastPrimJump.SetMaxQp(1.0 / 0.5); trackingIterFastPrimJump.SetMaxDZ(0); trackingIterFastPrimJump.SetTargetPosSigmaXY(5, 5); trackingIterFastPrimJump.SetPrimaryFlag(true); @@ -673,7 +673,7 @@ InitStatus CbmL1::Init() auto trackingIterAllPrimJump = L1CAIteration(trIterDefault, "AllPrimJumpIter"); trackingIterAllPrimJump.SetTripletChi2Cut(18.7560f); trackingIterAllPrimJump.SetTripletFinalChi2Cut(18.7560f); - trackingIterAllPrimJump.SetMaxInvMom(1.0 / 0.1); + trackingIterAllPrimJump.SetMaxQp(1.0 / 0.1); trackingIterAllPrimJump.SetTargetPosSigmaXY(5, 5); trackingIterAllPrimJump.SetPrimaryFlag(true); trackingIterAllPrimJump.SetJumpedFlag(true); @@ -681,7 +681,7 @@ InitStatus CbmL1::Init() auto trackingIterAllSecJump = L1CAIteration(trIterDefault, "AllSecJumpIter"); trackingIterAllSecJump.SetTripletChi2Cut(21.1075f); trackingIterAllSecJump.SetTripletFinalChi2Cut(21.1075f); - trackingIterAllSecJump.SetMaxInvMom(1.0 / 0.1); + trackingIterAllSecJump.SetMaxQp(1.0 / 0.1); trackingIterAllSecJump.SetMaxSlopePV(1.5f); trackingIterAllSecJump.SetTargetPosSigmaXY(10, 10); trackingIterAllSecJump.SetPrimaryFlag(false); @@ -689,7 +689,7 @@ InitStatus CbmL1::Init() auto trackingIterAllPrimE = L1CAIteration(trIterDefault, "AllPrimEIter"); trackingIterAllPrimE.SetMinNhitsStation0(3); - trackingIterAllPrimE.SetMaxInvMom(1.0 / 0.05); + trackingIterAllPrimE.SetMaxQp(1.0 / 0.05); trackingIterAllPrimE.SetTargetPosSigmaXY(1, 1); trackingIterAllPrimE.SetPrimaryFlag(true); trackingIterAllPrimE.SetElectronFlag(true); @@ -697,7 +697,7 @@ InitStatus CbmL1::Init() auto trackingIterAllSecE = L1CAIteration(trIterDefault, "AllSecEIter"); trackingIterAllSecE.SetTripletChi2Cut(18.7560f); trackingIterAllSecE.SetTripletFinalChi2Cut(18.7560f); - trackingIterAllSecE.SetMaxInvMom(1.0 / 0.05); + trackingIterAllSecE.SetMaxQp(1.0 / 0.05); trackingIterAllSecE.SetMaxSlopePV(1.5f); trackingIterAllSecE.SetTargetPosSigmaXY(10, 10); trackingIterAllSecE.SetPrimaryFlag(false); @@ -711,17 +711,17 @@ InitStatus CbmL1::Init() trackingIterAllSecE.SetMinNhits(4); trackingIterAllSecE.SetMinNhitsStation0(4); - trackingIterAllPrim.SetMaxInvMom(1. / 0.1); - trackingIterAllPrimE.SetMaxInvMom(1. / 0.1); - trackingIterAllSecE.SetMaxInvMom(1. / 0.1); + trackingIterAllPrim.SetMaxQp(1. / 0.1); + trackingIterAllPrimE.SetMaxQp(1. / 0.1); + trackingIterAllSecE.SetMaxQp(1. / 0.1); trackingIterAllSecJump.SetMinNhits(4); trackingIterAllSecJump.SetMinNhitsStation0(4); - trackingIterFastPrim.SetMaxInvMom(1.0 / 0.3); - trackingIterAllSec.SetMaxInvMom(1.0 / 0.3); - trackingIterFastPrimJump.SetMaxInvMom(1.0 / 0.3); - trackingIterAllPrimJump.SetMaxInvMom(1.0 / 0.3); - trackingIterAllSecJump.SetMaxInvMom(1.0 / 0.3); + trackingIterFastPrim.SetMaxQp(1.0 / 0.3); + trackingIterAllSec.SetMaxQp(1.0 / 0.3); + trackingIterFastPrimJump.SetMaxQp(1.0 / 0.3); + trackingIterAllPrimJump.SetMaxQp(1.0 / 0.3); + trackingIterAllSecJump.SetMaxQp(1.0 / 0.3); trackingIterAllSec.SetMinNhits(4); trackingIterAllSec.SetMinNhitsStation0(4); @@ -751,7 +751,7 @@ InitStatus CbmL1::Init() it.SetDoubletChi2Cut(7.56327f); // = 1.3449 * 2.f / 3.f; // prob = 0.1 it.SetPickGather(3.0f); it.SetTripletLinkChi2(16.0); - it.SetMaxInvMom(1.0 / 0.1); //(1.0 / 0.5); + it.SetMaxQp(1.0 / 0.1); //(1.0 / 0.5); it.SetMaxSlopePV(.1f); it.SetMaxSlope(.5f); it.SetMaxDZ(0.05); @@ -771,7 +771,7 @@ InitStatus CbmL1::Init() trd2dIter2.SetDoubletChi2Cut(4. * 7.56327f); // = 1.3449 * 2.f / 3.f; // prob = 0.1 trd2dIter2.SetPickGather(3.0f); trd2dIter2.SetTripletLinkChi2(16.); - trd2dIter2.SetMaxInvMom(1.0 / 0.05); //(1.0 / 0.5); + trd2dIter2.SetMaxQp(1.0 / 0.05); //(1.0 / 0.5); trd2dIter2.SetMaxSlopePV(.5f); trd2dIter2.SetMaxSlope(.5f); trd2dIter2.SetMaxDZ(0.05); @@ -788,7 +788,7 @@ InitStatus CbmL1::Init() trd2dIter3.SetDoubletChi2Cut(15.); // = 1.3449 * 2.f / 3.f; // prob = 0.1 trd2dIter3.SetPickGather(3.0f); trd2dIter3.SetTripletLinkChi2(200.); - trd2dIter3.SetMaxInvMom(1.0 / 0.1); //(1.0 / 0.5); + trd2dIter3.SetMaxQp(1.0 / 0.1); //(1.0 / 0.5); trd2dIter3.SetMaxSlopePV(.01); trd2dIter3.SetMaxSlope(.4); //.5f); trd2dIter3.SetMaxDZ(0.05); diff --git a/reco/L1/CbmL1Performance.cxx b/reco/L1/CbmL1Performance.cxx index 99d15a41f43b6dda25b57d6addbf4a1c9f384d30..5b38e7d06c95d4c7a07220dce7a428977871f1b1 100644 --- a/reco/L1/CbmL1Performance.cxx +++ b/reco/L1/CbmL1Performance.cxx @@ -2254,8 +2254,8 @@ void CbmL1::InputPerformance() void CbmL1::DumpMCTripletsToTree() { if (!fpMcTripletsTree) { - auto* currentDir = gDirectory; - auto* currentFile = gFile; + TDirectory* currentDir = gDirectory; + TFile* currentFile = gFile; // Get prefix and directory @@ -2324,7 +2324,6 @@ void CbmL1::DumpMCTripletsToTree() float x; ///< x-component of point position [cm] float y; ///< y-component of point position [cm] float z; ///< z-component of point position [cm] - bool operator<(const ReducedMcPoint& other) { return s < other.s; } }; for (const auto& tr : fvMCTracks) { @@ -2338,7 +2337,9 @@ void CbmL1::DumpMCTripletsToTree() vPoints.emplace_back(ReducedMcPoint {point.iStation, float(point.x), float(point.y), float(point.z)}); } - std::sort(vPoints.begin(), vPoints.end()); + std::sort(vPoints.begin(), vPoints.end(), + [](const ReducedMcPoint& lhs, const ReducedMcPoint& rhs) { return lhs.s < rhs.s; }); + for (unsigned int i = 0; i + 2 < vPoints.size(); ++i) { // Condition to collect only triplets without gaps in stations // TODO: SZh 20.10.2022 Add cases for jump iterations diff --git a/reco/L1/L1Algo/L1CAIteration.cxx b/reco/L1/L1Algo/L1CAIteration.cxx index 5fe919b75dc50e1accb3feb78bbfce55e7d95d4b..e70460b1206ee14106f70a978584dababe7716a8 100644 --- a/reco/L1/L1Algo/L1CAIteration.cxx +++ b/reco/L1/L1Algo/L1CAIteration.cxx @@ -36,7 +36,7 @@ bool L1CAIteration::Check() const res = this->CheckValueLimits<float>("doublet_chi2_cut", fDoubletChi2Cut, 0.f, kMaxFloat) && res; res = this->CheckValueLimits<float>("pick_gather", fPickGather, 0.f, kMaxFloat) && res; res = this->CheckValueLimits<float>("triplet_link_chi2", fTripletLinkChi2, 0.f, kMaxFloat) && res; - res = this->CheckValueLimits<float>("min_momentum", fMaxInvMom, 1.f / kMaxFloat, 1.f / 0.001f) && res; + res = this->CheckValueLimits<float>("max_qp", fMaxQp, 0.001f, kMaxFloat) && res; res = this->CheckValueLimits<float>("max_slope_pv", fMaxSlopePV, 0.f, kMaxFloat) && res; res = this->CheckValueLimits<float>("max_slope", fMaxSlope, 0.f, kMaxFloat) && res; res = this->CheckValueLimits<float>("max_dz", fMaxDZ, 0.f, kMaxFloat) && res; @@ -85,7 +85,7 @@ std::string L1CAIteration::ToString(int indentLevel) const aStream << indent << indCh << "Doublet chi2 cut: " << fDoubletChi2Cut << '\n'; aStream << indent << indCh << "Pick gather: " << fPickGather << '\n'; aStream << indent << indCh << "Triplet link chi2: " << fTripletLinkChi2 << '\n'; - aStream << indent << indCh << "Max inverse momentum: " << fMaxInvMom << '\n'; + aStream << indent << indCh << "Max q / p: " << fMaxQp << '\n'; aStream << indent << indCh << "Max slope at primary vertex: " << fMaxSlopePV << '\n'; aStream << indent << indCh << "Max slope: " << fMaxSlope << '\n'; aStream << indent << indCh << "Max DZ: " << fMaxDZ << '\n'; diff --git a/reco/L1/L1Algo/L1CAIteration.h b/reco/L1/L1Algo/L1CAIteration.h index 9892efe44581a14a18d478ffb892cf188736af55..1d61d40a388d168ca6a3bf25874c3d4027926a91 100644 --- a/reco/L1/L1Algo/L1CAIteration.h +++ b/reco/L1/L1Algo/L1CAIteration.h @@ -75,7 +75,7 @@ public: float GetMaxDZ() const { return fMaxDZ; } /// Gets max considered q/p for tracks - float GetMaxInvMom() const { return fMaxInvMom; } + float GetMaxQp() const { return fMaxQp; } /// Gets max slope (tx\ty) in 3D hit position of a triplet float GetMaxSlope() const { return fMaxSlope; } @@ -151,8 +151,7 @@ public: void SetMaxDZ(float input) { fMaxDZ = input; } /// Sets max considered q/p for tracks - /// TODO: Replace with minimum momentum setter (S.Zharko) - void SetMaxInvMom(float input) { fMaxInvMom = input; } + void SetMaxQp(float input) { fMaxQp = input; } /// Sets max slope (tx\ty) in 3D hit position of a triplet void SetMaxSlope(float input) { fMaxSlope = input; } @@ -224,7 +223,7 @@ private: float fDoubletChi2Cut = 11.3449 * 2.f / 3.f; ///< Doublet chi2 upper cut float fPickGather = 3.0; ///< Size of region to attach new hits to the created track float fTripletLinkChi2 = 25.0; ///< Min value of dp^2/dp_error^2, for which two tiplets are neighbours - float fMaxInvMom = 1.0 / 0.5; ///< Max considered q/p for tracks + float fMaxQp = 1.0 / 0.5; ///< Max considered q/p for tracks float fMaxSlopePV = 1.1; ///< Max slope (tx\ty) in primary vertex float fMaxSlope = 2.748; ///< Max slope (tx\ty) in 3D hit position of a triplet float fMaxDZ = 0.f; ///< Correction for accounting overlaping and iff z [cm] @@ -264,7 +263,7 @@ private: ar& fDoubletChi2Cut; ar& fPickGather; ar& fTripletLinkChi2; - ar& fMaxInvMom; + ar& fMaxQp; ar& fMaxSlopePV; ar& fMaxSlope; ar& fMaxDZ; diff --git a/reco/L1/L1Algo/L1CATrackFinder.cxx b/reco/L1/L1Algo/L1CATrackFinder.cxx index 08afa4422bf19d4df45e58b042e385dda3d36cae..887b191264fa057e03bef51c10cc7479ebd6bd1c 100644 --- a/reco/L1/L1Algo/L1CATrackFinder.cxx +++ b/reco/L1/L1Algo/L1CATrackFinder.cxx @@ -1734,7 +1734,7 @@ void L1Algo::CATrackFinder() fTripletFinalChi2Cut = caIteration.GetTripletFinalChi2Cut(); fPickGather = caIteration.GetPickGather(); //3.0; fTripletLinkChi2 = caIteration.GetTripletLinkChi2(); //5.0; - fMaxInvMom = caIteration.GetMaxInvMom(); //1.0 / 0.5; // max considered q/p + fMaxInvMom = caIteration.GetMaxQp(); //1.0 / 0.5; // max considered q/p fMaxSlopePV = caIteration.GetMaxSlopePV(); //1.1; fMaxSlope = caIteration.GetMaxSlope(); //2.748; // corresponds to 70 grad diff --git a/reco/L1/L1Algo/L1ConfigExample.yaml b/reco/L1/L1Algo/L1ConfigExample.yaml index 4ded80ef8f168d90b8352a320807ca80c8f439d6..dccfe35a95653a7e5e2895d1d5130323e0f18bb3 100644 --- a/reco/L1/L1Algo/L1ConfigExample.yaml +++ b/reco/L1/L1Algo/L1ConfigExample.yaml @@ -12,83 +12,91 @@ l1: # Iterations will be used in the same sequence as they defined below iterations: - name: "TESTFastPrimIter" - track_chi2_cut: 10. - triplet_chi2_cut: 23.4450 - doublet_chi2_cut: 7.56327 - pick_gather: 3.0 - pick_neighbour: 5.0 - min_momentum: 0.5 # GeV/c - max_slope_pv: 1.1 - max_slope: 2.748 - max_dz: 0. # cm - min_start_triplet_lvl: 0 - first_station_index: 0 - target_pos_sigma_x: 1. # cm - target_pos_sigma_y: 1. # cm - is_primary: true - is_electron: false - is_jumped: false - if_extend_tracks: true - if_suppress_ghost: false - is_track_from_triplets: false + min_n_hits: 4 + min_n_hits_sta_0: 3 + track_chi2_cut: 10. + triplet_chi2_cut: 23.4450 + doublet_chi2_cut: 7.56327 + pick_gather: 3.0 + pick_neighbour: 5.0 + max_qp: 2. # (GeV/c)^-1, 1 / 0.5 + max_slope_pv: 1.1 + max_slope: 2.748 + max_dz: 0. # cm + min_start_triplet_lvl: 0 + first_station_index: 0 + target_pos_sigma_x: 1. # cm + target_pos_sigma_y: 1. # cm + is_primary: true + is_electron: false + is_jumped: false + if_extend_tracks: true + if_suppress_ghost: false + is_track_from_triplets: false - name: "AllPrimIter" - track_chi2_cut: 10. - triplet_chi2_cut: 23.4450 - doublet_chi2_cut: 7.56327 - pick_gather: 4.0 - pick_neighbour: 5.0 - min_momentum: 0.05 # GeV/c - max_slope_pv: 1.1 - max_slope: 2.748 - max_dz: 0.1 # cm - min_start_triplet_lvl: 0 - first_station_index: 0 - target_pos_sigma_x: 1. # cm - target_pos_sigma_y: 1. # cm - is_primary: true - is_electron: false - is_jumped: false - if_extend_tracks: true - if_suppress_ghost: false - is_track_from_triplets: false + min_n_hits: 4 + min_n_hits_sta_0: 3 + track_chi2_cut: 10. + triplet_chi2_cut: 23.4450 + doublet_chi2_cut: 7.56327 + pick_gather: 4.0 + pick_neighbour: 5.0 + max_qp: 20. # (GeV/c)^-1, 1 / 0.05 + max_slope_pv: 1.1 + max_slope: 2.748 + max_dz: 0.1 # cm + min_start_triplet_lvl: 0 + first_station_index: 0 + target_pos_sigma_x: 1. # cm + target_pos_sigma_y: 1. # cm + is_primary: true + is_electron: false + is_jumped: false + if_extend_tracks: true + if_suppress_ghost: false + is_track_from_triplets: false - name: "AllPrimJumpIter" - track_chi2_cut: 10. - triplet_chi2_cut: 18.7560 - doublet_chi2_cut: 7.56327 - pick_gather: 4.0 - pick_neighbour: 5.0 - min_momentum: 0.1 # GeV/c - max_slope_pv: 1.1 - max_slope: 2.748 - max_dz: 0.1 # cm - min_start_triplet_lvl: 0 - first_station_index: 0 - target_pos_sigma_x: 5. # cm - target_pos_sigma_y: 5. # cm - is_primary: true - is_electron: false - is_jumped: true - if_extend_tracks: true - if_suppress_ghost: true - is_track_from_triplets: false + min_n_hits: 4 + min_n_hits_sta_0: 4 + track_chi2_cut: 10. + triplet_chi2_cut: 18.7560 + doublet_chi2_cut: 7.56327 + pick_gather: 4.0 + pick_neighbour: 5.0 + max_qp: 10. # (GeV/c)^-1, 1 / 0.1 + max_slope_pv: 1.1 + max_slope: 2.748 + max_dz: 0.1 # cm + min_start_triplet_lvl: 0 + first_station_index: 0 + target_pos_sigma_x: 5. # cm + target_pos_sigma_y: 5. # cm + is_primary: true + is_electron: false + is_jumped: true + if_extend_tracks: true + if_suppress_ghost: true + is_track_from_triplets: false - name: "AllSecIter" - track_chi2_cut: 10. - triplet_chi2_cut: 18.7560 - doublet_chi2_cut: 7.56327 - pick_gather: 4.0 - pick_neighbour: 5.0 - min_momentum: 0.1 # GeV/c - max_slope_pv: 1.5 - max_slope: 2.748 - max_dz: 0.1 # cm - min_start_triplet_lvl: 1 - first_station_index: 0 - target_pos_sigma_x: 10. # cm - target_pos_sigma_y: 10. # cm - is_primary: false - is_electron: false - is_jumped: false - if_extend_tracks: true - if_suppress_ghost: true - is_track_from_triplets: false + min_n_hits: 4 + min_n_hits_sta_0: 4 + track_chi2_cut: 10. + triplet_chi2_cut: 18.7560 + doublet_chi2_cut: 7.56327 + pick_gather: 4.0 + pick_neighbour: 5.0 + max_qo: 10. # (GeV/c)^-1, 1 / 0.1 + max_slope_pv: 1.5 + max_slope: 2.748 + max_dz: 0.1 # cm + min_start_triplet_lvl: 1 + first_station_index: 0 + target_pos_sigma_x: 10. # cm + target_pos_sigma_y: 10. # cm + is_primary: false + is_electron: false + is_jumped: false + if_extend_tracks: true + if_suppress_ghost: true + is_track_from_triplets: false ... diff --git a/reco/L1/L1Algo/L1ConfigRW.cxx b/reco/L1/L1Algo/L1ConfigRW.cxx index 562df5ef82208f2d557121d5da85c2fae064ac1c..1f4fb02bf48813211b8a72d633610e87558ccbdd 100644 --- a/reco/L1/L1Algo/L1ConfigRW.cxx +++ b/reco/L1/L1Algo/L1ConfigRW.cxx @@ -15,7 +15,6 @@ #include <yaml-cpp/yaml.h> -#include "L1CAIteration.h" #include "L1InitManager.h" using namespace std::string_literals; @@ -46,17 +45,10 @@ std::vector<std::string> L1ConfigRW::GetNodeKeys(const YAML::Node& node) const // --------------------------------------------------------------------------------------------------------------------- // -void L1ConfigRW::ReadCAIterations(const YAML::Node& node) +std::vector<L1CAIteration> L1ConfigRW::ReadCAIterations(const YAML::Node& node) const { + std::vector<L1CAIteration> vIters; if (node) { - if (fVerbose > -1) { - LOG(info) << "L1 config: Reading CA tracking iterations sequence. Default iterations will be ignored"; - } - fpInitManager->ClearCAIterations(); - fpInitManager->SetCAIterationsNumberCrosscheck(node.size()); - if (fVerbose > 2) { LOG(info) << "L1 config: " << fVerbose << " CA iterations were recorded"; } - if (fVerbose > 3) { LOG(info) << "L1 config: Recorded iterations:"; } - // Loop over input sub-nodes. Each sub-node corresponds to one L1CAIteration object for (const auto& input : node) { try { @@ -67,7 +59,7 @@ void L1ConfigRW::ReadCAIterations(const YAML::Node& node) caIter.SetDoubletChi2Cut(input["doublet_chi2_cut"].as<float>(caIter.GetDoubletChi2Cut())); caIter.SetPickGather(input["pick_gather"].as<float>(caIter.GetPickGather())); caIter.SetTripletLinkChi2(input["triplet_link_chi2"].as<float>(caIter.GetTripletLinkChi2())); - caIter.SetMaxInvMom(1. / input["min_momentum"].as<float>(caIter.GetMaxInvMom())); + caIter.SetMaxQp(input["max_qp"].as<float>(caIter.GetMaxQp())); caIter.SetMaxSlopePV(input["max_slope_pv"].as<float>(caIter.GetMaxSlopePV())); caIter.SetMaxSlope(input["max_slope"].as<float>(caIter.GetMaxSlope())); caIter.SetMaxDZ(input["max_dz"].as<float>(caIter.GetMaxDZ())); @@ -79,10 +71,10 @@ void L1ConfigRW::ReadCAIterations(const YAML::Node& node) caIter.SetTrackFromTripletsFlag(input["is_track_from_triplets"].as<bool>(caIter.GetTrackFromTripletsFlag())); caIter.SetExtendTracksFlag(input["if_extend_tracks"].as<bool>(caIter.GetExtendTracksFlag())); caIter.SetJumpedFlag(input["is_jumped"].as<bool>(caIter.GetJumpedFlag())); - caIter.SetMinNhits(input["min_n_hits"].as<bool>(caIter.GetMinNhits())); - caIter.SetMinNhitsStation0(input["min_n_hits_sta_0"].as<bool>(caIter.GetMinNhitsStation0())); + caIter.SetMinNhits(input["min_n_hits"].as<int>(caIter.GetMinNhits())); + caIter.SetMinNhitsStation0(input["min_n_hits_sta_0"].as<int>(caIter.GetMinNhitsStation0())); if (fVerbose > 3) { LOG(info) << "L1 config:\n" << caIter.ToString(1); } - fpInitManager->PushBackCAIteration(caIter); + vIters.push_back(caIter); } catch (const YAML::InvalidNode& exc) { const auto nodeKeys = this->GetNodeKeys(input); @@ -94,10 +86,7 @@ void L1ConfigRW::ReadCAIterations(const YAML::Node& node) } } // Loop over input sub-nodes: end } - else { - LOG(warn) << "L1 config: CA tracking iterations sequence was not found in the parameters file, default will be " - << "used. To define iterations please use the following path in the YAML file: l1/algorithm/iterations"; - } + return vIters; } // --------------------------------------------------------------------------------------------------------------------- @@ -117,7 +106,31 @@ void L1ConfigRW::ReadYaml(const std::string& filename) } // Tracking iterations - this->ReadCAIterations(config["l1"]["algorithm"]["iterations"]); + this->InitCAIterations(config["l1"]["algorithm"]["iterations"]); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void L1ConfigRW::InitCAIterations(const YAML::Node& node) +{ + assert(fpInitManager); // Class itself can be used without the init manager, but this function cannot + auto vIters = this->ReadCAIterations(node); + if (vIters.size()) { + if (fVerbose > -1) { + LOG(info) << "L1 config: Reading CA tracking iterations sequence. Default iterations will be ignored"; + } + fpInitManager->ClearCAIterations(); + fpInitManager->SetCAIterationsNumberCrosscheck(vIters.size()); + if (fVerbose > 2) { LOG(info) << "L1 config: " << fVerbose << " CA iterations were recorded"; } + if (fVerbose > 3) { LOG(info) << "L1 config: Recorded iterations:"; } + for (const auto& caIter : vIters) { + fpInitManager->PushBackCAIteration(caIter); + } + } + else { + LOG(warn) << "L1 config: CA tracking iterations sequence was not found in the parameters file, default will be " + << "used. To define iterations please use the following path in the YAML file: l1/algorithm/iterations"; + } } // --------------------------------------------------------------------------------------------------------------------- diff --git a/reco/L1/L1Algo/L1ConfigRW.h b/reco/L1/L1Algo/L1ConfigRW.h index accde1d92cdda9e78d943cc742983a4173c0691a..0a1a16f40a45191d096d9d5d2c09c3cc2af17881 100644 --- a/reco/L1/L1Algo/L1ConfigRW.h +++ b/reco/L1/L1Algo/L1ConfigRW.h @@ -13,6 +13,8 @@ #include <string> #include <vector> +#include "L1CAIteration.h" + namespace YAML { class Node; @@ -37,10 +39,15 @@ public: /// \param filename Name of the configuration file void WriteYaml(const std::string& filename); -private: /// Reads CA track finder iterations from YAML node - /// \param node YAML node - void ReadCAIterations(const YAML::Node& node); + /// \param node YAML node containing the iterations + /// \return A vector of iterations + std::vector<L1CAIteration> ReadCAIterations(const YAML::Node& node) const; + +private: + /// Calls CA track finder iterations reader and initialize the iterations in the init manager + /// \param node YAML node containing the iterations + void InitCAIterations(const YAML::Node& node); /// Gets parameters content of the node /// \param node YAML node diff --git a/reco/L1/L1Algo/L1InitManager.cxx b/reco/L1/L1Algo/L1InitManager.cxx index 9da08993deeb53ea96d0a3f0048b61b90a9a0acd..dfd1e5eda6f56113924e872588b38f07d7235ab8 100644 --- a/reco/L1/L1Algo/L1InitManager.cxx +++ b/reco/L1/L1Algo/L1InitManager.cxx @@ -10,6 +10,7 @@ #include <boost/archive/binary_iarchive.hpp> #include <boost/archive/binary_oarchive.hpp> +#include <boost/archive/text_iarchive.hpp> #include <algorithm> #include <fstream> @@ -261,12 +262,12 @@ void L1InitManager::PushBackCAIteration(const L1CAIteration& iteration) void L1InitManager::ReadParametersObject(const std::string& fileName) { // Open input binary file - std::ifstream ifs(fileName, std::ios::binary); + std::ifstream ifs(fileName); if (!ifs) { LOG(fatal) << "L1InitManager: parameters data file \"" << fileName << "\" was not found"; } // Get L1InputData object try { - boost::archive::binary_iarchive ia(ifs); + boost::archive::text_iarchive ia(ifs); ia >> fParameters; } catch (const std::exception&) { @@ -279,12 +280,15 @@ 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); + std::ifstream ifs(fileName); if (!ifs) { LOG(fatal) << "L1InitManager: search window file \"" << fileName << "\" was not found"; } try { - boost::archive::binary_iarchive ia(ifs); + boost::archive::text_iarchive ia(ifs); + int nPars = -1; int nWindows = -1; + ia >> nPars; + assert(nPars == 1); // Currently only the constant windows are available ia >> nWindows; std::stringstream errMsg; for (int iW = 0; iW < nWindows; ++iW) { diff --git a/reco/L1/L1Algo/L1Parameters.cxx b/reco/L1/L1Algo/L1Parameters.cxx index 876a9bc5da0425d9f302c8d6e608ab232478665c..2b98dcc874a827a358ff522e7cbfdd227681de7d 100644 --- a/reco/L1/L1Algo/L1Parameters.cxx +++ b/reco/L1/L1Algo/L1Parameters.cxx @@ -279,7 +279,16 @@ std::string L1Parameters::ToString(int verbosity, int indentLevel) const 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 + + if (fDevIsParSearchWUsed) { + aStream << indent << "SEARCH WINDOWS:\n"; + for (int iSt = 1; iSt < fNstationsActiveTotal; ++iSt) { + for (int iIter = 0; iIter < (int) fCAIterations.size(); ++iIter) { + aStream << indent << "- station: " << iSt << ", iteration: " << iIter << '\n'; + aStream << GetSearchWindow(iSt, iIter).ToString() << '\n'; + } + } + } aStream << indent << "--------------------------------------------------------------------------------------------------\n"; diff --git a/reco/L1/L1Algo/L1Parameters.cxx.orig b/reco/L1/L1Algo/L1Parameters.cxx.orig deleted file mode 100644 index 768656ee986c272ddc898a13267220a0653fec61..0000000000000000000000000000000000000000 --- a/reco/L1/L1Algo/L1Parameters.cxx.orig +++ /dev/null @@ -1,360 +0,0 @@ -/* 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 a86d09947c2a5ec2b8ee1c9005126a43a6c88842..e49462ed83b4f5e9718a5015628b9d838705d95d 100644 --- a/reco/L1/L1Algo/L1Parameters.h +++ b/reco/L1/L1Algo/L1Parameters.h @@ -63,7 +63,7 @@ public: L1Parameters(L1Parameters&& other) noexcept = default; /// Move assignment operator - L1Parameters& operator=(L1Parameters&& other) noexcept = default; + L1Parameters& operator=(L1Parameters&& other) = default; /// Prints configuration void Print(int verbosityLevel = 0) const; @@ -140,6 +140,8 @@ public: /// \param iTrackGr Index of a track group const L1SearchWindow& GetSearchWindow(int iStation, int iTrackGr) const { + assert(iStation < fNstationsActiveTotal && iStation > 0); + assert(iTrackGr < int(fCAIterations.size())); return fSearchWindows[iTrackGr * L1Constants::size::kMaxNstations + iStation]; } diff --git a/reco/L1/L1Algo/L1SearchWindow.cxx b/reco/L1/L1Algo/L1SearchWindow.cxx index c7418a58efa62cf3e8f46f67f9e9cb8b902b3313..ee92ae19ec764e3db6ced0a8fc4b3d9adae1b1c1 100644 --- a/reco/L1/L1Algo/L1SearchWindow.cxx +++ b/reco/L1/L1Algo/L1SearchWindow.cxx @@ -4,6 +4,7 @@ #include "L1SearchWindow.h" +#include <cassert> #include <iomanip> #include <sstream> @@ -22,7 +23,7 @@ L1SearchWindow::L1SearchWindow(int stationID, int trackGrID) : fStationID(statio // this class is supposed to be used inside the algorithm core // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDxMaxVsX0(int id, float val) +void L1SearchWindow::SetParamDxMaxVsX0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDxMaxVsX0 * kNpars + id] = val; @@ -30,7 +31,7 @@ void SetParamDxMaxVsX0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDxMinVsX0(int id, float val) +void L1SearchWindow::SetParamDxMinVsX0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDxMinVsX0 * kNpars + id] = val; @@ -38,7 +39,7 @@ void SetParamDxMinVsX0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDxMaxVsY0(int id, float val) +void L1SearchWindow::SetParamDxMaxVsY0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDxMaxVsY0 * kNpars + id] = val; @@ -46,7 +47,7 @@ void SetParamDxMaxVsY0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDxMinVsY0(int id, float val) +void L1SearchWindow::SetParamDxMinVsY0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDxMinVsY0 * kNpars + id] = val; @@ -54,7 +55,7 @@ void SetParamDxMinVsY0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDyMaxVsX0(int id, float val) +void L1SearchWindow::SetParamDyMaxVsX0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDyMaxVsX0 * kNpars + id] = val; @@ -62,7 +63,7 @@ void SetParamDyMaxVsX0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDyMinVsX0(int id, float val) +void L1SearchWindow::SetParamDyMinVsX0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDyMinVsX0 * kNpars + id] = val; @@ -70,7 +71,7 @@ void SetParamDyMinVsX0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDyMaxVsY0(int id, float val) +void L1SearchWindow::SetParamDyMaxVsY0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDyMaxVsY0 * kNpars + id] = val; @@ -78,7 +79,7 @@ void SetParamDyMaxVsY0(int id, float val) // --------------------------------------------------------------------------------------------------------------------- // -void SetParamDyMinVsY0(int id, float val) +void L1SearchWindow::SetParamDyMinVsY0(int id, float val) { assert(id > -1 && id < kNpars); fvParams[kDyMinVsY0 * kNpars + id] = val; @@ -91,7 +92,7 @@ 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 << "\ttracks group ID: " << fTrackGroupID << '\n'; msg << "\tparameters:\n"; msg << "\t\t" << std::setw(6) << std::setfill(' ') << "No." << ' '; msg << std::setw(12) << std::setfill(' ') << "dx_max(x0)" << ' '; diff --git a/reco/L1/L1Algo/L1SearchWindow.h b/reco/L1/L1Algo/L1SearchWindow.h index 13dc50c0d910495f3b276b54f9f3ab509e263201..98899d9ce4d85d5201c2a54515adab51ede5b9d0 100644 --- a/reco/L1/L1Algo/L1SearchWindow.h +++ b/reco/L1/L1Algo/L1SearchWindow.h @@ -11,6 +11,7 @@ #define L1SearchWindow_h 1 #include <boost/serialization/array.hpp> +#include <boost/serialization/string.hpp> #include <array> #include <string> @@ -39,7 +40,7 @@ public: L1SearchWindow& operator=(const L1SearchWindow& other) = default; /// Move constructor - L1SearchWindow(L1SearchWindow&& other) = default; + L1SearchWindow(L1SearchWindow&& other) noexcept = default; /// Move assignment operator L1SearchWindow& operator=(L1SearchWindow&& other) = default; @@ -75,6 +76,9 @@ public: /// Gets track group id int GetTrackGroupID() const { return fTrackGroupID; } + /// Sets tag + /// A tag can be used for insurance, if this search window corresponds to a desired track finder iteration + void SetTag(const char* name) { fsTag = name; } /// TODO: SZh 08.11.2022: Implement variadic template function /// TODO: SZh 08.11.2022: Try to reduce number of functions @@ -151,7 +155,7 @@ private: 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?) + std::string fsTag = ""; ///< Tag, containing information on the tracks group (TODO: can be omitted?) /// Serialization function friend class boost::serialization::access; @@ -161,6 +165,7 @@ private: ar& fvParams; ar& fStationID; ar& fTrackGroupID; + ar& fsTag; } }; diff --git a/reco/L1/catools/CaToolsWFExpression.cxx b/reco/L1/catools/CaToolsWFExpression.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7f9fbd2aa39a5365b9f8578ef0991598def5ff57 --- /dev/null +++ b/reco/L1/catools/CaToolsWFExpression.cxx @@ -0,0 +1,211 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + + +#include "CaToolsWFExpression.h" + +#include "Logger.h" + +#include "TBox.h" +#include "TF1.h" +#include "TGraph.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TPad.h" +#include "TTree.h" + +#include <algorithm> + +using namespace ca::tools; + +// --------------------------------------------------------------------------------------------------------------------- +// +WFExpression::WFExpression(TTree* pTree, const char* exprDist, const char* exprParam) + : fpTree(pTree) + , fsExprDist(exprDist) + , fsExprParam(exprParam) +{ + // Assertions + // TODO: SZh 11.11.2022: REPLACE ALL THE ASSERTIONS WITH EXCEPTIONS!!!! + assert(fsExprDist.Length()); + assert(fsExprParam.Length()); + assert(fpTree); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::tuple<std::vector<float>, std::vector<float>> WFExpression::CalculateParameters() +{ + // Check, if data were initialized + assert(fpPadBase); + assert(fpPadSlices); + + // Unique name, used to access a histogram + fsName = Form("%s:%s_%s", fsExprDist.Data(), fsExprParam.Data(), fCut.GetTitle()); + fsName.ReplaceAll(" ", ""); + + // Expression to be drawn from the tree + TString sExpr = Form("%s:%s>>htemp(%d,,,%d)", fsExprDist.Data(), fsExprParam.Data(), fNbinsParam, fNbinsDist); + + // Get base distribution + fpPadBase->cd(); + fpTree->Draw(sExpr.Data(), fCut, "colz"); + fpHistBase = (TH2F*) gPad->GetPrimitive("htemp"); + fpHistBase->Sumw2(); + fpHistBase->SetStats(kFALSE); + fpHistBase->SetName(fsName); + fpHistBase->SetTitle(fsTitle); + + // Create slices + int sliceSize = fNbinsParam / fNslices; + fpPadSlices->cd(); + fpPadSlices->Divide(fNslices == 1 ? 1 : 2, (fNslices + 1) / 2); + + /// Vectors to store the upper and lower boundaries from each slice + for (int iS = 0; iS < fNslices; ++iS) { + fpPadSlices->cd(iS + 1); + int iBinMin = sliceSize * iS; + int iBinMax = sliceSize * (iS + 1) - 1; + std::tie(fvLoSBoundaries[iS], fvUpSBoundaries[iS], fvSCenters[iS]) = ProcessSlice(iBinMin, iBinMax); + assert(fvLoSBoundaries[iS] <= fvUpSBoundaries[iS]); + } + + // Draw edges, obtained for different slices + fpPadBase->cd(); + TGraph* pGrUpper = new TGraph(fNslices, fvSCenters.data(), fvUpSBoundaries.data()); + pGrUpper->SetMarkerColor(kOrange + 2); + pGrUpper->SetMarkerStyle(20); + pGrUpper->Draw("PSAME"); + TGraph* pGrLower = new TGraph(fNslices, fvSCenters.data(), fvLoSBoundaries.data()); + pGrLower->SetMarkerColor(kOrange + 2); + pGrLower->SetMarkerStyle(20); + pGrLower->Draw("PSAME"); + + // Get window parameters + GetConstWindowParams(); + + return std::tie(fvLoParams, fvUpParams); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::tuple<float, float, float> WFExpression::ProcessSlice(int iBinMin, int iBinMax) +{ + // ----- Create a slice + assert(iBinMin <= iBinMax); + float lEdge = fpHistBase->GetXaxis()->GetBinLowEdge(iBinMin + 1); + float uEdge = fpHistBase->GetXaxis()->GetBinUpEdge(iBinMax + 1); + float sliceCenter = (lEdge + uEdge) * 0.5; + const char* parTitle = fpHistBase->GetXaxis()->GetTitle(); + TString sSliceTitle = Form("%.2f < %s < %.2f (bins %d-%d)", lEdge, parTitle, uEdge, iBinMin, iBinMax); + TString sSliceName = Form("%s_slice%d-%d", fpHistBase->GetName(), iBinMin, iBinMax); + TH1F* pHistSlice = (TH1F*) fpHistBase->ProjectionY(sSliceName, iBinMin, iBinMax); + pHistSlice->SetTitle(sSliceTitle); + + // Slice drawing attributes + constexpr float maximumScale = 1.1; + pHistSlice->SetMaximum(pHistSlice->GetMaximum() * maximumScale); + pHistSlice->Draw(""); + + // ----- Find selection boundaries + // A simple algorithm, which finds boundaries containing eps/2 entries to the left and right from the central region. + int contentL = 0; + int contentR = 0; + float windowMin = 0.f; + float windowMax = 0.f; + float nEntriesTot = pHistSlice->GetEntries(); + + // left side + for (int iBin = 1; contentL < nEntriesTot * fEps * 0.5; ++iBin) { + windowMin = pHistSlice->GetXaxis()->GetBinLowEdge(iBin); + contentL += pHistSlice->GetBinContent(iBin); + } + + // right side + for (int iBin = pHistSlice->GetXaxis()->GetNbins(); contentR < nEntriesTot * fEps * 0.5; --iBin) { + windowMax = pHistSlice->GetXaxis()->GetBinUpEdge(iBin); + contentR += pHistSlice->GetBinContent(iBin); + } + + // ----- Draw selection box on the histogram + TBox* pWindowBox = new TBox(windowMin, pHistSlice->GetMinimum(), windowMax, pHistSlice->GetMaximum()); + pWindowBox->SetFillColor(kGreen); + pWindowBox->Draw("SAME"); + pHistSlice->Draw("SAME"); + + return std::tie(windowMin, windowMax, sliceCenter); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WFExpression::GetConstWindowParams() +{ + assert(kNpars == 1); // Cannot be used for a different number of parameters + assert(fvUpParams.size() == 1); + assert(fvLoParams.size() == 1); + // In case of several slices we select the most outlying point as a boundary of the window + fvUpParams[0] = *(std::max_element(fvUpSBoundaries.begin(), fvUpSBoundaries.end())); + fvLoParams[0] = *(std::min_element(fvLoSBoundaries.begin(), fvLoSBoundaries.end())); + + // ----- Draw the estimated parameterisations + fpPadBase->cd(); + float xMin = fpHistBase->GetXaxis()->GetBinLowEdge(1); + float xMax = fpHistBase->GetXaxis()->GetBinUpEdge(fpHistBase->GetXaxis()->GetNbins()); + TF1* fMin = new TF1("fMin", "[0]", xMin, xMax); + fMin->SetParameter(0, fvLoParams[0]); + fMin->SetLineColor(kOrange + 2); + fMin->Draw("LSAME"); + TF1* fMax = new TF1("fMax", "[0]", xMin, xMax); + fMax->SetParameter(0, fvUpParams[0]); + fMax->SetLineColor(kOrange + 2); + fMax->Draw("LSAME"); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WFExpression::SetEps(float eps) +{ + assert(eps > 0 && eps < 1.0); + fEps = eps; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WFExpression::SetNslices(int nSlices) +{ + assert(nSlices > 0); + fNslices = nSlices; + fvUpSBoundaries.clear(); + fvLoSBoundaries.clear(); + fvSCenters.clear(); + fvUpSBoundaries.resize(fNslices); + fvLoSBoundaries.resize(fNslices); + fvSCenters.resize(fNslices); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WFExpression::SetNbins(int nBinsDist, int nBinsParam) +{ + assert(nBinsDist > 0); + assert(nBinsParam > 0); + fNbinsDist = nBinsDist; + fNbinsParam = nBinsParam; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WFExpression::SetPadBase(TPad* pad) +{ + assert(pad); + fpPadBase = pad; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WFExpression::SetPadSlices(TPad* pad) +{ + assert(pad); + fpPadSlices = pad; +} diff --git a/reco/L1/catools/CaToolsWFExpression.h b/reco/L1/catools/CaToolsWFExpression.h new file mode 100644 index 0000000000000000000000000000000000000000..99bd7f7e8bb94d89b8d7ffcbb42b4831925763af --- /dev/null +++ b/reco/L1/catools/CaToolsWFExpression.h @@ -0,0 +1,131 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergey Gorbunov, Sergei Zharko [committer] */ + +#ifndef CaToolsWFExpression_h +#define CaToolsWFExpression_h 1 + +#include "TCut.h" +#include "TString.h" + +#include <cassert> +#include <tuple> +#include <vector> + +class TTree; +class TH2F; +class TPad; + +namespace ca +{ + namespace tools + { + /// A helper class for ca::tools::WindowFinder to handle a particular expression (dx vs. x0 etc.) and all related + /// methods to work with it. + /// \note DISTANCE (expression, axis) -- dx or dy, signed distance between the extrapolated point and real MC-point + /// PARAMETER (expression, axis) -- x0 or y0, a parameter, vs. which the distance is studied + class WFExpression { + public: + static constexpr int kNpars = 1; /// TMP: number of parameters + + /// Default constructor + WFExpression() = delete; + + /// Constructor + /// \param pChain A pointer to a tree with MC triplets + /// \param exprDist Expression for distance + /// \param exprParam Expression for parameter + WFExpression(TTree* pTree, const char* exprDist, const char* exprParam); + + /// Copy constructor + WFExpression(const WFExpression& other) = delete; + + /// Move constructor + WFExpression(WFExpression&& other) = delete; + + /// Destructor + ~WFExpression() = default; + + /// Copy assignment operator + WFExpression& operator=(const WFExpression& other) = delete; + + /// Move assignment operator + WFExpression& operator=(WFExpression&& other) = delete; + + /// Calculates parameters + /// \param pTree Pointer to a tree with MC triplets + /// \return A tuple: + /// - vector of parameters for upper bound + /// - vector of parameters for lower bound + std::tuple<std::vector<float>, std::vector<float>> CalculateParameters(); + + /// Sets cut, including information on the station and track finder iteration + void SetCut(const TCut& cut) { fCut = cut; } + + /// Sets fraction of the events, which can be left out of boundaries + void SetEps(float eps); + + /// Sets number of slices + void SetNslices(int nSlices); + + /// Sets number of bins + /// \param nBinsDist Number of bins along the distance axis + /// \param nBinsParam Number of bins along the parameter axis + void SetNbins(int nBinsDist, int nBinsParam); + + /// Sets base pad pointer + void SetPadBase(TPad* pad); + + /// Sets slices pad pointer + void SetPadSlices(TPad* pad); + + /// Sets title of the histograms + void SetTitle(const char* title) { fsTitle = title; } + + private: + // ***************************** + // ** Private class functions ** + // ***************************** + + /// Process slice + /// \param iBinMax Max bin of the parameter axis to start a projection (date from the bin are included) + /// \return Tuple: lower bound, upper bound, slice center + std::tuple<float, float, float> ProcessSlice(int iBinMin, int iBinMax); + + /// Gets window parameterisations assuming there is no dependence from parameter + void GetConstWindowParams(); + // TODO: use other functions for other window shapes: GetParabWindowParams, GetEllipticWindowParams etc. + + + // ********************* + // ** Class variables ** + // ********************* + TTree* fpTree = nullptr; ///< Tree to be analyzed + TH2F* fpHistBase = nullptr; ///< Base histogram (distance vs. parameter (x0 or y0)) + + TString fsExprDist = ""; ///< Expression along the distance axis + TString fsExprParam = ""; ///< Expression along the parameter axis + + TCut fCut = ""; ///< Cut used to draw and expression + int fNslices = 8; ///< Number of slices along the parameter axis + float fEps = 0.0005; ///< A fraction of triplets, which can be lost + + + std::vector<float> fvUpSBoundaries = std::vector<float>(fNslices); ///< Upper boundaries for diff. slices + std::vector<float> fvLoSBoundaries = std::vector<float>(fNslices); ///< Lower boundaries for diff. slices + std::vector<float> fvSCenters = std::vector<float>(fNslices); ///< Slice centers + std::vector<float> fvUpParams = std::vector<float>(kNpars); ///< Parameters for max + std::vector<float> fvLoParams = std::vector<float>(kNpars); ///< Parameters for min + + // ----- Plotting options + int fNbinsParam = 400; ///< Number of bins along the parameter axis + int fNbinsDist = 400; ///< Number of bins along the distance axis + TString fsTitle = ""; ///< Title of expression + TString fsName = ""; ///< Name of the expression (expr + cut, must be unique!!, TODO: make a check) + TPad* fpPadBase = nullptr; ///< Pointer to a pad for base histogram + TPad* fpPadSlices = nullptr; ///< Pointer to a pad for slices + }; + } // namespace tools +} // namespace ca + +#endif // CaToolsWFExpression_h diff --git a/reco/L1/catools/CaToolsWindowFinder.cxx b/reco/L1/catools/CaToolsWindowFinder.cxx index d663c7cc5bd78b0e2dfd9fc0b21b4c00904cf814..a46a424349644c7f438ef353453de6b98c699b79 100644 --- a/reco/L1/catools/CaToolsWindowFinder.cxx +++ b/reco/L1/catools/CaToolsWindowFinder.cxx @@ -9,11 +9,25 @@ #include "CaToolsWindowFinder.h" -#include <Logger.h> +#include "Logger.h" +#include "TCanvas.h" #include "TChain.h" +#include "TPad.h" +#include "TPaveText.h" +#include "TString.h" +#include <boost/archive/text_oarchive.hpp> + +#include <fstream> +#include <sstream> + +#include <yaml-cpp/yaml.h> + +#include "CaToolsWFExpression.h" +#include "L1ConfigRW.h" #include "L1Constants.h" +#include "L1SearchWindow.h" using namespace ca::tools; using namespace L1Constants::clrs; // for colored logs @@ -41,7 +55,237 @@ void WindowFinder::AddInputFile(const char* filename) // --------------------------------------------------------------------------------------------------------------------- // -void WindowFinder::Process(EBuildingMode) { fpMcTripletsTree->Draw("zv"); } +L1SearchWindow WindowFinder::CreateSW(int iStation, const L1CAIteration& caIter) +{ + + // Get a cut + TCut cut = GetTrackSelectionCut(iStation, caIter); + + if (TString(fExtraCut.GetTitle()).Length()) { cut = cut && fExtraCut; } + + // Set a unique to a canvas using the cut expression + TString sUniqueName = cut.GetTitle(); + sUniqueName.ReplaceAll(" ", ""); + + // Prepare a canvas and pads to draw the histograms + TString canvName = TString("canv_") + sUniqueName; + TCanvas* canv = new TCanvas(canvName, canvName, 3000, 2000); + fvpCanvases.push_back(canv); // Register canvas + + // Pads for base distributions + TPad* padBase[EExpr::kEND]; /// dx vs. x0, dx vs. y0, dy vs. x0, dy vs. y0 + padBase[EExpr::kDxVsX0] = new TPad("padBase_dx_x0", "padBase_dx_x0", 0.00, 0.50, 0.25, 0.80); + padBase[EExpr::kDxVsY0] = new TPad("padBase_dx_y0", "padBase_dx_y0", 0.25, 0.50, 0.50, 0.80); + padBase[EExpr::kDyVsX0] = new TPad("padBase_dy_x0", "padBase_dy_x0", 0.50, 0.50, 0.75, 0.80); + padBase[EExpr::kDyVsY0] = new TPad("padBase_dy_y0", "padBase_dy_y0", 0.75, 0.50, 1.00, 0.80); + + // Pads for slices + TPad* padSlices[EExpr::kEND]; /// projections + padSlices[EExpr::kDxVsX0] = new TPad("padSlices_dx_x0", "padSlices_dx_x0", 0.00, 0.00, 0.25, 0.50); + padSlices[EExpr::kDxVsY0] = new TPad("padSlices_dx_y0", "padSlices_dx_y0", 0.25, 0.00, 0.50, 0.50); + padSlices[EExpr::kDyVsX0] = new TPad("padSlices_dy_x0", "padSlices_dy_x0", 0.50, 0.00, 0.75, 0.50); + padSlices[EExpr::kDyVsY0] = new TPad("padSlices_dy_y0", "padSlices_dy_y0", 0.75, 0.00, 1.00, 0.50); + + for (int iExpr = 0; iExpr < EExpr::kEND; ++iExpr) { + padSlices[iExpr]->Draw(); + padBase[iExpr]->Draw(); + } + + // A pad for text + TPad* padDescr = new TPad("padDescr", "padDescr", 0.00, 0.80, 1.00, 1.00); /// Definitions of dx and dy, cut + padDescr->Draw(); + + PrintCaseInformation(padDescr, iStation, caIter); + + + // Process expressions + WFExpression exprDxVsX0(fpMcTripletsTree, GetDistExpr(EExpr::kDxVsX0), "x0"); + exprDxVsX0.SetEps(fEps); + exprDxVsX0.SetNbins(fNbinsY, fNbinsX); + exprDxVsX0.SetNslices(fNslices); + exprDxVsX0.SetCut(cut); + exprDxVsX0.SetTitle("dx vs. x0;x0 [cm];dx [cm]"); + exprDxVsX0.SetPadBase(padBase[EExpr::kDxVsX0]); + exprDxVsX0.SetPadSlices(padSlices[EExpr::kDxVsX0]); + + WFExpression exprDxVsY0(fpMcTripletsTree, GetDistExpr(EExpr::kDxVsY0), "y0"); + exprDxVsY0.SetEps(fEps); + exprDxVsY0.SetNbins(fNbinsY, fNbinsX); + exprDxVsY0.SetNslices(fNslices); + exprDxVsY0.SetCut(cut); + exprDxVsY0.SetTitle("dx vs. y0;y0 [cm];dx [cm]"); + exprDxVsY0.SetPadBase(padBase[EExpr::kDxVsY0]); + exprDxVsY0.SetPadSlices(padSlices[EExpr::kDxVsY0]); + + WFExpression exprDyVsX0(fpMcTripletsTree, GetDistExpr(EExpr::kDyVsX0), "x0"); + exprDyVsX0.SetEps(fEps); + exprDyVsX0.SetNbins(fNbinsY, fNbinsX); + exprDyVsX0.SetNslices(fNslices); + exprDyVsX0.SetCut(cut); + exprDyVsX0.SetTitle("dy vs. x0;x0 [cm];dy [cm]"); + exprDyVsX0.SetPadBase(padBase[EExpr::kDyVsX0]); + exprDyVsX0.SetPadSlices(padSlices[EExpr::kDyVsX0]); + + WFExpression exprDyVsY0(fpMcTripletsTree, GetDistExpr(EExpr::kDyVsY0), "y0"); + exprDyVsY0.SetEps(fEps); + exprDyVsY0.SetNbins(fNbinsY, fNbinsX); + exprDyVsY0.SetNslices(fNslices); + exprDyVsY0.SetCut(cut); + exprDyVsY0.SetTitle("dy vs. y0;y0 [cm];dy [cm]"); + exprDyVsY0.SetPadBase(padBase[EExpr::kDyVsY0]); + exprDyVsY0.SetPadSlices(padSlices[EExpr::kDyVsY0]); + + auto [parsUpperDxVsX0, parsLowerDxVsX0] = exprDxVsX0.CalculateParameters(); + auto [parsUpperDxVsY0, parsLowerDxVsY0] = exprDxVsY0.CalculateParameters(); + auto [parsUpperDyVsX0, parsLowerDyVsX0] = exprDyVsX0.CalculateParameters(); + auto [parsUpperDyVsY0, parsLowerDyVsY0] = exprDyVsY0.CalculateParameters(); + + // Prepare a searching window + int iCaIter = &caIter - &fvCaIters[0]; + L1SearchWindow sw(iStation, iCaIter); + sw.SetTag(caIter.GetName().c_str()); + assert(fNparams == 1); // TMP: At the moment only constant windows available + for (int iP = 0; iP < fNparams; ++iP) { + sw.SetParamDxMaxVsX0(iP, parsUpperDxVsX0[iP]); + sw.SetParamDxMinVsX0(iP, parsLowerDxVsX0[iP]); + sw.SetParamDxMaxVsY0(iP, parsUpperDxVsY0[iP]); + sw.SetParamDxMinVsY0(iP, parsLowerDxVsY0[iP]); + sw.SetParamDyMaxVsX0(iP, parsUpperDyVsX0[iP]); + sw.SetParamDyMinVsX0(iP, parsLowerDyVsX0[iP]); + sw.SetParamDyMaxVsY0(iP, parsUpperDyVsY0[iP]); + sw.SetParamDyMinVsY0(iP, parsLowerDyVsY0[iP]); + } + return sw; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::DumpCanvasesToPdf(const char* filename) const +{ + for (int iC = 0; iC < (int) fvpCanvases.size(); ++iC) { + TString sCanvName = Form("%s_%d.pdf", filename, iC); + fvpCanvases[iC]->SaveAs(sCanvName); + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +const char* WindowFinder::GetDistExpr(EExpr expr) const +{ + assert(fTargetPos[0] == 0); + assert(fTargetPos[1] == 0); + switch (expr) { + case EExpr::kDxVsX0: + case EExpr::kDxVsY0: return Form("x1 - x0 * (z1 - (%f)) / (z0 - (%f))", fTargetPos[2], fTargetPos[2]); + case EExpr::kDyVsX0: + case EExpr::kDyVsY0: return Form("y1 - y0 * (z1 - (%f)) / (z0 - (%f))", fTargetPos[2], fTargetPos[2]); + default: return ""; // TODO: throw an exception + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// TODO: SZh 10.11.2022: Should it be a static function?? +TCut WindowFinder::GetTrackSelectionCut(int iStation, const L1CAIteration& caIter) const +{ + TCut cut; + + // Select station + // NOTE: iStation stands for global index of an active tracking station for which a searching window is estimated. + // In the MC triplets tree the station index ("s") is stored for the left station of the triplet. Thus, for + // doublets the station is to be selected as "iStation - 1" (search window is estimated on the middle station), + // and as "iStation - 2" for the triplets (search window is estimated on the right station). + cut = cut && Form("s==%d", iStation - 1); + + // Select q/p + cut = cut && Form("abs(q/p)<%f", caIter.GetMaxQp()); + + // Select origin (primary/secondary) + cut = cut && (caIter.GetPrimaryFlag() ? "processId==0" : "processId!=0"); + + // TODO: SZh 10.11.2022: Try to apply other cuts (electron, slope etc.) + return cut; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::PrintCaseInformation(TPad* pPad, int iStation, const L1CAIteration& caIter) const +{ + pPad->cd(); + + TPaveText* textL = new TPaveText(0.01, 0.01, 0.49, 0.99); + textL->SetBorderSize(1); + textL->SetTextFont(42); + textL->SetFillColor(kWhite); + textL->SetTextAlign(11); + textL->SetTextSize(0.1); + textL->AddText(Form("Global index of active station: %d", iStation)); + textL->AddText(Form("Track finder iteration: %s", caIter.GetName().c_str())); + textL->AddText(Form(" - |q/p| < %.2f e(Gev/c)^{-1}", caIter.GetMaxQp())); + textL->AddText(Form(" - primary: %s", caIter.GetPrimaryFlag() ? "yes" : "no")); + if (TString(fExtraCut.GetTitle()).Length()) { textL->AddText(Form("Optional cut: %s", fExtraCut.GetTitle())); } + textL->Draw(); + + TPaveText* textR = new TPaveText(0.51, 0.01, 0.99, 0.99); + textR->SetBorderSize(1); + textR->SetTextFont(42); + textR->SetTextAlign(11); + textR->SetTextSize(0.1); + textR->SetFillColor(kWhite); + textR->AddText("Distance expressions:"); + textR->AddText(Form(" dx = %s", GetDistExpr(EExpr::kDxVsY0))); + textR->AddText(Form(" dy = %s", GetDistExpr(EExpr::kDyVsY0))); + + textR->Draw(); + //pPad->Draw(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::Process(Option_t* /*opt*/) +{ + std::ofstream ofs(fsOutputName); + if (!ofs) { + LOG(error) << "WindowFinder: failed opening file \"" << fsOutputName << " for writing search windows\""; + return; + } + + boost::archive::text_oarchive oa(ofs); + oa << fNparams; + oa << int(fvStationIndexes.size() * fvCaIters.size()); + for (auto iStation : fvStationIndexes) { + for (const auto& iter : fvCaIters) { + LOG(info) << "WindowFinder: processing global active station index " << kCLb << iStation << kCL + << " and track finder iteration " << kCLb << iter.GetName() << kCL; + auto sw = CreateSW(iStation, iter); + oa << sw; + } + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::ReadTrackingIterationsFromYAML(const char* filename) +{ + L1ConfigRW reader(/*pInitManager = */ nullptr, 0); + YAML::Node config; + try { + config = YAML::LoadFile(filename); + } + catch (const YAML::BadFile& exc) { + throw std::runtime_error("file does not exist"); + } + catch (const YAML::ParserException& exc) { + throw std::runtime_error("file is formatted improperly"); + } + + // Get iterations + fvCaIters = reader.ReadCAIterations(config["l1"]["algorithm"]["iterations"]); + + // Print iterations: + for (const auto& iter : fvCaIters) { + LOG(info) << iter.ToString() << '\n'; + } +} // **************************** @@ -74,6 +318,21 @@ void WindowFinder::SetNslices(int nSlices) fNslices = nSlices; } +// --------------------------------------------------------------------------------------------------------------------- +// +void WindowFinder::SetStationIndexes(const std::vector<int>& vStationIndexes) +{ + fvStationIndexes.clear(); + for (auto iSt : vStationIndexes) { + if (iSt < 1) { + LOG(warn) << "WindowFinder::SetStationIndexes: attempt to estimate searching window for station with index " + << iSt << " < 1. This index will be omitted"; + continue; + } + fvStationIndexes.push_back(iSt); + } +} + // --------------------------------------------------------------------------------------------------------------------- // void WindowFinder::SetTarget(double x, double y, double z) diff --git a/reco/L1/catools/CaToolsWindowFinder.h b/reco/L1/catools/CaToolsWindowFinder.h index 1ea7e53314524582ddaeacf09030e04b4b48fb79..9ab2dcc0fb7b4e18f4c2bd051caa38b44a6e0ce4 100644 --- a/reco/L1/catools/CaToolsWindowFinder.h +++ b/reco/L1/catools/CaToolsWindowFinder.h @@ -10,31 +10,33 @@ #ifndef CaToolsWindowFinder_h #define CaToolsWindowFinder_h 1 +#include "TCut.h" #include "TObject.h" +#include <array> +#include <vector> + +#include "L1CAIteration.h" + // TODO: Replace tmp asserts with exceptions class TChain; +class L1SearchWindow; +class TPad; +class TCanvas; namespace ca { namespace tools { - - /// Enumeration of parameterisations used to describe a search window - enum class EWindowForm - { - kConstant, - kLinear, - kParabolic, - kElliptic - }; - - /// Enumeration - enum class EBuildingMode + /// Enumeration to handle processed expressions + enum EExpr { - kDouplets, ///< Windows are built from doublets and a target - kTriplets ///< Windows are built from triplets without using target + kDxVsX0, + kDxVsY0, + kDyVsX0, + kDyVsY0, + kEND }; /// TODO: ... write an instruction ... @@ -47,6 +49,7 @@ namespace ca /// Default constructor WindowFinder(); + /// Destructor virtual ~WindowFinder() = default; /// Copy and move are forbidden @@ -59,8 +62,16 @@ namespace ca /// \note Multiple file input is possible void AddInputFile(const char* filename); + /// Saves canvases to a set of canvases to pdf + void DumpCanvasesToPdf(const char* filename = "WFLog") const; + /// Process a tree (TEST) - void Process(EBuildingMode buildingMode); + /// \param opt Define options to process: + /// 'T' - triplets are used instead of doublets + void Process(Option_t* opt = ""); + + /// Reads the iterations from YAML config + void ReadTrackingIterationsFromYAML(const char* filename); /// Sets binning of the dx (dy) distribution /// \param nBinsX Number of bins for the x-axis @@ -70,11 +81,26 @@ namespace ca /// 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 + /// Sets additional cut (can be useful to reduce distribution contamination by outliers) + /// \param cut A cut object + void SetExtraCut(const TCut& cut) { fExtraCut = cut; } + + /// Sets number of slices along the x-axiso /// 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 name of output file with search windows array + /// \note Format of output file: + /// \note <number of parameters> <number of search windows stored> <array of serialized L1SearchWindow objects> + /// \param filename Name of the file + void SetOutputName(const char* filename) { fsOutputName = filename; } + + /// Define indexes of stations for which windows are needed + /// \note: A stution + /// TODO: Get number of stations from a tree ... + void SetStationIndexes(const std::vector<int>& vStationIndexes); + /// Sets components of the target center position /// \param x Position x-component [cm] /// \param y Position y-component [cm] @@ -82,22 +108,49 @@ namespace ca void SetTarget(double x, double y, double z); - // ****************************** - // ** Member variables ** - // ****************************** - private: - std::array<double, 3> fTargetPos = {0}; ///< Target position {x, y, z} [cm] + /// Creates a search window for a selected station and iteration + L1SearchWindow CreateSW(int iStation, const L1CAIteration& caIter); - // Window extraction settings + /// Returns expression for dx or dy to be drawn in a tree + const char* GetDistExpr(EExpr expr) const; + + /// Gets a cut for doublets/triplets defined by station and a tracking iteration + /// \param iStation Global index of an active station + /// \param caIter CA track finder iteration object + TCut GetTrackSelectionCut(int iStation, const L1CAIteration& caIter) const; + + /// Prints information on the dx and dy expression as well as used cuts on the pad + /// \param pPad A pad to print the information + /// \param iStation Global index of an active station + /// \param caIter CA track finder iteration object + void PrintCaseInformation(TPad* pPad, int iStation, const L1CAIteration& caIter) const; + + + // ********************* + // ** Class variables ** + // ********************* + int fNparams = 1; ///< number of parameters of the searching window - 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 + std::string fsOutputName = "SearchWindows.dat"; ///< Name for output file with estimated search windows + + // ----- Input parameters (iterations and stations) + std::vector<L1CAIteration> fvCaIters = {}; ///< Tracking iterations + std::vector<int> fvStationIndexes = {}; ///< Global indexes of active stations to find the windows + std::array<double, 3> fTargetPos = {0}; ///< Target position {x, y, z} [cm] + + TCut fExtraCut = TCut(""); ///< Optional cut on the triplets/doublets + + // Window extraction settings + int fNbinsX = 400; ///< Number of bins for the X axis of the distribution + int fNbinsY = 400; ///< 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 + std::vector<TCanvas*> fvpCanvases; // Vector of pointer to cavnases + ClassDef(WindowFinder, 0); }; } // namespace tools