diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx index 5ce7a4e51d717bc4ec01905717ad2644b32e54a8..374c23bb1e053d132dda601a4049746b910c90e7 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 5acd385893cffa7941e92182c268f44adbe0aed8..84e90a0eda1557717935c876b51dd6514b69235a 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 05815198dd6e6a228f9db995496470a830d18b2c..8d081862c78d399aca6ec01d0dda38e432517185 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 68d7d3a9b57e80099a6a4ce3854445622cca5384..0257a9b7483a588e0f06b89f54de477d08a1445a 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 caf6d34f758dcc976f9c70358f1c133605f1bbf6..1a182b62509860a32a86f5f4deb82a45c0a97758 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 119db83b1a43a26b37db80abe1e919ec39953f00..5abf282f3aecabec76ed6b541cd8f2877962360a 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 cbeaec0a7685c5391065c3561f0ac44a3904c907..0000000000000000000000000000000000000000 --- 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 41bc2ff13691a636060485442aea1e018348dae0..82c68535c758ac23cad2ddc4dcbd9b334a5b8c58 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 38773a0e813f9f7e5d3aa259caab1a1544480412..7b73fe77991c059b37d962a3694a552e36e278fd 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 0f933400df495d66049f9ef7e681c4091249806f..37c37b5088df2105c5d6d4aa562643bc52fb3de5 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 25a3f73a2a567d118aa3638b5feb85a6ba19e104..7795dda39642248cf56ea72f05843d2792f51da8 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 5677dc5f6dcafa86a2b7d5ee513a50e05d0985fd..5a5ddbc6e84370d9ad845f3c5ac6e08907ab794b 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 e34e543d26b6d31dcfc0b528bd191d5e28aef32e..ef8b1e22b72a335fa7c38b807f1f28e0d4ea2adb 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 621f4d0d88b2b11216b31c2d8df07455678766cc..f41a0597ac8adce96b374ee90e3ff00e02cdaf34 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 c328750aac9dd2aa74d9226754a0ee7f71238630..630fc02e63e52d9e07dd89bf53669b3994224a0c 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 dacc3705d843874c33d196909dd85b2ac655294e..4bd992e0cb406145ad29495f89acfc00827b6622 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 8b037a70e5f554f7aa3871bae62b46e6ec5fbc88..ce26ad980038dfe6439bfb621a8ab61eba0e8552 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 0000000000000000000000000000000000000000..e6eaa5500553524aaf4192d2a17108cd81b30da8 --- /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 520ed4e522e022e742179e2ecb4c5f564b95da4d..6c42b3a5237df1cad00eacd1d9b9a579cf661f6d 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 365d286e505137cabe5551fe180a53d4a2572318..841d86bd4a0bc680469527a9dfa2507c914a3cd6 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 71554dd1ad19a3a1523842d603a5e9aff97ae20a..29c1573452a1713f962b5a4347e47577000aca0e 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 d0843683605e1ffeec46e52a02158a289405d0ab..9328a585c1d7b5ed3640fea9f1126a30a34820bd 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 01e77b1855b37c5f3f763f6f1175faf7ff89af12..fc5599d3723479b6fc379a60f56e3d0d5983131c 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