From 5312f7538b1e66d83cb21486b26c7aa0f7e315e7 Mon Sep 17 00:00:00 2001 From: jesgum Date: Tue, 10 Feb 2026 10:14:27 +0100 Subject: [PATCH] A3 Track Smearer as a service --- ALICE3/Core/CMakeLists.txt | 2 + ALICE3/Core/TrackSmearerService.cxx | 158 ++++++++++++++++++ ALICE3/Core/TrackSmearerService.h | 56 +++++++ .../OTF/onTheFlyDetectorGeometryProvider.cxx | 16 +- ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx | 66 +------- ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx | 66 +------- ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 73 ++------ 7 files changed, 252 insertions(+), 185 deletions(-) create mode 100644 ALICE3/Core/TrackSmearerService.cxx create mode 100644 ALICE3/Core/TrackSmearerService.h diff --git a/ALICE3/Core/CMakeLists.txt b/ALICE3/Core/CMakeLists.txt index 6d44d580c45..837b5b56e2e 100644 --- a/ALICE3/Core/CMakeLists.txt +++ b/ALICE3/Core/CMakeLists.txt @@ -13,6 +13,7 @@ o2physics_add_library(ALICE3Core SOURCES TOFResoALICE3.cxx TrackUtilities.cxx DelphesO2TrackSmearer.cxx + TrackSmearerService.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) @@ -20,6 +21,7 @@ o2physics_target_root_dictionary(ALICE3Core HEADERS TOFResoALICE3.h TrackUtilities.h DelphesO2TrackSmearer.h + TrackSmearerService.h LINKDEF ALICE3CoreLinkDef.h) o2physics_add_library(FastTracker diff --git a/ALICE3/Core/TrackSmearerService.cxx b/ALICE3/Core/TrackSmearerService.cxx new file mode 100644 index 00000000000..48a181f16bf --- /dev/null +++ b/ALICE3/Core/TrackSmearerService.cxx @@ -0,0 +1,158 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackSmearerService.cxx +/// \brief Implementation for smearer service for the on-the-fly simulation +/// \author Jesper Karlsson Gumprecht + + +#include "ALICE3/Core/TrackSmearerService.h" +#include +#include +#include +#include + +#include +#include + +#include + +bool o2::upgrade::TrackSmearerImpl::mIsInit = false; +bool o2::upgrade::TrackSmearerImpl::mCleanLutWhenLoaded = true; + +void o2::upgrade::TrackSmearerImpl::initSmearer(o2::ccdb::BasicCCDBManager* ccdb, bool cleanLutWhenLoaded) +{ + if (mIsInit) { + LOG(fatal) << "TrackSmearerImpl already initialized, cannot re-initialize"; + } + + if (!ccdb) { + LOG(fatal) << "CCDB manager is not set, cannot initialize TrackSmearerImpl"; + } + + mIsInit = true; + mCcdb = ccdb; + mCcdb->setURL("http://alice-ccdb.cern.ch"); + mCcdb->setTimestamp(-1); + mCleanLutWhenLoaded = cleanLutWhenLoaded; +} + + +std::vector> o2::upgrade::TrackSmearerImpl::smearerContainer; +void o2::upgrade::TrackSmearerImpl::initCfg(int icfg, std::map globalConfiguration) +{ + smearerContainer.emplace_back(std::make_unique()); + smearerContainer[icfg]->setCcdbManager(mCcdb); + smearerContainer[icfg]->setDownloadPath("./.ALICE3/"); + smearerContainer[icfg]->setCleanupDownloadedFile(mCleanLutWhenLoaded); + for (const auto& entry : globalConfiguration) { + int pdg = 0; + if (entry.first.find("lut") != 0) { + continue; + } + if (entry.first.find("lutEl") != std::string::npos) { + pdg = kElectron; + } else if (entry.first.find("lutMu") != std::string::npos) { + pdg = kMuonMinus; + } else if (entry.first.find("lutPi") != std::string::npos) { + pdg = kPiPlus; + } else if (entry.first.find("lutKa") != std::string::npos) { + pdg = kKPlus; + } else if (entry.first.find("lutPr") != std::string::npos) { + pdg = kProton; + } else if (entry.first.find("lutDe") != std::string::npos) { + pdg = o2::constants::physics::kDeuteron; + } else if (entry.first.find("lutTr") != std::string::npos) { + pdg = o2::constants::physics::kTriton; + } else if (entry.first.find("lutHe3") != std::string::npos) { + pdg = o2::constants::physics::kHelium3; + } else if (entry.first.find("lutAl") != std::string::npos) { + pdg = o2::constants::physics::kAlpha; + } + + std::string filename = entry.second; + if (pdg == 0) { + LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration"; + } + LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'"; + if (filename.empty()) { + LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; + } + // strip from leading/trailing spaces + filename.erase(0, filename.find_first_not_of(" ")); + filename.erase(filename.find_last_not_of(" ") + 1); + if (filename.empty()) { + LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; + } + bool success = smearerContainer[icfg]->loadTable(pdg, filename.c_str()); + if (!success) { + LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename; + } + LOG(info) << "Successfully loaded LUT for pdg " << pdg; + } +} + +o2::delphes::DelphesO2TrackSmearer* o2::upgrade::TrackSmearerImpl::getSmearer(int icfg) +{ + if (icfg < 0 || icfg >= static_cast(smearerContainer.size())) { + LOG(fatal) << "Configuration index " << icfg << " out of bounds"; + return nullptr; + } + if (!smearerContainer[icfg]) { + LOG(fatal) << "nullptr entry in tracksmearer container"; + return nullptr; + } + return smearerContainer[icfg].get(); +} + + +void o2::upgrade::TrackSmearerImpl::setReady() +{ + std::ofstream okFile(".TrackSmearerOK"); + okFile.close(); + LOG(info) << "Track smearer ready"; +} + +void o2::upgrade::TrackSmearerImpl::waitReady() +{ + while (!std::ifstream(".TrackSmearerOK")) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } +} + +struct TrackSmearerSupport : o2::framework::ServicePlugin { + o2::framework::ServiceSpec* create() final + { + return new o2::framework::ServiceSpec{ + .name = "track-smearer", + .init = [](o2::framework::ServiceRegistryRef, o2::framework::DeviceState&, fair::mq::ProgOptions&) -> o2::framework::ServiceHandle { + auto* wrapper = new o2::upgrade::TrackSmearerContainer(); + auto* ptr = new o2::upgrade::TrackSmearerImpl(); + wrapper->setInstance(ptr); + return o2::framework::ServiceHandle{o2::framework::TypeIdHelpers::uniqueId(), + wrapper, + o2::framework::ServiceKind::Serial, + "database-pdg"}; + }, + .configure = o2::framework::CommonServices::noConfiguration(), + .exit = [](o2::framework::ServiceRegistryRef, void* service) { + auto* s = reinterpret_cast(service); + delete s; + }, + .kind = o2::framework::ServiceKind::Serial + }; + } +}; + +DEFINE_DPL_PLUGINS_BEGIN +DEFINE_DPL_PLUGIN_INSTANCE(TrackSmearerSupport, CustomService); +DEFINE_DPL_PLUGINS_END + diff --git a/ALICE3/Core/TrackSmearerService.h b/ALICE3/Core/TrackSmearerService.h new file mode 100644 index 00000000000..a4c546b7529 --- /dev/null +++ b/ALICE3/Core/TrackSmearerService.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackSmearerService.h +/// \brief Implementation for smearer service for the on-the-fly simulation +/// \author Jesper Karlsson Gumprecht + + +#ifndef ALICE3_CORE_TRACKSMEARERSERVICE_H_ +#define ALICE3_CORE_TRACKSMEARERSERVICE_H_ + +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "Framework/Plugins.h" +#include "CCDB/BasicCCDBManager.h" +#include "ALICE3/Core/FastTracker.h" + +#include +#include +#include +#include + +namespace o2::upgrade { + +struct TrackSmearerImpl { + static std::vector> smearerContainer; + void initSmearer(o2::ccdb::BasicCCDBManager* ccdb, bool cleanLutWhenLoaded); + void initCfg(int icfg, std::map globalConfiguration); + size_t size() { return smearerContainer.size(); } + void setReady(); + void waitReady(); + o2::delphes::DelphesO2TrackSmearer* getSmearer(int icfg = 0); + + +private: + static bool mIsInit; + static bool mCleanLutWhenLoaded; + o2::ccdb::BasicCCDBManager* mCcdb = nullptr; +}; + +struct TrackSmearerContainer : o2::framework::LoadableServicePlugin { + TrackSmearerContainer() : LoadableServicePlugin{"O2PhysicsALICE3Core:TrackSmearerSupport"} + { + } +}; + +} // namespace o2::upgrade + +#endif // ALICE3_CORE_TRACKSMEARERSERVICE_H_ \ No newline at end of file diff --git a/ALICE3/TableProducer/OTF/onTheFlyDetectorGeometryProvider.cxx b/ALICE3/TableProducer/OTF/onTheFlyDetectorGeometryProvider.cxx index 58d03054d06..668effd3f49 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDetectorGeometryProvider.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDetectorGeometryProvider.cxx @@ -17,24 +17,32 @@ /// #include "ALICE3/Core/FastTracker.h" +#include "ALICE3/Core/TrackSmearerService.h" #include #include #include #include + #include #include #include struct OnTheFlyDetectorGeometryProvider { o2::framework::HistogramRegistry histos{"Histos", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + o2::framework::Configurable cleanLutWhenLoaded{"cleanLutWhenLoaded", true, "Flag to delete the local lut files after loading them into memory"}; o2::framework::Configurable> detectorConfiguration{"detectorConfiguration", std::vector{"$O2PHYSICS_ROOT/share/alice3/a3geometry_v3.ini"}, "Paths of the detector geometry configuration files"}; o2::framework::Service ccdb; + o2::framework::Service smearerContainer; void init(o2::framework::InitContext&) { + if (std::ifstream(".TrackSmearerOK")) { + std::remove(".TrackSmearerOK"); + } + ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setTimestamp(-1); o2::fastsim::GeometryContainer geometryContainer; // Checking that the geometry files can be accessed and loaded @@ -70,13 +78,11 @@ struct OnTheFlyDetectorGeometryProvider { // First we check that the magnetic field is consistent const int nGeometries = geometryContainer.getNumberOfConfigurations(); - const float mMagneticField = geometryContainer.getFloatValue(0, "global", "magneticfield"); + smearerContainer->initSmearer(ccdb.operator->(), cleanLutWhenLoaded.value); for (int icfg = 0; icfg < nGeometries; ++icfg) { - const float cfgBfield = geometryContainer.getFloatValue(icfg, "global", "magneticfield"); - if (std::abs(cfgBfield - mMagneticField) > 1e-3) { - LOG(fatal) << "Inconsistent magnetic field values between configurations 0 and " << icfg << ": " << mMagneticField << " vs " << cfgBfield; - } + smearerContainer->initCfg(icfg, geometryContainer.getConfiguration(icfg, "global")); } + smearerContainer->setReady(); LOG(info) << "Initialization completed"; } diff --git a/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx index f849e28b740..c64dbc9cc84 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx @@ -39,6 +39,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include +#include "ALICE3/Core/TrackSmearerService.h" #include #include #include @@ -134,7 +135,7 @@ struct OnTheFlyRichPid { o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // Track smearer array, one per geometry - std::vector> mSmearer; + Service smearerContainer; // needed: random number generator for smearing TRandom3 pRandomNumberGenerator; @@ -290,65 +291,10 @@ struct OnTheFlyRichPid { void init(o2::framework::InitContext& initContext) { mGeoContainer.init(initContext); - - const int nGeometries = mGeoContainer.getNumberOfConfigurations(); + smearerContainer->waitReady(); mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); - pRandomNumberGenerator.SetSeed(0); // fully randomize - for (int icfg = 0; icfg < nGeometries; ++icfg) { - const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; - mSmearer.emplace_back(std::make_unique()); - mSmearer[icfg]->setCleanupDownloadedFile(cleanLutWhenLoaded.value); - mSmearer[icfg]->setCcdbManager(ccdb.operator->()); - mSmearer[icfg]->setDownloadPath("./.ALICE3/RICHPID/"); - std::map globalConfiguration = mGeoContainer.getConfiguration(icfg, "global"); - for (const auto& entry : globalConfiguration) { - int pdg = 0; - if (entry.first.find("lut") != 0) { - continue; - } - if (entry.first.find("lutEl") != std::string::npos) { - pdg = kElectron; - } else if (entry.first.find("lutMu") != std::string::npos) { - pdg = kMuonMinus; - } else if (entry.first.find("lutPi") != std::string::npos) { - pdg = kPiPlus; - } else if (entry.first.find("lutKa") != std::string::npos) { - pdg = kKPlus; - } else if (entry.first.find("lutPr") != std::string::npos) { - pdg = kProton; - } else if (entry.first.find("lutDe") != std::string::npos) { - pdg = o2::constants::physics::kDeuteron; - } else if (entry.first.find("lutTr") != std::string::npos) { - pdg = o2::constants::physics::kTriton; - } else if (entry.first.find("lutHe3") != std::string::npos) { - pdg = o2::constants::physics::kHelium3; - } else if (entry.first.find("lutAl") != std::string::npos) { - pdg = o2::constants::physics::kAlpha; - } - - std::string filename = entry.second; - if (pdg == 0) { - LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration"; - } - LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'"; - if (filename.empty()) { - LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; - } - // strip from leading/trailing spaces - filename.erase(0, filename.find_first_not_of(" ")); - filename.erase(filename.find_last_not_of(" ") + 1); - if (filename.empty()) { - LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; - } - bool success = mSmearer[icfg]->loadTable(pdg, filename.c_str()); - if (!success) { - LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename; - } - } - } - if (doQAplots) { const AxisSpec axisMomentum{static_cast(nBinsP), 0.0f, +20.0f, "#it{p} (GeV/#it{c})"}; const AxisSpec axisAngle{static_cast(nBinsThetaRing), 0.0f, +0.30f, "Measured Cherenkov angle (rad)"}; @@ -870,9 +816,9 @@ struct OnTheFlyRichPid { double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(recoTrack.getSigma1Pt2()); double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-recoTrack.getEta())))) * std::sqrt(recoTrack.getSigmaTgl2()); if (flagRICHLoadDelphesLUTs) { - if (mSmearer[collision.lutConfigId()]->hasTable(kParticlePdgs[ii])) { - ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum); - etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum); + if (smearerContainer->getSmearer(collision.lutConfigId())->hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded + ptResolution = smearerContainer->getSmearer(collision.lutConfigId())->getAbsPtRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum); + etaResolution = smearerContainer->getSmearer(collision.lutConfigId())->getAbsEtaRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum); } } // cout << endl << "Pt resolution: " << ptResolution << ", Eta resolution: " << etaResolution << endl << endl; diff --git a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx index d4b94be0410..b4aae11171d 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx @@ -33,6 +33,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include +#include "ALICE3/Core/TrackSmearerService.h" #include #include #include @@ -133,7 +134,7 @@ struct OnTheFlyTofPid { o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // Track smearer array, one per geometry - std::vector> mSmearer; + Service smearerContainer; // needed: random number generator for smearing TRandom3 pRandomNumberGenerator; @@ -149,65 +150,10 @@ struct OnTheFlyTofPid { void init(o2::framework::InitContext& initContext) { mGeoContainer.init(initContext); - - const int nGeometries = mGeoContainer.getNumberOfConfigurations(); + smearerContainer->waitReady(); mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); - pRandomNumberGenerator.SetSeed(0); // fully randomize - for (int icfg = 0; icfg < nGeometries; ++icfg) { - const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; - mSmearer.emplace_back(std::make_unique()); - mSmearer[icfg]->setCleanupDownloadedFile(cleanLutWhenLoaded.value); - mSmearer[icfg]->setCcdbManager(ccdb.operator->()); - mSmearer[icfg]->setDownloadPath("./.ALICE3/TOFPID/"); - std::map globalConfiguration = mGeoContainer.getConfiguration(icfg, "global"); - for (const auto& entry : globalConfiguration) { - int pdg = 0; - if (entry.first.find("lut") != 0) { - continue; - } - if (entry.first.find("lutEl") != std::string::npos) { - pdg = kElectron; - } else if (entry.first.find("lutMu") != std::string::npos) { - pdg = kMuonMinus; - } else if (entry.first.find("lutPi") != std::string::npos) { - pdg = kPiPlus; - } else if (entry.first.find("lutKa") != std::string::npos) { - pdg = kKPlus; - } else if (entry.first.find("lutPr") != std::string::npos) { - pdg = kProton; - } else if (entry.first.find("lutDe") != std::string::npos) { - pdg = o2::constants::physics::kDeuteron; - } else if (entry.first.find("lutTr") != std::string::npos) { - pdg = o2::constants::physics::kTriton; - } else if (entry.first.find("lutHe3") != std::string::npos) { - pdg = o2::constants::physics::kHelium3; - } else if (entry.first.find("lutAl") != std::string::npos) { - pdg = o2::constants::physics::kAlpha; - } - - std::string filename = entry.second; - if (pdg == 0) { - LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration"; - } - LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'"; - if (filename.empty()) { - LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; - } - // strip from leading/trailing spaces - filename.erase(0, filename.find_first_not_of(" ")); - filename.erase(filename.find_last_not_of(" ") + 1); - if (filename.empty()) { - LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; - } - bool success = mSmearer[icfg]->loadTable(pdg, filename.c_str()); - if (!success) { - LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename; - } - } - } - if (plotsConfig.doQAplots) { const AxisSpec axisdNdeta{plotsConfig.nBinsMult, 0.0f, plotsConfig.maxMultRange, Form("dN/d#eta in |#eta| < %f", simConfig.multiplicityEtaRange.value)}; @@ -877,9 +823,9 @@ struct OnTheFlyTofPid { double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(trkWithTime.mMomentum.second); double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-pseudorapidity)))) * std::sqrt(trkWithTime.mPseudorapidity.second); if (simConfig.flagTOFLoadDelphesLUTs) { - if (mSmearer[collision.lutConfigId()]->hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded - ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); - etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); + if (smearerContainer->getSmearer(collision.lutConfigId())->hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded + ptResolution = smearerContainer->getSmearer(collision.lutConfigId())->getAbsPtRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); + etaResolution = smearerContainer->getSmearer(collision.lutConfigId())->getAbsEtaRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); } } const float innerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.innerTOFRadius, mMagneticField); diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index ae1055b86d5..a756ed48c2a 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -51,6 +51,7 @@ #include #include #include +#include "ALICE3/Core/TrackSmearerService.h" #include #include @@ -288,7 +289,7 @@ struct OnTheFlyTracker { o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // Track smearer array, one per geometry - std::vector> mSmearer; + Service smearerContainer; // For processing and vertexing std::vector tracksAlice3; @@ -308,6 +309,9 @@ struct OnTheFlyTracker { float mMagneticField = 0.0f; void init(o2::framework::InitContext& initContext) { + // need geo provider to load smearer into memory before continuing + smearerContainer->waitReady(); + LOG(info) << "Initializing OnTheFlyTracker task"; ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setTimestamp(-1); @@ -315,65 +319,14 @@ struct OnTheFlyTracker { const int nGeometries = mGeoContainer.getNumberOfConfigurations(); mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); - for (int icfg = 0; icfg < nGeometries; ++icfg) { + for (int icfg = 0; icfg < nGeometries; ++icfg) { const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; - mSmearer.emplace_back(std::make_unique()); - mSmearer[icfg]->setCleanupDownloadedFile(cleanLutWhenLoaded.value); - mSmearer[icfg]->setCcdbManager(ccdb.operator->()); - mSmearer[icfg]->setDownloadPath("./.ALICE3/Tracker/"); - std::map globalConfiguration = mGeoContainer.getConfiguration(icfg, "global"); if (enablePrimarySmearing) { - // load LUTs for primaries - for (const auto& entry : globalConfiguration) { - int pdg = 0; - if (entry.first.find("lut") != 0) { - continue; - } - if (entry.first.find("lutEl") != std::string::npos) { - pdg = kElectron; - } else if (entry.first.find("lutMu") != std::string::npos) { - pdg = kMuonMinus; - } else if (entry.first.find("lutPi") != std::string::npos) { - pdg = kPiPlus; - } else if (entry.first.find("lutKa") != std::string::npos) { - pdg = kKPlus; - } else if (entry.first.find("lutPr") != std::string::npos) { - pdg = kProton; - } else if (entry.first.find("lutDe") != std::string::npos) { - pdg = o2::constants::physics::kDeuteron; - } else if (entry.first.find("lutTr") != std::string::npos) { - pdg = o2::constants::physics::kTriton; - } else if (entry.first.find("lutHe3") != std::string::npos) { - pdg = o2::constants::physics::kHelium3; - } else if (entry.first.find("lutAl") != std::string::npos) { - pdg = o2::constants::physics::kAlpha; - } - - std::string filename = entry.second; - if (pdg == 0) { - LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration"; - } - LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'"; - if (filename.empty()) { - LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; - } - // strip from leading/trailing spaces - filename.erase(0, filename.find_first_not_of(" ")); - filename.erase(filename.find_last_not_of(" ") + 1); - if (filename.empty()) { - LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; - } - bool success = mSmearer[icfg]->loadTable(pdg, filename.c_str()); - if (!success) { - LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename; - } - } - // interpolate efficiencies if requested to do so - mSmearer[icfg]->interpolateEfficiency(interpolateLutEfficiencyVsNch.value); - + smearerContainer->getSmearer(icfg)->interpolateEfficiency(interpolateLutEfficiencyVsNch.value); + // smear un-reco'ed tracks if asked to do so - mSmearer[icfg]->skipUnreconstructed(!processUnreconstructedTracks.value); + smearerContainer->getSmearer(icfg)->skipUnreconstructed(!processUnreconstructedTracks.value); insertHist(histPath + "hPtGenerated", "hPtGenerated", {kTH1D, {{axes.axisMomentum}}}); insertHist(histPath + "hPhiGenerated", "hPhiGenerated", {kTH1D, {{100, 0.0f, 2 * M_PI, "#phi (rad)"}}}); @@ -1310,7 +1263,7 @@ struct OnTheFlyTracker { bool reconstructed = true; if (enablePrimarySmearing && !fastPrimaryTrackerSettings.fastTrackPrimaries) { - reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + reconstructed = smearerContainer->getSmearer(icfg)->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); } else if (fastPrimaryTrackerSettings.fastTrackPrimaries) { o2::track::TrackParCov o2Track; o2::upgrade::convertMCParticleToO2Track(mcParticle, o2Track, pdgDB); @@ -1592,7 +1545,7 @@ struct OnTheFlyTracker { void processOnTheFly(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { - for (size_t icfg = 0; icfg < mSmearer.size(); ++icfg) { + for (size_t icfg = 0; icfg < smearerContainer->size(); ++icfg) { LOG(debug) << " -> Processing OTF tracking with LUT configuration ID " << icfg; processWithLUTs(mcCollision, mcParticles, static_cast(icfg)); } @@ -1696,7 +1649,7 @@ struct OnTheFlyTracker { bool reconstructed = false; if (enablePrimarySmearing && mcParticle.isPrimary()) { o2::upgrade::convertMCParticleToO2Track(mcParticle, trackParCov, pdgDB); - reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + reconstructed = smearerContainer->getSmearer(icfg)->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); } else if (enableSecondarySmearing) { o2::track::TrackParCov perfectTrackParCov; o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); @@ -1855,7 +1808,7 @@ struct OnTheFlyTracker { void processDecayer(aod::McCollision const& mcCollision, aod::McParticlesWithDau const& mcParticles) { - for (size_t icfg = 0; icfg < mSmearer.size(); ++icfg) { + for (size_t icfg = 0; icfg < smearerContainer->size(); ++icfg) { processConfigurationDev(mcCollision, mcParticles, static_cast(icfg)); } }