From 6e91016a5bd50ad6250d40782fc1072219c7a39e Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Wed, 5 Feb 2025 20:03:41 +0100 Subject: [PATCH 01/17] online: BMON digi calibrator --- algo/detectors/bmon/Calibrate.cxx | 7 ------- core/data/tof/CbmTofAddress.cxx | 1 + external/InstallParameter.cmake | 2 ++ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/algo/detectors/bmon/Calibrate.cxx b/algo/detectors/bmon/Calibrate.cxx index d55198549..fc2a17f29 100644 --- a/algo/detectors/bmon/Calibrate.cxx +++ b/algo/detectors/bmon/Calibrate.cxx @@ -57,13 +57,6 @@ Calibrate::Calibrate(CalibrateSetup setup) : fSetup(setup), fSelectionBitsOffset } fChannelDeadTime = std::vector<double>(fChannelOffset.back(), std::numeric_limits<double>::quiet_NaN()); - // **** DEBUG: BEGIN - for (size_t iO = 0; iO < fChannelOffset.size(); ++iO) { - L_(info) << "Channel offset: diamond=" << iO << ", offset=" << fChannelOffset[iO]; - } - L_(info) << "Selection mask: 0b" << std::bitset<32>(fSetup.selectionMask); - L_(info) << "Bits offset: " << static_cast<uint32_t>(fSelectionBitsOffset); - L_(info) << "Size of the channel dead time vector: " << fChannelDeadTime.size(); // **** DEBUG: END } diff --git a/core/data/tof/CbmTofAddress.cxx b/core/data/tof/CbmTofAddress.cxx index 29c157345..71554dd1a 100644 --- a/core/data/tof/CbmTofAddress.cxx +++ b/core/data/tof/CbmTofAddress.cxx @@ -66,3 +66,4 @@ std::string CbmTofAddress::ToString(int32_t address) msg << ", RpcType=" << setw(2) << CbmTofAddress::GetRpcType(address); return msg.str(); } + diff --git a/external/InstallParameter.cmake b/external/InstallParameter.cmake index 77e3f424d..7d02e04ad 100644 --- a/external/InstallParameter.cmake +++ b/external/InstallParameter.cmake @@ -1,5 +1,7 @@ set(PARAMETER_VERSION cf6a880a56a8695b485efe358231270e9179cb82) # 2025/02/15 set(PARAMETER_SRC_URL "https://git.cbm.gsi.de/CbmSoft/cbmroot_parameter.git") +#set(PARAMETER_VERSION 96b2189ac86b3d49c32f63da76e68f66544bba55) # 2025/05/02, BMON hitfinder parameters for online +#set(PARAMETER_SRC_URL "https://git.cbm.gsi.de/s.zharko/cbmroot_parameter.git") download_project_if_needed(PROJECT Parameter_source GIT_REPOSITORY ${PARAMETER_SRC_URL} -- GitLab From e4cbd0fafa90eb6396f1d4b5e618d68fe29c7982 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Sun, 9 Feb 2025 15:48:30 +0100 Subject: [PATCH 02/17] online: BMON hitfinder --- algo/global/Reco.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 8460ea28b..087fbe575 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -396,6 +396,8 @@ RecoResults Reco::Run(const fles::Timeslice& ts) // ***** DEBUG: BEGIN if constexpr (0) { int nEvents = events.size(); + size_t nBmonHitsOneChannel{0}; + size_t nBmonHitsTwoChannels{0}; for (int iE = 0; iE < nEvents; ++iE) { const auto& event = events[iE]; // Calibrate TOF digis: @@ -408,6 +410,8 @@ RecoResults Reco::Run(const fles::Timeslice& ts) fBmonHitFinderQa->Exec(); } } + L_(info) << "!!!! BMON hits with two channels: " << nBmonHitsTwoChannels << " / " + << (nBmonHitsTwoChannels + nBmonHitsOneChannel); } // ***** DEBUG: END -- GitLab From 745b61828fad09ba78d936cd4a8f98e25ba824f6 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 30 Jan 2025 01:18:07 +0100 Subject: [PATCH 03/17] - ca: misalignment tolerances of x and y are set to 0 - V0Finder: - YAML config - cuts on velocity of pion and proton candidates - enhanced cut for decay length (0.1 -> 5 cm) --- algo/evselector/KfpfV0FinderConfig.h | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 algo/evselector/KfpfV0FinderConfig.h diff --git a/algo/evselector/KfpfV0FinderConfig.h b/algo/evselector/KfpfV0FinderConfig.h new file mode 100644 index 000000000..cbeaec0a7 --- /dev/null +++ b/algo/evselector/KfpfV0FinderConfig.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpfV0FinderConfig.h +/// \date 29.01.2025 +/// \brief Configuration structure for V0 selector in mCBM +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "yaml/Yaml.h" + +#include <vector> + +namespace cbm::algo::kfpf +{ + /// \struct CutsKfpf + /// \brief Cuts for the KFParticleFinder + struct CutsKfpf { + float minDecayLength; ///< Minimal decay length of particles [cm] + float minDecayLDL; ///< Minimal value of decay length to decay length error ratio + float maxChi2NdfPrim; ///< Maximal chi2/NDF for primary particles (coming from the PV) + float maxChi2NdfGeo; ///< Maximal chi2/NDF for V0 candidates + + CBM_YAML_PROPERTIES( + yaml::Property(&CutsKfpf::minDecayLength, "min_decay_length", "Minimal decay length of particles [cm]"), + yaml::Property(&CutsKfpf::minDecayLDL, "min_decay_ldl", "Minimal value of decay length to decay length error ratio"), + yaml::Property(&CutsKfpf::maxChi2NdfPrim, "max_chi2_ndf_prim", "Maximal chi2/NDF for primary particles"), + yaml::Property(&CutsKfpf::maxChi2NdfGeo, "max_chi2_ndf_geo", "Maximal chi2/NDF for V0 candidates")); + }; + + /// \struct ParticlePid + /// \brief PID and pre-selection cuts for a given particle + struct ParticlePid { + int pdg; ///< PDG code for particle + double minDca; ///< Minimal DCA to PV [cm] + double minVelocity; ///< Minimal velocity [cm/ns] + double maxVelocity; ///< Maximal velocity [cm/ns] + + CBM_YAML_PROPERTIES( + yaml::Property(&ParticlePid::pdg, "pdg", "PDG code of the particle"), + yaml::Property(&ParticlePid::minDca, "min_dca", "Minimal DCA to PV [cm]"), + yaml::Property(&ParticlePid::minVelocity, "min_velocity", "Minimal velocity [cm/ns]"), + yaml::Property(&ParticlePid::maxVelocity, "max_velocity", "Maximal velocity [cm/ns]")); + }; + + /// \struct Cuts; + struct Cuts { + CutsKfpf kfpf; ///< KFParticleFinder specific cuts + std::vector<ParticlePid> particles; ///< Daughter PID cuts and other properties + + CBM_YAML_PROPERTIES( + yaml::Property(&Cuts::kfpf, "kfpf", "Specific cuts for the KFParticleFinder"), + yaml::Property(&Cuts::particles, "particles", "Particle identification cuts and properties")); + }; + + /// \struct LambdaFinderConfig + /// \brief Configuration for the V0 finder + struct V0FinderConfig { + Cuts cuts; ///< Different selection cuts + double tZeroOffset; ///< Offset for T0 [ns] + double qpAssignedUncertainty; ///< Assigned relative uncertainty for q/p estimation + int primaryAssignedPdg; ///< Assigned PDG hypothesis for primary particles + int reconstructPdg; ///< PDG of the particle, the decay of which is to be reconstructed + + CBM_YAML_PROPERTIES( + yaml::Property(&V0FinderConfig::cuts, "cuts", "Different selection cuts"), + yaml::Property(&V0FinderConfig::tZeroOffset, "t0_offset", "The t0 offset [ns]"), + yaml::Property(&V0FinderConfig::qpAssignedUncertainty, "qa_uncertainty", "Assigned relative uncertainty for q/p"), + yaml::Property(&V0FinderConfig::primaryAssignedPdg, "primary_pdg", "Assigned PDG code for primary tracks"), + yaml::Property(&V0FinderConfig::reconstructPdg, "reconstruct_pdg", "PDG code of the particle to be reconstructed")); + }; +} // namespace cbm::algo::kfpf -- GitLab From b389473c0e2684e31d9c552b840baf1120fe7856 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Mon, 27 Jan 2025 11:55:39 +0100 Subject: [PATCH 04/17] cbmreco: Hit reconstruction in digi-events --- algo/base/Options.cxx | 1 + algo/base/Options.h | 3 ++ algo/global/Reco.cxx | 73 ++++++++++++++++++++++++++++++++----------- algo/global/Reco.h | 5 ++- 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/algo/base/Options.cxx b/algo/base/Options.cxx index ea9ecace3..abce4f27d 100644 --- a/algo/base/Options.cxx +++ b/algo/base/Options.cxx @@ -93,6 +93,7 @@ Options::Options(int argc, char** argv) ("compress-archive", po::bool_switch(&fCompressArchive)->default_value(false), "Enable compression for output archives") ("steps", po::value(&fRecoSteps)->multitoken()->default_value({Step::Unpack, Step::DigiTrigger, Step::LocalReco, Step::Tracking})->value_name("<steps>"), "space separated list of reconstruction steps (unpack, digitrigger, localreco, ...)") + ("event-reco", po::bool_switch(&fReconstructDigiEvents)->default_value(false), "runs digi event reconstruction (local reco, tracking, trigger)") ("systems,s", po::value(&fDetectors)->multitoken()->default_value({Subsystem::STS, Subsystem::TOF, Subsystem::BMON, Subsystem::MUCH, Subsystem::RICH, Subsystem::TRD, Subsystem::TRD2D})->value_name("<detectors>"), "space separated list of detectors to process (sts, mvd, ...)") ("child-id,c", po::value(&fChildId)->default_value("00")->value_name("<id>"), "online process id on node") diff --git a/algo/base/Options.h b/algo/base/Options.h index 5a9d232fc..f1b508a06 100644 --- a/algo/base/Options.h +++ b/algo/base/Options.h @@ -68,6 +68,8 @@ namespace cbm::algo bool Has(QaStep qastep) const; + bool ReconstructDigiEvents() const { return fReconstructDigiEvents; } + private: // members std::string fParamsDir; // TODO: can we make this a std::path? std::string fInputLocator; @@ -97,6 +99,7 @@ namespace cbm::algo uint64_t fRunId = 2391; uint64_t fRunStartTime = 0; bool fCollectAuxData = false; + bool fReconstructDigiEvents = false; }; } // namespace cbm::algo diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 087fbe575..a990278ad 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -241,6 +241,15 @@ void Reco::Init(const Options& opts) fTrdHitfind = std::make_unique<trd::Hitfind>(setup, setup2d); } + // Digi event reconstruction: + { + fbReconstructDigiEvents = Opts().ReconstructDigiEvents(); + // It makes no sence to reconstruct an event, if there is no STS, TRD or TOF + fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::STS); + fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::TRD); + fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::TOF); + } + // Tracking if (Opts().Has(Step::Tracking)) { if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) { @@ -393,27 +402,16 @@ RecoResults Reco::Run(const fles::Timeslice& ts) QueueEvbuildMetrics(evbuildMonitor); } - // ***** DEBUG: BEGIN - if constexpr (0) { - int nEvents = events.size(); - size_t nBmonHitsOneChannel{0}; - size_t nBmonHitsTwoChannels{0}; - for (int iE = 0; iE < nEvents; ++iE) { - const auto& event = events[iE]; - // Calibrate TOF digis: - auto [bmonDigis, bmonCalMonitor] = (*fBmonCalibrator)(event.fBmon); - auto [bmonHits, hitmonitor, digiIndices] = (*fBmonHitFinder)(bmonDigis); - if (fBmonHitFinderQa != nullptr) { - fBmonHitFinderQa->RegisterDigis(&bmonDigis); - fBmonHitFinderQa->RegisterHits(&bmonHits); - fBmonHitFinderQa->RegisterDigiIndices(&digiIndices); - fBmonHitFinderQa->Exec(); + // --- Reconstruct and select digi events + if (Opts().ReconstructDigiEvents()) { + size_t nDiscardedEvents{0}; + for (const auto& event : events) { + if (!ReconstructEvent(event)) { + ++nDiscardedEvents; } } - L_(info) << "!!!! BMON hits with two channels: " << nBmonHitsTwoChannels << " / " - << (nBmonHitsTwoChannels + nBmonHitsOneChannel); + L_(info) << "Rate of discarded events " << double(nDiscardedEvents) / events.size(); } - // ***** DEBUG: END // --- Filter data for output if (Opts().HasOutput(RecoData::DigiTimeslice)) { @@ -491,6 +489,45 @@ void Reco::PrintTimings(xpu::timings& timings) } } +bool Reco::ReconstructEvent(const DigiEvent& digiEvent) +{ + RecoResults recoEvent; + //* STS hit reconstruction + { + auto stsResults = (*fStsHitFinder)(digiEvent.fSts); + if (stsResults.hits.NElements() < 2) { // TODO: Provide a config for cuts (testing mode for now) + return false; + } + recoEvent.stsHits = stsResults.hits; + } + + //* TOF hit reconstruction + { + auto [caldigis, calmonitor] = (*fTofCalibrator)(digiEvent.fTof); + auto [hits, hitmonitor, digiindices] = (*fTofHitFinder)(caldigis); + if (hits.NElements() < 1) { // TODO: Provide a config for cuts (testing mode for now) + return false; + } + recoEvent.tofHits = std::move(hits); + } + + //* TRD hit reconstruction + { + // FIXME: additional copy of digis, figure out how to pass 1d + 2d digis at once to hitfinder + const auto& digis1d = digiEvent.fTrd; + const auto& digis2d = digiEvent.fTrd2d; + PODVector<CbmTrdDigi> allDigis{}; + allDigis.reserve(digis1d.size() + digis2d.size()); + std::copy(digis1d.begin(), digis1d.end(), std::back_inserter(allDigis)); + std::copy(digis2d.begin(), digis2d.end(), std::back_inserter(allDigis)); + auto trdResults = (*fTrdHitfind)(allDigis); + recoEvent.trdHits = std::move(std::get<0>(trdResults)); + } + + return true; +} + + template<class Unpacker> auto Reco::RunUnpacker(const std::unique_ptr<Unpacker>& unpacker, const fles::Timeslice& ts) -> UnpackResult_t<Unpacker> { diff --git a/algo/global/Reco.h b/algo/global/Reco.h index 6182decda..5a2c62e63 100644 --- a/algo/global/Reco.h +++ b/algo/global/Reco.h @@ -130,13 +130,16 @@ namespace cbm::algo void Init(const Options&); RecoResults Run(const fles::Timeslice&); + + bool ReconstructEvent(const DigiEvent& event); void Finalize(); void PrintTimings(xpu::timings&); void QueueProcessingExtraMetrics(const ProcessingExtraMonitor&); private: - bool fInitialized = false; + bool fInitialized = false; + bool fbReconstructDigiEvents = false; ChainContext fContext; xpu::timings fTimesliceTimesAcc; std::shared_ptr<HistogramSender> fSender; -- GitLab From c3c14ff6073ac6697be3fdaf131f3ffcea07bc29 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Tue, 28 Jan 2025 13:58:00 +0100 Subject: [PATCH 05/17] online: adding tracking into digi-event reconstruction; some modifications to tracking data reading --- algo/ca/TrackingChain.cxx | 57 ++++++++++++---- algo/ca/TrackingChain.h | 6 +- algo/ca/core/data/CaDataManager.cxx | 48 ++++++-------- algo/ca/core/data/CaDataManager.h | 13 ++-- algo/ca/core/utils/CaTrackingMonitor.h | 10 +++ algo/evselector/RecoEventSelectorMonitor.h | 75 ++++++++++++++++++++++ algo/global/Reco.cxx | 64 ++++++++++++++++-- algo/global/Reco.h | 7 +- algo/global/RecoResults.h | 1 + 9 files changed, 225 insertions(+), 56 deletions(-) create mode 100644 algo/evselector/RecoEventSelectorMonitor.h diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx index 1d481261a..d3ee72ab7 100644 --- a/algo/ca/TrackingChain.cxx +++ b/algo/ca/TrackingChain.cxx @@ -40,8 +40,9 @@ using cbm::algo::ca::constants::clrs::GNb; // grin bald text // --------------------------------------------------------------------------------------------------------------------- // -TrackingChain::TrackingChain(const std::unique_ptr<cbm::algo::qa::Manager>& qaManager, std::string_view name) +TrackingChain::TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager, std::string_view name) : fQa(Qa(qaManager, name)) + , fRecoMode(recoMode) { } @@ -116,8 +117,13 @@ void TrackingChain::Init() // ------ Initialize CA framework fCaMonitor.Reset(); - fCaFramework.SetNofThreads(Opts().NumOMPThreads() == std::nullopt ? openmp::GetMaxThreads() - : *(Opts().NumOMPThreads())); + if (ECbmRecoMode::Timeslice == fRecoMode) { + fCaFramework.SetNofThreads(Opts().NumOMPThreads() == std::nullopt ? openmp::GetMaxThreads() + : *(Opts().NumOMPThreads())); + } + else { + fCaFramework.SetNofThreads(1); + } fCaFramework.ReceiveParameters(std::move(parameters)); fCaFramework.Init(ca::TrackingMode::kMcbm); @@ -174,18 +180,26 @@ void TrackingChain::PrepareInput(Input_t recoResults) faHitExternalIndices.clear(); faHitExternalIndices.reserve(nHitsTot); if (fbDetUsed[EDetectorID::kSts]) { + fCaMonitorData.StartTimer(ca::ETimer::PrepareStsHits); ReadHits<EDetectorID::kSts>(recoResults.stsHits); + fCaMonitorData.StopTimer(ca::ETimer::PrepareStsHits); } if (fbDetUsed[EDetectorID::kTrd]) { + fCaMonitorData.StartTimer(ca::ETimer::PrepareTrdHits); ReadHits<EDetectorID::kTrd>(recoResults.trdHits); + fCaMonitorData.StopTimer(ca::ETimer::PrepareTrdHits); } if (fbDetUsed[EDetectorID::kTof]) { + fCaMonitorData.StartTimer(ca::ETimer::PrepareTofHits); ReadHits<EDetectorID::kTof>(recoResults.tofHits); + fCaMonitorData.StopTimer(ca::ETimer::PrepareTofHits); } faHitExternalIndices.shrink_to_fit(); fCaDataManager.SetNhitKeys(fNofHitKeys); L_(debug) << "Tracking chain: " << fCaDataManager.GetNofHits() << " hits will be passed to the ca::Framework"; + fCaMonitorData.StartTimer(ca::ETimer::InputDataTransmission); fCaFramework.ReceiveInputData(fCaDataManager.TakeInputData()); + fCaMonitorData.StopTimer(ca::ETimer::InputDataTransmission); } // --------------------------------------------------------------------------------------------------------------------- @@ -223,12 +237,13 @@ TrackingChain::Output_t TrackingChain::PrepareOutput() trackFirstHit += nHits; } - L_(info) << "TrackingChain: Timeslice contains " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrack) - << " tracks, with " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoStsHit) << " sts hits, " - << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTofHit) << " tof hits, " - << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrdHit) << " trd hits" - << "; the FindTracks routine ran " << fCaMonitorData.GetTimer(ca::ETimer::FindTracks).GetTotal() << " s"; - + if (ECbmRecoMode::Timeslice == fRecoMode) { + L_(info) << "TrackingChain: Timeslice contains " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrack) + << " tracks, with " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoStsHit) << " sts hits, " + << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTofHit) << " tof hits, " + << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrdHit) << " trd hits" + << "; the FindTracks routine ran " << fCaMonitorData.GetTimer(ca::ETimer::FindTracks).GetTotal() << " s"; + } // QA if (fQa.IsActive()) { @@ -327,6 +342,7 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi //int iHitExt = iOffset + iPartHit; // ---- Fill ca::Hit + fCaMonitorData.StartTimer(ca::ETimer::CaHitCreation); ca::Hit caHit; if constexpr (IsSts) { caHit.SetFrontKey(firstHitKey + hit.fFrontClusterId); @@ -337,6 +353,15 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi caHit.SetFrontKey(firstHitKey + iPartHit); caHit.SetBackKey(caHit.FrontKey()); } + + if constexpr (IsTof) { + // Cut the BMon hits (if any) + if (hit.Z() < 0.1) { + // FIXME: Provide BMon addresses explicitly in all the parameter files + continue; + } + } + caHit.SetX(hit.X()); caHit.SetY(hit.Y()); caHit.SetZ(hit.Z()); @@ -366,11 +391,16 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi caHit.SetStation(iStActive); caHit.SetId(fCaDataManager.GetNofHits()); if (caHit.Check()) { - if ((caHit.T() < lastTime - 1000.) && (dataStream < 100000)) { - dataStream++; + if (ECbmRecoMode::Timeslice == fRecoMode) { + if ((caHit.T() < lastTime - 1000.) && (dataStream < 100000)) { + dataStream++; + } + lastTime = caHit.T(); + fCaDataManager.PushBackHit(caHit, dataStreamDet | dataStream); + } + else { + fCaDataManager.PushBackHit(caHit); // A single data stream in event-by-event mode } - lastTime = caHit.T(); - fCaDataManager.PushBackHit(caHit, dataStreamDet | dataStream); faHitExternalIndices.push_back(std::make_tuple(DetID, iPartition, iPartHit)); if (fNofHitKeys <= caHit.FrontKey()) { fNofHitKeys = caHit.FrontKey() + 1; @@ -396,6 +426,7 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedTofHit); } } + fCaMonitorData.StopTimer(ca::ETimer::CaHitCreation); //prevTime = caHit.T(); // ---- Update number of hit keys } // iPartHit diff --git a/algo/ca/TrackingChain.h b/algo/ca/TrackingChain.h index 3f949d360..5d30319fb 100644 --- a/algo/ca/TrackingChain.h +++ b/algo/ca/TrackingChain.h @@ -41,9 +41,10 @@ namespace cbm::algo class TrackingChain : public SubChain { public: /// \brief Constructor from parameters + /// \param recoMode Reconstruction mode /// \param pManager a QA-manager /// \param name A name of the task (histograms directory) - TrackingChain(const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr, std::string_view name = ""); + TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr, std::string_view name = ""); /// \struct Input_t /// \brief Input to the TrackingChain @@ -92,6 +93,7 @@ namespace cbm::algo /// \brief Provides action in the end of the run void Finalize(); + private: // ********************* // ** Utility functions @@ -132,6 +134,8 @@ namespace cbm::algo /// \note Indexing: [globalHitID], value: (DetID, partitionID, hitID) ca::Vector<std::tuple<ca::EDetectorID, uint32_t, uint32_t>> faHitExternalIndices{"faHitExternalIndices"}; + ECbmRecoMode fRecoMode{ECbmRecoMode::Undefined}; ///< Reconstruction mode + static constexpr bool kDEBUG = false; ///< Debug mode }; diff --git a/algo/ca/core/data/CaDataManager.cxx b/algo/ca/core/data/CaDataManager.cxx index 7d237151d..4e74a2524 100644 --- a/algo/ca/core/data/CaDataManager.cxx +++ b/algo/ca/core/data/CaDataManager.cxx @@ -17,23 +17,6 @@ using cbm::algo::ca::DataManager; using cbm::algo::ca::InputData; -// --------------------------------------------------------------------------------------------------------------------- -// -bool DataManager::SendInputData(InputData& destination) -{ - // Set boundary hit indexes - InitData(); - - // Check data before input - if (CheckInputData<constants::control::InputDataQaLevel>()) { - destination = std::move(fInputData); - assert(this->GetNofHits() == 0); - return true; - } - LOG(error) << "L1: Attempt to set up inconsistent input data"; - return false; -} - // --------------------------------------------------------------------------------------------------------------------- // InputData&& DataManager::TakeInputData() @@ -93,16 +76,21 @@ void DataManager::InitData() { // set the end pointers to data streams // TODO: SZh 14.08.2023: Move the max allowed number of streams to the constants.h - if (fInputData.fvStreamStartIndices.size() > 3000) { - LOG(warning) << "ca::DataManager: unexpected order of input data: too many data streams!!! "; - fInputData.fvStreamStartIndices.shrink(3000); - } + int nStreams = fInputData.fvStreamStartIndices.size(); - fInputData.fvStreamStopIndices.reset(nStreams); - for (int i = 0; i < nStreams - 1; i++) { - fInputData.fvStreamStopIndices[i] = fInputData.fvStreamStartIndices[i + 1]; + if (!nStreams) { // No data streams provided + fInputData.fvStreamStartIndices.push_back(0); + fInputData.fvStreamStopIndices.push_back(fInputData.fvHits.size()); } - if (nStreams > 0) { + else { + if (nStreams > 3000) { + LOG(warning) << "ca::DataManager: unexpected order of input data: too many data streams!!! "; + fInputData.fvStreamStartIndices.shrink(3000); + } + fInputData.fvStreamStopIndices.reset(nStreams); + for (int i = 0; i < nStreams - 1; i++) { + fInputData.fvStreamStopIndices[i] = fInputData.fvStreamStartIndices[i + 1]; + } fInputData.fvStreamStopIndices[nStreams - 1] = fInputData.fvHits.size(); } } @@ -112,10 +100,12 @@ void DataManager::InitData() void DataManager::WriteInputData(const std::string& fileName) const { // Check current data object for consistency - if (!CheckInputData<constants::control::InputDataQaLevel>()) { - LOG(error) << "ca::DataManager: input data writer: attempt to write invalid input data object to file \"" - << fileName << "\""; - return; + if constexpr (constants::control::InputDataQaLevel > 0) { + if (!CheckInputData<constants::control::InputDataQaLevel>()) { + LOG(error) << "ca::DataManager: input data writer: attempt to write invalid input data object to file \"" + << fileName << "\""; + return; + } } // Open output binary file diff --git a/algo/ca/core/data/CaDataManager.h b/algo/ca/core/data/CaDataManager.h index d210e52b9..b8dac8630 100644 --- a/algo/ca/core/data/CaDataManager.h +++ b/algo/ca/core/data/CaDataManager.h @@ -54,8 +54,9 @@ namespace cbm::algo::ca /// \param nHits Number of hits to reserve void ResetInputData(HitIndex_t nHits = 0) noexcept; - /// \brief Pushes back a hit - /// \param hit An ca::Hit object + /// \brief Pushes back a hit (with a data stream info) + /// \param hit An ca::Hit object + /// \param streamId Index of a data stream void PushBackHit(const Hit& hit, int64_t streamId) { if (fInputData.fvStreamStartIndices.size() == 0 || fLastStreamId != streamId) { // new data stream @@ -67,14 +68,14 @@ namespace cbm::algo::ca fInputData.fvHits.push_back(hit); } + /// \brief Pushes back a hit + /// \param hit An ca::Hit object + void PushBackHit(const Hit& hit) { fInputData.fvHits.push_back(hit); } + /// \brief Sets the number of hit keys /// \param nKeys Number of hit keys void SetNhitKeys(int nKeys) { fInputData.fNhitKeys = nKeys; } - /// \brief Sends (moves) input data to an object (alternative method of data sending) - /// \param destination Destination object of input data - bool SendInputData(InputData& destination); - /// \brief Takes (moves) the instance of the input data object InputData&& TakeInputData(); diff --git a/algo/ca/core/utils/CaTrackingMonitor.h b/algo/ca/core/utils/CaTrackingMonitor.h index f91de1d75..ffcee0c35 100644 --- a/algo/ca/core/utils/CaTrackingMonitor.h +++ b/algo/ca/core/utils/CaTrackingMonitor.h @@ -52,6 +52,11 @@ namespace cbm::algo::ca { TrackingChain, PrepareInputData, + PrepareStsHits, + PrepareTrdHits, + PrepareTofHits, + InputDataTransmission, + CaHitCreation, Tracking, PrepareTimeslice, TrackingThread, @@ -103,6 +108,11 @@ namespace cbm::algo::ca SetTimerName(ETimer::TrackingChain, "tracking chain"); SetTimerName(ETimer::PrepareInputData, "input data preparation"); + SetTimerName(ETimer::PrepareStsHits, "STS hits preparation"); + SetTimerName(ETimer::PrepareTrdHits, "TRD hits preparation"); + SetTimerName(ETimer::PrepareTofHits, "TOF hits preparation"); + SetTimerName(ETimer::InputDataTransmission, "input data transmission"); + SetTimerName(ETimer::CaHitCreation, "CA hit creation"); SetTimerName(ETimer::Tracking, "algorithm execution"); SetTimerName(ETimer::PrepareTimeslice, "timeslice preparation"); SetTimerName(ETimer::TrackingThread, "tracking on one thread"); diff --git a/algo/evselector/RecoEventSelectorMonitor.h b/algo/evselector/RecoEventSelectorMonitor.h new file mode 100644 index 000000000..330f70702 --- /dev/null +++ b/algo/evselector/RecoEventSelectorMonitor.h @@ -0,0 +1,75 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file RecoEventSelectorMonitor.h +/// \date 28.01.2025 +/// \brief A monitor for reco event selector +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "CaMonitor.h" + +#include <boost/serialization/base_object.hpp> + +namespace cbm::algo::evselect +{ + /// \enum ECounter + /// \brief Counter keys for the event selector monitor + enum class ECounter + { + EventsTotal, ///< Total number of events processed + EventsNeStsHits, ///< Events with not enough STS hits + EventsNeTofHits, ///< Events with enough STS hits, but not enough TOF hits + EventsNeTracks, ///< Events with enough hits, but not enough tracks + EventsSelected, ///< Number of selected events + END + }; + + /// \enum ETimer + /// \brief Timer keys for the event selector monitor + /* clang-format off */ + enum class ETimer { + EventReconstruction, + StsHitFinder, + TofHitFinder, + TrdHitFinder, + TrackFinder, + END + }; + /* clang-format on */ + + /// \brief Specification of ca::MonitorData for the event selector + using MonitorData_t = ca::MonitorData<ECounter, ETimer>; + + /// \class Monitor + /// \brief A monitor for the event selector + class Monitor : public ca::Monitor<ECounter, ETimer> { + public: + /// \brief Default constructor + Monitor() : ca::Monitor<ECounter, ETimer>("Event-selector Monitor") + { + SetCounterName(ECounter::EventsTotal, "total events"); + SetCounterName(ECounter::EventsNeStsHits, "events with not enough STS hits"); + SetCounterName(ECounter::EventsNeTofHits, "events with enough STS hits, but not enough TOF hits"); + SetCounterName(ECounter::EventsNeTracks, "events with enough STS and TOF hits, but not enough tracks"); + SetCounterName(ECounter::EventsSelected, "selected events"); + + SetTimerName(ETimer::EventReconstruction, "event reconstruction"); + SetTimerName(ETimer::StsHitFinder, "hit finding in STS"); + SetTimerName(ETimer::TofHitFinder, "hit finding in TOF"); + SetTimerName(ETimer::TrdHitFinder, "hit finding in TRD"); + SetTimerName(ETimer::TrackFinder, "track finding"); + } + + private: + friend class boost::serialization::access; + template<typename Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& boost::serialization::base_object<ca::Monitor<ECounter, ETimer>>(*this); + } + }; + +} // namespace cbm::algo::evselect diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index a990278ad..cfde9b3b4 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -253,16 +253,29 @@ void Reco::Init(const Options& opts) // Tracking if (Opts().Has(Step::Tracking)) { if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) { - fTracking = std::make_unique<TrackingChain>(fQaManager, "CaTimeslice"); + fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::Timeslice, fQaManager, "CaTimeslice"); } else { - fTracking = std::make_unique<TrackingChain>(); + fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::Timeslice); } fTracking->RegisterSetup(pTrackingSetup); fTracking->SetContext(&fContext); fTracking->Init(); } + if (fbReconstructDigiEvents) { + fEvSelectingMonitor.Reset(); + + if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) { + fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent, fQaManager, "CaEvent"); + } + else { + fTrackingEvent = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent); + } + fTrackingEvent->RegisterSetup(pTrackingSetup); + fTrackingEvent->SetContext(&fContext); + fTrackingEvent->Init(); + // Initialize the QA manager if (fQaManager != nullptr) { fQaManager->Init(); @@ -403,12 +416,15 @@ RecoResults Reco::Run(const fles::Timeslice& ts) } // --- Reconstruct and select digi events - if (Opts().ReconstructDigiEvents()) { + if (fbReconstructDigiEvents) { size_t nDiscardedEvents{0}; + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsTotal, events.size()); for (const auto& event : events) { + fEvSelectingMonitor.StartTimer(evselect::ETimer::EventReconstruction); if (!ReconstructEvent(event)) { ++nDiscardedEvents; } + fEvSelectingMonitor.StopTimer(evselect::ETimer::EventReconstruction); } L_(info) << "Rate of discarded events " << double(nDiscardedEvents) / events.size(); } @@ -461,8 +477,17 @@ void Reco::Finalize() fStsHitFinder->Finalize(); } if (fTracking) { + L_(info) << "Track finding in a timeslice:"; fTracking->Finalize(); } + if (fTrackingEvent) { + L_(info) << "Track finding in digi events:"; + fTrackingEvent->Finalize(); + } + if (fbReconstructDigiEvents) { + L_(info) << fEvSelectingMonitor.ToString(); + } + if (Opts().Profiling() >= ProfilingSummary) { L_(info) << MakeReportSubtimers("Run Summary", fTimesliceTimesAcc) << "\n" @@ -494,8 +519,11 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) RecoResults recoEvent; //* STS hit reconstruction { + fEvSelectingMonitor.StartTimer(evselect::ETimer::StsHitFinder); auto stsResults = (*fStsHitFinder)(digiEvent.fSts); - if (stsResults.hits.NElements() < 2) { // TODO: Provide a config for cuts (testing mode for now) + fEvSelectingMonitor.StopTimer(evselect::ETimer::StsHitFinder); + if (stsResults.hits.NElements() < 4) { // TODO: Provide a config for cuts (testing mode for now) + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeStsHits); return false; } recoEvent.stsHits = stsResults.hits; @@ -503,9 +531,12 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) //* TOF hit reconstruction { + fEvSelectingMonitor.StartTimer(evselect::ETimer::TofHitFinder); auto [caldigis, calmonitor] = (*fTofCalibrator)(digiEvent.fTof); auto [hits, hitmonitor, digiindices] = (*fTofHitFinder)(caldigis); - if (hits.NElements() < 1) { // TODO: Provide a config for cuts (testing mode for now) + fEvSelectingMonitor.StopTimer(evselect::ETimer::TofHitFinder); + if (hits.NElements() < 2) { // TODO: Provide a config for cuts (testing mode for now) + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeTofHits); return false; } recoEvent.tofHits = std::move(hits); @@ -514,16 +545,37 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) //* TRD hit reconstruction { // FIXME: additional copy of digis, figure out how to pass 1d + 2d digis at once to hitfinder + fEvSelectingMonitor.StartTimer(evselect::ETimer::TrdHitFinder); const auto& digis1d = digiEvent.fTrd; const auto& digis2d = digiEvent.fTrd2d; PODVector<CbmTrdDigi> allDigis{}; allDigis.reserve(digis1d.size() + digis2d.size()); std::copy(digis1d.begin(), digis1d.end(), std::back_inserter(allDigis)); std::copy(digis2d.begin(), digis2d.end(), std::back_inserter(allDigis)); - auto trdResults = (*fTrdHitfind)(allDigis); + auto trdResults = (*fTrdHitfind)(allDigis); + fEvSelectingMonitor.StopTimer(evselect::ETimer::TrdHitFinder); recoEvent.trdHits = std::move(std::get<0>(trdResults)); } + //* Tracking + { + fEvSelectingMonitor.StartTimer(evselect::ETimer::TrackFinder); + TrackingChain::Input_t input{.stsHits = recoEvent.stsHits, + .tofHits = recoEvent.tofHits, + .trdHits = recoEvent.trdHits}; + TrackingChain::Output_t output = fTrackingEvent->Run(input); + recoEvent.tracks = std::move(output.tracks); + recoEvent.trackStsHitIndices = std::move(output.stsHitIndices); + recoEvent.trackTofHitIndices = std::move(output.tofHitIndices); + recoEvent.trackTrdHitIndices = std::move(output.trdHitIndices); + fEvSelectingMonitor.StopTimer(evselect::ETimer::TrackFinder); + if (recoEvent.tracks.size() < 2) { // Reject all events with less then two tracks + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeTracks); + return false; + } + } + + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsSelected); return true; } diff --git a/algo/global/Reco.h b/algo/global/Reco.h index 5a2c62e63..1ab27d58d 100644 --- a/algo/global/Reco.h +++ b/algo/global/Reco.h @@ -5,6 +5,7 @@ #include "AlgoTraits.h" #include "SubChain.h" +#include "evselector/RecoEventSelectorMonitor.h" #include "global/RecoResults.h" #include <xpu/host.h> @@ -181,7 +182,11 @@ namespace cbm::algo std::unique_ptr<evbuild::EventbuildChain> fEventBuild; // Tracking - std::unique_ptr<TrackingChain> fTracking; + std::unique_ptr<TrackingChain> fTracking; ///< Tracking in timeslice + std::unique_ptr<TrackingChain> fTrackingEvent; ///< Tracking in event + + // Event selection + evselect::Monitor fEvSelectingMonitor; ///< Monitor for event selecting // QA std::unique_ptr<qa::Manager> fQaManager; diff --git a/algo/global/RecoResults.h b/algo/global/RecoResults.h index eb64fa236..670927953 100644 --- a/algo/global/RecoResults.h +++ b/algo/global/RecoResults.h @@ -45,5 +45,6 @@ namespace cbm::algo ca::Vector<ca::Track> tracks; ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackStsHitIndices; ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTofHitIndices; + ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTrdHitIndices; }; } // namespace cbm::algo -- GitLab From 2454920f311ff930686d3b850f9d19a63b2a8d87 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Sat, 1 Feb 2025 23:55:22 +0100 Subject: [PATCH 06/17] online: an empty chain for V0-finding --- algo/CMakeLists.txt | 3 ++ algo/global/Reco.cxx | 13 ++++++++- algo/global/Reco.h | 4 +++ algo/kfp/KfpV0Finder.cxx | 25 +++++++++++++++++ algo/kfp/KfpV0Finder.h | 47 +++++++++++++++++++++++++++++++ algo/kfp/KfpV0FinderChain.cxx | 30 ++++++++++++++++++++ algo/kfp/KfpV0FinderChain.h | 53 +++++++++++++++++++++++++++++++++++ core/data/CbmEventTriggers.h | 3 ++ 8 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 algo/kfp/KfpV0Finder.cxx create mode 100644 algo/kfp/KfpV0Finder.h create mode 100644 algo/kfp/KfpV0FinderChain.cxx create mode 100644 algo/kfp/KfpV0FinderChain.h diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index a2a052fa4..0524146a4 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory(log) add_subdirectory(data) add_subdirectory(kf) add_subdirectory(ca) +#add_subdirectory(kfp) # For KFParticleOnline # exclude unittests from being build inside the container if (NOT CBM_ONLINE_STANDALONE) @@ -160,6 +161,8 @@ set(SRCS ca/TrackingSetup.cxx ca/TrackingChain.cxx ca/qa/CaQa.cxx + kfp/KfpV0Finder.cxx + kfp/KfpV0FinderChain.cxx kfp/KfpV0FinderConfig.cxx ) diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index cfde9b3b4..7f7de2d06 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -22,6 +22,7 @@ #include "ca/core/data/CaTrack.h" #include "compat/OpenMP.h" #include "evbuild/Config.h" +#include "kfp/KfpV0FinderChain.h" #include "much/Unpack.h" #include "qa/QaManager.h" #include "qa/hitfind/BmonHitfindQa.h" @@ -275,7 +276,12 @@ void Reco::Init(const Options& opts) fTrackingEvent->RegisterSetup(pTrackingSetup); fTrackingEvent->SetContext(&fContext); fTrackingEvent->Init(); - + + fV0Finder = std::make_unique<V0FinderChain>(); + fV0Finder->SetContext(&fContext); + fV0Finder->Init(); + } + // Initialize the QA manager if (fQaManager != nullptr) { fQaManager->Init(); @@ -575,6 +581,11 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) } } + //* V0-selector + { + auto triggers = fV0Finder->ProcessEvent(recoEvent); + } + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsSelected); return true; } diff --git a/algo/global/Reco.h b/algo/global/Reco.h index 1ab27d58d..eb8ba804a 100644 --- a/algo/global/Reco.h +++ b/algo/global/Reco.h @@ -21,6 +21,7 @@ namespace cbm::algo class HistogramSender; class Options; class TrackingChain; + class V0FinderChain; template<class M> struct UnpackMonitor; @@ -185,6 +186,9 @@ namespace cbm::algo std::unique_ptr<TrackingChain> fTracking; ///< Tracking in timeslice std::unique_ptr<TrackingChain> fTrackingEvent; ///< Tracking in event + // V0-finding + std::unique_ptr<V0FinderChain> fV0Finder; ///< V0-finding chain (in event or a bunch of events) + // Event selection evselect::Monitor fEvSelectingMonitor; ///< Monitor for event selecting diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx new file mode 100644 index 000000000..58ca42939 --- /dev/null +++ b/algo/kfp/KfpV0Finder.cxx @@ -0,0 +1,25 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0Finder.cxx +/// \date 01.02.2025 +/// \brief A V0 finding algorithm (implementation) +/// \author Sergei Zharko <s.zharko@gsi.de> + +#include "kfp/KfpV0Finder.h" + +using cbm::algo::kfp::V0Finder; + + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0Finder::Init() {} + +// --------------------------------------------------------------------------------------------------------------------- +// +CbmEventTriggers V0Finder::Process(const RecoResults&) +{ + CbmEventTriggers res; + return res; +} diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h new file mode 100644 index 000000000..d0a8a451a --- /dev/null +++ b/algo/kfp/KfpV0Finder.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0Finder.h +/// \date 01.02.2025 +/// \brief A V0 finding algorithm +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "CbmEventTriggers.h" +#include "global/RecoResults.h" + +namespace cbm::algo::kfp +{ + /// \class V0Finder + /// \brief A V0-finding algorithm + class V0Finder { + public: + /// \brief Default constructor + V0Finder() = default; + + /// \brief Copy constructor + V0Finder(const V0Finder&) = delete; + + /// \brief Move constructor + V0Finder(V0Finder&&) = delete; + + /// \brief Destructor + ~V0Finder() = default; + + /// \brief Copy assignment operator + V0Finder& operator=(const V0Finder&) = delete; + + /// \brief Move assignment operator + V0Finder& operator=(V0Finder&&) = delete; + + /// \brief Initializes the instance (called in the beginning of the run) + void Init(); + + /// \brief Processes a reconstructed data sample, returns a collection of fired triggers + CbmEventTriggers Process(const RecoResults& recoEvent); + + private: + }; +} // namespace cbm::algo::kfp diff --git a/algo/kfp/KfpV0FinderChain.cxx b/algo/kfp/KfpV0FinderChain.cxx new file mode 100644 index 000000000..a2a78be1c --- /dev/null +++ b/algo/kfp/KfpV0FinderChain.cxx @@ -0,0 +1,30 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0FinderChain.cxx +/// \date 01.02.2025 +/// \brief A chain for V0 finding (implementation) +/// \author Sergei Zharko <s.zharko@gsi.de> + +#include "kfp/KfpV0FinderChain.h" + +#include "log/AlgoFairloggerCompat.h" + +using cbm::algo::V0FinderChain; + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0FinderChain::Finalize() {} + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0FinderChain::Init() +{ + L_(info) << "Initializing the V0-finder chain ..."; + L_(info) << "Initializing the V0-finder chain ... done"; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +CbmEventTriggers V0FinderChain::ProcessEvent(const RecoResults& recoEvent) { return fV0Finder.Process(recoEvent); } diff --git a/algo/kfp/KfpV0FinderChain.h b/algo/kfp/KfpV0FinderChain.h new file mode 100644 index 000000000..e3582f931 --- /dev/null +++ b/algo/kfp/KfpV0FinderChain.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0FinderChain.h +/// \date 01.02.2025 +/// \brief A chain for V0 finding +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "CbmEventTriggers.h" +#include "base/SubChain.h" +#include "global/RecoResults.h" +#include "kfp/KfpV0Finder.h" + +namespace cbm::algo +{ + /// \class V0FinderChain + /// \brief A chain for the V0 finder + class V0FinderChain : public SubChain { + public: + /// \brief Default constructor + V0FinderChain() = default; + + /// \brief Copy constructor + V0FinderChain(const V0FinderChain&) = delete; + + /// \brief Move constructor + V0FinderChain(V0FinderChain&&) = delete; + + /// \brief Destructor + ~V0FinderChain() = default; + + /// \brief Copy assignment operator + V0FinderChain& operator=(const V0FinderChain&) = delete; + + /// \brief Move assignment operator + V0FinderChain& operator=(V0FinderChain&&) = delete; + + /// \brief Finalizes the instance (called in the end of the run) + void Finalize(); + + /// \brief Initializes the instance (called in the beginning of the run) + void Init(); + + /// \brief Processes an event, returns a collection of fired triggers + CbmEventTriggers ProcessEvent(const RecoResults& recoEvent); + + private: + kfp::V0Finder fV0Finder; ///< Instance of the V0-finding algorithm + }; +} // namespace cbm::algo diff --git a/core/data/CbmEventTriggers.h b/core/data/CbmEventTriggers.h index ce1b8de53..365d286e5 100644 --- a/core/data/CbmEventTriggers.h +++ b/core/data/CbmEventTriggers.h @@ -9,6 +9,9 @@ #pragma once +#include <cstdint> +#include <string> + #if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA #include <Rtypes.h> // for ClassDef #endif -- GitLab From c05f21ff66b904712ae4796e298f202ffe677a96 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Mon, 3 Feb 2025 20:39:35 +0100 Subject: [PATCH 07/17] online: online interface for the KFParticle and intialization of V0Finder --- algo/CMakeLists.txt | 3 + algo/evselector/RecoEventSelectorMonitor.h | 6 +- algo/global/ParFiles.cxx | 6 ++ algo/global/ParFiles.h | 4 + algo/kfp/CMakeLists.txt | 1 + algo/kfp/KfpV0Finder.cxx | 1 - algo/kfp/KfpV0Finder.h | 87 ++++++++++++++++++++++ algo/kfp/KfpV0FinderChain.cxx | 83 ++++++++++++++++++++- algo/kfp/interface/CMakeLists.txt | 42 +++++++++++ 9 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 algo/kfp/CMakeLists.txt create mode 100644 algo/kfp/interface/CMakeLists.txt diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 0524146a4..6ba7a06c0 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -52,6 +52,7 @@ if (CBM_ONLINE_STANDALONE) add_subdirectory(../external external) endif() +add_subdirectory(kfp) add_subdirectory(log) add_subdirectory(data) add_subdirectory(kf) @@ -226,6 +227,7 @@ target_link_libraries(Algo external::fles_monitoring cppzmq poolstl + PRIVATE CbmKFParticleOnlineInterface ) target_compile_definitions(Algo PUBLIC NO_ROOT) xpu_attach(Algo ${DEVICE_SRCS}) @@ -299,6 +301,7 @@ if (NOT CBM_ONLINE_STANDALONE) external::fles_monitoring cppzmq poolstl + PRIVATE CbmKFParticleOfflineInterface ) xpu_attach(AlgoOffline ${DEVICE_SRCS}) diff --git a/algo/evselector/RecoEventSelectorMonitor.h b/algo/evselector/RecoEventSelectorMonitor.h index 330f70702..41bc2ff13 100644 --- a/algo/evselector/RecoEventSelectorMonitor.h +++ b/algo/evselector/RecoEventSelectorMonitor.h @@ -51,9 +51,9 @@ namespace cbm::algo::evselect Monitor() : ca::Monitor<ECounter, ETimer>("Event-selector Monitor") { SetCounterName(ECounter::EventsTotal, "total events"); - SetCounterName(ECounter::EventsNeStsHits, "events with not enough STS hits"); - SetCounterName(ECounter::EventsNeTofHits, "events with enough STS hits, but not enough TOF hits"); - SetCounterName(ECounter::EventsNeTracks, "events with enough STS and TOF hits, but not enough tracks"); + SetCounterName(ECounter::EventsNeStsHits, "events discarded by N STS hits"); + SetCounterName(ECounter::EventsNeTofHits, "events discarded by N TOF hits"); + SetCounterName(ECounter::EventsNeTracks, "events discarded by N tracks"); SetCounterName(ECounter::EventsSelected, "selected events"); SetTimerName(ETimer::EventReconstruction, "event reconstruction"); diff --git a/algo/global/ParFiles.cxx b/algo/global/ParFiles.cxx index ac2c3b410..38773a0e8 100644 --- a/algo/global/ParFiles.cxx +++ b/algo/global/ParFiles.cxx @@ -45,6 +45,8 @@ ParFiles::ParFiles(uint32_t runId) trd.hitfinder2d = "TrdHitfinder2DPar_mcbm2022.yaml"; ca.mainConfig = "TrackingChainConfig_mcbm2022.yaml"; + + kfp.V0FinderConfig = "mcbm_kfp_lambda.yaml"; break; case Setup::mCBM2024_03: @@ -68,6 +70,8 @@ ParFiles::ParFiles(uint32_t runId) trd.hitfinder2d = "TrdHitfinder2DPar_mcbm2024.yaml"; ca.mainConfig = "TrackingChainConfig_mcbm2024.yaml"; + + kfp.V0FinderConfig = "mcbm_kfp_lambda.yaml"; break; case Setup::mCBM2024_05: @@ -91,6 +95,8 @@ ParFiles::ParFiles(uint32_t runId) trd.hitfinder2d = "mcbm2024_05/TrdHitfinder2DPar.yaml"; ca.mainConfig = "mcbm2024_05/TrackingChainConfig.yaml"; + + kfp.V0FinderConfig = "mcbm_kfp_lambda.yaml"; break; case Setup::mCBM2025_02: diff --git a/algo/global/ParFiles.h b/algo/global/ParFiles.h index 691e27b39..0fe7b3094 100644 --- a/algo/global/ParFiles.h +++ b/algo/global/ParFiles.h @@ -54,6 +54,10 @@ namespace cbm::algo struct { fs::path mainConfig; } ca; + + struct { + fs::path V0FinderConfig; + } kfp; }; } // namespace cbm::algo diff --git a/algo/kfp/CMakeLists.txt b/algo/kfp/CMakeLists.txt new file mode 100644 index 000000000..cc41f095b --- /dev/null +++ b/algo/kfp/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(interface) diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx index 58ca42939..52a8f0d03 100644 --- a/algo/kfp/KfpV0Finder.cxx +++ b/algo/kfp/KfpV0Finder.cxx @@ -11,7 +11,6 @@ using cbm::algo::kfp::V0Finder; - // --------------------------------------------------------------------------------------------------------------------- // void V0Finder::Init() {} diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h index d0a8a451a..5240085b8 100644 --- a/algo/kfp/KfpV0Finder.h +++ b/algo/kfp/KfpV0Finder.h @@ -10,8 +10,12 @@ #pragma once #include "CbmEventTriggers.h" +#include "KFParticleTopoReconstructor.h" #include "global/RecoResults.h" +#include <memory> + + namespace cbm::algo::kfp { /// \class V0Finder @@ -36,12 +40,95 @@ namespace cbm::algo::kfp /// \brief Move assignment operator V0Finder& operator=(V0Finder&&) = delete; + /// \brief Adds particle to reconstruction list + /// \param pdg A PDG code of the particle to be reconstructed + void AddDecayToReconstructionList(int pdg) { GetKFParticleFinder()->AddDecayToReconstructionList(pdg); } + + /// \brief Mutable access to the KfParticleFinder of the run topology reconstructor + KFParticleFinder* GetKFParticleFinder() { return fpTopoReconstructor->GetKFParticleFinder(); } + + /// \brief Constant access to the KfParticleFinder of the run topology reconstructor + const KFParticleFinder* GetKFParticleFinder() const { return fpTopoReconstructor->GetKFParticleFinder(); } + /// \brief Initializes the instance (called in the beginning of the run) void Init(); /// \brief Processes a reconstructed data sample, returns a collection of fired triggers CbmEventTriggers Process(const RecoResults& recoEvent); + /// \brief Sets minimal pion DCA to primary vertex + /// \param dca DCA [cm] + void SetMinPionDca(double dca) { fMinPionDca = dca; } + + /// \brief Sets minimal proton DCA to primary vertex + /// \param dca DCA [cm] + void SetMinProtonDca(double dca) { fMinProtonDca = dca; } + + /// \brief Sets pion velocity range + /// \param vMin Minimal velocity [cm/ns] + /// \param vMax Maximal velocity [cm/ns] + void SetPionVelocityRange(double vMin, double vMax) + { + fMinBetaPion = vMin / kSpeedOfLight; + fMaxBetaPion = vMax / kSpeedOfLight; + } + + /// \brief Sets proton velocity range + /// \param vMin Minimal velocity [cm/ns] + /// \param vMax Maximal velocity [cm/ns] + void SetProtonVelocityRange(double vMin, double vMax) + { + fMinBetaProton = vMin / kSpeedOfLight; + fMaxBetaProton = vMax / kSpeedOfLight; + } + + /// \brief Sets the assigned PDG for primary particles + /// \param pdg PDG code of the particle + void SetPrimaryAssignedPdg(int pdg) { fPrimaryAssignedPdg = pdg; } + + /// \brief Assignes an uncertainty to the momentum measurement + /// \param uncertainty Relative uncertainty ( = sqrt(var(q/p)) / (q/p)) + void SetQpAssignedUncertainty(double uncertainty) { fQpAssignedUncertainty = uncertainty; } + + /// \brief Sets an offset to t0 + /// \param offset An offset [ns] + void SetTzeroOffset(double offset) { fTzeroOffset = offset; } + + //* Specific parameters for the KFParticleFinder + /// \brief Sets cut on the distance to the primary vertex from the decay vertex + /// \param cut Cut value [cm] + void SetLCut(float cut) { GetKFParticleFinder()->SetLCut(cut); } + + /// \brief Sets cut on \f$\chi^2_{prim}\f$ of each track for 2-daughter decays + /// \param cut Cut value + void SetChiPrimaryCut2D(float cut) { GetKFParticleFinder()->SetChiPrimaryCut2D(cut); } + + /// \brief Sets cut on \f$\chi^2_{geo}\f$ for 2-daughter decays + /// \param cut Cut value + void SetChi2Cut2D(float cut) { GetKFParticleFinder()->SetChi2Cut2D(cut); } + + /// \brief Sets cut on \f$l/\Delta l\f$ for 2-daughter decays + /// \param cut Cut value + void SetLdLCut2D(float cut) { GetKFParticleFinder()->SetLdLCut2D(cut); } + private: + //* 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] + + /// \brief An instance of the topology reconstructor + std::unique_ptr<KFParticleTopoReconstructor> fpTopoReconstructor{std::make_unique<KFParticleTopoReconstructor>()}; + + //* Different run-time cuts and flags (TODO: define in a config) + double fTzeroOffset{0.}; ///< Offset for T0 + double fMinPionDca{1.5}; ///< Minimum DCA to PV for pions + double fMinProtonDca{0.5}; ///< Minimum DCA to PV for protons + double fQpAssignedUncertainty{0.1}; ///< Assigned relative uncertainty for q/p estimation + int fPrimaryAssignedPdg{321}; ///< Assigned PDG hypothesis for primary particles + double fMinBetaProton{0.}; ///< Minimal proton velocity (beta) [c] + double fMaxBetaProton{1.}; ///< Maximal proton velocity (beta) [c] + double fMinBetaPion{0.}; ///< Minimal proton velocity (beta) [c] + double fMaxBetaPion{1.}; ///< Maximal proton velocity (beta) [c] }; } // namespace cbm::algo::kfp diff --git a/algo/kfp/KfpV0FinderChain.cxx b/algo/kfp/KfpV0FinderChain.cxx index a2a78be1c..1fb1a7a9d 100644 --- a/algo/kfp/KfpV0FinderChain.cxx +++ b/algo/kfp/KfpV0FinderChain.cxx @@ -9,7 +9,12 @@ #include "kfp/KfpV0FinderChain.h" +#include "global/ParFiles.h" +#include "kfp/KfpV0FinderConfig.h" #include "log/AlgoFairloggerCompat.h" +#include "yaml/Yaml.h" + +#include <sstream> using cbm::algo::V0FinderChain; @@ -20,9 +25,81 @@ void V0FinderChain::Finalize() {} // --------------------------------------------------------------------------------------------------------------------- // void V0FinderChain::Init() -{ - L_(info) << "Initializing the V0-finder chain ..."; - L_(info) << "Initializing the V0-finder chain ... done"; +try { + L_(info) << "kfp::V0FinderChain: initializing the V0-finder chain ..."; + + // ----- Read configuration file + ParFiles parFiles(Opts().RunId()); + auto config = yaml::ReadFromFile<kfp::V0FinderConfig>(Opts().ParamsDir() / parFiles.kfp.V0FinderConfig); + L_(info) << config.ToString(); + + //* Check the V0 type + if (config.reconstructPdg != 3122) { // At the moment only Lambda analysis is possible + std::stringstream msg; + msg << "kfp::V0FinderChain: at the moment only lambda finding is possible. Provided PDG: " << config.reconstructPdg; + throw std::runtime_error(msg.str()); + } + + //* Define daughter particles + auto& particles{config.cuts.particles}; + int iPion{-1}; + int iProton{-1}; + for (int iParticle = 0; iParticle < int(particles.size()); ++iParticle) { + const auto& particle = particles[iParticle]; + auto CheckOutParticle = [&](int pdg, int& iParticleToFind) { + if (particle.pdg == pdg) { + if (iParticleToFind == -1) { + iParticleToFind = iParticle; + } + else { + std::stringstream msg; + msg << "kfp::V0FinderChain: entry for pdg= " << pdg << " is defined more then one time in the "; + msg << "config.cuts.particles"; + throw std::runtime_error(msg.str()); + } + } + }; + CheckOutParticle(-211, iPion); + CheckOutParticle(2212, iProton); + } + if (iProton == -1 || iPion == -1) { + std::stringstream msg; + msg << "kfp::V0FinderChain: config cuts/particles: either pion or proton settings are not found"; + throw std::runtime_error(msg.str()); + } + const auto& pion{particles[iPion]}; + const auto& proton{particles[iProton]}; + + // ----- Set the V0-finder properties + // TODO: In future, there are will be a several instances of the V0Finder, each for a particular thread + { + //* Set particle PID properties + fV0Finder.SetMinPionDca(pion.minDca); + fV0Finder.SetMinProtonDca(proton.minDca); + fV0Finder.SetPionVelocityRange(pion.minVelocity, pion.maxVelocity); + fV0Finder.SetProtonVelocityRange(proton.minVelocity, proton.maxVelocity); + + //* Set KFParticleFinder properties + auto& kfpCuts{config.cuts.kfp}; + fV0Finder.SetLdLCut2D(kfpCuts.minDecayLDL); + fV0Finder.SetLCut(kfpCuts.minDecayLength); + fV0Finder.SetChi2Cut2D(kfpCuts.maxChi2NdfGeo); + fV0Finder.SetChiPrimaryCut2D(kfpCuts.maxChi2NdfPrim); + + //* Set other properties + fV0Finder.SetTzeroOffset(config.tZeroOffset); + fV0Finder.SetQpAssignedUncertainty(config.qpAssignedUncertainty); + fV0Finder.AddDecayToReconstructionList(config.reconstructPdg); + fV0Finder.SetPrimaryAssignedPdg(config.primaryAssignedPdg); + + //* Init the V0 finder + fV0Finder.Init(); + } + L_(info) << "kfp::V0FinderChain: initializing the V0-finder chain ... done"; +} +catch (const std::exception& err) { + L_(info) << "kfp::V0FinderChain: initializing the V0-finder chain ... failed. Reason: " << err.what(); + throw std::runtime_error("initialization of V0-finder chain failed"); } // --------------------------------------------------------------------------------------------------------------------- diff --git a/algo/kfp/interface/CMakeLists.txt b/algo/kfp/interface/CMakeLists.txt new file mode 100644 index 000000000..8b037a70e --- /dev/null +++ b/algo/kfp/interface/CMakeLists.txt @@ -0,0 +1,42 @@ +# The script creates two libraries: +# 1) CbmKFParticleOnlineInterface -- a specific KFParticle library interface for the CBM online reconstruction; +# 2) CbmKFParticleOfflineInterface -- a specific interface for the offline reconstruction in CBM. +# The both libraries contain only the KFParticle core and do not include KFParticleTest or KFParticlePerformance. + +set(KFP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/KFParticle/KFParticle) + +set(SRCS + ${KFP_SOURCE_DIR}/KFParticle.cxx + ${KFP_SOURCE_DIR}/KFParticleBase.cxx + ${KFP_SOURCE_DIR}/KFParticleBaseSIMD.cxx + ${KFP_SOURCE_DIR}/KFParticleDatabase.cxx + ${KFP_SOURCE_DIR}/KFParticleFinder.cxx + ${KFP_SOURCE_DIR}/KFParticlePVReconstructor.cxx + ${KFP_SOURCE_DIR}/KFParticleSIMD.cxx + ${KFP_SOURCE_DIR}/KFParticleTopoReconstructor.cxx + ${KFP_SOURCE_DIR}/KFPEmcCluster.cxx + ${KFP_SOURCE_DIR}/KFPTrack.cxx + ${KFP_SOURCE_DIR}/KFPTrackVector.cxx + ${KFP_SOURCE_DIR}/KFPVertex.cxx + ${KFP_SOURCE_DIR}/KFVertex.cxx +) + +### CbmKFParticleOnlineInterface +add_library(CbmKFParticleOnlineInterface INTERFACE) +target_include_directories(CbmKFParticleOnlineInterface INTERFACE) +target_compile_definitions(CbmKFParticleOnlineInterface + INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) +target_link_libraries(CbmKFParticleOnlineInterface + INTERFACE ROOT::Core KFParticle) +install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) + +if(NOT CBM_ONLINE_STANDALONE) +### CbmKFParticleOfflineInterface + add_library(CbmKFParticleOfflineInterface INTERFACE) + target_include_directories(CbmKFParticleOfflineInterface INTERFACE) + target_compile_definitions(CbmKFParticleOfflineInterface + INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) + target_link_libraries(CbmKFParticleOfflineInterface + INTERFACE ROOT::Core KFParticle) + install(TARGETS CbmKFParticleOfflineInterface DESTINATION lib) +endif() -- GitLab From 933f7d5481ac9d611e6212cff39b9c5eece4cdb1 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Mon, 3 Feb 2025 23:18:49 +0100 Subject: [PATCH 08/17] online V0 finder: adding a monitor --- algo/ca/TrackingChain.cxx | 3 +- algo/ca/TrackingChain.h | 3 +- algo/ca/core/utils/CaMonitor.h | 12 +++-- algo/global/Reco.cxx | 1 + algo/kfp/KfpV0Finder.cxx | 3 ++ algo/kfp/KfpV0Finder.h | 8 +++- algo/kfp/KfpV0FinderChain.cxx | 37 +++++++++------ algo/kfp/KfpV0FinderChain.h | 16 +++++-- algo/kfp/KfpV0FinderMonitor.h | 86 ++++++++++++++++++++++++++++++++++ 9 files changed, 143 insertions(+), 26 deletions(-) create mode 100644 algo/kfp/KfpV0FinderMonitor.h diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx index d3ee72ab7..5ce7a4e51 100644 --- a/algo/ca/TrackingChain.cxx +++ b/algo/ca/TrackingChain.cxx @@ -40,7 +40,8 @@ using cbm::algo::ca::constants::clrs::GNb; // grin bald text // --------------------------------------------------------------------------------------------------------------------- // -TrackingChain::TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager, std::string_view name) +TrackingChain::TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager, + std::string_view name) : fQa(Qa(qaManager, name)) , fRecoMode(recoMode) { diff --git a/algo/ca/TrackingChain.h b/algo/ca/TrackingChain.h index 5d30319fb..39ba48e26 100644 --- a/algo/ca/TrackingChain.h +++ b/algo/ca/TrackingChain.h @@ -44,7 +44,8 @@ namespace cbm::algo /// \param recoMode Reconstruction mode /// \param pManager a QA-manager /// \param name A name of the task (histograms directory) - TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr, std::string_view name = ""); + TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr, + std::string_view name = ""); /// \struct Input_t /// \brief Input to the TrackingChain diff --git a/algo/ca/core/utils/CaMonitor.h b/algo/ca/core/utils/CaMonitor.h index 389b196fe..6d26469cf 100644 --- a/algo/ca/core/utils/CaMonitor.h +++ b/algo/ca/core/utils/CaMonitor.h @@ -171,12 +171,13 @@ namespace cbm::algo::ca using std::setfill; using std::setw; std::stringstream msg; - constexpr size_t widthKey = 30; constexpr size_t width = 24; + auto Cmp = [](const std::string& l, const std::string& r) { return l.size() < r.size(); }; msg << "\n===== Monitor: " << fsName << "\n"; if constexpr (!std::is_same_v<ETimerKey, EDummy>) { + size_t widthKeyTimer{std::max_element(faTimerNames.begin(), faTimerNames.end(), Cmp)->size() + 1}; msg << "\n----- Timers:\n"; - msg << setw(widthKey) << left << "Key" << ' '; + msg << setw(widthKeyTimer) << left << "Key" << ' '; msg << setw(width) << left << "N Calls" << ' '; msg << setw(width) << left << "Average [s]" << ' '; msg << setw(width) << left << "Min [s]" << ' '; @@ -185,7 +186,7 @@ namespace cbm::algo::ca msg << right; for (int iKey = 0; iKey < fMonitorData.GetNofTimers(); ++iKey) { const Timer& timer = fMonitorData.GetTimer(static_cast<ETimerKey>(iKey)); - msg << setw(widthKey) << faTimerNames[iKey] << ' '; + msg << setw(widthKeyTimer) << faTimerNames[iKey] << ' '; msg << setw(width) << timer.GetNofCalls() << ' '; msg << setw(width) << timer.GetAverage() << ' '; msg << setw(width) << timer.GetMin() << ' '; @@ -195,7 +196,8 @@ namespace cbm::algo::ca } msg << "\n----- Counters:\n"; - msg << setw(widthKey) << left << "Key" << ' '; + size_t widthKeyCounter{std::max_element(faCounterNames.begin(), faCounterNames.end(), Cmp)->size() + 1}; + msg << setw(widthKeyCounter) << left << "Key" << ' '; msg << setw(width) << left << "Total" << ' '; for (auto key : fvCounterRatioKeys) { msg << setw(width) << left << std::string("per ") + faCounterNames[key] << ' '; @@ -203,7 +205,7 @@ namespace cbm::algo::ca msg << '\n'; for (int iKey = 0; iKey < fMonitorData.GetNofCounters(); ++iKey) { auto counterValue = fMonitorData.GetCounterValue(static_cast<ECounterKey>(iKey)); - msg << setw(widthKey) << left << faCounterNames[iKey] << ' '; + msg << setw(widthKeyCounter) << left << faCounterNames[iKey] << ' '; msg << setw(width) << right << counterValue << ' '; for (auto keyDen : fvCounterRatioKeys) { auto ratio = static_cast<double>(counterValue) / fMonitorData.GetCounterValue(keyDen); diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 7f7de2d06..e9d10bdd3 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -491,6 +491,7 @@ void Reco::Finalize() fTrackingEvent->Finalize(); } if (fbReconstructDigiEvents) { + fV0Finder->Finalize(); L_(info) << fEvSelectingMonitor.ToString(); } diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx index 52a8f0d03..5677dc5f6 100644 --- a/algo/kfp/KfpV0Finder.cxx +++ b/algo/kfp/KfpV0Finder.cxx @@ -20,5 +20,8 @@ void V0Finder::Init() {} CbmEventTriggers V0Finder::Process(const RecoResults&) { CbmEventTriggers res; + fEventMonitor.Reset(); + fEventMonitor.StartTimer(ETimer::Event); + fEventMonitor.StopTimer(ETimer::Event); return res; } diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h index 5240085b8..e34e543d2 100644 --- a/algo/kfp/KfpV0Finder.h +++ b/algo/kfp/KfpV0Finder.h @@ -12,6 +12,7 @@ #include "CbmEventTriggers.h" #include "KFParticleTopoReconstructor.h" #include "global/RecoResults.h" +#include "kfp/KfpV0FinderMonitor.h" #include <memory> @@ -50,10 +51,13 @@ namespace cbm::algo::kfp /// \brief Constant access to the KfParticleFinder of the run topology reconstructor const KFParticleFinder* GetKFParticleFinder() const { return fpTopoReconstructor->GetKFParticleFinder(); } + /// \brief Gets monitor data + const V0FinderMonitorData_t& GetEventMonitor() const { return fEventMonitor; } + /// \brief Initializes the instance (called in the beginning of the run) void Init(); - /// \brief Processes a reconstructed data sample, returns a collection of fired triggers + /// \brief Processes a reconstructed data sample, returns a collection of fired triggers CbmEventTriggers Process(const RecoResults& recoEvent); /// \brief Sets minimal pion DCA to primary vertex @@ -120,6 +124,8 @@ namespace cbm::algo::kfp /// \brief An instance of the topology reconstructor std::unique_ptr<KFParticleTopoReconstructor> fpTopoReconstructor{std::make_unique<KFParticleTopoReconstructor>()}; + V0FinderMonitorData_t fEventMonitor; ///< Monitor data instance (per event) + //* Different run-time cuts and flags (TODO: define in a config) double fTzeroOffset{0.}; ///< Offset for T0 double fMinPionDca{1.5}; ///< Minimum DCA to PV for pions diff --git a/algo/kfp/KfpV0FinderChain.cxx b/algo/kfp/KfpV0FinderChain.cxx index 1fb1a7a9d..621f4d0d8 100644 --- a/algo/kfp/KfpV0FinderChain.cxx +++ b/algo/kfp/KfpV0FinderChain.cxx @@ -20,7 +20,7 @@ using cbm::algo::V0FinderChain; // --------------------------------------------------------------------------------------------------------------------- // -void V0FinderChain::Finalize() {} +void V0FinderChain::Finalize() { L_(info) << fMonitorRun.ToString(); } // --------------------------------------------------------------------------------------------------------------------- // @@ -74,26 +74,26 @@ try { // TODO: In future, there are will be a several instances of the V0Finder, each for a particular thread { //* Set particle PID properties - fV0Finder.SetMinPionDca(pion.minDca); - fV0Finder.SetMinProtonDca(proton.minDca); - fV0Finder.SetPionVelocityRange(pion.minVelocity, pion.maxVelocity); - fV0Finder.SetProtonVelocityRange(proton.minVelocity, proton.maxVelocity); + fFinder.SetMinPionDca(pion.minDca); + fFinder.SetMinProtonDca(proton.minDca); + fFinder.SetPionVelocityRange(pion.minVelocity, pion.maxVelocity); + fFinder.SetProtonVelocityRange(proton.minVelocity, proton.maxVelocity); //* Set KFParticleFinder properties auto& kfpCuts{config.cuts.kfp}; - fV0Finder.SetLdLCut2D(kfpCuts.minDecayLDL); - fV0Finder.SetLCut(kfpCuts.minDecayLength); - fV0Finder.SetChi2Cut2D(kfpCuts.maxChi2NdfGeo); - fV0Finder.SetChiPrimaryCut2D(kfpCuts.maxChi2NdfPrim); + fFinder.SetLdLCut2D(kfpCuts.minDecayLDL); + fFinder.SetLCut(kfpCuts.minDecayLength); + fFinder.SetChi2Cut2D(kfpCuts.maxChi2NdfGeo); + fFinder.SetChiPrimaryCut2D(kfpCuts.maxChi2NdfPrim); //* Set other properties - fV0Finder.SetTzeroOffset(config.tZeroOffset); - fV0Finder.SetQpAssignedUncertainty(config.qpAssignedUncertainty); - fV0Finder.AddDecayToReconstructionList(config.reconstructPdg); - fV0Finder.SetPrimaryAssignedPdg(config.primaryAssignedPdg); + fFinder.SetTzeroOffset(config.tZeroOffset); + fFinder.SetQpAssignedUncertainty(config.qpAssignedUncertainty); + fFinder.AddDecayToReconstructionList(config.reconstructPdg); + fFinder.SetPrimaryAssignedPdg(config.primaryAssignedPdg); //* Init the V0 finder - fV0Finder.Init(); + fFinder.Init(); } L_(info) << "kfp::V0FinderChain: initializing the V0-finder chain ... done"; } @@ -104,4 +104,11 @@ catch (const std::exception& err) { // --------------------------------------------------------------------------------------------------------------------- // -CbmEventTriggers V0FinderChain::ProcessEvent(const RecoResults& recoEvent) { return fV0Finder.Process(recoEvent); } +V0FinderChain::EventOutput V0FinderChain::ProcessEvent(const RecoResults& recoEvent) +{ + EventOutput res; + res.triggers = fFinder.Process(recoEvent); + res.monitor = fFinder.GetEventMonitor(); + fMonitorRun.AddMonitorData(res.monitor); + return res; +} diff --git a/algo/kfp/KfpV0FinderChain.h b/algo/kfp/KfpV0FinderChain.h index e3582f931..2be7ddf5d 100644 --- a/algo/kfp/KfpV0FinderChain.h +++ b/algo/kfp/KfpV0FinderChain.h @@ -13,6 +13,7 @@ #include "base/SubChain.h" #include "global/RecoResults.h" #include "kfp/KfpV0Finder.h" +#include "kfp/KfpV0FinderMonitor.h" namespace cbm::algo { @@ -20,6 +21,13 @@ namespace cbm::algo /// \brief A chain for the V0 finder class V0FinderChain : public SubChain { public: + /// \struct EventOutput + /// \brief Output from the event + struct EventOutput { + CbmEventTriggers triggers; ///< Set of triggers + kfp::V0FinderMonitorData_t monitor; ///< Monitor + }; + /// \brief Default constructor V0FinderChain() = default; @@ -44,10 +52,12 @@ namespace cbm::algo /// \brief Initializes the instance (called in the beginning of the run) void Init(); - /// \brief Processes an event, returns a collection of fired triggers - CbmEventTriggers ProcessEvent(const RecoResults& recoEvent); + /// \brief Processes an event, returns a collection of fired triggers + EventOutput ProcessEvent(const RecoResults& recoEvent); + private: - kfp::V0Finder fV0Finder; ///< Instance of the V0-finding algorithm + kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm + kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run }; } // namespace cbm::algo diff --git a/algo/kfp/KfpV0FinderMonitor.h b/algo/kfp/KfpV0FinderMonitor.h new file mode 100644 index 000000000..1f63bb246 --- /dev/null +++ b/algo/kfp/KfpV0FinderMonitor.h @@ -0,0 +1,86 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file KfpV0FinderMonitor.h +/// \date 03.02.2025 +/// \brief A monitor for the V0Finder +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "CaMonitor.h" + +namespace cbm::algo::kfp +{ + /// \enum ECounter + /// \brief Counter keys for the V0FinderMonitor + enum class ECounter + { + TracksTotal, ///< Total number of tracks + TracksSelected, ///< Tracks, which satisfy topology PID applicability + TracksInfiniteParam, ///< Tracks, which have infinite parameters + TracksWoTofHits, ///< Tracks, which have no TOF hits + TracksWNegativeTofHitTime, ///< Tracks, the last TOF hit of which has a negative time (it's time is less then the t0) + TracksWoStsHits, ///< Tracks, which have no STS hits + TracksWoPid, ///< Tracks, which has undefined PID + TracksWoMomentum, ///< Tracks, which has no momentum + TracksWUnphysicalBeta, ///< Tracks with beta > 1 + Pions, ///< Number of pion-candidates + Protons, ///< Number of proton-candidates + EventsTotal, ///< Total number of events + EventsWoTzero, ///< Number of events with undefined t-zero + EventsLambdaCand, ///< Events with at least one pion and one proton candidate + KfpEventsLambdaCand, ///< Events with lambda-candidates in KF-particle + KfpLambdaCandidates, ///< Number of lambda-candidates + END + }; + + /// \enum ETimer + /// \brief Timer keys for the V0FinderMonitor + enum class ETimer + { + Event, ///< Timer to process a single event + END + }; + + /// \brief Specification of ca::MonitorData for the V0Finder + using V0FinderMonitorData_t = ca::MonitorData<ECounter, ETimer>; + + /// \class Monitor + /// \brief A monitor for the V0Finder + class V0FinderMonitor : public ca::Monitor<ECounter, ETimer> { + public: + /// \brief Default constructor + V0FinderMonitor() : ca::Monitor<ECounter, ETimer>("V0 finder monitor") + { + SetCounterName(ECounter::TracksTotal, "all tracks"); + SetCounterName(ECounter::TracksSelected, "pre-selected tracks"); + SetCounterName(ECounter::TracksInfiniteParam, "tracks satisfying PID selection"); + SetCounterName(ECounter::TracksWoTofHits, "tracks w/o TOF hits"); + SetCounterName(ECounter::TracksWNegativeTofHitTime, "tracks w/ negative TOF time"); + SetCounterName(ECounter::TracksWoStsHits, "tracks w/o STS hits"); + SetCounterName(ECounter::TracksWoPid, "tracks w/o PID"); + SetCounterName(ECounter::TracksWoMomentum, "tracks w/o momentum"); + SetCounterName(ECounter::TracksWUnphysicalBeta, "tracks w/ beta > 1"); + SetCounterName(ECounter::Pions, "pion candidates"); + SetCounterName(ECounter::Protons, "proton candidates"); + SetCounterName(ECounter::EventsTotal, "all events"); + SetCounterName(ECounter::EventsWoTzero, "events w/o t0"); + SetCounterName(ECounter::EventsLambdaCand, "events passed to KFP"); + SetCounterName(ECounter::KfpEventsLambdaCand, "events w/ lambda candidates"); + SetCounterName(ECounter::KfpLambdaCandidates, "lambda candidates"); + + SetTimerName(ETimer::Event, "event processing"); + } + + private: + friend class boost::serialization::access; + template<typename Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& boost::serialization::base_object<ca::Monitor<ECounter, ETimer>>(*this); + } + }; + +} // namespace cbm::algo::kfp -- GitLab From 172082af59152be0aab0b73006a01ef0a8fcd5e4 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Tue, 11 Feb 2025 05:59:27 +0100 Subject: [PATCH 09/17] online: Adding BMON hit-finder to event reconstruction --- algo/global/Reco.cxx | 41 +++++++++++++++++++++++-------------- algo/global/RecoResults.h | 2 ++ algo/kfp/KfpV0FinderChain.h | 1 + 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index e9d10bdd3..0f933400d 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -212,21 +212,6 @@ void Reco::Init(const Options& opts) fStsHitFinder->SetParameters(hitFinderPars); } - // BMON Hitfinder - if (Opts().Has(fles::Subsystem::BMON) && Opts().Has(Step::LocalReco)) { - auto calibSetup = yaml::ReadFromFile<bmon::CalibrateSetup>(opts.ParamsDir() / parFiles.bmon.calibrate); - fBmonCalibrator = std::make_unique<bmon::Calibrate>(calibSetup); - - auto hitfindSetup = yaml::ReadFromFile<bmon::HitfindSetup>(opts.ParamsDir() / parFiles.bmon.hitfinder); - fBmonHitFinder = std::make_unique<bmon::Hitfind>(hitfindSetup); - - if (fQaManager != nullptr && Opts().Has(QaStep::RecoBmon)) { - fBmonHitFinderQa = std::make_unique<bmon::HitfindQa>(fQaManager, "BmonHitfindEvent"); - fBmonHitFinderQa->InitParameters(calibSetup, hitfindSetup); - fBmonHitFinderQa->Init(); - } - } - // TOF Hitfinder if (Opts().Has(fles::Subsystem::TOF) && Opts().Has(Step::LocalReco)) { auto calibSetup = yaml::ReadFromFile<tof::CalibrateSetup>(opts.ParamsDir() / parFiles.tof.calibrate); @@ -249,6 +234,7 @@ void Reco::Init(const Options& opts) fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::STS); fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::TRD); fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::TOF); + fbReconstructDigiEvents &= Opts().Has(fles::Subsystem::BMON); } // Tracking @@ -267,6 +253,18 @@ void Reco::Init(const Options& opts) if (fbReconstructDigiEvents) { fEvSelectingMonitor.Reset(); + // BMON hit finding in event reconstruction + auto bmonCalSetup = yaml::ReadFromFile<bmon::CalibrateSetup>(opts.ParamsDir() / parFiles.bmon.calibrate); + auto bmonHitSetup = yaml::ReadFromFile<bmon::HitfindSetup>(opts.ParamsDir() / parFiles.bmon.hitfinder); + fBmonCalibrator = std::make_unique<bmon::Calibrate>(bmonCalSetup); + fBmonHitFinder = std::make_unique<bmon::Hitfind>(bmonHitSetup); + if (fQaManager != nullptr && Opts().Has(QaStep::RecoBmon)) { + fBmonHitFinderQa = std::make_unique<bmon::HitfindQa>(fQaManager, "BmonHitfindEvent"); + fBmonHitFinderQa->InitParameters(bmonCalSetup, bmonHitSetup); + fBmonHitFinderQa->Init(); + } + + // Tracking in event reconstruction if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) { fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent, fQaManager, "CaEvent"); } @@ -524,6 +522,19 @@ void Reco::PrintTimings(xpu::timings& timings) bool Reco::ReconstructEvent(const DigiEvent& digiEvent) { RecoResults recoEvent; + //* BMON hit reconstruction + { + auto [calDigis, calMonitor] = (*fBmonCalibrator)(recoEvent.fBmon); + auto [hits, hitMonitor, digiIndices] = (*fBmonHitFinder)(calDigis); + if (fBmonHitFinderQa != nullptr) { + fBmonHitFinderQa->RegisterDigis(&calDigis); + fBmonHitFinderQa->RegisterHits(&hits); + fBmonHitFinderQa->RegisterDigiIndices(&digiIndices); + fBmonHitFinderQa->Exec(); + } + recoEvent.bmonHits = std::move(hits); + } + //* STS hit reconstruction { fEvSelectingMonitor.StartTimer(evselect::ETimer::StsHitFinder); diff --git a/algo/global/RecoResults.h b/algo/global/RecoResults.h index 670927953..25a3f73a2 100644 --- a/algo/global/RecoResults.h +++ b/algo/global/RecoResults.h @@ -12,6 +12,7 @@ #include "DigiData.h" #include "PartitionedSpan.h" #include "PartitionedVector.h" +#include "bmon/Hit.h" #include "ca/core/data/CaTrack.h" #include "ca/core/utils/CaVector.h" #include "sts/Cluster.h" @@ -41,6 +42,7 @@ namespace cbm::algo PartitionedSpan<sts::Hit> stsHits; PartitionedVector<tof::Hit> tofHits; PartitionedVector<trd::Hit> trdHits; + PartitionedVector<bmon::Hit> bmonHits; ca::Vector<ca::Track> tracks; ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackStsHitIndices; diff --git a/algo/kfp/KfpV0FinderChain.h b/algo/kfp/KfpV0FinderChain.h index 2be7ddf5d..c328750aa 100644 --- a/algo/kfp/KfpV0FinderChain.h +++ b/algo/kfp/KfpV0FinderChain.h @@ -59,5 +59,6 @@ namespace cbm::algo private: kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run + uint32_t fBmonAddress; ///< Address of selected BMON }; } // namespace cbm::algo -- GitLab From 25b3a198ccc23026bfacc03d26454bbe6229b54a Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Tue, 11 Feb 2025 16:52:06 +0100 Subject: [PATCH 10/17] linking KFParticle library to statndalone cbmreco - using a KFParticle version with no ROOT dependencies --- algo/ca/TrackingChain.cxx | 2 + algo/ca/core/utils/CaEnumArray.h | 2 +- algo/ca/qa/CaQa.cxx | 18 +++--- algo/detectors/bmon/Hitfind.h | 5 +- algo/detectors/tof/Clusterizer.cxx | 22 ++++++- algo/detectors/tof/Hitfind.cxx | 1 - algo/evselector/KfpfV0FinderConfig.h | 74 ---------------------- algo/evselector/RecoEventSelectorMonitor.h | 14 ++-- algo/global/ParFiles.cxx | 6 +- algo/global/Reco.cxx | 7 +- algo/global/RecoResults.h | 6 +- algo/kfp/KfpV0Finder.cxx | 70 +++++++++++++++++++- algo/kfp/KfpV0Finder.h | 44 ++++++++++++- algo/kfp/KfpV0FinderChain.cxx | 19 ++++++ algo/kfp/KfpV0FinderChain.h | 12 ++-- algo/kfp/KfpV0FinderConfig.h | 2 + algo/kfp/interface/CMakeLists.txt | 63 ++++++++++-------- algo/kfp/interface/RootTypesDef.h | 18 ++++++ algo/qa/QaData.cxx | 1 + core/data/CbmEventTriggers.h | 2 +- core/data/tof/CbmTofAddress.cxx | 1 - external/CMakeLists.txt | 15 +++++ macro/KF/configs/mcbm_kfpf_lambda.yaml | 10 +-- 23 files changed, 273 insertions(+), 141 deletions(-) delete mode 100644 algo/evselector/KfpfV0FinderConfig.h create mode 100644 algo/kfp/interface/RootTypesDef.h diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx index 5ce7a4e51..374c23bb1 100644 --- a/algo/ca/TrackingChain.cxx +++ b/algo/ca/TrackingChain.cxx @@ -133,6 +133,7 @@ void TrackingChain::Init() fQa.RegisterParameters(&fCaFramework.GetParameters()); fQa.Init(); } + L_(info) << "TRACKING QA: " << fQa.IsActive(); } // --------------------------------------------------------------------------------------------------------------------- @@ -225,6 +226,7 @@ TrackingChain::Output_t TrackingChain::PrepareOutput() int iHitInternal = fCaFramework.GetInputData().GetHit(fCaFramework.fRecoHits[trackFirstHit + iHit]).Id(); const auto [detID, iPartition, iPartHit] = faHitExternalIndices[iHitInternal]; switch (detID) { + // FIXME: store a global hit index instead of (partition, hit) case ca::EDetectorID::kSts: output.stsHitIndices[iTrk].push_back(std::make_pair(iPartition, iPartHit)); break; case ca::EDetectorID::kTof: output.tofHitIndices[iTrk].push_back(std::make_pair(iPartition, iPartHit)); break; case ca::EDetectorID::kTrd: output.trdHitIndices[iTrk].push_back(std::make_pair(iPartition, iPartHit)); break; diff --git a/algo/ca/core/utils/CaEnumArray.h b/algo/ca/core/utils/CaEnumArray.h index 5acd38589..84e90a0ed 100644 --- a/algo/ca/core/utils/CaEnumArray.h +++ b/algo/ca/core/utils/CaEnumArray.h @@ -38,7 +38,7 @@ namespace cbm::algo::ca public: /// \brief Mutable access operator, indexed by enum entry - T& operator[](const E& entry) + T& operator[](const E entry) { return std::array<T, static_cast<std::size_t>(E::END)>::operator[](static_cast<U>(entry)); } diff --git a/algo/ca/qa/CaQa.cxx b/algo/ca/qa/CaQa.cxx index 05815198d..8d081862c 100644 --- a/algo/ca/qa/CaQa.cxx +++ b/algo/ca/qa/CaQa.cxx @@ -187,22 +187,22 @@ void Qa::Init() continue; } { - auto sName = format("track_{}_theta", vsPointName[i]); + auto sName = format("{}_track_{}_theta", GetTaskName(), vsPointName[i]); auto sTitl = format("#theta at {} hit; #theta", vsPointName[i]); fvphTrkTheta[i] = MakeObj<H1D>(sName, sTitl, 62, 0., 90.); } { - auto sName = format("track_{}_phi", vsPointName[i]); + auto sName = format("{}_track_{}_phi", GetTaskName(), vsPointName[i]); auto sTitl = format("#phi at {} hit; #phi", vsPointName[i]); fvphTrkPhi[i] = MakeObj<H1D>(sName, sTitl, 62, -180., 180.); } { - auto sName = format("track_{}_thata_phi", vsPointName[i]); + auto sName = format("{}_track_{}_thata_phi", GetTaskName(), vsPointName[i]); auto sTitl = format("#theta vs #phi at {} hit; #phi; #theta", vsPointName[i]); fvphTrkPhiTheta[i] = MakeObj<H2D>(sName, sTitl, 62, -180., 180., 62, 0., 90.); } { - auto sName = format("track_{}_chi2_ndf", vsPointName[i]); + auto sName = format("{}_track_{}_chi2_ndf", GetTaskName(), vsPointName[i]); auto sTitl = format("#chi^{{2}}/NDF at {} hit; #chi^{{2}}/NDF", vsPointName[i]); fvphTrkChi2Ndf[i] = MakeObj<H1D>(sName, sTitl, 100, 0., 20.); } @@ -212,7 +212,7 @@ void Qa::Init() double xMin = -0.5; double xMax = double(knStaMax) - 0.5; { - auto sName = "track_fst_lst_sta"; + auto sName = format("{}_track_fst_lst_sta", GetTaskName()); auto sTitl = "First vs. last station index;ID^{last}_{station};ID^{first}_{station}"; fphTrkFstLstSta = MakeObj<H2D>(sName, sTitl, nBins, xMin, xMax, nBins, xMin, xMax); } @@ -227,7 +227,7 @@ void Qa::Init() auto setNm = EHitSet::Input == hitSet ? "input" : "used"; auto setTl = EHitSet::Input == hitSet ? "Input" : "Used"; { // XY - auto name = format("ca_hit_{}_occupancy_xy", setNm); + auto name = format("{}_ca_hit_{}_occupancy_xy", GetTaskName(), setNm); auto titl = format("{} hit occupancy in different stations in XY plane", setNm); auto canv = CanvasConfig(name, titl); for (int iSt = 0; iSt < nSt; ++iSt) { @@ -238,7 +238,7 @@ void Qa::Init() AddCanvasConfig(canv); } { // ZX and ZY - auto name = format("ca_hit_{}_occupancy_zx_zy", setNm); + auto name = format("{}_ca_hit_{}_occupancy_zx_zy", GetTaskName(), setNm); auto titl = format("{} hit occupancy in different stations in ZX and ZY planes", setTl); auto canv = CanvasConfig(name, titl); { // ZX @@ -259,7 +259,7 @@ void Qa::Init() } } if (kDebug) { - auto name = format("ca_hit_usage_xy"); + auto name = format("{}_ca_hit_usage_xy", GetTaskName()); auto titl = format("Hit usage in different stations in XY plane"); auto canv = CanvasConfig(name, titl); for (int iSt = 0; iSt < nSt; ++iSt) { @@ -273,7 +273,7 @@ void Qa::Init() // Tracks canvas { - auto canv = CanvasConfig("ca_tracks", "Tracking output QA"); + auto canv = CanvasConfig(format("{}_ca_tracks", GetTaskName()), "Tracking output QA"); { auto pad = PadConfig(true, true, false, false, true); pad.RegisterHistogram(fvphTrkPhiTheta[0], "colz"); diff --git a/algo/detectors/bmon/Hitfind.h b/algo/detectors/bmon/Hitfind.h index 68d7d3a9b..0257a9b74 100644 --- a/algo/detectors/bmon/Hitfind.h +++ b/algo/detectors/bmon/Hitfind.h @@ -45,11 +45,14 @@ namespace cbm::algo::bmon /// \param iThread Index of thread Output_t operator()(gsl::span<CbmBmonDigi> digisIn, uint32_t iThread = 0); - private: // members /// \brief Returns an index of the diamond by the address /// \param address A hardware address of the digi size_t GetDiamondIndex(uint32_t address) const { return ((fSelectionBitmask & address) >> fSelectionBitsOffset); } + /// \brief Gets diamond addresses vector + const PODVector<uint32_t>& GetDiamondAddresses() const { return fDiamondAddress; } + + private: // members uint32_t fNofThreads; ///< Number of threads uint32_t fSelectionBitsOffset; ///< Number of bits to ther right from the first bit in the selection mask uint32_t fSelectionBitmask; ///< Selection bitmask diff --git a/algo/detectors/tof/Clusterizer.cxx b/algo/detectors/tof/Clusterizer.cxx index caf6d34f7..1a182b625 100644 --- a/algo/detectors/tof/Clusterizer.cxx +++ b/algo/detectors/tof/Clusterizer.cxx @@ -12,6 +12,9 @@ #include <iomanip> #include <iostream> #include <map> +#include <numeric> + +#include <fmt/format.h> namespace cbm::algo::tof { @@ -49,6 +52,8 @@ namespace cbm::algo::tof //Iterator-based version. Faster than index-based version. Clusterizer::resultType Clusterizer::buildClusters(std::vector<inputType>& input) { + size_t nInputDigis{ + std::accumulate(input.begin(), input.end(), 0, [](size_t s, const auto& v) { return s + v.size(); })}; // Hit variables Hit cluster; @@ -72,6 +77,10 @@ namespace cbm::algo::tof lastChanPos.push_back(input[chan].begin()); } + size_t nInputDigisUsed{0}; + if (nInputDigis > 0) { + //std::cout << "------------- call: buildClusters: number of digis: " << nInputDigis << '\n'; + } for (int32_t chan = 0; (size_t) chan < numChan; chan++) { // Set partition vectors @@ -83,11 +92,18 @@ namespace cbm::algo::tof chanSizes.back() = 0; continue; } + nInputDigisUsed += input[chan].size(); inputType& storDigi = input[chan]; auto digiIt = storDigi.begin(); + if (std::distance(storDigi.begin(), storDigi.end())) { + //std::cout << "DISTANCE: " << std::distance(storDigi.begin(), storDigi.end()) << '\n'; + for (const auto& digi : storDigi) { + std::string sAddress = fmt::format("{:#08x}", digi.first->GetAddress()); + //std::cout << " " << digi.first->GetTime() << "ns, address: " << sAddress << '\n'; + } + } while (1 < std::distance(digiIt, storDigi.end())) { - while (digiIt->first->GetSide() == std::next(digiIt)->first->GetSide()) { // Not one Digi of each end! digiIt++; if (2 > std::distance(digiIt, storDigi.end())) { @@ -181,6 +197,10 @@ namespace cbm::algo::tof storDigi.clear(); } // for( int32_t chan = 0; chan < iNbCh; chan++ ) + //if (nInputDigis> 0) { + // std::cout << ">>>>>> " << nInputDigisUsed << "/" << nInputDigis << '\n'; + //} + // Now check if another hit/cluster is started // and save it if it's the case. if (0 < cluster.numChan()) { diff --git a/algo/detectors/tof/Hitfind.cxx b/algo/detectors/tof/Hitfind.cxx index 119db83b1..5abf282f3 100644 --- a/algo/detectors/tof/Hitfind.cxx +++ b/algo/detectors/tof/Hitfind.cxx @@ -28,7 +28,6 @@ namespace cbm::algo::tof for (int32_t Sm = 0; Sm < NbSm; Sm++) { for (int32_t Rpc = 0; Rpc < NbRpc; Rpc++) { - auto par = std::make_unique<cbm::algo::tof::ClusterizerRpcPar>(); HitfindSetup::Rpc rpcPar = setup.rpcs[SmType][Sm * NbRpc + Rpc]; diff --git a/algo/evselector/KfpfV0FinderConfig.h b/algo/evselector/KfpfV0FinderConfig.h deleted file mode 100644 index cbeaec0a7..000000000 --- a/algo/evselector/KfpfV0FinderConfig.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// \file KfpfV0FinderConfig.h -/// \date 29.01.2025 -/// \brief Configuration structure for V0 selector in mCBM -/// \author Sergei Zharko <s.zharko@gsi.de> - -#pragma once - -#include "yaml/Yaml.h" - -#include <vector> - -namespace cbm::algo::kfpf -{ - /// \struct CutsKfpf - /// \brief Cuts for the KFParticleFinder - struct CutsKfpf { - float minDecayLength; ///< Minimal decay length of particles [cm] - float minDecayLDL; ///< Minimal value of decay length to decay length error ratio - float maxChi2NdfPrim; ///< Maximal chi2/NDF for primary particles (coming from the PV) - float maxChi2NdfGeo; ///< Maximal chi2/NDF for V0 candidates - - CBM_YAML_PROPERTIES( - yaml::Property(&CutsKfpf::minDecayLength, "min_decay_length", "Minimal decay length of particles [cm]"), - yaml::Property(&CutsKfpf::minDecayLDL, "min_decay_ldl", "Minimal value of decay length to decay length error ratio"), - yaml::Property(&CutsKfpf::maxChi2NdfPrim, "max_chi2_ndf_prim", "Maximal chi2/NDF for primary particles"), - yaml::Property(&CutsKfpf::maxChi2NdfGeo, "max_chi2_ndf_geo", "Maximal chi2/NDF for V0 candidates")); - }; - - /// \struct ParticlePid - /// \brief PID and pre-selection cuts for a given particle - struct ParticlePid { - int pdg; ///< PDG code for particle - double minDca; ///< Minimal DCA to PV [cm] - double minVelocity; ///< Minimal velocity [cm/ns] - double maxVelocity; ///< Maximal velocity [cm/ns] - - CBM_YAML_PROPERTIES( - yaml::Property(&ParticlePid::pdg, "pdg", "PDG code of the particle"), - yaml::Property(&ParticlePid::minDca, "min_dca", "Minimal DCA to PV [cm]"), - yaml::Property(&ParticlePid::minVelocity, "min_velocity", "Minimal velocity [cm/ns]"), - yaml::Property(&ParticlePid::maxVelocity, "max_velocity", "Maximal velocity [cm/ns]")); - }; - - /// \struct Cuts; - struct Cuts { - CutsKfpf kfpf; ///< KFParticleFinder specific cuts - std::vector<ParticlePid> particles; ///< Daughter PID cuts and other properties - - CBM_YAML_PROPERTIES( - yaml::Property(&Cuts::kfpf, "kfpf", "Specific cuts for the KFParticleFinder"), - yaml::Property(&Cuts::particles, "particles", "Particle identification cuts and properties")); - }; - - /// \struct LambdaFinderConfig - /// \brief Configuration for the V0 finder - struct V0FinderConfig { - Cuts cuts; ///< Different selection cuts - double tZeroOffset; ///< Offset for T0 [ns] - double qpAssignedUncertainty; ///< Assigned relative uncertainty for q/p estimation - int primaryAssignedPdg; ///< Assigned PDG hypothesis for primary particles - int reconstructPdg; ///< PDG of the particle, the decay of which is to be reconstructed - - CBM_YAML_PROPERTIES( - yaml::Property(&V0FinderConfig::cuts, "cuts", "Different selection cuts"), - yaml::Property(&V0FinderConfig::tZeroOffset, "t0_offset", "The t0 offset [ns]"), - yaml::Property(&V0FinderConfig::qpAssignedUncertainty, "qa_uncertainty", "Assigned relative uncertainty for q/p"), - yaml::Property(&V0FinderConfig::primaryAssignedPdg, "primary_pdg", "Assigned PDG code for primary tracks"), - yaml::Property(&V0FinderConfig::reconstructPdg, "reconstruct_pdg", "PDG code of the particle to be reconstructed")); - }; -} // namespace cbm::algo::kfpf diff --git a/algo/evselector/RecoEventSelectorMonitor.h b/algo/evselector/RecoEventSelectorMonitor.h index 41bc2ff13..82c68535c 100644 --- a/algo/evselector/RecoEventSelectorMonitor.h +++ b/algo/evselector/RecoEventSelectorMonitor.h @@ -19,11 +19,12 @@ namespace cbm::algo::evselect /// \brief Counter keys for the event selector monitor enum class ECounter { - EventsTotal, ///< Total number of events processed - EventsNeStsHits, ///< Events with not enough STS hits - EventsNeTofHits, ///< Events with enough STS hits, but not enough TOF hits - EventsNeTracks, ///< Events with enough hits, but not enough tracks - EventsSelected, ///< Number of selected events + EventsTotal, ///< Total number of events processed + EventsNeStsHits, ///< Events with not enough STS hits + EventsNeTofHits, ///< Events with enough STS hits, but not enough TOF hits + EventsNeBmonHits, ///< Events with not enough BMon hits + EventsNeTracks, ///< Events with enough hits, but not enough tracks + EventsSelected, ///< Number of selected events END }; @@ -32,6 +33,7 @@ namespace cbm::algo::evselect /* clang-format off */ enum class ETimer { EventReconstruction, + BmonHitFinder, StsHitFinder, TofHitFinder, TrdHitFinder, @@ -53,10 +55,12 @@ namespace cbm::algo::evselect SetCounterName(ECounter::EventsTotal, "total events"); SetCounterName(ECounter::EventsNeStsHits, "events discarded by N STS hits"); SetCounterName(ECounter::EventsNeTofHits, "events discarded by N TOF hits"); + SetCounterName(ECounter::EventsNeBmonHits, "events discarded by N BMon hits"); SetCounterName(ECounter::EventsNeTracks, "events discarded by N tracks"); SetCounterName(ECounter::EventsSelected, "selected events"); SetTimerName(ETimer::EventReconstruction, "event reconstruction"); + SetTimerName(ETimer::BmonHitFinder, "hit finding in Bmon"); SetTimerName(ETimer::StsHitFinder, "hit finding in STS"); SetTimerName(ETimer::TofHitFinder, "hit finding in TOF"); SetTimerName(ETimer::TrdHitFinder, "hit finding in TRD"); diff --git a/algo/global/ParFiles.cxx b/algo/global/ParFiles.cxx index 38773a0e8..7b73fe779 100644 --- a/algo/global/ParFiles.cxx +++ b/algo/global/ParFiles.cxx @@ -46,7 +46,7 @@ ParFiles::ParFiles(uint32_t runId) ca.mainConfig = "TrackingChainConfig_mcbm2022.yaml"; - kfp.V0FinderConfig = "mcbm_kfp_lambda.yaml"; + kfp.V0FinderConfig = "kfp_lambda_v22a.yaml"; break; case Setup::mCBM2024_03: @@ -71,7 +71,7 @@ ParFiles::ParFiles(uint32_t runId) ca.mainConfig = "TrackingChainConfig_mcbm2024.yaml"; - kfp.V0FinderConfig = "mcbm_kfp_lambda.yaml"; + kfp.V0FinderConfig = "kfp_lambda_v24a.yaml"; break; case Setup::mCBM2024_05: @@ -96,7 +96,7 @@ ParFiles::ParFiles(uint32_t runId) ca.mainConfig = "mcbm2024_05/TrackingChainConfig.yaml"; - kfp.V0FinderConfig = "mcbm_kfp_lambda.yaml"; + kfp.V0FinderConfig = "kfp_lambda_v24b.yaml"; break; case Setup::mCBM2025_02: diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 0f933400d..37c37b508 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -266,7 +266,7 @@ void Reco::Init(const Options& opts) // Tracking in event reconstruction if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) { - fTracking = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent, fQaManager, "CaEvent"); + fTrackingEvent = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent, fQaManager, "CaEvent"); } else { fTrackingEvent = std::make_unique<TrackingChain>(ECbmRecoMode::EventByEvent); @@ -277,6 +277,7 @@ void Reco::Init(const Options& opts) fV0Finder = std::make_unique<V0FinderChain>(); fV0Finder->SetContext(&fContext); + fV0Finder->SetBmonDefinedAddresses(fBmonHitFinder->GetDiamondAddresses()); fV0Finder->Init(); } @@ -524,8 +525,10 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) RecoResults recoEvent; //* BMON hit reconstruction { - auto [calDigis, calMonitor] = (*fBmonCalibrator)(recoEvent.fBmon); + fEvSelectingMonitor.StartTimer(evselect::ETimer::BmonHitFinder); + auto [calDigis, calMonitor] = (*fBmonCalibrator)(digiEvent.fBmon); auto [hits, hitMonitor, digiIndices] = (*fBmonHitFinder)(calDigis); + fEvSelectingMonitor.StopTimer(evselect::ETimer::BmonHitFinder); if (fBmonHitFinderQa != nullptr) { fBmonHitFinderQa->RegisterDigis(&calDigis); fBmonHitFinderQa->RegisterHits(&hits); diff --git a/algo/global/RecoResults.h b/algo/global/RecoResults.h index 25a3f73a2..7795dda39 100644 --- a/algo/global/RecoResults.h +++ b/algo/global/RecoResults.h @@ -45,8 +45,8 @@ namespace cbm::algo PartitionedVector<bmon::Hit> bmonHits; ca::Vector<ca::Track> tracks; - ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackStsHitIndices; - ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTofHitIndices; - ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTrdHitIndices; + ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackStsHitIndices; // [trk][hit][(iPart, iHit)] + ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTofHitIndices; // [trk][hit][(iPart, iHit)] + ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTrdHitIndices; // [trk][hit][(iPart, iHit)] }; } // namespace cbm::algo diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx index 5677dc5f6..5a5ddbc6e 100644 --- a/algo/kfp/KfpV0Finder.cxx +++ b/algo/kfp/KfpV0Finder.cxx @@ -9,19 +9,87 @@ #include "kfp/KfpV0Finder.h" +#include "global/RecoResults.h" + +#include <algorithm> +#include <limits> +#include <sstream> + +using cbm::algo::RecoResults; using cbm::algo::kfp::V0Finder; +// --------------------------------------------------------------------------------------------------------------------- +// +std::vector<double> V0Finder::CollectDca(const RecoResults& recoEvent) const +{ + std::vector<double> dca(recoEvent.trackStsHitIndices.size(), std::numeric_limits<double>::signaling_NaN()); + const auto& stsHitIndices = recoEvent.trackStsHitIndices; + for (size_t iTrk = 0; iTrk < stsHitIndices.size(); ++iTrk) { + const auto& stsHitIndicesInTrack = stsHitIndices[iTrk]; + if (stsHitIndicesInTrack.size() < 2) { // less then two sts hits + continue; + } + auto [iPtFst, iHitFst] = stsHitIndicesInTrack[0]; + auto [iPtSnd, iHitSnd] = stsHitIndicesInTrack[1]; + dca[iTrk] = EstimateDca(recoEvent.stsHits[iPtFst][iHitFst], recoEvent.stsHits[iPtSnd][iHitSnd]); + } + return dca; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::vector<double> V0Finder::CollectT0(gsl::span<const bmon::Hit> bmonHits) const +{ + std::vector<double> t0; + t0.reserve(bmonHits.size()); + std::transform(bmonHits.begin(), bmonHits.end(), std::back_inserter(t0), [&](const auto& h) { return h.GetTime(); }); + return t0; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +double V0Finder::EstimateDca(const sts::Hit& fst, const sts::Hit& snd) const +{ + double factor{(fst.Z() - fOrigin[2]) / (snd.Z() - fst.Z())}; + double dcaX{fst.X() - fOrigin[0] - factor * (snd.X() - fst.X())}; + double dcaY{fst.Y() - fOrigin[1] - factor * (snd.Y() - fst.Y())}; + return std::sqrt(dcaX * dcaX + dcaY * dcaY); +} + // --------------------------------------------------------------------------------------------------------------------- // void V0Finder::Init() {} // --------------------------------------------------------------------------------------------------------------------- // -CbmEventTriggers V0Finder::Process(const RecoResults&) +CbmEventTriggers V0Finder::Process(const RecoResults& recoEvent) { CbmEventTriggers res; fEventMonitor.Reset(); fEventMonitor.StartTimer(ETimer::Event); + fEventMonitor.IncrementCounter(ECounter::EventsTotal); + + // ----- Define T0 + // So far we cannot preselect a hit from multiple ones, we will be using all of them iteratively to find lambdas + auto vT0 = CollectT0(recoEvent.bmonHits[fBmonPartitionIndex]); + if (vT0.empty()) { + fEventMonitor.IncrementCounter(ECounter::EventsWoTzero); + return res; + } + + //L_(info) << "------- Event: "; + + // ----- Estimate DCA of tracks + // If a track has less then two STS hits, and undefined DCA value is stored + std::vector<double> vDca = CollectDca(recoEvent); + + // ***** DEBUG: BEGIN + //for (auto dca: vDca) { + // L_(info) << "dca=" << dca; + //} + // ***** DEBUG: END + + fEventMonitor.StopTimer(ETimer::Event); return res; } diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h index e34e543d2..ef8b1e22b 100644 --- a/algo/kfp/KfpV0Finder.h +++ b/algo/kfp/KfpV0Finder.h @@ -14,6 +14,7 @@ #include "global/RecoResults.h" #include "kfp/KfpV0FinderMonitor.h" +#include <limits> #include <memory> @@ -60,7 +61,10 @@ namespace cbm::algo::kfp /// \brief Processes a reconstructed data sample, returns a collection of fired triggers CbmEventTriggers Process(const RecoResults& recoEvent); - /// \brief Sets minimal pion DCA to primary vertex + /// \brief Sets an address of a reference BMON diamond + /// \param iPartition An index of the BMON hit partition: used to selected the hits from the particular config + void SetBmonPartitionIndex(int iPartition) { fBmonPartitionIndex = iPartition; } + /// \param dca DCA [cm] void SetMinPionDca(double dca) { fMinPionDca = dca; } @@ -68,6 +72,14 @@ namespace cbm::algo::kfp /// \param dca DCA [cm] void SetMinProtonDca(double dca) { fMinProtonDca = dca; } + /// \brief Sets origin + /// \param x X-coordinate of the origin [cm] + /// \param y Y-coordinate of the origin [cm] + /// \param z Z-coordinate of the origin [cm] + // FIXME: for now origin is defined as the target center, later it can be changed + void SetOrigin(double x, double y, double z) { fOrigin = {x, y, z}; } + + /// \brief Sets minimal pion DCA to primary vertex /// \brief Sets pion velocity range /// \param vMin Minimal velocity [cm/ns] /// \param vMax Maximal velocity [cm/ns] @@ -116,13 +128,29 @@ namespace cbm::algo::kfp void SetLdLCut2D(float cut) { GetKFParticleFinder()->SetLdLCut2D(cut); } private: + /// \brief Collects T0 values among the BMON hits + /// \param bmonHits A span of BMON hits + /// \return A vector of T0-s + /// + /// If multiple T0-s are found, the routine will run multiple times, until V0-candidates are found + std::vector<double> CollectT0(gsl::span<const bmon::Hit> bmonHits) const; + + /// \brief Collects a vector of DCA + /// \param recoEvent Instance of a reconstructed event + /// \return A vector of DCAs to origin + std::vector<double> CollectDca(const RecoResults& recoEvent) const; + + /// \brief Estimate DCA of a track to origin + /// \param fst first STS hit + /// \param snd second STS hit + /// \return dca [cm] + double EstimateDca(const sts::Hit& fst, const sts::Hit& snd) const; + //* 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] - /// \brief An instance of the topology reconstructor - std::unique_ptr<KFParticleTopoReconstructor> fpTopoReconstructor{std::make_unique<KFParticleTopoReconstructor>()}; V0FinderMonitorData_t fEventMonitor; ///< Monitor data instance (per event) @@ -136,5 +164,15 @@ namespace cbm::algo::kfp double fMaxBetaProton{1.}; ///< Maximal proton velocity (beta) [c] double fMinBetaPion{0.}; ///< Minimal proton velocity (beta) [c] double fMaxBetaPion{1.}; ///< Maximal proton velocity (beta) [c] + + + //* Run-time variables, provided by framework + int fBmonPartitionIndex{-1}; ///< Index of selected partition in BMON hit vector + std::array<double, 3> fOrigin{0., 0., 0.}; ///< Coordinates of origin [cm] + + //* Auxilary variables + + /// \brief An instance of the topology reconstructor + std::unique_ptr<KFParticleTopoReconstructor> fpTopoReconstructor{std::make_unique<KFParticleTopoReconstructor>()}; }; } // namespace cbm::algo::kfp diff --git a/algo/kfp/KfpV0FinderChain.cxx b/algo/kfp/KfpV0FinderChain.cxx index 621f4d0d8..f41a0597a 100644 --- a/algo/kfp/KfpV0FinderChain.cxx +++ b/algo/kfp/KfpV0FinderChain.cxx @@ -70,10 +70,29 @@ try { const auto& pion{particles[iPion]}; const auto& proton{particles[iProton]}; + // ----- Define a BMON diamond + if (fBmonDefinedAddresses.empty()) { + throw std::runtime_error("kfp::V0FinderChain: BMON available addresses were not set"); + } + int iBmonPartitionSelect = -1; + for (int iPart = 0; iPart < static_cast<int>(fBmonDefinedAddresses.size()); ++iPart) { + if (config.bmonAddress == fBmonDefinedAddresses[iPart]) { + iBmonPartitionSelect = iPart; + break; + } + } + if (iBmonPartitionSelect < 0) { + std::stringstream msg; + msg << "kfp::V0FinderChain: a reference BMON address ( " << std::hex << config.bmonAddress << std::dec + << " ) differs from ones, provided by hitfinder. Please check your configuration"; + throw std::runtime_error(msg.str()); + } + // ----- Set the V0-finder properties // TODO: In future, there are will be a several instances of the V0Finder, each for a particular thread { //* Set particle PID properties + fFinder.SetBmonPartitionIndex(iBmonPartitionSelect); fFinder.SetMinPionDca(pion.minDca); fFinder.SetMinProtonDca(proton.minDca); fFinder.SetPionVelocityRange(pion.minVelocity, pion.maxVelocity); diff --git a/algo/kfp/KfpV0FinderChain.h b/algo/kfp/KfpV0FinderChain.h index c328750aa..630fc02e6 100644 --- a/algo/kfp/KfpV0FinderChain.h +++ b/algo/kfp/KfpV0FinderChain.h @@ -10,6 +10,7 @@ #pragma once #include "CbmEventTriggers.h" +#include "PODVector.h" #include "base/SubChain.h" #include "global/RecoResults.h" #include "kfp/KfpV0Finder.h" @@ -49,16 +50,19 @@ namespace cbm::algo /// \brief Finalizes the instance (called in the end of the run) void Finalize(); + /// \brief Sets BMON diamond addresses array + /// \note The addresses must be taken from bmon::Hitfind::GetDiamondAddresses() + void SetBmonDefinedAddresses(const PODVector<uint32_t>& addresses) { fBmonDefinedAddresses = addresses; } + /// \brief Initializes the instance (called in the beginning of the run) void Init(); /// \brief Processes an event, returns a collection of fired triggers EventOutput ProcessEvent(const RecoResults& recoEvent); - private: - kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm - kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run - uint32_t fBmonAddress; ///< Address of selected BMON + kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm + kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run + PODVector<uint32_t> fBmonDefinedAddresses; ///< Available addresses of BMON }; } // namespace cbm::algo diff --git a/algo/kfp/KfpV0FinderConfig.h b/algo/kfp/KfpV0FinderConfig.h index dacc3705d..4bd992e0c 100644 --- a/algo/kfp/KfpV0FinderConfig.h +++ b/algo/kfp/KfpV0FinderConfig.h @@ -69,6 +69,7 @@ namespace cbm::algo::kfp /// \brief Configuration for the V0 finder struct V0FinderConfig { Cuts cuts; ///< Different selection cuts + uint32_t bmonAddress; ///< Address of BMON diamond (if multiple alternative are present, only one must be selected) double tZeroOffset; ///< Offset for T0 [ns] double qpAssignedUncertainty; ///< Assigned relative uncertainty for q/p estimation int primaryAssignedPdg; ///< Assigned PDG hypothesis for primary particles @@ -76,6 +77,7 @@ namespace cbm::algo::kfp CBM_YAML_PROPERTIES( yaml::Property(&V0FinderConfig::cuts, "cuts", "Different selection cuts"), + yaml::Property(&V0FinderConfig::bmonAddress, "bmon_address", "Address of reference BMON diamond"), yaml::Property(&V0FinderConfig::tZeroOffset, "t0_offset", "The t0 offset [ns]"), yaml::Property(&V0FinderConfig::qpAssignedUncertainty, "qa_uncertainty", "Assigned relative uncertainty for q/p"), yaml::Property(&V0FinderConfig::primaryAssignedPdg, "primary_pdg", "Assigned PDG code for primary tracks"), diff --git a/algo/kfp/interface/CMakeLists.txt b/algo/kfp/interface/CMakeLists.txt index 8b037a70e..ce26ad980 100644 --- a/algo/kfp/interface/CMakeLists.txt +++ b/algo/kfp/interface/CMakeLists.txt @@ -3,35 +3,19 @@ # 2) CbmKFParticleOfflineInterface -- a specific interface for the offline reconstruction in CBM. # The both libraries contain only the KFParticle core and do not include KFParticleTest or KFParticlePerformance. -set(KFP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/KFParticle/KFParticle) -set(SRCS - ${KFP_SOURCE_DIR}/KFParticle.cxx - ${KFP_SOURCE_DIR}/KFParticleBase.cxx - ${KFP_SOURCE_DIR}/KFParticleBaseSIMD.cxx - ${KFP_SOURCE_DIR}/KFParticleDatabase.cxx - ${KFP_SOURCE_DIR}/KFParticleFinder.cxx - ${KFP_SOURCE_DIR}/KFParticlePVReconstructor.cxx - ${KFP_SOURCE_DIR}/KFParticleSIMD.cxx - ${KFP_SOURCE_DIR}/KFParticleTopoReconstructor.cxx - ${KFP_SOURCE_DIR}/KFPEmcCluster.cxx - ${KFP_SOURCE_DIR}/KFPTrack.cxx - ${KFP_SOURCE_DIR}/KFPTrackVector.cxx - ${KFP_SOURCE_DIR}/KFPVertex.cxx - ${KFP_SOURCE_DIR}/KFVertex.cxx -) - -### CbmKFParticleOnlineInterface -add_library(CbmKFParticleOnlineInterface INTERFACE) -target_include_directories(CbmKFParticleOnlineInterface INTERFACE) -target_compile_definitions(CbmKFParticleOnlineInterface - INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) -target_link_libraries(CbmKFParticleOnlineInterface - INTERFACE ROOT::Core KFParticle) -install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) if(NOT CBM_ONLINE_STANDALONE) -### CbmKFParticleOfflineInterface + ### CbmKFParticleOnlineInterface + add_library(CbmKFParticleOnlineInterface INTERFACE) + target_include_directories(CbmKFParticleOnlineInterface INTERFACE) + target_compile_definitions(CbmKFParticleOnlineInterface + INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) + target_link_libraries(CbmKFParticleOnlineInterface + INTERFACE ROOT::Core KFParticle) + install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) + + ### CbmKFParticleOfflineInterface add_library(CbmKFParticleOfflineInterface INTERFACE) target_include_directories(CbmKFParticleOfflineInterface INTERFACE) target_compile_definitions(CbmKFParticleOfflineInterface @@ -39,4 +23,31 @@ if(NOT CBM_ONLINE_STANDALONE) target_link_libraries(CbmKFParticleOfflineInterface INTERFACE ROOT::Core KFParticle) install(TARGETS CbmKFParticleOfflineInterface DESTINATION lib) +else() + # Creating a replacement of the CbmKFParticleOnlineInterface library for a standalone mode + set(KFP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/KFParticle/KFParticle) + + set(SRCS + ${KFP_SOURCE_DIR}/KFParticle.cxx + ${KFP_SOURCE_DIR}/KFParticleBase.cxx + ${KFP_SOURCE_DIR}/KFParticleBaseSIMD.cxx + ${KFP_SOURCE_DIR}/KFParticleDatabase.cxx + ${KFP_SOURCE_DIR}/KFParticleFinder.cxx + ${KFP_SOURCE_DIR}/KFParticlePVReconstructor.cxx + ${KFP_SOURCE_DIR}/KFParticleSIMD.cxx + ${KFP_SOURCE_DIR}/KFParticleTopoReconstructor.cxx + ${KFP_SOURCE_DIR}/KFPEmcCluster.cxx + ${KFP_SOURCE_DIR}/KFPTrack.cxx + ${KFP_SOURCE_DIR}/KFPTrackVector.cxx + ${KFP_SOURCE_DIR}/KFPVertex.cxx + ${KFP_SOURCE_DIR}/KFVertex.cxx + ) + + add_library(CbmKFParticleOnlineInterface SHARED ${SRCS}) + target_include_directories(CbmKFParticleOnlineInterface PUBLIC ${KFP_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + target_compile_definitions(CbmKFParticleOnlineInterface PUBLIC NonhomogeneousField CBM CBM_ONLINE) + target_link_libraries(CbmKFParticleOnlineInterface + PUBLIC Vc::Vc + ROOT::Core) + install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) endif() diff --git a/algo/kfp/interface/RootTypesDef.h b/algo/kfp/interface/RootTypesDef.h new file mode 100644 index 000000000..e6eaa5500 --- /dev/null +++ b/algo/kfp/interface/RootTypesDef.h @@ -0,0 +1,18 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file RootTypesDef.h +/// \date 11.02.2025 +/// \brief A compatibility header for the KFParticle code +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#if __has_include(<RtypesCore.h>) +#include <RtypesCore.h> +#else +using Bool_t = bool; +using Int_t = int; +using Float_t = float; +#endif diff --git a/algo/qa/QaData.cxx b/algo/qa/QaData.cxx index 520ed4e52..6c42b3a52 100644 --- a/algo/qa/QaData.cxx +++ b/algo/qa/QaData.cxx @@ -57,6 +57,7 @@ try { << " with inconsistent flags (see HistogramMetadata::CheckFlags for detailes)"; throw std::runtime_error(msg.str()); } + L_(info) << " - task: " << task.fsName << ", histogram: " << h.GetName(); vHistCfgs.emplace_back(h.GetName() + "!" + h.GetMetadataString(), task.fsName); }; fsTaskNames += fmt::format("{} ", task.fsName); diff --git a/core/data/CbmEventTriggers.h b/core/data/CbmEventTriggers.h index 365d286e5..841d86bd4 100644 --- a/core/data/CbmEventTriggers.h +++ b/core/data/CbmEventTriggers.h @@ -73,7 +73,7 @@ class CbmEventTriggers { std::string ToString() const; private: - Trigger_t fTriggers; + Trigger_t fTriggers{0}; #if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA ClassDefNV(CbmEventTriggers, 1); diff --git a/core/data/tof/CbmTofAddress.cxx b/core/data/tof/CbmTofAddress.cxx index 71554dd1a..29c157345 100644 --- a/core/data/tof/CbmTofAddress.cxx +++ b/core/data/tof/CbmTofAddress.cxx @@ -66,4 +66,3 @@ std::string CbmTofAddress::ToString(int32_t address) msg << ", RpcType=" << setw(2) << CbmTofAddress::GetRpcType(address); return msg.str(); } - diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index d08436836..9328a585c 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -70,6 +70,7 @@ if(DOWNLOAD_EXTERNALS) Include(InstallYamlCpp.cmake) Include(InstallPoolSTL.cmake) + if (NOT CBM_ONLINE_STANDALONE) # Not required for online standalone Include(InstallKFParticle.cmake) @@ -86,8 +87,22 @@ if(DOWNLOAD_EXTERNALS) Include(InstallQa.cmake) endif() + else() + + # Download KFParticle source from the repository, but do not install it + download_project_if_needed(PROJECT kfparticle_source + GIT_REPOSITORY "https://github.com/szharko/KFParticle.git" + GIT_TAG "d088e3e019ac588a0528aa560ceaca247580d881" # CBM_ONLINE directive to turn off dependencies on ROOT + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/KFParticle + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + endif() + + else() # Define targets which are needed by CbmRoot but are not available # whithout the external packages diff --git a/macro/KF/configs/mcbm_kfpf_lambda.yaml b/macro/KF/configs/mcbm_kfpf_lambda.yaml index 01e77b185..fc5599d37 100644 --- a/macro/KF/configs/mcbm_kfpf_lambda.yaml +++ b/macro/KF/configs/mcbm_kfpf_lambda.yaml @@ -7,11 +7,11 @@ # \brief Standard configuration for the lambda finding in mCBM # \author Sergei Zharko <s.zharko@gsi.de> -reconstruct_pdg: 3122 # Lambda -> pi- p - -t0_offset: 0.12 # Time offset for T0 [ns] -qa_uncertainty: 0.1 # Assigned relative uncertainty for the q/p estimation -primary_pdg: 321 # Assigned PDG code for primary tracks +reconstruct_pdg: 3122 # Lambda -> pi- p +bmon_address: 0x00202806 # Address of reference BMON diamond +t0_offset: 0.12 # Time offset for T0 [ns] +qa_uncertainty: 0.1 # Assigned relative uncertainty for the q/p estimation +primary_pdg: 321 # Assigned PDG code for primary tracks cuts: # Different cuts kfp: # KFParticleFinder specific cuts -- GitLab From a861698509c55f0961aca1ad151c07cab7d442e2 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Wed, 12 Feb 2025 00:51:57 +0100 Subject: [PATCH 11/17] kfp-online: linking ROOT::Hist and ROOT::MathCore, changed the dependency on CbmKFParticle<Online/Offline>Interface to PUBLIC --- algo/CMakeLists.txt | 4 ++-- algo/kfp/interface/CMakeLists.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 6ba7a06c0..3b03adb99 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -227,7 +227,7 @@ target_link_libraries(Algo external::fles_monitoring cppzmq poolstl - PRIVATE CbmKFParticleOnlineInterface + CbmKFParticleOnlineInterface ) target_compile_definitions(Algo PUBLIC NO_ROOT) xpu_attach(Algo ${DEVICE_SRCS}) @@ -301,7 +301,7 @@ if (NOT CBM_ONLINE_STANDALONE) external::fles_monitoring cppzmq poolstl - PRIVATE CbmKFParticleOfflineInterface + CbmKFParticleOfflineInterface ) xpu_attach(AlgoOffline ${DEVICE_SRCS}) diff --git a/algo/kfp/interface/CMakeLists.txt b/algo/kfp/interface/CMakeLists.txt index ce26ad980..c5c21f04a 100644 --- a/algo/kfp/interface/CMakeLists.txt +++ b/algo/kfp/interface/CMakeLists.txt @@ -12,7 +12,7 @@ if(NOT CBM_ONLINE_STANDALONE) target_compile_definitions(CbmKFParticleOnlineInterface INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) target_link_libraries(CbmKFParticleOnlineInterface - INTERFACE ROOT::Core KFParticle) + INTERFACE ROOT::Core ROOT::Hist ROOT::MathCore KFParticle) install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) ### CbmKFParticleOfflineInterface @@ -21,7 +21,7 @@ if(NOT CBM_ONLINE_STANDALONE) target_compile_definitions(CbmKFParticleOfflineInterface INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) target_link_libraries(CbmKFParticleOfflineInterface - INTERFACE ROOT::Core KFParticle) + INTERFACE ROOT::Core ROOT::Hist ROOT::MathCore KFParticle) install(TARGETS CbmKFParticleOfflineInterface DESTINATION lib) else() # Creating a replacement of the CbmKFParticleOnlineInterface library for a standalone mode -- GitLab From 394b7e37ccff0a32a0165de18160c1aeb73511ea Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Wed, 12 Feb 2025 11:52:37 +0100 Subject: [PATCH 12/17] online: remove temporary debugging output --- algo/CMakeLists.txt | 4 ++-- algo/detectors/tof/Clusterizer.cxx | 21 -------------------- algo/kfp/interface/CMakeLists.txt | 32 +++++++++++++----------------- 3 files changed, 16 insertions(+), 41 deletions(-) diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 3b03adb99..9e7f23db7 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -227,7 +227,7 @@ target_link_libraries(Algo external::fles_monitoring cppzmq poolstl - CbmKFParticleOnlineInterface + PRIVATE CbmKFParticleOnlineInterface ) target_compile_definitions(Algo PUBLIC NO_ROOT) xpu_attach(Algo ${DEVICE_SRCS}) @@ -301,7 +301,7 @@ if (NOT CBM_ONLINE_STANDALONE) external::fles_monitoring cppzmq poolstl - CbmKFParticleOfflineInterface + PRIVATE CbmKFParticleOnlineInterface ) xpu_attach(AlgoOffline ${DEVICE_SRCS}) diff --git a/algo/detectors/tof/Clusterizer.cxx b/algo/detectors/tof/Clusterizer.cxx index 1a182b625..fb36f7d47 100644 --- a/algo/detectors/tof/Clusterizer.cxx +++ b/algo/detectors/tof/Clusterizer.cxx @@ -12,9 +12,6 @@ #include <iomanip> #include <iostream> #include <map> -#include <numeric> - -#include <fmt/format.h> namespace cbm::algo::tof { @@ -52,8 +49,6 @@ namespace cbm::algo::tof //Iterator-based version. Faster than index-based version. Clusterizer::resultType Clusterizer::buildClusters(std::vector<inputType>& input) { - size_t nInputDigis{ - std::accumulate(input.begin(), input.end(), 0, [](size_t s, const auto& v) { return s + v.size(); })}; // Hit variables Hit cluster; @@ -77,10 +72,6 @@ namespace cbm::algo::tof lastChanPos.push_back(input[chan].begin()); } - size_t nInputDigisUsed{0}; - if (nInputDigis > 0) { - //std::cout << "------------- call: buildClusters: number of digis: " << nInputDigis << '\n'; - } for (int32_t chan = 0; (size_t) chan < numChan; chan++) { // Set partition vectors @@ -92,17 +83,9 @@ namespace cbm::algo::tof chanSizes.back() = 0; continue; } - nInputDigisUsed += input[chan].size(); inputType& storDigi = input[chan]; auto digiIt = storDigi.begin(); - if (std::distance(storDigi.begin(), storDigi.end())) { - //std::cout << "DISTANCE: " << std::distance(storDigi.begin(), storDigi.end()) << '\n'; - for (const auto& digi : storDigi) { - std::string sAddress = fmt::format("{:#08x}", digi.first->GetAddress()); - //std::cout << " " << digi.first->GetTime() << "ns, address: " << sAddress << '\n'; - } - } while (1 < std::distance(digiIt, storDigi.end())) { while (digiIt->first->GetSide() == std::next(digiIt)->first->GetSide()) { // Not one Digi of each end! digiIt++; @@ -197,10 +180,6 @@ namespace cbm::algo::tof storDigi.clear(); } // for( int32_t chan = 0; chan < iNbCh; chan++ ) - //if (nInputDigis> 0) { - // std::cout << ">>>>>> " << nInputDigisUsed << "/" << nInputDigis << '\n'; - //} - // Now check if another hit/cluster is started // and save it if it's the case. if (0 < cluster.numChan()) { diff --git a/algo/kfp/interface/CMakeLists.txt b/algo/kfp/interface/CMakeLists.txt index c5c21f04a..c1eaadf76 100644 --- a/algo/kfp/interface/CMakeLists.txt +++ b/algo/kfp/interface/CMakeLists.txt @@ -1,10 +1,3 @@ -# The script creates two libraries: -# 1) CbmKFParticleOnlineInterface -- a specific KFParticle library interface for the CBM online reconstruction; -# 2) CbmKFParticleOfflineInterface -- a specific interface for the offline reconstruction in CBM. -# The both libraries contain only the KFParticle core and do not include KFParticleTest or KFParticlePerformance. - - - if(NOT CBM_ONLINE_STANDALONE) ### CbmKFParticleOnlineInterface add_library(CbmKFParticleOnlineInterface INTERFACE) @@ -12,17 +5,19 @@ if(NOT CBM_ONLINE_STANDALONE) target_compile_definitions(CbmKFParticleOnlineInterface INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) target_link_libraries(CbmKFParticleOnlineInterface - INTERFACE ROOT::Core ROOT::Hist ROOT::MathCore KFParticle) + INTERFACE KFParticle + ROOT::Core + ROOT::Hist + ROOT::MathCore + ROOT::Gpad + ROOT::Graf + ROOT::Physics + ROOT::EG + ROOT::RIO + ROOT::Tree + ROOT::MathCore + ) install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) - - ### CbmKFParticleOfflineInterface - add_library(CbmKFParticleOfflineInterface INTERFACE) - target_include_directories(CbmKFParticleOfflineInterface INTERFACE) - target_compile_definitions(CbmKFParticleOfflineInterface - INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) - target_link_libraries(CbmKFParticleOfflineInterface - INTERFACE ROOT::Core ROOT::Hist ROOT::MathCore KFParticle) - install(TARGETS CbmKFParticleOfflineInterface DESTINATION lib) else() # Creating a replacement of the CbmKFParticleOnlineInterface library for a standalone mode set(KFP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/KFParticle/KFParticle) @@ -48,6 +43,7 @@ else() target_compile_definitions(CbmKFParticleOnlineInterface PUBLIC NonhomogeneousField CBM CBM_ONLINE) target_link_libraries(CbmKFParticleOnlineInterface PUBLIC Vc::Vc - ROOT::Core) + ROOT::Core + ) install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) endif() -- GitLab From aeeec7b9b1c779cb4703cba032db9f7fa00a0622 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 13 Feb 2025 03:39:52 +0100 Subject: [PATCH 13/17] online: V0Finder implementation --- algo/ca/core/data/CaTrack.h | 8 +- algo/ca/core/utils/CaMonitorData.h | 4 + algo/data/sts/Hit.h | 15 +- algo/detectors/tof/Hit.h | 15 +- algo/evselector/RecoEventSelectorMonitor.h | 2 + algo/global/Reco.cxx | 7 +- algo/global/RecoResults.h | 8 +- algo/kfp/KfpV0Finder.cxx | 398 +++++++++++++++++++-- algo/kfp/KfpV0Finder.h | 123 ++++++- algo/kfp/KfpV0FinderConfig.cxx | 6 + algo/kfp/KfpV0FinderMonitor.h | 24 +- 11 files changed, 540 insertions(+), 70 deletions(-) diff --git a/algo/ca/core/data/CaTrack.h b/algo/ca/core/data/CaTrack.h index 29b7f3859..cf4663610 100644 --- a/algo/ca/core/data/CaTrack.h +++ b/algo/ca/core/data/CaTrack.h @@ -27,6 +27,8 @@ namespace cbm::algo::ca /// class Track { public: + using TrackParam_t = cbm::algo::kf::TrackParamS; + friend class boost::serialization::access; Track() = default; @@ -43,9 +45,9 @@ namespace cbm::algo::ca public: int fNofHits{kfdefs::Undef<int>}; ///< Number of hits in track - cbm::algo::kf::TrackParamS fParFirst; ///< Track parameters on the first station - cbm::algo::kf::TrackParamS fParLast; ///< Track parameters on the last station - cbm::algo::kf::TrackParamS fParPV; ///< Track parameters in the primary vertex + TrackParam_t fParFirst; ///< Track parameters on the first station + TrackParam_t fParLast; ///< Track parameters on the last station + TrackParam_t fParPV; ///< Track parameters in the primary vertex }; } // namespace cbm::algo::ca diff --git a/algo/ca/core/utils/CaMonitorData.h b/algo/ca/core/utils/CaMonitorData.h index 09b3d0e11..5d93816c1 100644 --- a/algo/ca/core/utils/CaMonitorData.h +++ b/algo/ca/core/utils/CaMonitorData.h @@ -82,6 +82,10 @@ namespace cbm::algo::ca /// \brief Resets all the counters and timers void Reset(); + /// \brief Resets a particular counter + /// \param key Counter key + void ResetCounter(ECounterKey key) { faCounters[key] = 0; } + /// \brief Starts timer /// \param key Timer key void StartTimer(ETimerKey key) { faTimers[key].Start(); } diff --git a/algo/data/sts/Hit.h b/algo/data/sts/Hit.h index ab1a733f2..2df0d8370 100644 --- a/algo/data/sts/Hit.h +++ b/algo/data/sts/Hit.h @@ -26,14 +26,13 @@ namespace cbm::algo::sts u32 fBackClusterId; ///< Index of back-side cluster, used by tracking to reduce combinatorics // Interface for tracking - real X() const { return fX; } - real Y() const { return fY; } - real Z() const { return fZ; } - u32 Time() const { return fTime; } - - real Dx() const { return fDx; } - real Dy() const { return fDy; } - real TimeError() const { return fTimeError; } + double X() const { return fX; } + double Y() const { return fY; } + double Z() const { return fZ; } + double Time() const { return fTime; } + double Dx() const { return fDx; } + double Dy() const { return fDy; } + double TimeError() const { return fTimeError; } private: // serialization friend class boost::serialization::access; diff --git a/algo/detectors/tof/Hit.h b/algo/detectors/tof/Hit.h index a7608fc72..8e3a1a068 100644 --- a/algo/detectors/tof/Hit.h +++ b/algo/detectors/tof/Hit.h @@ -53,14 +53,13 @@ namespace cbm::algo::tof // Interface for tracker - real X() const { return hitPos.X(); } - real Y() const { return hitPos.Y(); } - real Z() const { return hitPos.Z(); } - u32 Time() const { return hitTime; } - - real Dx() const { return hitPosErr.X(); } - real Dy() const { return hitPosErr.Y(); } - real TimeError() const { return hitTimeErr; } + double X() const { return hitPos.X(); } + double Y() const { return hitPos.Y(); } + double Z() const { return hitPos.Z(); } + double Time() const { return hitTime; } + double Dx() const { return hitPosErr.X(); } + double Dy() const { return hitPosErr.Y(); } + double TimeError() const { return hitTimeErr; } // Interface end diff --git a/algo/evselector/RecoEventSelectorMonitor.h b/algo/evselector/RecoEventSelectorMonitor.h index 82c68535c..de2eb4a27 100644 --- a/algo/evselector/RecoEventSelectorMonitor.h +++ b/algo/evselector/RecoEventSelectorMonitor.h @@ -38,6 +38,7 @@ namespace cbm::algo::evselect TofHitFinder, TrdHitFinder, TrackFinder, + V0Finder, END }; /* clang-format on */ @@ -65,6 +66,7 @@ namespace cbm::algo::evselect SetTimerName(ETimer::TofHitFinder, "hit finding in TOF"); SetTimerName(ETimer::TrdHitFinder, "hit finding in TRD"); SetTimerName(ETimer::TrackFinder, "track finding"); + SetTimerName(ETimer::V0Finder, "V0 finding"); } private: diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 37c37b508..b2a735559 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -597,9 +597,10 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) } //* V0-selector - { - auto triggers = fV0Finder->ProcessEvent(recoEvent); - } + fEvSelectingMonitor.StartTimer(evselect::ETimer::V0Finder); + auto triggers = fV0Finder->ProcessEvent(recoEvent); + fEvSelectingMonitor.StopTimer(evselect::ETimer::V0Finder); + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsSelected); return true; diff --git a/algo/global/RecoResults.h b/algo/global/RecoResults.h index 7795dda39..3bcee8be6 100644 --- a/algo/global/RecoResults.h +++ b/algo/global/RecoResults.h @@ -27,6 +27,8 @@ namespace cbm::algo /// @name RecoResults /// @brief Structure to keep reconstructed results: digi-events, hits and tracks struct RecoResults { + using HitId_t = std::pair<uint32_t, uint32_t>; // Hit ID by track + PODVector<CbmBmonDigi> bmonDigis; PODVector<CbmStsDigi> stsDigis; PODVector<CbmMuchDigi> muchDigis; @@ -45,8 +47,8 @@ namespace cbm::algo PartitionedVector<bmon::Hit> bmonHits; ca::Vector<ca::Track> tracks; - ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackStsHitIndices; // [trk][hit][(iPart, iHit)] - ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTofHitIndices; // [trk][hit][(iPart, iHit)] - ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trackTrdHitIndices; // [trk][hit][(iPart, iHit)] + ca::Vector<std::vector<HitId_t>> trackStsHitIndices; // [trk][hit][(iPart, iHit)] + ca::Vector<std::vector<HitId_t>> trackTofHitIndices; // [trk][hit][(iPart, iHit)] + ca::Vector<std::vector<HitId_t>> trackTrdHitIndices; // [trk][hit][(iPart, iHit)] }; } // namespace cbm::algo diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx index 5a5ddbc6e..2488ba89e 100644 --- a/algo/kfp/KfpV0Finder.cxx +++ b/algo/kfp/KfpV0Finder.cxx @@ -18,32 +18,99 @@ using cbm::algo::RecoResults; using cbm::algo::kfp::V0Finder; + +// --------------------------------------------------------------------------------------------------------------------- +// +bool V0Finder::AssignMomentum(const PartitionedVector<tof::Hit>& tofHits, + const std::vector<RecoResults::HitId_t>& tofHitIds, double t0, ParticleInfo& particleInfo) +{ + if (tofHitIds.empty()) { + fEventMonitor.IncrementCounter(ECounter::TracksWoTofHits); + return false; + } + + double beta{0.}; + if constexpr (kUseAverageSpeed) { + for (const auto& hitId : tofHitIds) { + beta += EstimateBeta(tofHits[hitId.first][hitId.second], t0); + } + beta /= tofHitIds.size(); + } + else { + const auto& hitId = tofHitIds.back(); + beta = EstimateBeta(tofHits[hitId.first][hitId.second], t0); + } + if (beta < 0.) { + fEventMonitor.IncrementCounter(ECounter::TracksWNegativeTofHitTime); + return false; + } + else if (beta > 1.) { + fEventMonitor.IncrementCounter(ECounter::TracksWUnphysicalBeta); + return false; + } + double gamma{1. / sqrt(1. - beta * beta)}; + particleInfo.fBeta = beta; + particleInfo.fQp = particleInfo.fQp / (gamma * beta * particleInfo.fMass); + return true; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0Finder::AssignPid(ParticleInfo& particleInfo) +{ + if (std::isnan(particleInfo.fDca)) { + particleInfo.fPdg = kUndefPdg; + fEventMonitor.IncrementCounter(ECounter::TracksWoPid); + } + else if (particleInfo.fDca > fMinPionDca) { + // pi- + particleInfo.fPdg = -211; + particleInfo.fMass = kPionMass; + particleInfo.fCharge = -1; + fEventMonitor.IncrementCounter(ECounter::PionsDca); + } + else if (particleInfo.fDca > fMinProtonDca) { + // proton + particleInfo.fPdg = 2212; + particleInfo.fMass = kProtonMass; + particleInfo.fCharge = 1; + fEventMonitor.IncrementCounter(ECounter::ProtonsDca); + } + else { + // primary + //particleInfo.fPdg = fPrimaryAssignedPdg; + particleInfo.fPdg = kUndefPdg; + fEventMonitor.IncrementCounter(ECounter::TracksWoPid); + } +} + // --------------------------------------------------------------------------------------------------------------------- // -std::vector<double> V0Finder::CollectDca(const RecoResults& recoEvent) const +void V0Finder::CollectDca(const RecoResults& recoEvent) { - std::vector<double> dca(recoEvent.trackStsHitIndices.size(), std::numeric_limits<double>::signaling_NaN()); const auto& stsHitIndices = recoEvent.trackStsHitIndices; for (size_t iTrk = 0; iTrk < stsHitIndices.size(); ++iTrk) { const auto& stsHitIndicesInTrack = stsHitIndices[iTrk]; if (stsHitIndicesInTrack.size() < 2) { // less then two sts hits + fEventMonitor.IncrementCounter(ECounter::TracksWoStsHits); continue; } - auto [iPtFst, iHitFst] = stsHitIndicesInTrack[0]; - auto [iPtSnd, iHitSnd] = stsHitIndicesInTrack[1]; - dca[iTrk] = EstimateDca(recoEvent.stsHits[iPtFst][iHitFst], recoEvent.stsHits[iPtSnd][iHitSnd]); + 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]); + AssignPid(particleInfo); } - return dca; } // --------------------------------------------------------------------------------------------------------------------- // -std::vector<double> V0Finder::CollectT0(gsl::span<const bmon::Hit> bmonHits) const +void V0Finder::CollectT0(gsl::span<const bmon::Hit> bmonHits) { - std::vector<double> t0; - t0.reserve(bmonHits.size()); - std::transform(bmonHits.begin(), bmonHits.end(), std::back_inserter(t0), [&](const auto& h) { return h.GetTime(); }); - return t0; + fvT0s.clear(); + fvT0s.reserve(bmonHits.size()); + std::transform(bmonHits.begin(), bmonHits.end(), std::back_inserter(fvT0s), + [&](const auto& h) { return h.GetTime(); }); } // --------------------------------------------------------------------------------------------------------------------- @@ -58,38 +125,317 @@ double V0Finder::EstimateDca(const sts::Hit& fst, const sts::Hit& snd) const // --------------------------------------------------------------------------------------------------------------------- // -void V0Finder::Init() {} +double V0Finder::EstimateBeta(const tof::Hit& hit, double t0) const +{ + double t = hit.Time() - t0 - fTzeroOffset; + double x{hit.X() - fOrigin[0]}; + double y{hit.Y() - fOrigin[1]}; + double z{hit.Y() - fOrigin[2]}; + double x2{x * x}; + double y2{y * y}; + double z2{z * z}; + double r2{x2 + y2 + z2}; + return std::sqrt(r2) / (t * kSpeedOfLight); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +bool V0Finder::FindV0Candidates(const RecoResults& recoEvent, double t0) +{ + const auto& tracks = recoEvent.tracks; + + // Reset temporary data structures + InitTrackParamVectors(tracks); + fpTopoReconstructor->Clear(); + fvSelectedTrackIds.clear(); + fvSelectedTrackIds.reserve(tracks.size()); + fEventMonitor.ResetCounter(ECounter::TracksWoMomentum); + fEventMonitor.ResetCounter(ECounter::TracksSelected); + fEventMonitor.ResetCounter(ECounter::Pions); + fEventMonitor.ResetCounter(ECounter::Protons); + fEventMonitor.ResetCounter(ECounter::EventsLambdaCand); + + // Preselect tracks + uint32_t nProtonCandidates{0}; + uint32_t nPionCandidates{0}; + uint32_t nSelectedTracks{0}; + fEventMonitor.StartTimer(ETimer::PreselectTracks); + for (size_t iTrk = 0; iTrk < tracks.size(); ++iTrk) { // Over all tracks + auto& particleInfo = fvParticleInfo[iTrk]; + + // Cut tracks with undefined dca (by PID == -2) + // NOTE: if fPdg == kUndefPdg, beta and QP were not estimated for this track on previous iterations as well + if (particleInfo.fPdg == kUndefPdg) { + continue; + } + + // Reset fields of the ParticleInfo, which could be filled on the previous iteration + particleInfo.fBeta = std::numeric_limits<double>::quiet_NaN(); + particleInfo.fQp = std::numeric_limits<double>::quiet_NaN(); + particleInfo.fbSelected = false; + + // Assign momentum to tracks + if (!AssignMomentum(recoEvent.tofHits, recoEvent.trackTofHitIndices[iTrk], t0, particleInfo)) { + fEventMonitor.IncrementCounter(ECounter::TracksWoMomentum); + continue; // No momentum was assigned + } + + // Select tracks + if (!SelectTrack(particleInfo)) { + continue; + } + fvSelectedTrackIds.push_back(iTrk); + particleInfo.fbSelected = true; + + // Update track parameters + double qpVar{particleInfo.fQp * fQpAssignedUncertainty}; + qpVar = qpVar * qpVar; + auto& trkParam{fvTrackParam[iTrk]}; + trkParam.first.SetQp(particleInfo.fQp); + trkParam.first.SetC44(qpVar); + trkParam.second.SetQp(particleInfo.fQp); + trkParam.second.SetC44(qpVar); + + switch (particleInfo.fPdg) { + case -211: ++nPionCandidates; break; + case 2212: ++nProtonCandidates; break; + } + ++nSelectedTracks; + } + fEventMonitor.StopTimer(ETimer::PreselectTracks); + if (!nPionCandidates || !nProtonCandidates) { + return false; // no Lambda can be found + } + fEventMonitor.IncrementCounter(ECounter::EventsLambdaCand); + fEventMonitor.IncrementCounter(ECounter::TracksSelected, nSelectedTracks); + fEventMonitor.IncrementCounter(ECounter::Pions, nPionCandidates); + fEventMonitor.IncrementCounter(ECounter::Protons, nProtonCandidates); + + // Initialize and run the KFParticleFinder + fEventMonitor.StartTimer(ETimer::InitKfp); + KFPTrackVector kfpTracksFst; + KFPTrackVector kfpTracksLst; + kfpTracksFst.Resize(nSelectedTracks); + kfpTracksLst.Resize(nSelectedTracks); + fpTopoReconstructor->Init(kfpTracksFst, kfpTracksLst); + for (uint32_t iKfpTrk = 0; iKfpTrk < fvSelectedTrackIds.size(); ++iKfpTrk) { // Over selected tracks + uint32_t iCaTrk{fvSelectedTrackIds[iKfpTrk]}; + const auto& trkParam{fvTrackParam[iCaTrk]}; + const auto& particleInfo{fvParticleInfo[iCaTrk]}; + SetKfpTrackParameters(kfpTracksFst, iKfpTrk, iCaTrk, trkParam.first, particleInfo); + SetKfpTrackParameters(kfpTracksLst, iKfpTrk, iCaTrk, trkParam.second, particleInfo); + } + fpTopoReconstructor->AddPV(MakeKfpPrimaryVertex(fOrigin)); + fpTopoReconstructor->SortTracks(); + fEventMonitor.StopTimer(ETimer::InitKfp); + fEventMonitor.StartTimer(ETimer::ExecKfp); + fpTopoReconstructor->ReconstructParticles(); + fEventMonitor.StopTimer(ETimer::ExecKfp); + const auto& particles{fpTopoReconstructor->GetParticles()}; + + // Scan for Lambda-candidates + uint32_t nLambdaCandidates = + std::count_if(particles.begin(), particles.end(), [&](const auto& p) { return p.GetPDG() == 3122; }); + fEventMonitor.IncrementCounter(ECounter::KfpLambdaCandidates, nLambdaCandidates); + + return static_cast<bool>(nLambdaCandidates); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0Finder::Init() { fpTopoReconstructor->SetTarget({float(fOrigin[0]), float(fOrigin[1]), float(fOrigin[2])}); } + +// --------------------------------------------------------------------------------------------------------------------- +// +void V0Finder::InitTrackParamVectors(const ca::Vector<ca::Track>& tracks) +{ + fvTrackParam.clear(); + fvTrackParam.reserve(tracks.size()); + std::transform(tracks.begin(), tracks.end(), std::back_inserter(fvTrackParam), + [&](const auto& t) { return std::make_pair(t.fParFirst, t.fParLast); }); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +KFVertex V0Finder::MakeKfpPrimaryVertex(const std::array<float, 3>& r) +{ + KFVertex kfVertex; + kfVertex.X() = r[0]; + kfVertex.Y() = r[1]; + kfVertex.Z() = r[2]; + for (int iC = 0; iC < 6; ++iC) { + kfVertex.Covariance(iC) = 0.f; + } + kfVertex.Chi2() = -100.f; + return kfVertex; +} // --------------------------------------------------------------------------------------------------------------------- // CbmEventTriggers V0Finder::Process(const RecoResults& recoEvent) { + //L_(info) << "----------------------------- EVENT --------------"; CbmEventTriggers res; fEventMonitor.Reset(); - fEventMonitor.StartTimer(ETimer::Event); + fEventMonitor.StartTimer(ETimer::ProcessEvent); fEventMonitor.IncrementCounter(ECounter::EventsTotal); + fEventMonitor.IncrementCounter(ECounter::TracksTotal, recoEvent.tracks.size()); + + // ----- Initialize data-structures + fvParticleInfo.clear(); + fvParticleInfo.resize(recoEvent.tracks.size()); // ----- Define T0 // So far we cannot preselect a hit from multiple ones, we will be using all of them iteratively to find lambdas - auto vT0 = CollectT0(recoEvent.bmonHits[fBmonPartitionIndex]); - if (vT0.empty()) { + fEventMonitor.StartTimer(ETimer::CollectT0); + CollectT0(recoEvent.bmonHits[fBmonPartitionIndex]); + if (fvT0s.empty()) { fEventMonitor.IncrementCounter(ECounter::EventsWoTzero); return res; } + fEventMonitor.StopTimer(ETimer::CollectT0); - //L_(info) << "------- Event: "; - - // ----- Estimate DCA of tracks + // ----- Estimate DCA of tracks and assign PID // If a track has less then two STS hits, and undefined DCA value is stored - std::vector<double> vDca = CollectDca(recoEvent); + fEventMonitor.StartTimer(ETimer::CollectDca); + CollectDca(recoEvent); + fEventMonitor.StopTimer(ETimer::CollectDca); - // ***** DEBUG: BEGIN - //for (auto dca: vDca) { - // L_(info) << "dca=" << dca; - //} - // ***** DEBUG: END + // ----- Try to find lambdas for different T0 + fSelectedT0 = std::numeric_limits<double>::quiet_NaN(); + fEventMonitor.StartTimer(ETimer::FindV0Candidates); + for (double t0 : fvT0s) { + if (FindV0Candidates(recoEvent, t0)) { + fSelectedT0 = t0; + res.Set(CbmEventTriggers::ETrigger::Lambda); + fEventMonitor.IncrementCounter(ECounter::EventsLambdaCand); + break; // Lambda-candidates were found, there is no sense to scan further + } + } + fEventMonitor.StopTimer(ETimer::FindV0Candidates); + fEventMonitor.StopTimer(ETimer::ProcessEvent); + return res; +} +// --------------------------------------------------------------------------------------------------------------------- +// +bool V0Finder::SelectTrack(const ParticleInfo& particleInfo) const +{ + // Speed cut + if (particleInfo.fPdg == -211) { + if (particleInfo.fBeta < fMinBetaPion || particleInfo.fBeta > fMaxBetaPion) { + return false; + } + } + else if (particleInfo.fPdg == 2212) { + if (particleInfo.fBeta < fMinBetaProton || particleInfo.fBeta > fMaxBetaProton) { + return false; + } + } + return true; +} - fEventMonitor.StopTimer(ETimer::Event); - return res; +// --------------------------------------------------------------------------------------------------------------------- +// +void V0Finder::SetKfpTrackParameters(KFPTrackVector& trackVector, uint32_t iKfpTrk, uint32_t iCaTrk, + const ca::Track::TrackParam_t& trkParam, const ParticleInfo& particleInfo) const +{ + // ----- Parameter definition + double tx{trkParam.GetTx()}; + double ty{trkParam.GetTy()}; + double qp{trkParam.GetQp()}; + double p{particleInfo.fCharge / qp}; + double p2{p * p}; + double t2inv{1. / (1. + tx * tx + ty * ty)}; + double pz{std::sqrt(t2inv * p2)}; + double px{tx * pz}; + double py{ty * pz}; + + trackVector.SetParameter(trkParam.GetX(), 0, iKfpTrk); + trackVector.SetParameter(trkParam.GetY(), 1, iKfpTrk); + trackVector.SetParameter(trkParam.GetZ(), 2, iKfpTrk); + trackVector.SetParameter(px, 3, iKfpTrk); + trackVector.SetParameter(py, 4, iKfpTrk); + trackVector.SetParameter(pz, 5, iKfpTrk); + + // Jacobian matrix for (tx, ty, qp) -> (px, py, pz) + std::array<std::array<double, 3>, 3> Jp; + Jp[2][0] = -t2inv * px; // d(pz)/d(tx) + Jp[2][1] = -t2inv * py; // d(pz)/d(ty) + Jp[2][2] = -pz / qp; // d(pz)/d(qp) + Jp[0][0] = tx * Jp[2][0] + pz; // d(px)/d(tx) + Jp[0][1] = tx * Jp[2][1]; // d(px)/d(ty) + Jp[0][2] = tx * Jp[2][2]; // d(px)/d(qp) + Jp[1][0] = ty * Jp[2][0]; // d(py)/d(tx) + Jp[1][1] = ty * Jp[2][1] + pz; // d(py)/d(ty) + Jp[1][2] = ty * Jp[2][2]; // d(py)/d(qp) + + + // ----- Covariance matrix definition + // Position covariance + trackVector.SetCovariance(trkParam.C00(), 0, iKfpTrk); // var(x) + trackVector.SetCovariance(trkParam.C01(), 1, iKfpTrk); // cov(x, y) + trackVector.SetCovariance(trkParam.C11(), 2, iKfpTrk); // var(y) + + // Momentum-position covariances + auto MomPosCovariance = [&](const int k, const int l) constexpr->double + { + double val{0.}; + const auto& JpA = Jp[k]; + for (int i = 0; i < 3; ++i) { + val += JpA[i] * trkParam.C(i + 2, l); + } + return val; + }; + trackVector.SetCovariance(MomPosCovariance(0, 0), 6, iKfpTrk); // cov(x, px) + trackVector.SetCovariance(MomPosCovariance(0, 1), 7, iKfpTrk); // cov(y, px) + trackVector.SetCovariance(MomPosCovariance(1, 0), 10, iKfpTrk); // cov(x, py) + trackVector.SetCovariance(MomPosCovariance(1, 1), 11, iKfpTrk); // cov(y, py) + trackVector.SetCovariance(MomPosCovariance(2, 0), 15, iKfpTrk); // cov(x, pz) + trackVector.SetCovariance(MomPosCovariance(2, 1), 16, iKfpTrk); // cov(y, pz) + + // Momentum covariances + auto MomentumCovariance = [&](const int k, const int l) constexpr->double + { + double val{0.}; + const auto& JpA = Jp[k]; + const auto& JpB = Jp[l]; + for (int i = 0; i < 3; ++i) { + double factor{0.}; + for (int j = 0; j < 3; ++j) { + factor += JpB[j] * trkParam.C(i + 2, j + 2); + } + val += JpA[i] * factor; + } + return val; + }; + trackVector.SetCovariance(MomentumCovariance(0, 0), 9, iKfpTrk); // var(px) + trackVector.SetCovariance(MomentumCovariance(1, 0), 13, iKfpTrk); // cov(px, py) + trackVector.SetCovariance(MomentumCovariance(1, 1), 14, iKfpTrk); // var(py) + trackVector.SetCovariance(MomentumCovariance(2, 0), 18, iKfpTrk); // cov(px, pz) + trackVector.SetCovariance(MomentumCovariance(2, 1), 19, iKfpTrk); // cov(py, pz) + trackVector.SetCovariance(MomentumCovariance(2, 2), 20, iKfpTrk); // var(pz) + + // Zero covariances (with z-coordinate) + trackVector.SetCovariance(0.f, 3, iKfpTrk); // cov(x,z) + trackVector.SetCovariance(0.f, 4, iKfpTrk); // cov(y,z) + trackVector.SetCovariance(0.f, 5, iKfpTrk); // var(z) + trackVector.SetCovariance(0.f, 8, iKfpTrk); // cov(z,px) + trackVector.SetCovariance(0.f, 12, iKfpTrk); // cov(z,py) + trackVector.SetCovariance(0.f, 17, iKfpTrk); // var(z,pz) + + // ----- Other quantities + // Magnetic field (NOTE: zero fom mCBM) + // FIXME: Provide a proper initialization for full CBM + for (int iF = 0; iF < 10; ++iF) { + trackVector.SetFieldCoefficient(0.f, iF, iKfpTrk); + } + + trackVector.SetId(iCaTrk, iKfpTrk); + trackVector.SetPDG(particleInfo.fPdg, iKfpTrk); + trackVector.SetQ(particleInfo.fCharge, iKfpTrk); + trackVector.SetNPixelHits(0, iKfpTrk); + + // NOTE: 0 - primary tracks, -1 - secondary tracks. Here for now we assign ALL tracks as secondary + trackVector.SetPVIndex(-1, iKfpTrk); } diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h index ef8b1e22b..0272b0ab8 100644 --- a/algo/kfp/KfpV0Finder.h +++ b/algo/kfp/KfpV0Finder.h @@ -24,6 +24,18 @@ namespace cbm::algo::kfp /// \brief A V0-finding algorithm class V0Finder { public: + /// \struct ParticleInfo + /// \brief A structure to keep temporary PID information for tracks + struct ParticleInfo { + double fMass{std::numeric_limits<double>::quiet_NaN()}; //< Estimated mass of the particle [GeV/c2] + double fDca{std::numeric_limits<double>::quiet_NaN()}; //< DCA to the origin [cm] + double fBeta{std::numeric_limits<double>::quiet_NaN()}; //< Speed of the particle [c] + double fQp{std::numeric_limits<double>::quiet_NaN()}; //< q/p of the particle [GeV^-1] + int32_t fPdg{V0Finder::kUndefPdg}; //< PDG code + int32_t fCharge{0}; //< Charge of the particle + bool fbSelected{false}; //< The track was selected + }; + /// \brief Default constructor V0Finder() = default; @@ -46,14 +58,30 @@ namespace cbm::algo::kfp /// \param pdg A PDG code of the particle to be reconstructed void AddDecayToReconstructionList(int pdg) { GetKFParticleFinder()->AddDecayToReconstructionList(pdg); } + /// \brief Gets monitor data + const V0FinderMonitorData_t& GetEventMonitor() const { return fEventMonitor; } + + /// \brief Gets origin + const std::array<float, 3>& GetOrigin() const { return fOrigin; } + /// \brief Mutable access to the KfParticleFinder of the run topology reconstructor KFParticleFinder* GetKFParticleFinder() { return fpTopoReconstructor->GetKFParticleFinder(); } /// \brief Constant access to the KfParticleFinder of the run topology reconstructor const KFParticleFinder* GetKFParticleFinder() const { return fpTopoReconstructor->GetKFParticleFinder(); } - /// \brief Gets monitor data - const V0FinderMonitorData_t& GetEventMonitor() const { return fEventMonitor; } + /// \brief Gets a vector of particle info + const std::vector<ParticleInfo> GetParticleInfo() const { return fvParticleInfo; } + + /// \brief Gets selected t0 + /// \note NaN, if Lambda-candidate was not found + double GetSelectedT0() const { return fSelectedT0; } + + /// \brief Gets indices of selected tracks + const std::vector<uint32_t>& GetSelectedTrackIds() const { return fvSelectedTrackIds; } + + /// \brief Gets found t0s + const std::vector<double>& GetT0s() const { return fvT0s; } /// \brief Initializes the instance (called in the beginning of the run) void Init(); @@ -77,7 +105,7 @@ namespace cbm::algo::kfp /// \param y Y-coordinate of the origin [cm] /// \param z Z-coordinate of the origin [cm] // FIXME: for now origin is defined as the target center, later it can be changed - void SetOrigin(double x, double y, double z) { fOrigin = {x, y, z}; } + void SetOrigin(double x, double y, double z) { fOrigin = {float(x), float(y), float(z)}; } /// \brief Sets minimal pion DCA to primary vertex /// \brief Sets pion velocity range @@ -110,7 +138,6 @@ namespace cbm::algo::kfp /// \param offset An offset [ns] void SetTzeroOffset(double offset) { fTzeroOffset = offset; } - //* Specific parameters for the KFParticleFinder /// \brief Sets cut on the distance to the primary vertex from the decay vertex /// \param cut Cut value [cm] void SetLCut(float cut) { GetKFParticleFinder()->SetLCut(cut); } @@ -128,17 +155,40 @@ namespace cbm::algo::kfp void SetLdLCut2D(float cut) { GetKFParticleFinder()->SetLdLCut2D(cut); } private: + /// \brief Assigns momentum based on the TOF measurement + /// \param[in] tofHits Tof hits container + /// \param[in] tofHitIds Tof hit indices, used by the track + /// \param[in] t0 A t0 value + /// \param[inout] pidInfo PID information for the track + /// \return true A physically reasonable momentum assigned + /// \return false Momentum was not assigned, because it was nonphysical + /* clang-format off */ + bool AssignMomentum(const PartitionedVector<tof::Hit>& tofHits, + const std::vector<RecoResults::HitId_t>& tofHitIds, + double t0, + ParticleInfo& pidInfo); + /* clang-format on */ + + /// \brief Assigns PID info based on the estimated DCA + /// \param dca DCA of track to origin + /// \return (mass, charge, pid) + void AssignPid(ParticleInfo& info); + + /// \brief Collects a vector of DCA + /// \param recoEvent Instance of a reconstructed event + void CollectDca(const RecoResults& recoEvent); + /// \brief Collects T0 values among the BMON hits /// \param bmonHits A span of BMON hits - /// \return A vector of T0-s /// /// If multiple T0-s are found, the routine will run multiple times, until V0-candidates are found - std::vector<double> CollectT0(gsl::span<const bmon::Hit> bmonHits) const; + void CollectT0(gsl::span<const bmon::Hit> bmonHits); - /// \brief Collects a vector of DCA - /// \param recoEvent Instance of a reconstructed event - /// \return A vector of DCAs to origin - std::vector<double> CollectDca(const RecoResults& recoEvent) const; + /// \brief Estimates speed of particle, using TOF measurement + /// \param tofHit A TOF hit + /// \param t0 An t0 value + /// \return Speed of particle [c] + double EstimateBeta(const tof::Hit& tofHit, double t0) const; /// \brief Estimate DCA of a track to origin /// \param fst first STS hit @@ -146,29 +196,68 @@ namespace cbm::algo::kfp /// \return dca [cm] double EstimateDca(const sts::Hit& fst, const sts::Hit& snd) const; - //* Physical constants + /// \brief Tries to find V0-candidates for a given t0 + /// \param recoEvent Instance of a reconstructed event + /// \param t0 An estimated t0 value + /// \return true V0-candidates found + /// \return false V0-candidates not found + bool FindV0Candidates(const RecoResults& recoEvent, double t0); + + /// \brief Initializes copies of track parameter vectors + /// \param tracks A container of tracks + void InitTrackParamVectors(const ca::Vector<ca::Track>& tracks); + + /// \brief Makes a KF vertex + /// \param r coordinates of PV [cm] + static KFVertex MakeKfpPrimaryVertex(const std::array<float, 3>& r); + + /// \brief Applies selection cut on the track + /// \param particleInfo Particle collected information + /// \return true Track is selected + /// \return false Track is rejected + bool SelectTrack(const ParticleInfo& particleInfo) const; + + /// \brief Sets KFP track parameters + /// \param[inout] kfpTrkVector Reference to the KFP track vector + /// \param[in] iKfpTrk Index of the KFP track + /// \param[in] iCaTrk Index of the CA track + /// \param[in] trkParam Track parameters + /// \param[in] particleInfo Particle information + 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 - - V0FinderMonitorData_t fEventMonitor; ///< Monitor data instance (per event) + V0FinderMonitorData_t fEventMonitor; ///< Main monitor data instance //* Different run-time cuts and flags (TODO: define in a config) double fTzeroOffset{0.}; ///< Offset for T0 double fMinPionDca{1.5}; ///< Minimum DCA to PV for pions double fMinProtonDca{0.5}; ///< Minimum DCA to PV for protons double fQpAssignedUncertainty{0.1}; ///< Assigned relative uncertainty for q/p estimation - int fPrimaryAssignedPdg{321}; ///< Assigned PDG hypothesis for primary particles double fMinBetaProton{0.}; ///< Minimal proton velocity (beta) [c] double fMaxBetaProton{1.}; ///< Maximal proton velocity (beta) [c] double fMinBetaPion{0.}; ///< Minimal proton velocity (beta) [c] double fMaxBetaPion{1.}; ///< Maximal proton velocity (beta) [c] - + int fPrimaryAssignedPdg{321}; ///< Assigned PDG hypothesis for primary particles //* Run-time variables, provided by framework - int fBmonPartitionIndex{-1}; ///< Index of selected partition in BMON hit vector - std::array<double, 3> fOrigin{0., 0., 0.}; ///< Coordinates of origin [cm] + int fBmonPartitionIndex{-1}; ///< Index of selected partition in BMON hit vector + + //* Temporary data arrays (NOTE: keep them here for QA) + std::array<float, 3> fOrigin{0.f, 0.f, 0.f}; ///< Coordinates of origin [cm] + std::vector<double> fvT0s; ///< Found t0s [ns] (in event) + std::vector<ParticleInfo> fvParticleInfo; ///< PID info of tracks (in event) + std::vector<uint32_t> fvSelectedTrackIds; ///< IDs of selected tracks (in event) + double fSelectedT0{std::numeric_limits<double>::quiet_NaN()}; ///< A t0 value selected by the lambda-finder + + /// \brief A copy of track parameters (first, last) + std::vector<std::pair<ca::Track::TrackParam_t, ca::Track::TrackParam_t>> fvTrackParam; //* Auxilary variables diff --git a/algo/kfp/KfpV0FinderConfig.cxx b/algo/kfp/KfpV0FinderConfig.cxx index 54e08ec32..d74e4d8b2 100644 --- a/algo/kfp/KfpV0FinderConfig.cxx +++ b/algo/kfp/KfpV0FinderConfig.cxx @@ -9,6 +9,7 @@ #include "KfpV0FinderConfig.h" +#include <iomanip> #include <sstream> using cbm::algo::kfp::Cuts; @@ -58,12 +59,17 @@ std::string Cuts::ToString() const // std::string V0FinderConfig::ToString() const { + using std::dec; + using std::hex; + using std::setfill; + using std::setw; std::stringstream msg; msg << "\n-------------- KFP V0-finder Configuration: ------------------------------------------------"; msg << "\nGOAL V0 (PDG): " << reconstructPdg; msg << '\n' << cuts.ToString(); msg << "\nOTHER PARAMETERS:"; msg << "\n\tt0-offset: " << tZeroOffset << " [ns]"; + msg << "\n\tReference BMON: 0x" << hex << setw(8) << setfill('0') << bmonAddress << dec; msg << "\n\tq/p relative uncertainty: " << qpAssignedUncertainty; msg << "\n\tassigned PDG of primary: " << primaryAssignedPdg; msg << "\n--------------------------------------------------------------------------------------------"; diff --git a/algo/kfp/KfpV0FinderMonitor.h b/algo/kfp/KfpV0FinderMonitor.h index 1f63bb246..5bb4311b6 100644 --- a/algo/kfp/KfpV0FinderMonitor.h +++ b/algo/kfp/KfpV0FinderMonitor.h @@ -26,6 +26,8 @@ namespace cbm::algo::kfp TracksWoPid, ///< Tracks, which has undefined PID TracksWoMomentum, ///< Tracks, which has no momentum TracksWUnphysicalBeta, ///< Tracks with beta > 1 + PionsDca, ///< Number of raw pion-candidates + ProtonsDca, ///< Number of raw proton-candidates Pions, ///< Number of pion-candidates Protons, ///< Number of proton-candidates EventsTotal, ///< Total number of events @@ -38,11 +40,20 @@ namespace cbm::algo::kfp /// \enum ETimer /// \brief Timer keys for the V0FinderMonitor + /* clang-format off */ enum class ETimer { - Event, ///< Timer to process a single event + ProcessEvent, ///< Processing of a single event + CollectT0, ///< Collecting T0s + CollectDca, ///< Estimating DCAs + FindV0Candidates, ///< V0-finder procedure for a given t0 + PrepareContainers, ///< Prepare data containers + PreselectTracks, ///< Track preselection + InitKfp, ///< Init KFParticleFinder inside the event + ExecKfp, ///< Run KFParticleFinder inside the event END }; + /* clang-format on */ /// \brief Specification of ca::MonitorData for the V0Finder using V0FinderMonitorData_t = ca::MonitorData<ECounter, ETimer>; @@ -63,6 +74,8 @@ namespace cbm::algo::kfp SetCounterName(ECounter::TracksWoPid, "tracks w/o PID"); SetCounterName(ECounter::TracksWoMomentum, "tracks w/o momentum"); SetCounterName(ECounter::TracksWUnphysicalBeta, "tracks w/ beta > 1"); + SetCounterName(ECounter::PionsDca, "raw pion candidates"); + SetCounterName(ECounter::ProtonsDca, "raw proton candidates"); SetCounterName(ECounter::Pions, "pion candidates"); SetCounterName(ECounter::Protons, "proton candidates"); SetCounterName(ECounter::EventsTotal, "all events"); @@ -71,7 +84,14 @@ namespace cbm::algo::kfp SetCounterName(ECounter::KfpEventsLambdaCand, "events w/ lambda candidates"); SetCounterName(ECounter::KfpLambdaCandidates, "lambda candidates"); - SetTimerName(ETimer::Event, "event processing"); + SetTimerName(ETimer::ProcessEvent, "event processing"); + SetTimerName(ETimer::CollectT0, "t0 container preparation"); + SetTimerName(ETimer::CollectDca, "DCA container preparation"); + SetTimerName(ETimer::FindV0Candidates, "V0-candidates finding"); + SetTimerName(ETimer::PrepareContainers, "Container initialization"); + SetTimerName(ETimer::PreselectTracks, "Track preselection"); + SetTimerName(ETimer::InitKfp, "KFParticleFinder initialization"); + SetTimerName(ETimer::ExecKfp, "KFParticleFinder execution"); } private: -- GitLab From cfaa652d31fd51cbbb41716114a9a2b77687e27e Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 13 Feb 2025 07:00:31 +0100 Subject: [PATCH 14/17] online: QA for V0 finder --- algo/CMakeLists.txt | 1 + algo/base/Definitions.h | 4 +- algo/global/Reco.cxx | 7 +- algo/kfp/KfpV0Finder.cxx | 8 +-- algo/kfp/KfpV0Finder.h | 20 ++++-- algo/kfp/KfpV0FinderChain.cxx | 17 +++++ algo/kfp/KfpV0FinderChain.h | 20 +++++- algo/kfp/KfpV0FinderQa.cxx | 97 +++++++++++++++++++++++++++ algo/kfp/KfpV0FinderQa.h | 82 ++++++++++++++++++++++ algo/qa/hitfind/BmonHitfindQa.h | 3 - services/histserv/app/Application.cxx | 20 +++--- 11 files changed, 252 insertions(+), 27 deletions(-) create mode 100644 algo/kfp/KfpV0FinderQa.cxx create mode 100644 algo/kfp/KfpV0FinderQa.h diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 9e7f23db7..a70b0872c 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 6c6d77ba8..b1ff4c9cc 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 b2a735559..f312ebaaa 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 2488ba89e..bc06d7800 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 0272b0ab8..72d1d1c57 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 f41a0597a..e23bc9e81 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 630fc02e6..8053c93f7 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 000000000..4239174a7 --- /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 000000000..39a1289ba --- /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 020f62fa8..b2a8b3e30 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 5eb5362f0..d2215633e 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(); -- GitLab From ee69fbcc364c38aa03b0dcfa8df67b3147b68de6 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 13 Feb 2025 07:32:47 +0100 Subject: [PATCH 15/17] online-kfp: bugfix --- algo/kfp/KfpV0Finder.cxx | 10 +++++----- algo/kfp/KfpV0Finder.h | 3 +++ algo/kfp/KfpV0FinderQa.cxx | 15 +++++++++------ algo/kfp/KfpV0FinderQa.h | 4 +++- services/histserv/app/Application.cxx | 24 ++++++++++++------------ 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/algo/kfp/KfpV0Finder.cxx b/algo/kfp/KfpV0Finder.cxx index bc06d7800..c95965bc8 100644 --- a/algo/kfp/KfpV0Finder.cxx +++ b/algo/kfp/KfpV0Finder.cxx @@ -50,7 +50,7 @@ bool V0Finder::AssignMomentum(const PartitionedVector<tof::Hit>& tofHits, } double gamma{1. / sqrt(1. - beta * beta)}; particleInfo.fBeta = beta; - particleInfo.fQp = particleInfo.fQp / (gamma * beta * particleInfo.fMass); + particleInfo.fQp = particleInfo.fCharge / (gamma * beta * particleInfo.fMass); return true; } @@ -91,7 +91,7 @@ void V0Finder::CollectDca(const RecoResults& recoEvent) const auto& stsHitIndices = recoEvent.trackStsHitIndices; for (size_t iTrk = 0; iTrk < stsHitIndices.size(); ++iTrk) { const auto& stsHitIndicesInTrack = stsHitIndices[iTrk]; - if (stsHitIndicesInTrack.size() < 2) { // less then two sts hits + if (stsHitIndicesInTrack.size() < 2) { // DCA cannot be estimated fEventMonitor.IncrementCounter(ECounter::TracksWoStsHits); continue; } @@ -130,7 +130,7 @@ double V0Finder::EstimateBeta(const tof::Hit& hit, double t0) const double t = hit.Time() - t0 - fTzeroOffset; double x{hit.X() - fOrigin[0]}; double y{hit.Y() - fOrigin[1]}; - double z{hit.Y() - fOrigin[2]}; + double z{hit.Z() - fOrigin[2]}; double x2{x * x}; double y2{y * y}; double z2{z * z}; @@ -217,7 +217,6 @@ bool V0Finder::FindV0Candidates(const RecoResults& recoEvent, double t0) KFPTrackVector kfpTracksLst; kfpTracksFst.Resize(nSelectedTracks); kfpTracksLst.Resize(nSelectedTracks); - fpTopoReconstructor->Init(kfpTracksFst, kfpTracksLst); for (uint32_t iKfpTrk = 0; iKfpTrk < fvSelectedTrackIds.size(); ++iKfpTrk) { // Over selected tracks uint32_t iCaTrk{fvSelectedTrackIds[iKfpTrk]}; const auto& trkParam{fvTrackParam[iCaTrk]}; @@ -225,6 +224,7 @@ bool V0Finder::FindV0Candidates(const RecoResults& recoEvent, double t0) SetKfpTrackParameters(kfpTracksFst, iKfpTrk, iCaTrk, trkParam.first, particleInfo); SetKfpTrackParameters(kfpTracksLst, iKfpTrk, iCaTrk, trkParam.second, particleInfo); } + fpTopoReconstructor->Init(kfpTracksFst, kfpTracksLst); fpTopoReconstructor->AddPV(MakeKfpPrimaryVertex(fOrigin)); fpTopoReconstructor->SortTracks(); fEventMonitor.StopTimer(ETimer::InitKfp); @@ -308,7 +308,7 @@ CbmEventTriggers V0Finder::Process(const RecoResults& recoEvent) if (FindV0Candidates(recoEvent, t0)) { fSelectedT0 = t0; res.Set(CbmEventTriggers::ETrigger::Lambda); - fEventMonitor.IncrementCounter(ECounter::EventsLambdaCand); + fEventMonitor.IncrementCounter(ECounter::KfpEventsLambdaCand); break; // Lambda-candidates were found, there is no sense to scan further } } diff --git a/algo/kfp/KfpV0Finder.h b/algo/kfp/KfpV0Finder.h index 72d1d1c57..9605b581b 100644 --- a/algo/kfp/KfpV0Finder.h +++ b/algo/kfp/KfpV0Finder.h @@ -92,6 +92,9 @@ namespace cbm::algo::kfp /// \brief Accessor to topology reconstructor const std::unique_ptr<KFParticleTopoReconstructor>& GetTopoReconstructor() const { return fpTopoReconstructor; } + /// \brief Gets track parameters + const auto& GetTrackAssignedParams() const { return fvTrackParam; } + /// \brief Initializes the instance (called in the beginning of the run) void Init(); diff --git a/algo/kfp/KfpV0FinderQa.cxx b/algo/kfp/KfpV0FinderQa.cxx index 4239174a7..ffc903e2a 100644 --- a/algo/kfp/KfpV0FinderQa.cxx +++ b/algo/kfp/KfpV0FinderQa.cxx @@ -29,17 +29,18 @@ void V0FinderQa::Init() 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); + fvphMomAll = MakeObj<H1D>("kfp_mom_all", "Momentum of tracks;p [GeV/c];Counts", kBetaB, kBetaL, kBetaU); + fvphMomPion = MakeObj<H1D>("kfp_mom_pion", "Momentum of #pi-candidates;p [GeV/c];Counts", kBetaB, kBetaL, kBetaU); + fvphMomProton = + MakeObj<H1D>("kfp_mom_proton", "Momentum of proton-candidates;p [GeV/c];Counts", kBetaB, kBetaL, kBetaU); //* Canvas initialisation - auto canv = CanvasConfig("kfp_lambda", "Lambda-trigger summary QA", 4, 2); + auto canv = CanvasConfig("kfp_lambda", "Lambda-trigger summary QA", 3, 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); @@ -54,16 +55,18 @@ void V0FinderQa::Exec(const RecoResults& recoEvent, const V0Finder& v0Finder) if (v0Finder.GetT0s().size() == 1) { for (uint32_t iTrk = 0; iTrk < tracks.size(); ++iTrk) { const auto& particleInfo{v0Finder.GetParticleInfo()[iTrk]}; + const auto& trkParFst{(v0Finder.GetTrackAssignedParams()[iTrk]).first}; 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); + fvphMomPion->Fill(trkParFst.GetP()); } else if (particleInfo.fPdg == 2212) { fvphBetaProton->Fill(particleInfo.fBeta); + fvphMomProton->Fill(trkParFst.GetP()); } } } @@ -75,9 +78,9 @@ void V0FinderQa::Exec(const RecoResults& recoEvent, const V0Finder& v0Finder) fvphDcaAll->Fill(bPdgDefined ? particleInfo.fDca : -999); fvphBetaAll->Fill(-999); if (bPdgDefined) { - fvphBetaPdg->Fill(-999); if (particleInfo.fPdg == -211) { fvphBetaPion->Fill(-999); + fvphMomPion->Fill(-999); } else if (particleInfo.fPdg == 2212) { fvphBetaProton->Fill(-999); diff --git a/algo/kfp/KfpV0FinderQa.h b/algo/kfp/KfpV0FinderQa.h index 39a1289ba..35b914e18 100644 --- a/algo/kfp/KfpV0FinderQa.h +++ b/algo/kfp/KfpV0FinderQa.h @@ -75,8 +75,10 @@ namespace cbm::algo::kfp 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 + qa::H1D* fvphMomAll{nullptr}; ///< Speed of all particles + qa::H1D* fvphMomPion{nullptr}; ///< Speed of pion-candidates + qa::H1D* fvphMomProton{nullptr}; ///< Speed of proton-candidates }; } // namespace cbm::algo::kfp diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx index d2215633e..a4978c303 100644 --- a/services/histserv/app/Application.cxx +++ b/services/histserv/app/Application.cxx @@ -800,21 +800,21 @@ bool Application::PrepareCanvas(uint32_t uCanvIdx) if ("nullptr" != sName) { TObject* pObj = fArrayHisto[FindHistogram(sName)]; - if (auto* pHist = dynamic_cast<TProfile2D*>(pObj)) { - pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + if (auto* pHistP2 = dynamic_cast<TProfile2D*>(pObj)) { + pHistP2->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TProfile *>( pObj ) ) - else if (auto* pHist = dynamic_cast<TProfile*>(pObj)) { - pHist->SetLineColor(uObjIdx + 1); - pHist->SetMarkerColor(uObjIdx + 1); - pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + else if (auto* pHistP1 = dynamic_cast<TProfile*>(pObj)) { + pHistP1->SetLineColor(uObjIdx + 1); + pHistP1->SetMarkerColor(uObjIdx + 1); + pHistP1->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TProfile *>( pObj ) ) - else if (auto* pHist = dynamic_cast<TH2*>(pObj)) { - pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + else if (auto* pHistH2 = dynamic_cast<TH2*>(pObj)) { + pHistH2->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TH2 *>( pObj ) ) - else if (auto* pHist = dynamic_cast<TH1*>(pObj)) { - pHist->SetLineColor(uObjIdx + 1); - pHist->SetMarkerColor(uObjIdx + 1); - pHist->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + else if (auto* pHistH1 = dynamic_cast<TH1*>(pObj)) { + pHistH1->SetLineColor(uObjIdx + 1); + pHistH1->SetMarkerColor(uObjIdx + 1); + pHistH1->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(); -- GitLab From 5c51fa5c2cc510c2752f39b073b76a4f7f74f9f4 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 13 Feb 2025 16:56:58 +0100 Subject: [PATCH 16/17] online: integrating event selection triggers into framework --- algo/base/DigiData.cxx | 8 ++-- algo/base/DigiData.h | 2 + algo/evselector/RecoEventSelectorMonitor.h | 6 +++ algo/global/Reco.cxx | 36 +++++++-------- algo/global/Reco.h | 4 +- algo/kfp/KfpV0FinderChain.cxx | 24 +++++++--- algo/kfp/KfpV0FinderChain.h | 11 +++-- algo/kfp/KfpV0FinderMonitor.h | 2 + core/data/CbmEventTriggers.h | 52 +++++++++++++++------- core/data/global/CbmDigiEvent.h | 39 +++++++++------- 10 files changed, 115 insertions(+), 69 deletions(-) diff --git a/algo/base/DigiData.cxx b/algo/base/DigiData.cxx index 179c8ca31..79fd5a483 100644 --- a/algo/base/DigiData.cxx +++ b/algo/base/DigiData.cxx @@ -119,14 +119,16 @@ DigiEvent::DigiEvent(const CbmDigiEvent& storable) : DigiData(storable.fData) , fNumber(storable.fNumber) , fTime(storable.fTime) + , fSelectionTriggers(storable.fSelectionTriggers) { } CbmDigiEvent DigiEvent::ToStorable() const { return CbmDigiEvent{ - .fData = DigiData::ToStorable(), - .fNumber = fNumber, - .fTime = fTime, + .fData = DigiData::ToStorable(), + .fNumber = fNumber, + .fTime = fTime, + .fSelectionTriggers = fSelectionTriggers, }; } diff --git a/algo/base/DigiData.h b/algo/base/DigiData.h index c19b685d9..09b82d933 100644 --- a/algo/base/DigiData.h +++ b/algo/base/DigiData.h @@ -7,6 +7,7 @@ #include "CbmBmonDigi.h" #include "CbmDigiData.h" #include "CbmDigiEvent.h" +#include "CbmEventTriggers.h" #include "CbmFsdDigi.h" #include "CbmMuchDigi.h" #include "CbmPsdDigi.h" @@ -80,6 +81,7 @@ namespace cbm::algo // FIXME: Event number not set yet! uint64_t fNumber = -1; ///< Event identifier double fTime = 0; ///< Event trigger time [ns] + CbmEventTriggers fSelectionTriggers; static std::vector<DigiEvent> FromCbmDigiEvents(const std::vector<CbmDigiEvent>& events); static std::vector<CbmDigiEvent> ToCbmDigiEvents(const std::vector<DigiEvent>& events); diff --git a/algo/evselector/RecoEventSelectorMonitor.h b/algo/evselector/RecoEventSelectorMonitor.h index de2eb4a27..ae6524f80 100644 --- a/algo/evselector/RecoEventSelectorMonitor.h +++ b/algo/evselector/RecoEventSelectorMonitor.h @@ -19,12 +19,14 @@ namespace cbm::algo::evselect /// \brief Counter keys for the event selector monitor enum class ECounter { + Timeslices, ///< number of processed timeslices EventsTotal, ///< Total number of events processed EventsNeStsHits, ///< Events with not enough STS hits EventsNeTofHits, ///< Events with enough STS hits, but not enough TOF hits EventsNeBmonHits, ///< Events with not enough BMon hits EventsNeTracks, ///< Events with enough hits, but not enough tracks EventsSelected, ///< Number of selected events + LambdaCandidates, ///< Number of lambda-candidates, returned by KFParticleFinder END }; @@ -53,11 +55,13 @@ namespace cbm::algo::evselect /// \brief Default constructor Monitor() : ca::Monitor<ECounter, ETimer>("Event-selector Monitor") { + SetCounterName(ECounter::Timeslices, "processed timeslices"); SetCounterName(ECounter::EventsTotal, "total events"); SetCounterName(ECounter::EventsNeStsHits, "events discarded by N STS hits"); SetCounterName(ECounter::EventsNeTofHits, "events discarded by N TOF hits"); SetCounterName(ECounter::EventsNeBmonHits, "events discarded by N BMon hits"); SetCounterName(ECounter::EventsNeTracks, "events discarded by N tracks"); + SetCounterName(ECounter::LambdaCandidates, "potential lambda candidates"); SetCounterName(ECounter::EventsSelected, "selected events"); SetTimerName(ETimer::EventReconstruction, "event reconstruction"); @@ -67,6 +71,8 @@ namespace cbm::algo::evselect SetTimerName(ETimer::TrdHitFinder, "hit finding in TRD"); SetTimerName(ETimer::TrackFinder, "track finding"); SetTimerName(ETimer::V0Finder, "V0 finding"); + + SetRatioKeys({ECounter::Timeslices}); } private: diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index f312ebaaa..0f192df1b 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -45,10 +45,6 @@ #include <xpu/host.h> -// DEBUG: BEGIN -#include <set> -// DEBUG: END - using namespace cbm::algo; using fles::Subsystem; @@ -427,16 +423,16 @@ RecoResults Reco::Run(const fles::Timeslice& ts) // --- Reconstruct and select digi events if (fbReconstructDigiEvents) { - size_t nDiscardedEvents{0}; + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::Timeslices); fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsTotal, events.size()); - for (const auto& event : events) { + for (auto& event : events) { fEvSelectingMonitor.StartTimer(evselect::ETimer::EventReconstruction); - if (!ReconstructEvent(event)) { - ++nDiscardedEvents; - } + event.fSelectionTriggers = ReconstructEvent(event); fEvSelectingMonitor.StopTimer(evselect::ETimer::EventReconstruction); } - L_(info) << "Rate of discarded events " << double(nDiscardedEvents) / events.size(); + auto v0FinderMonitor = fV0Finder->GetMonitor(); + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::LambdaCandidates, + v0FinderMonitor.GetCounterValue(kfp::ECounter::KfpLambdaCandidates)); } // --- Filter data for output @@ -525,8 +521,9 @@ void Reco::PrintTimings(xpu::timings& timings) } } -bool Reco::ReconstructEvent(const DigiEvent& digiEvent) +CbmEventTriggers Reco::ReconstructEvent(const DigiEvent& digiEvent) { + CbmEventTriggers triggers(0); RecoResults recoEvent; //* BMON hit reconstruction { @@ -550,7 +547,7 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) fEvSelectingMonitor.StopTimer(evselect::ETimer::StsHitFinder); if (stsResults.hits.NElements() < 4) { // TODO: Provide a config for cuts (testing mode for now) fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeStsHits); - return false; + return triggers; } recoEvent.stsHits = stsResults.hits; } @@ -563,7 +560,7 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) fEvSelectingMonitor.StopTimer(evselect::ETimer::TofHitFinder); if (hits.NElements() < 2) { // TODO: Provide a config for cuts (testing mode for now) fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeTofHits); - return false; + return triggers; } recoEvent.tofHits = std::move(hits); } @@ -597,18 +594,19 @@ bool Reco::ReconstructEvent(const DigiEvent& digiEvent) fEvSelectingMonitor.StopTimer(evselect::ETimer::TrackFinder); if (recoEvent.tracks.size() < 2) { // Reject all events with less then two tracks fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsNeTracks); - return false; + return triggers; } } //* V0-selector fEvSelectingMonitor.StartTimer(evselect::ETimer::V0Finder); - auto triggers = fV0Finder->ProcessEvent(recoEvent); + triggers = fV0Finder->ProcessEvent(recoEvent); + if (triggers.Test(CbmEventTriggers::ETrigger::Lambda)) { + L_(info) << "!!! Found event with potential lambda candidates"; + fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsSelected); + } fEvSelectingMonitor.StopTimer(evselect::ETimer::V0Finder); - - - fEvSelectingMonitor.IncrementCounter(evselect::ECounter::EventsSelected); - return true; + return triggers; } diff --git a/algo/global/Reco.h b/algo/global/Reco.h index eb8ba804a..35cb5c346 100644 --- a/algo/global/Reco.h +++ b/algo/global/Reco.h @@ -11,6 +11,8 @@ #include <xpu/host.h> // fwd declarations +class CbmEventTriggers; + namespace fles { class Timeslice; @@ -133,7 +135,7 @@ namespace cbm::algo void Init(const Options&); RecoResults Run(const fles::Timeslice&); - bool ReconstructEvent(const DigiEvent& event); + CbmEventTriggers ReconstructEvent(const DigiEvent& event); void Finalize(); void PrintTimings(xpu::timings&); diff --git a/algo/kfp/KfpV0FinderChain.cxx b/algo/kfp/KfpV0FinderChain.cxx index e23bc9e81..96dc60a59 100644 --- a/algo/kfp/KfpV0FinderChain.cxx +++ b/algo/kfp/KfpV0FinderChain.cxx @@ -27,7 +27,21 @@ V0FinderChain::V0FinderChain(const std::unique_ptr<qa::Manager>& qaManager) // --------------------------------------------------------------------------------------------------------------------- // -void V0FinderChain::Finalize() { L_(info) << fMonitorRun.ToString(); } +void V0FinderChain::Finalize() +{ + GetMonitor(); // A hack to update the run monitor + L_(info) << fMonitorRun.ToString(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +cbm::algo::kfp::V0FinderMonitorData_t V0FinderChain::GetMonitor() +{ + cbm::algo::kfp::V0FinderMonitorData_t monitorData = fMonitorTimeslice; + fMonitorTimeslice.Reset(); + fMonitorRun.AddMonitorData(monitorData); + return monitorData; +} // --------------------------------------------------------------------------------------------------------------------- // @@ -76,8 +90,6 @@ 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()) { @@ -139,12 +151,10 @@ catch (const std::exception& err) { // V0FinderChain::EventOutput V0FinderChain::ProcessEvent(const RecoResults& recoEvent) { - EventOutput res; - res.triggers = fFinder.Process(recoEvent); - res.monitor = fFinder.GetEventMonitor(); + EventOutput res = fFinder.Process(recoEvent); if (fpFinderQa != nullptr) { fpFinderQa->Exec(recoEvent, fFinder); } - fMonitorRun.AddMonitorData(res.monitor); + fMonitorTimeslice.AddMonitorData(fFinder.GetEventMonitor()); return res; } diff --git a/algo/kfp/KfpV0FinderChain.h b/algo/kfp/KfpV0FinderChain.h index 8053c93f7..95f10ebba 100644 --- a/algo/kfp/KfpV0FinderChain.h +++ b/algo/kfp/KfpV0FinderChain.h @@ -31,12 +31,7 @@ namespace cbm::algo /// \brief A chain for the V0 finder class V0FinderChain : public SubChain { public: - /// \struct EventOutput - /// \brief Output from the event - struct EventOutput { - CbmEventTriggers triggers; ///< Set of triggers - kfp::V0FinderMonitorData_t monitor; ///< Monitor - }; + using EventOutput = CbmEventTriggers; /// \brief Default constructor V0FinderChain() = default; @@ -63,6 +58,9 @@ namespace cbm::algo /// \brief Finalizes the instance (called in the end of the run) void Finalize(); + /// \brief Gets a monitor + kfp::V0FinderMonitorData_t GetMonitor(); + /// \brief Sets BMON diamond addresses array /// \note The addresses must be taken from bmon::Hitfind::GetDiamondAddresses() void SetBmonDefinedAddresses(const PODVector<uint32_t>& addresses) { fBmonDefinedAddresses = addresses; } @@ -76,6 +74,7 @@ namespace cbm::algo private: kfp::V0Finder fFinder; ///< Instance of the V0-finding algorithm kfp::V0FinderMonitor fMonitorRun; ///< Monitor per run + kfp::V0FinderMonitorData_t fMonitorTimeslice; ///< Monitor per timeslice std::unique_ptr<kfp::V0FinderQa> fpFinderQa{nullptr}; ///< QA module PODVector<uint32_t> fBmonDefinedAddresses; ///< Available addresses of BMON }; diff --git a/algo/kfp/KfpV0FinderMonitor.h b/algo/kfp/KfpV0FinderMonitor.h index 5bb4311b6..d60d5b135 100644 --- a/algo/kfp/KfpV0FinderMonitor.h +++ b/algo/kfp/KfpV0FinderMonitor.h @@ -92,6 +92,8 @@ namespace cbm::algo::kfp SetTimerName(ETimer::PreselectTracks, "Track preselection"); SetTimerName(ETimer::InitKfp, "KFParticleFinder initialization"); SetTimerName(ETimer::ExecKfp, "KFParticleFinder execution"); + + SetRatioKeys({ECounter::EventsTotal, ECounter::TracksTotal, ECounter::TracksSelected}); } private: diff --git a/core/data/CbmEventTriggers.h b/core/data/CbmEventTriggers.h index 841d86bd4..a2c252df5 100644 --- a/core/data/CbmEventTriggers.h +++ b/core/data/CbmEventTriggers.h @@ -16,24 +16,30 @@ #include <Rtypes.h> // for ClassDef #endif +#include <boost/serialization/access.hpp> + /// \class CbmEventTriggers /// \brief Class to store different triggers for a given event class CbmEventTriggers { public: /// \enum ETrigger - /// \brief Defines a trigger address - enum class ETrigger : uint8_t + /// \brief Defines a trigger bitmask + enum class ETrigger : uint32_t { - Lambda = 0b00000001, ///< Lambda-trigger - Ks = 0b00000010 ///< Ks-trigger + Lambda = 0x00000001, ///< Lambda-trigger + Ks = 0x00000002 ///< Ks-trigger }; //using Trigger_t = std::underlying_type_t<ETrigger>; - using Trigger_t = uint8_t; + using Trigger_t = uint32_t; /// \brief Default constructor CbmEventTriggers() = default; + /// \brief A constructor from integer + /// \param bitmap A bitmap of the triggers + explicit CbmEventTriggers(uint32_t bitmap) { fBitmap = bitmap; } + /// \brief Copy constructor CbmEventTriggers(const CbmEventTriggers&) = default; @@ -49,33 +55,47 @@ class CbmEventTriggers { /// \brief Move assignment operator CbmEventTriggers& operator=(CbmEventTriggers&&) = default; + /// \brief Gets a bitmap + /// \return bitmap (integer) + Trigger_t GetBitmap() const { return fBitmap; } + /// \brief Sets a trigger /// \param key Trigger key - void Set(ETrigger key) { fTriggers |= static_cast<Trigger_t>(key); } + void Set(ETrigger key) { fBitmap |= static_cast<Trigger_t>(key); } /// \brief Resets a trigger /// \param key Trigger key - void Reset(ETrigger key) { fTriggers &= ~static_cast<Trigger_t>(key); } + void Reset(ETrigger key) { fBitmap &= ~static_cast<Trigger_t>(key); } + + /// \brief Resets all the triggers + void ResetAll() { fBitmap = 0; } /// \brief Tests a particular single trigger /// \param key Trigger key - bool Test(ETrigger key) const { return static_cast<bool>(fTriggers & static_cast<Trigger_t>(key)); } + bool Test(ETrigger key) const { return static_cast<bool>(fBitmap & static_cast<Trigger_t>(key)); } - /// \brief Tests, if ALL the triggers in the mask are on - /// \param mask Trigger mask - bool TestAll(Trigger_t mask) const { return mask == (fTriggers & mask); } + /// \brief Tests, if ALL the triggers in the bitmask are on + /// \param bitmask Trigger bitmask + bool TestAll(Trigger_t bitmask) const { return bitmask == (fBitmap & bitmask); } - /// \brief Tests, if ANY of the triggers in the mask are on - /// \param mask Trigger mask - bool TestAny(Trigger_t mask) const { return static_cast<bool>(fTriggers | mask); } + /// \brief Tests, if ANY of the triggers in the bitmask are on + /// \param bitmask Trigger bitmask + bool TestAny(Trigger_t bitmask) const { return static_cast<bool>(fBitmap | bitmask); } /// \brief String representation of the class content std::string ToString() const; private: - Trigger_t fTriggers{0}; + Trigger_t fBitmap{0}; ///< bitmap storing the triggers according to ETrigger + + friend class boost::serialization::access; + template<class Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& fBitmap; + } #if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA - ClassDefNV(CbmEventTriggers, 1); + ClassDefNV(CbmEventTriggers, 2); #endif }; diff --git a/core/data/global/CbmDigiEvent.h b/core/data/global/CbmDigiEvent.h index 242740e57..ec90985bb 100644 --- a/core/data/global/CbmDigiEvent.h +++ b/core/data/global/CbmDigiEvent.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021-22 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt +/* Copyright (C) 2021-25 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only Authors: Volker Friese [committer] */ @@ -6,6 +6,7 @@ #define CBMDIGIEVENT_H 1 #include "CbmDigiData.h" +#include "CbmEventTriggers.h" #include <boost/serialization/access.hpp> @@ -14,29 +15,32 @@ ** @brief Collection of digis from all detector systems within one event ** @author Volker Friese <v.friese@gsi.de> ** @since 7.12.2022 - ** @version 2.0 + ** @version 3.0 **/ class CbmDigiEvent { public: - CbmDigiData fData; ///< Event data - uint64_t fNumber; ///< Event identifier - double fTime; ///< Event trigger time [ns] - - - friend class boost::serialization::access; - /** @brief BOOST serializer**/ - template<class Archive> - void serialize(Archive& ar, const unsigned int /*version*/) - { - ar& fData; - ar& fNumber; - ar& fTime; - } + CbmDigiData fData; ///< Event data + uint64_t fNumber; ///< Event identifier + double fTime; ///< Event trigger time [ns] + CbmEventTriggers fSelectionTriggers; ///< Event selection triggers + + friend class boost::serialization::access; + /** @brief BOOST serializer**/ + template<class Archive> + void serialize(Archive& ar, const unsigned int version) + { + ar& fData; + ar& fNumber; + ar& fTime; + if (version >= 3) { + ar& fSelectionTriggers; + } + } // --- ROOT serializer #ifndef NO_ROOT - ClassDefNV(CbmDigiEvent, 2); + ClassDefNV(CbmDigiEvent, 3); #endif /** @brief Clear content **/ @@ -45,6 +49,7 @@ public: fData.Clear(); fNumber = 0; fTime = 0.; + fSelectionTriggers.ResetAll(); } }; -- GitLab From 3614fb4ed51db87889e57c87cdfc4ac8b1ad8540 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Sat, 15 Feb 2025 10:03:44 +0100 Subject: [PATCH 17/17] Removing ROOT library linking to CbmKFParticleOnlineInterface --- algo/kfp/interface/CMakeLists.txt | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/algo/kfp/interface/CMakeLists.txt b/algo/kfp/interface/CMakeLists.txt index c1eaadf76..4beacabb1 100644 --- a/algo/kfp/interface/CMakeLists.txt +++ b/algo/kfp/interface/CMakeLists.txt @@ -1,25 +1,14 @@ if(NOT CBM_ONLINE_STANDALONE) ### CbmKFParticleOnlineInterface + # Just reusing the KFParticle library, compiled in the external add_library(CbmKFParticleOnlineInterface INTERFACE) target_include_directories(CbmKFParticleOnlineInterface INTERFACE) target_compile_definitions(CbmKFParticleOnlineInterface INTERFACE DO_TPCCATRACKER_EFF_PERFORMANCE NonhomogeneousField CBM USE_TIMERS) - target_link_libraries(CbmKFParticleOnlineInterface - INTERFACE KFParticle - ROOT::Core - ROOT::Hist - ROOT::MathCore - ROOT::Gpad - ROOT::Graf - ROOT::Physics - ROOT::EG - ROOT::RIO - ROOT::Tree - ROOT::MathCore - ) + target_link_libraries(CbmKFParticleOnlineInterface INTERFACE KFParticle) install(TARGETS CbmKFParticleOnlineInterface DESTINATION lib) else() - # Creating a replacement of the CbmKFParticleOnlineInterface library for a standalone mode + # Creating a replacement of the KFParticle library for a standalone mode set(KFP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/KFParticle/KFParticle) set(SRCS -- GitLab