diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 9e7f23db7eb3f749cecba0efae05fcd4ad236b5f..a70b0872c98516d229715c67c7f86b14d8102a83 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -165,6 +165,7 @@ set(SRCS kfp/KfpV0Finder.cxx kfp/KfpV0FinderChain.cxx kfp/KfpV0FinderConfig.cxx + kfp/KfpV0FinderQa.cxx ) set(BUILD_INFO_CXX ${CMAKE_CURRENT_BINARY_DIR}/base/BuildInfo.cxx) diff --git a/algo/base/Definitions.h b/algo/base/Definitions.h index 6c6d77ba8715786fada47c3483207254bb269b49..b1ff4c9ccc8e804a33a67fe0ab40d81d74dd616e 100644 --- a/algo/base/Definitions.h +++ b/algo/base/Definitions.h @@ -78,6 +78,7 @@ namespace cbm::algo RecoTof, RecoFsd, Tracking, + V0Finder, }; } // namespace cbm::algo @@ -148,7 +149,8 @@ CBM_ENUM_DICT(cbm::algo::QaStep, {"RecoMuch", cbm::algo::QaStep::RecoMuch}, {"RecoTof", cbm::algo::QaStep::RecoTof}, {"RecoFsd", cbm::algo::QaStep::RecoFsd}, - {"Tracking", cbm::algo::QaStep::Tracking} + {"Tracking", cbm::algo::QaStep::Tracking}, + {"V0Finder", cbm::algo::QaStep::V0Finder} ); #endif diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index b2a7355599cb93d886743aa37cd2accfbac6712e..f312ebaaab85e36f0a9c689883a4e9c09e8ca13e 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -275,7 +275,12 @@ void Reco::Init(const Options& opts) fTrackingEvent->SetContext(&fContext); fTrackingEvent->Init(); - fV0Finder = std::make_unique<V0FinderChain>(); + if (fQaManager != nullptr && Opts().Has(QaStep::V0Finder)) { + fV0Finder = std::make_unique<V0FinderChain>(fQaManager); + } + else { + fV0Finder = std::make_unique<V0FinderChain>(); + } fV0Finder->SetContext(&fContext); fV0Finder->SetBmonDefinedAddresses(fBmonHitFinder->GetDiamondAddresses()); fV0Finder->Init(); diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx index 2488ba89e29fcdcbdf690ed56c4e6ff7f20bf958..bc06d78009a0e876ea425d35df1249c3deb06f72 100644 --- a/algo/kfp/KfpV0Finder.cxx +++ b/algo/kfp/KfpV0Finder.cxx @@ -95,10 +95,10 @@ void V0Finder::CollectDca(const RecoResults& recoEvent) fEventMonitor.IncrementCounter(ECounter::TracksWoStsHits); continue; } - auto& particleInfo = fvParticleInfo[iTrk]; - auto [iPtFst, iHitFst] = stsHitIndicesInTrack[0]; - auto [iPtSnd, iHitSnd] = stsHitIndicesInTrack[1]; - fvParticleInfo[iTrk].fDca = EstimateDca(recoEvent.stsHits[iPtFst][iHitFst], recoEvent.stsHits[iPtSnd][iHitSnd]); + auto& particleInfo = fvParticleInfo[iTrk]; + auto [iPtFst, iHitFst] = stsHitIndicesInTrack[0]; + auto [iPtSnd, iHitSnd] = stsHitIndicesInTrack[1]; + particleInfo.fDca = EstimateDca(recoEvent.stsHits[iPtFst][iHitFst], recoEvent.stsHits[iPtSnd][iHitSnd]); AssignPid(particleInfo); } } diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h index 0272b0ab891d36253451c77bbf4e94a45d5bf8d6..72d1d1c579b7f4a40918dd58c1b5981a0179b7d2 100644 --- a/algo/kfp/KfpV0Finder.h +++ b/algo/kfp/KfpV0Finder.h @@ -36,6 +36,12 @@ namespace cbm::algo::kfp bool fbSelected{false}; //< The track was selected }; + //* Framework and physical constants (public) + static constexpr double kPionMass{0.13957039}; ///< Pion mass [GeV/c2] + static constexpr double kProtonMass{0.938272088}; ///< Proton mass [GeV/c2] + static constexpr double kSpeedOfLight{29.9792458}; ///< Speed of light [cm/ns] + static constexpr int32_t kUndefPdg{-2}; ///< PDG for tracks, which PID cannot be inferred + /// \brief Default constructor V0Finder() = default; @@ -71,7 +77,7 @@ namespace cbm::algo::kfp const KFParticleFinder* GetKFParticleFinder() const { return fpTopoReconstructor->GetKFParticleFinder(); } /// \brief Gets a vector of particle info - const std::vector<ParticleInfo> GetParticleInfo() const { return fvParticleInfo; } + const std::vector<ParticleInfo>& GetParticleInfo() const { return fvParticleInfo; } /// \brief Gets selected t0 /// \note NaN, if Lambda-candidate was not found @@ -83,6 +89,9 @@ namespace cbm::algo::kfp /// \brief Gets found t0s const std::vector<double>& GetT0s() const { return fvT0s; } + /// \brief Accessor to topology reconstructor + const std::unique_ptr<KFParticleTopoReconstructor>& GetTopoReconstructor() const { return fpTopoReconstructor; } + /// \brief Initializes the instance (called in the beginning of the run) void Init(); @@ -226,12 +235,9 @@ namespace cbm::algo::kfp void SetKfpTrackParameters(KFPTrackVector& kfpTrkVector, uint32_t iKfpTrk, uint32_t iCaTrk, const ca::Track::TrackParam_t& trkParam, const ParticleInfo& particleInfo) const; - //* Framework and physical constants - static constexpr double kPionMass{0.13957039}; ///< Pion mass [GeV/c2] - static constexpr double kProtonMass{0.938272088}; ///< Proton mass [GeV/c2] - static constexpr double kSpeedOfLight{29.9792458}; ///< Speed of light [cm/ns] - static constexpr int32_t kUndefPdg{-2}; ///< PDG for tracks, which PID cannot be inferred - static constexpr bool kUseAverageSpeed{false}; ///< If an average speed of tof hits is used + + //* Framework and physical constants (private) + static constexpr bool kUseAverageSpeed{false}; ///< If an average speed of tof hits is used V0FinderMonitorData_t fEventMonitor; ///< Main monitor data instance diff --git a/algo/kfp/KfpV0FinderChain.cxx b/algo/kfp/KfpV0FinderChain.cxx index f41a0597ac8adce96b374ee90e3ff00e02cdaf34..e23bc9e812d3bfd6357e011032e448830fd23c4d 100644 --- a/algo/kfp/KfpV0FinderChain.cxx +++ b/algo/kfp/KfpV0FinderChain.cxx @@ -18,6 +18,13 @@ using cbm::algo::V0FinderChain; +// --------------------------------------------------------------------------------------------------------------------- +// +V0FinderChain::V0FinderChain(const std::unique_ptr<qa::Manager>& qaManager) + : fpFinderQa(qaManager != nullptr ? std::make_unique<kfp::V0FinderQa>(qaManager, "V0Finder") : nullptr) +{ +} + // --------------------------------------------------------------------------------------------------------------------- // void V0FinderChain::Finalize() { L_(info) << fMonitorRun.ToString(); } @@ -69,6 +76,8 @@ try { } const auto& pion{particles[iPion]}; const auto& proton{particles[iProton]}; + L_(info) << "!!!!!!!!!!! > pion: " << pion.minDca; + L_(info) << "!!!!!!!!!!! > proton: " << proton.minDca; // ----- Define a BMON diamond if (fBmonDefinedAddresses.empty()) { @@ -114,6 +123,11 @@ try { //* Init the V0 finder fFinder.Init(); } + + if (fpFinderQa != nullptr) { + fpFinderQa->Init(); + } + L_(info) << "kfp::V0FinderChain: initializing the V0-finder chain ... done"; } catch (const std::exception& err) { @@ -128,6 +142,9 @@ V0FinderChain::EventOutput V0FinderChain::ProcessEvent(const RecoResults& recoEv EventOutput res; res.triggers = fFinder.Process(recoEvent); res.monitor = fFinder.GetEventMonitor(); + if (fpFinderQa != nullptr) { + fpFinderQa->Exec(recoEvent, fFinder); + } fMonitorRun.AddMonitorData(res.monitor); return res; } diff --git a/algo/kfp/KfpV0FinderChain.h b/algo/kfp/KfpV0FinderChain.h index 630fc02e63e52d9e07dd89bf53669b3994224a0c..8053c93f79f686f5952542afa68e706a89c90f6d 100644 --- a/algo/kfp/KfpV0FinderChain.h +++ b/algo/kfp/KfpV0FinderChain.h @@ -15,6 +15,15 @@ #include "global/RecoResults.h" #include "kfp/KfpV0Finder.h" #include "kfp/KfpV0FinderMonitor.h" +#include "kfp/KfpV0FinderQa.h" + +namespace cbm::algo +{ + namespace qa + { + class Manager; + } +} // namespace cbm::algo namespace cbm::algo { @@ -32,6 +41,10 @@ namespace cbm::algo /// \brief Default constructor V0FinderChain() = default; + /// \brief Constructor from parameters + /// \param pQaManager A QA-manager + V0FinderChain(const std::unique_ptr<qa::Manager>& qaManager); + /// \brief Copy constructor V0FinderChain(const V0FinderChain&) = delete; @@ -61,8 +74,9 @@ namespace cbm::algo EventOutput ProcessEvent(const RecoResults& recoEvent); private: - kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm - kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run - PODVector<uint32_t> fBmonDefinedAddresses; ///< Available addresses of BMON + kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm + kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run + std::unique_ptr<kfp::V0FinderQa> fpFinderQa{nullptr}; ///< QA module + PODVector<uint32_t> fBmonDefinedAddresses; ///< Available addresses of BMON }; } // namespace cbm::algo diff --git a/algo/kfp/KfpV0FinderQa.cxx b/algo/kfp/KfpV0FinderQa.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4239174a71b61b3df7b97fbeeda5fff6fabe8d1a --- /dev/null +++ b/algo/kfp/KfpV0FinderQa.cxx @@ -0,0 +1,97 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0FinderQa.cxx +/// \date 13.02.2025 +/// \brief A V0 finding algorithm QA (implementation) +/// \author Sergei Zharko <s.zharko@gsi.de> + +#include "kfp/KfpV0FinderQa.h" + +#include "global/RecoResults.h" +#include "kfp/KfpV0Finder.h" + + +using cbm::algo::kfp::V0FinderQa; + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0FinderQa::Init() +{ + using qa::CanvasConfig; + using qa::H1D; + using qa::PadConfig; + + //* Histogram initialisation + fvphMassLambdaCand = + MakeObj<H1D>("kfp_mass_lambda", "Mass of #Lambda-candidates;m [GeV/c^{2}];Counts", kMassB, kMassL, kMassU); + fvphMassAll = MakeObj<H1D>("kfp_mass_all", "Mass of particles;m [GeV/c^{2}];Counts", 300, 0., 1.5); + fvphDcaAll = MakeObj<H1D>("kfp_dca_all", "DCA of tracks to origin;DCA [cm];Counts", kDcaB, kDcaL, kDcaU); + fvphBetaAll = MakeObj<H1D>("kfp_beta_all", "Speed of tracks;#beta;Counts", kBetaB, kBetaL, kBetaU); + fvphBetaPdg = MakeObj<H1D>("kfp_beta_pdg", "Speed of tracks w/ PDG;#beta;Counts", kBetaB, kBetaL, kBetaU); + fvphBetaPion = MakeObj<H1D>("kfp_beta_pion", "Speed of #pi-candidates;#beta;Counts", kBetaB, kBetaL, kBetaU); + fvphBetaProton = MakeObj<H1D>("kfp_beta_proton", "Speed of proton-candidates;#beta;Counts", kBetaB, kBetaL, kBetaU); + + //* Canvas initialisation + auto canv = CanvasConfig("kfp_lambda", "Lambda-trigger summary QA", 4, 2); + canv.AddPadConfig(PadConfig(fvphMassLambdaCand, "hist")); // (0, 0) + canv.AddPadConfig(PadConfig(fvphMassAll, "hist")); // (1, 0) + canv.AddPadConfig(PadConfig(fvphDcaAll, "hist")); // (0, 1) + canv.AddPadConfig(PadConfig(fvphBetaAll, "hist")); + canv.AddPadConfig(PadConfig(fvphBetaPdg, "hist")); + canv.AddPadConfig(PadConfig(fvphBetaPion, "hist")); + canv.AddPadConfig(PadConfig(fvphBetaProton, "hist")); + AddCanvasConfig(canv); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0FinderQa::Exec(const RecoResults& recoEvent, const V0Finder& v0Finder) +{ + //* Fill track distributions + const auto& tracks{recoEvent.tracks}; + if (v0Finder.GetT0s().size() == 1) { + for (uint32_t iTrk = 0; iTrk < tracks.size(); ++iTrk) { + const auto& particleInfo{v0Finder.GetParticleInfo()[iTrk]}; + bool bPdgDefined = (particleInfo.fPdg != V0Finder::kUndefPdg); + fvphDcaAll->Fill(bPdgDefined ? particleInfo.fDca : -999); + fvphBetaAll->Fill(particleInfo.fBeta); + if (bPdgDefined) { + fvphBetaPdg->Fill(particleInfo.fBeta); + if (particleInfo.fPdg == -211) { + fvphBetaPion->Fill(particleInfo.fBeta); + } + else if (particleInfo.fPdg == 2212) { + fvphBetaProton->Fill(particleInfo.fBeta); + } + } + } + } + else { + for (uint32_t iTrk = 0; iTrk < tracks.size(); ++iTrk) { + const auto& particleInfo{v0Finder.GetParticleInfo()[iTrk]}; + bool bPdgDefined = (particleInfo.fPdg != V0Finder::kUndefPdg); + fvphDcaAll->Fill(bPdgDefined ? particleInfo.fDca : -999); + fvphBetaAll->Fill(-999); + if (bPdgDefined) { + fvphBetaPdg->Fill(-999); + if (particleInfo.fPdg == -211) { + fvphBetaPion->Fill(-999); + } + else if (particleInfo.fPdg == 2212) { + fvphBetaProton->Fill(-999); + } + } + } + } + + //* Fill particle distributions + const auto& particles = v0Finder.GetTopoReconstructor()->GetParticles(); + for (const auto& particle : particles) { + fvphMassAll->Fill(particle.GetMass()); + if (particle.GetPDG() == 3122) { + fvphMassLambdaCand->Fill(particle.GetMass()); + } + } +} diff --git a/algo/kfp/KfpV0FinderQa.h b/algo/kfp/KfpV0FinderQa.h new file mode 100644 index 0000000000000000000000000000000000000000..39a1289bae0df797974d751642a59a8aa6b9b81f --- /dev/null +++ b/algo/kfp/KfpV0FinderQa.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0FinderQa.h +/// \date 13.02.2025 +/// \brief A V0 finding algorithm QA +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "qa/QaTaskHeader.h" + +namespace cbm::algo +{ + class RecoResults; + + namespace qa + { + class H1D; + class H2D; + } // namespace qa + + namespace kfp + { + class V0Finder; + } +} // namespace cbm::algo + +namespace cbm::algo::kfp +{ + /// \class V0FinderQa + /// \brief A QA-task for the V0-finding algorithm + class V0FinderQa : public qa::TaskHeader { + public: + /// \brief Constructor + /// \param pManager Pointer to the QA manager + /// \param name Name of the QA + V0FinderQa(const std::unique_ptr<qa::Manager>& pManager, std::string_view name) : qa::TaskHeader(pManager, name) {} + + /// \brief Copy constructor + V0FinderQa(const V0FinderQa&) = delete; + + /// \brief Move constructor + V0FinderQa(V0FinderQa&&) = delete; + + /// \brief Copy assignment operator + V0FinderQa& operator=(const V0FinderQa&) = delete; + + /// \brief Move assignment operator + V0FinderQa& operator=(V0FinderQa&&) = delete; + + /// \brief Executes the task, fills the histograms + /// \param recoEvent A reconstructed event instance + /// \param v0Finder A V0-finder instance + void Exec(const RecoResults& recoEvent, const V0Finder& v0Finder); + + /// \brief Initialized the task + void Init(); + + private: + //* Constants + static constexpr int kMassB = 200; ///< Lambda-candidate mass: number of bins + static constexpr double kMassL = 1.08; ///< Lambda-candidate mass: lower bound [GeV/c2] + static constexpr double kMassU = 1.18; ///< Lambda-candidate mass: upper bound [GeV/c2] + static constexpr int kDcaB = 240; ///< DCA to origin: number of bins + static constexpr double kDcaL = 0.; ///< DCA to origin: lower bound [cm] + static constexpr double kDcaU = 12.; ///< DCA to origin: upper bound [cm] + static constexpr int kBetaB = 240; ///< Speed of particle: number of bins + static constexpr double kBetaL = 0.; ///< Speed of particle: lower bound [c] + static constexpr double kBetaU = 1.2; ///< Speed of particle: upper bound [c] + + //* Histograms + qa::H1D* fvphMassLambdaCand{nullptr}; ///< Mass of Lambda-candidates + qa::H1D* fvphMassAll{nullptr}; ///< Mass of all particles in the topology + qa::H1D* fvphDcaAll{nullptr}; ///< DCA of particles to origin + qa::H1D* fvphBetaAll{nullptr}; ///< Speed of all particles + qa::H1D* fvphBetaPdg{nullptr}; ///< Speed of particles with PID hypothesis + qa::H1D* fvphBetaPion{nullptr}; ///< Speed of pion-candidates + qa::H1D* fvphBetaProton{nullptr}; ///< Speed of proton-candidates + }; +} // namespace cbm::algo::kfp diff --git a/algo/qa/hitfind/BmonHitfindQa.h b/algo/qa/hitfind/BmonHitfindQa.h index 020f62fa821a2c8ec298c8aa758684aee023cc21..b2a8b3e30e709d099ef1059aaa5a619864d02c54 100644 --- a/algo/qa/hitfind/BmonHitfindQa.h +++ b/algo/qa/hitfind/BmonHitfindQa.h @@ -34,8 +34,6 @@ namespace cbm::algo::bmon { /// \class HitfindQa /// \brief A QA module for the BMON hit-finder - /// \param pManager Pointer to the QA manager - /// \param name Name of the QA (directory) class HitfindQa : public qa::TaskHeader { public: /// \brief Constructor @@ -44,7 +42,6 @@ namespace cbm::algo::bmon HitfindQa(const std::unique_ptr<qa::Manager>& pManager, std::string_view name) : qa::TaskHeader(pManager, name) {} /// \brief Constructor from the configuration object - /// \param config QA configuration object HitfindQa() = default; /// \brief Copy constructor diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx index 5eb5362f051fc3f34fc1108e50bd17e1adf6e4f2..d2215633eb84dbbad3eba51509872f4da98f08af 100644 --- a/services/histserv/app/Application.cxx +++ b/services/histserv/app/Application.cxx @@ -800,17 +800,21 @@ bool Application::PrepareCanvas(uint32_t uCanvIdx) if ("nullptr" != sName) { TObject* pObj = fArrayHisto[FindHistogram(sName)]; - if (nullptr != dynamic_cast<TProfile2D*>(pObj)) { - dynamic_cast<TProfile2D*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + if (auto* pHist = dynamic_cast<TProfile2D*>(pObj)) { + pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TProfile *>( pObj ) ) - else if (nullptr != dynamic_cast<TProfile*>(pObj)) { - dynamic_cast<TProfile*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + else if (auto* pHist = dynamic_cast<TProfile*>(pObj)) { + pHist->SetLineColor(uObjIdx + 1); + pHist->SetMarkerColor(uObjIdx + 1); + pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TProfile *>( pObj ) ) - else if (nullptr != dynamic_cast<TH2*>(pObj)) { - dynamic_cast<TH2*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + else if (auto* pHist = dynamic_cast<TH2*>(pObj)) { + pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TH2 *>( pObj ) ) - else if (nullptr != dynamic_cast<TH1*>(pObj)) { - dynamic_cast<TH1*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + else if (auto* pHist = dynamic_cast<TH1*>(pObj)) { + pHist->SetLineColor(uObjIdx + 1); + pHist->SetMarkerColor(uObjIdx + 1); + pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TH1 *>( pObj ) ) else LOG(warning) << " Unsupported object type for " << sName << " when preparing canvas " << conf.GetName();