Skip to content

Commit 5312f75

Browse files
committed
A3 Track Smearer as a service
1 parent e1de32b commit 5312f75

File tree

7 files changed

+252
-185
lines changed

7 files changed

+252
-185
lines changed

ALICE3/Core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ o2physics_add_library(ALICE3Core
1313
SOURCES TOFResoALICE3.cxx
1414
TrackUtilities.cxx
1515
DelphesO2TrackSmearer.cxx
16+
TrackSmearerService.cxx
1617
PUBLIC_LINK_LIBRARIES O2::Framework
1718
O2Physics::AnalysisCore)
1819

1920
o2physics_target_root_dictionary(ALICE3Core
2021
HEADERS TOFResoALICE3.h
2122
TrackUtilities.h
2223
DelphesO2TrackSmearer.h
24+
TrackSmearerService.h
2325
LINKDEF ALICE3CoreLinkDef.h)
2426

2527
o2physics_add_library(FastTracker
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file TrackSmearerService.cxx
13+
/// \brief Implementation for smearer service for the on-the-fly simulation
14+
/// \author Jesper Karlsson Gumprecht <jesper.gumprecht@cern.ch>
15+
16+
17+
#include "ALICE3/Core/TrackSmearerService.h"
18+
#include <Framework/CommonServices.h>
19+
#include <Framework/Plugins.h>
20+
#include <Framework/ServiceHandle.h>
21+
#include <Framework/ServiceSpec.h>
22+
23+
#include <string>
24+
#include <TPDGCode.h>
25+
26+
#include <vector>
27+
28+
bool o2::upgrade::TrackSmearerImpl::mIsInit = false;
29+
bool o2::upgrade::TrackSmearerImpl::mCleanLutWhenLoaded = true;
30+
31+
void o2::upgrade::TrackSmearerImpl::initSmearer(o2::ccdb::BasicCCDBManager* ccdb, bool cleanLutWhenLoaded)
32+
{
33+
if (mIsInit) {
34+
LOG(fatal) << "TrackSmearerImpl already initialized, cannot re-initialize";
35+
}
36+
37+
if (!ccdb) {
38+
LOG(fatal) << "CCDB manager is not set, cannot initialize TrackSmearerImpl";
39+
}
40+
41+
mIsInit = true;
42+
mCcdb = ccdb;
43+
mCcdb->setURL("http://alice-ccdb.cern.ch");
44+
mCcdb->setTimestamp(-1);
45+
mCleanLutWhenLoaded = cleanLutWhenLoaded;
46+
}
47+
48+
49+
std::vector<std::unique_ptr<o2::delphes::DelphesO2TrackSmearer>> o2::upgrade::TrackSmearerImpl::smearerContainer;
50+
void o2::upgrade::TrackSmearerImpl::initCfg(int icfg, std::map<std::string, std::string> globalConfiguration)
51+
{
52+
smearerContainer.emplace_back(std::make_unique<o2::delphes::DelphesO2TrackSmearer>());
53+
smearerContainer[icfg]->setCcdbManager(mCcdb);
54+
smearerContainer[icfg]->setDownloadPath("./.ALICE3/");
55+
smearerContainer[icfg]->setCleanupDownloadedFile(mCleanLutWhenLoaded);
56+
for (const auto& entry : globalConfiguration) {
57+
int pdg = 0;
58+
if (entry.first.find("lut") != 0) {
59+
continue;
60+
}
61+
if (entry.first.find("lutEl") != std::string::npos) {
62+
pdg = kElectron;
63+
} else if (entry.first.find("lutMu") != std::string::npos) {
64+
pdg = kMuonMinus;
65+
} else if (entry.first.find("lutPi") != std::string::npos) {
66+
pdg = kPiPlus;
67+
} else if (entry.first.find("lutKa") != std::string::npos) {
68+
pdg = kKPlus;
69+
} else if (entry.first.find("lutPr") != std::string::npos) {
70+
pdg = kProton;
71+
} else if (entry.first.find("lutDe") != std::string::npos) {
72+
pdg = o2::constants::physics::kDeuteron;
73+
} else if (entry.first.find("lutTr") != std::string::npos) {
74+
pdg = o2::constants::physics::kTriton;
75+
} else if (entry.first.find("lutHe3") != std::string::npos) {
76+
pdg = o2::constants::physics::kHelium3;
77+
} else if (entry.first.find("lutAl") != std::string::npos) {
78+
pdg = o2::constants::physics::kAlpha;
79+
}
80+
81+
std::string filename = entry.second;
82+
if (pdg == 0) {
83+
LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration";
84+
}
85+
LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'";
86+
if (filename.empty()) {
87+
LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping.";
88+
}
89+
// strip from leading/trailing spaces
90+
filename.erase(0, filename.find_first_not_of(" "));
91+
filename.erase(filename.find_last_not_of(" ") + 1);
92+
if (filename.empty()) {
93+
LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping.";
94+
}
95+
bool success = smearerContainer[icfg]->loadTable(pdg, filename.c_str());
96+
if (!success) {
97+
LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename;
98+
}
99+
LOG(info) << "Successfully loaded LUT for pdg " << pdg;
100+
}
101+
}
102+
103+
o2::delphes::DelphesO2TrackSmearer* o2::upgrade::TrackSmearerImpl::getSmearer(int icfg)
104+
{
105+
if (icfg < 0 || icfg >= static_cast<int>(smearerContainer.size())) {
106+
LOG(fatal) << "Configuration index " << icfg << " out of bounds";
107+
return nullptr;
108+
}
109+
if (!smearerContainer[icfg]) {
110+
LOG(fatal) << "nullptr entry in tracksmearer container";
111+
return nullptr;
112+
}
113+
return smearerContainer[icfg].get();
114+
}
115+
116+
117+
void o2::upgrade::TrackSmearerImpl::setReady()
118+
{
119+
std::ofstream okFile(".TrackSmearerOK");
120+
okFile.close();
121+
LOG(info) << "Track smearer ready";
122+
}
123+
124+
void o2::upgrade::TrackSmearerImpl::waitReady()
125+
{
126+
while (!std::ifstream(".TrackSmearerOK")) {
127+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
128+
}
129+
}
130+
131+
struct TrackSmearerSupport : o2::framework::ServicePlugin {
132+
o2::framework::ServiceSpec* create() final
133+
{
134+
return new o2::framework::ServiceSpec{
135+
.name = "track-smearer",
136+
.init = [](o2::framework::ServiceRegistryRef, o2::framework::DeviceState&, fair::mq::ProgOptions&) -> o2::framework::ServiceHandle {
137+
auto* wrapper = new o2::upgrade::TrackSmearerContainer();
138+
auto* ptr = new o2::upgrade::TrackSmearerImpl();
139+
wrapper->setInstance(ptr);
140+
return o2::framework::ServiceHandle{o2::framework::TypeIdHelpers::uniqueId<o2::upgrade::TrackSmearerContainer>(),
141+
wrapper,
142+
o2::framework::ServiceKind::Serial,
143+
"database-pdg"};
144+
},
145+
.configure = o2::framework::CommonServices::noConfiguration(),
146+
.exit = [](o2::framework::ServiceRegistryRef, void* service) {
147+
auto* s = reinterpret_cast<o2::upgrade::TrackSmearerContainer*>(service);
148+
delete s;
149+
},
150+
.kind = o2::framework::ServiceKind::Serial
151+
};
152+
}
153+
};
154+
155+
DEFINE_DPL_PLUGINS_BEGIN
156+
DEFINE_DPL_PLUGIN_INSTANCE(TrackSmearerSupport, CustomService);
157+
DEFINE_DPL_PLUGINS_END
158+

ALICE3/Core/TrackSmearerService.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file TrackSmearerService.h
13+
/// \brief Implementation for smearer service for the on-the-fly simulation
14+
/// \author Jesper Karlsson Gumprecht <jesper.gumprecht@cern.ch>
15+
16+
17+
#ifndef ALICE3_CORE_TRACKSMEARERSERVICE_H_
18+
#define ALICE3_CORE_TRACKSMEARERSERVICE_H_
19+
20+
#include "ALICE3/Core/DelphesO2TrackSmearer.h"
21+
#include "Framework/Plugins.h"
22+
#include "CCDB/BasicCCDBManager.h"
23+
#include "ALICE3/Core/FastTracker.h"
24+
25+
#include <string>
26+
#include <vector>
27+
#include <mutex>
28+
#include <condition_variable>
29+
30+
namespace o2::upgrade {
31+
32+
struct TrackSmearerImpl {
33+
static std::vector<std::unique_ptr<o2::delphes::DelphesO2TrackSmearer>> smearerContainer;
34+
void initSmearer(o2::ccdb::BasicCCDBManager* ccdb, bool cleanLutWhenLoaded);
35+
void initCfg(int icfg, std::map<std::string, std::string> globalConfiguration);
36+
size_t size() { return smearerContainer.size(); }
37+
void setReady();
38+
void waitReady();
39+
o2::delphes::DelphesO2TrackSmearer* getSmearer(int icfg = 0);
40+
41+
42+
private:
43+
static bool mIsInit;
44+
static bool mCleanLutWhenLoaded;
45+
o2::ccdb::BasicCCDBManager* mCcdb = nullptr;
46+
};
47+
48+
struct TrackSmearerContainer : o2::framework::LoadableServicePlugin<TrackSmearerImpl> {
49+
TrackSmearerContainer() : LoadableServicePlugin{"O2PhysicsALICE3Core:TrackSmearerSupport"}
50+
{
51+
}
52+
};
53+
54+
} // namespace o2::upgrade
55+
56+
#endif // ALICE3_CORE_TRACKSMEARERSERVICE_H_

ALICE3/TableProducer/OTF/onTheFlyDetectorGeometryProvider.cxx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,32 @@
1717
///
1818

1919
#include "ALICE3/Core/FastTracker.h"
20+
#include "ALICE3/Core/TrackSmearerService.h"
2021

2122
#include <CCDB/BasicCCDBManager.h>
2223
#include <Framework/AnalysisTask.h>
2324
#include <Framework/HistogramRegistry.h>
2425
#include <Framework/runDataProcessing.h>
2526

27+
2628
#include <map>
2729
#include <string>
2830
#include <vector>
2931

3032
struct OnTheFlyDetectorGeometryProvider {
3133
o2::framework::HistogramRegistry histos{"Histos", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject};
34+
o2::framework::Configurable<bool> cleanLutWhenLoaded{"cleanLutWhenLoaded", true, "Flag to delete the local lut files after loading them into memory"};
3235
o2::framework::Configurable<std::vector<std::string>> detectorConfiguration{"detectorConfiguration",
3336
std::vector<std::string>{"$O2PHYSICS_ROOT/share/alice3/a3geometry_v3.ini"},
3437
"Paths of the detector geometry configuration files"};
3538
o2::framework::Service<o2::ccdb::BasicCCDBManager> ccdb;
39+
o2::framework::Service<o2::upgrade::TrackSmearerContainer> smearerContainer;
3640
void init(o2::framework::InitContext&)
3741
{
42+
if (std::ifstream(".TrackSmearerOK")) {
43+
std::remove(".TrackSmearerOK");
44+
}
45+
3846
ccdb->setURL("http://alice-ccdb.cern.ch");
3947
ccdb->setTimestamp(-1);
4048
o2::fastsim::GeometryContainer geometryContainer; // Checking that the geometry files can be accessed and loaded
@@ -70,13 +78,11 @@ struct OnTheFlyDetectorGeometryProvider {
7078

7179
// First we check that the magnetic field is consistent
7280
const int nGeometries = geometryContainer.getNumberOfConfigurations();
73-
const float mMagneticField = geometryContainer.getFloatValue(0, "global", "magneticfield");
81+
smearerContainer->initSmearer(ccdb.operator->(), cleanLutWhenLoaded.value);
7482
for (int icfg = 0; icfg < nGeometries; ++icfg) {
75-
const float cfgBfield = geometryContainer.getFloatValue(icfg, "global", "magneticfield");
76-
if (std::abs(cfgBfield - mMagneticField) > 1e-3) {
77-
LOG(fatal) << "Inconsistent magnetic field values between configurations 0 and " << icfg << ": " << mMagneticField << " vs " << cfgBfield;
78-
}
83+
smearerContainer->initCfg(icfg, geometryContainer.getConfiguration(icfg, "global"));
7984
}
85+
smearerContainer->setReady();
8086
LOG(info) << "Initialization completed";
8187
}
8288

ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "Common/DataModel/TrackSelectionTables.h"
4040

4141
#include <CCDB/BasicCCDBManager.h>
42+
#include "ALICE3/Core/TrackSmearerService.h"
4243
#include <CCDB/CcdbApi.h>
4344
#include <CommonConstants/GeomConstants.h>
4445
#include <CommonConstants/MathConstants.h>
@@ -134,7 +135,7 @@ struct OnTheFlyRichPid {
134135
o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE;
135136

136137
// Track smearer array, one per geometry
137-
std::vector<std::unique_ptr<o2::delphes::DelphesO2TrackSmearer>> mSmearer;
138+
Service<o2::upgrade::TrackSmearerContainer> smearerContainer;
138139

139140
// needed: random number generator for smearing
140141
TRandom3 pRandomNumberGenerator;
@@ -290,65 +291,10 @@ struct OnTheFlyRichPid {
290291
void init(o2::framework::InitContext& initContext)
291292
{
292293
mGeoContainer.init(initContext);
293-
294-
const int nGeometries = mGeoContainer.getNumberOfConfigurations();
294+
smearerContainer->waitReady();
295295
mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield");
296-
297296
pRandomNumberGenerator.SetSeed(0); // fully randomize
298297

299-
for (int icfg = 0; icfg < nGeometries; ++icfg) {
300-
const std::string histPath = "Configuration_" + std::to_string(icfg) + "/";
301-
mSmearer.emplace_back(std::make_unique<o2::delphes::DelphesO2TrackSmearer>());
302-
mSmearer[icfg]->setCleanupDownloadedFile(cleanLutWhenLoaded.value);
303-
mSmearer[icfg]->setCcdbManager(ccdb.operator->());
304-
mSmearer[icfg]->setDownloadPath("./.ALICE3/RICHPID/");
305-
std::map<std::string, std::string> globalConfiguration = mGeoContainer.getConfiguration(icfg, "global");
306-
for (const auto& entry : globalConfiguration) {
307-
int pdg = 0;
308-
if (entry.first.find("lut") != 0) {
309-
continue;
310-
}
311-
if (entry.first.find("lutEl") != std::string::npos) {
312-
pdg = kElectron;
313-
} else if (entry.first.find("lutMu") != std::string::npos) {
314-
pdg = kMuonMinus;
315-
} else if (entry.first.find("lutPi") != std::string::npos) {
316-
pdg = kPiPlus;
317-
} else if (entry.first.find("lutKa") != std::string::npos) {
318-
pdg = kKPlus;
319-
} else if (entry.first.find("lutPr") != std::string::npos) {
320-
pdg = kProton;
321-
} else if (entry.first.find("lutDe") != std::string::npos) {
322-
pdg = o2::constants::physics::kDeuteron;
323-
} else if (entry.first.find("lutTr") != std::string::npos) {
324-
pdg = o2::constants::physics::kTriton;
325-
} else if (entry.first.find("lutHe3") != std::string::npos) {
326-
pdg = o2::constants::physics::kHelium3;
327-
} else if (entry.first.find("lutAl") != std::string::npos) {
328-
pdg = o2::constants::physics::kAlpha;
329-
}
330-
331-
std::string filename = entry.second;
332-
if (pdg == 0) {
333-
LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration";
334-
}
335-
LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'";
336-
if (filename.empty()) {
337-
LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping.";
338-
}
339-
// strip from leading/trailing spaces
340-
filename.erase(0, filename.find_first_not_of(" "));
341-
filename.erase(filename.find_last_not_of(" ") + 1);
342-
if (filename.empty()) {
343-
LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping.";
344-
}
345-
bool success = mSmearer[icfg]->loadTable(pdg, filename.c_str());
346-
if (!success) {
347-
LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename;
348-
}
349-
}
350-
}
351-
352298
if (doQAplots) {
353299
const AxisSpec axisMomentum{static_cast<int>(nBinsP), 0.0f, +20.0f, "#it{p} (GeV/#it{c})"};
354300
const AxisSpec axisAngle{static_cast<int>(nBinsThetaRing), 0.0f, +0.30f, "Measured Cherenkov angle (rad)"};
@@ -870,9 +816,9 @@ struct OnTheFlyRichPid {
870816
double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(recoTrack.getSigma1Pt2());
871817
double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-recoTrack.getEta())))) * std::sqrt(recoTrack.getSigmaTgl2());
872818
if (flagRICHLoadDelphesLUTs) {
873-
if (mSmearer[collision.lutConfigId()]->hasTable(kParticlePdgs[ii])) {
874-
ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum);
875-
etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum);
819+
if (smearerContainer->getSmearer(collision.lutConfigId())->hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded
820+
ptResolution = smearerContainer->getSmearer(collision.lutConfigId())->getAbsPtRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum);
821+
etaResolution = smearerContainer->getSmearer(collision.lutConfigId())->getAbsEtaRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum);
876822
}
877823
}
878824
// cout << endl << "Pt resolution: " << ptResolution << ", Eta resolution: " << etaResolution << endl << endl;

0 commit comments

Comments
 (0)