diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 0524146a40df5e21ae4af1edf685216eb7e1847c..6ba7a06c032faec9f9a1832e0724a3b7c801d8da 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 330f7070209a70acf9725d45bd5dff101713cd71..41bc2ff13691a636060485442aea1e018348dae0 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 ac2c3b410accd1415bc4de89811785442eb9aca1..38773a0e813f9f7e5d3aa259caab1a1544480412 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 691e27b39bf8af9b64b89cc209422f786048e1e7..0fe7b3094b1e25eaa0d7f3ccb207a6977f5d2836 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 0000000000000000000000000000000000000000..cc41f095bbc59bdb98f1ebcafb9ac8c09ec67927 --- /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 58ca4293937fe17d28acce2f076541b40eb79c68..52a8f0d03113e0f9d70951a518b2f60cf728e073 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 d0a8a451ae92c3031f57cb1508d58c7f754d14b5..5240085b8924627f006c9cc3be35594b6d2e1480 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 a2a78be1c4679254c29c7a3084902537ce9c8210..1fb1a7a9d9a0a32606bbd3759e9006bd88c97a21 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 0000000000000000000000000000000000000000..8b037a70e5f554f7aa3871bae62b46e6ec5fbc88 --- /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()