Skip to content

Commit d745703

Browse files
authored
[ALICE3] Use A3 geo provider in OTF (#14272)
1 parent d109ef6 commit d745703

File tree

9 files changed

+300
-329
lines changed

9 files changed

+300
-329
lines changed

ALICE3/Core/FastTracker.cxx

Lines changed: 18 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -314,88 +314,31 @@ void FastTracker::AddTPC(float phiResMean, float zResMean)
314314
}
315315
}
316316

317-
std::map<std::string, std::map<std::string, std::string>> FastTracker::parseTEnvConfiguration(std::string filename)
317+
void FastTracker::AddGenericDetector(GeometryContainer::GeometryEntry configMap, o2::ccdb::BasicCCDBManager* ccdbManager)
318318
{
319-
std::map<std::string, std::map<std::string, std::string>> configMap;
320-
321-
TEnv env(filename.c_str());
322-
THashList* table = env.GetTable();
323-
std::vector<std::string> layers;
324-
for (int i = 0; i < table->GetEntries(); ++i) {
325-
const std::string key = table->At(i)->GetName();
326-
// key should contain exactly one dot
327-
if (key.find('.') == std::string::npos || key.find('.') != key.rfind('.')) {
328-
LOG(fatal) << "Key " << key << " does not contain exactly one dot";
319+
// Layers
320+
for (const auto& layer : configMap.getLayerNames()) {
321+
if (layer.find("global") != std::string::npos) { // Layers with global tag are skipped
322+
LOG(info) << " Skipping global configuration entry " << layer;
329323
continue;
330324
}
331-
const std::string firstPart = key.substr(0, key.find('.'));
332-
if (std::find(layers.begin(), layers.end(), firstPart) == layers.end()) {
333-
layers.push_back(firstPart);
334-
}
335-
}
336-
env.Print();
337325

338-
// Layers
339-
for (const auto& layer : layers) {
340326
LOG(info) << " Reading layer " << layer;
341-
for (int i = 0; i < table->GetEntries(); ++i) {
342-
const std::string key = table->At(i)->GetName();
343-
if (key.find(layer + ".") == 0) {
344-
const std::string paramName = key.substr(key.find('.') + 1);
345-
const std::string value = env.GetValue(key.c_str(), "");
346-
configMap[layer][paramName] = value;
347-
}
348-
}
349-
}
350-
return configMap;
351-
}
352-
353-
void FastTracker::AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBManager* ccdbManager)
354-
{
355-
LOG(info) << " Adding generic detector from file " << filename;
356-
// If the filename starts with ccdb: then take the file from the ccdb
357-
if (filename.rfind("ccdb:", 0) == 0) {
358-
std::string ccdbPath = filename.substr(5); // remove "ccdb:" prefix
359-
if (ccdbManager == nullptr) {
360-
LOG(fatal) << "CCDB manager is null, cannot retrieve file " << ccdbPath;
361-
return;
362-
}
363-
const std::string outPath = "/tmp/DetGeo/";
364-
filename = Form("%s/%s/snapshot.root", outPath.c_str(), ccdbPath.c_str());
365-
std::ifstream checkFile(filename); // Check if file already exists
366-
if (!checkFile.is_open()) { // File does not exist, retrieve from CCDB
367-
LOG(info) << " --- CCDB source detected for detector geometry " << filename;
368-
std::map<std::string, std::string> metadata;
369-
ccdbManager->getCCDBAccessor().retrieveBlob(ccdbPath, outPath, metadata, 1);
370-
// Add CCDB handling logic here if needed
371-
LOG(info) << " --- Now retrieving geometry configuration from CCDB to: " << filename;
372-
} else { // File exists, proceed to load
373-
LOG(info) << " --- Geometry configuration file already exists: " << filename << ". Skipping download.";
374-
checkFile.close();
375-
}
376-
AddGenericDetector(filename, nullptr);
377-
return;
378-
}
379-
380-
std::map<std::string, std::map<std::string, std::string>> configMap = parseTEnvConfiguration(filename);
381-
// Layers
382-
for (const auto& layer : configMap) {
383-
LOG(info) << " Reading layer " << layer.first;
384-
const float r = std::stof(layer.second.at("r"));
385-
LOG(info) << " Layer " << layer.first << " has radius " << r;
386-
const float z = std::stof(layer.second.at("z"));
387-
const float x0 = std::stof(layer.second.at("x0"));
388-
const float xrho = std::stof(layer.second.at("xrho"));
389-
const float resRPhi = std::stof(layer.second.at("resRPhi"));
390-
const float resZ = std::stof(layer.second.at("resZ"));
391-
const float eff = std::stof(layer.second.at("eff"));
392-
const int type = std::stoi(layer.second.at("type"));
393-
const std::string deadPhiRegions = layer.second.at("deadPhiRegions");
327+
const float r = configMap.getFloatValue(layer, "r");
328+
LOG(info) << " Layer " << layer << " has radius " << r;
329+
const float z = configMap.getFloatValue(layer, "z");
330+
const float x0 = configMap.getFloatValue(layer, "x0");
331+
const float xrho = configMap.getFloatValue(layer, "xrho");
332+
const float resRPhi = configMap.getFloatValue(layer, "resRPhi");
333+
const float resZ = configMap.getFloatValue(layer, "resZ");
334+
const float eff = configMap.getFloatValue(layer, "eff");
335+
const int type = configMap.getIntValue(layer, "type");
336+
const std::string deadPhiRegions = configMap.getValue(layer, "deadPhiRegions", false);
394337

395338
// void AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi = 0.0f, float resZ = 0.0f, float eff = 0.0f, int type = 0);
396-
LOG(info) << " Adding layer " << layer.first << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type << " deadPhiRegions=" << deadPhiRegions;
339+
LOG(info) << " Adding layer " << layer << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type << " deadPhiRegions=" << deadPhiRegions;
397340

398-
DetLayer* addedLayer = AddLayer(layer.first.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type);
341+
DetLayer* addedLayer = AddLayer(layer.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type);
399342
if (!deadPhiRegions.empty()) { // Taking it as ccdb path or local file
400343
// Check if it begins with ccdb:
401344
if (std::string(deadPhiRegions).rfind("ccdb:", 0) == 0) {
@@ -418,7 +361,7 @@ void FastTracker::AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBMa
418361
addedLayer->setDeadPhiRegions(g);
419362
}
420363
} else {
421-
LOG(debug) << " No dead phi regions for layer " << layer.first;
364+
LOG(debug) << " No dead phi regions for layer " << layer;
422365
}
423366
}
424367
}

ALICE3/Core/FastTracker.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,16 @@ class FastTracker
127127
void AddSiliconALICE3(float scaleX0VD, std::vector<float> pixelResolution);
128128
void AddTPC(float phiResMean, float zResMean);
129129

130-
/**
131-
* @brief Parses a TEnv configuration file and returns the key-value pairs split per entry
132-
* @param filename Path to the TEnv configuration file
133-
* @return A map where each key is a layer name and the value is another map of key-value pairs for that layer
134-
*/
135-
std::map<std::string, std::map<std::string, std::string>> parseTEnvConfiguration(std::string filename);
136-
137130
/**
138131
* @brief Adds a generic detector configuration from the specified file.
139132
*
140133
* This function loads and integrates a detector configuration into the tracker
141134
* using the provided filename. The file should contain the necessary parameters
142135
* and settings for the detector to be added.
143136
*
144-
* @param filename Path to the configuration file describing the detector.
145-
* @param ccdbManager Pointer to a BasicCCDBManager instance for database access (if needed).
137+
* @param configMap Configuration map describing the detector.
146138
*/
147-
void AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBManager* ccdbManager = nullptr);
139+
void AddGenericDetector(GeometryContainer::GeometryEntry configMap, o2::ccdb::BasicCCDBManager* ccdbManager = nullptr);
148140

149141
void Print();
150142

ALICE3/TableProducer/OTF/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@
1111

1212
o2physics_add_dpl_workflow(onthefly-tracker
1313
SOURCES onTheFlyTracker.cxx
14-
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2::DetectorsVertexing O2::DCAFitter O2Physics::ALICE3Core O2Physics::FastTracker
14+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2::DetectorsVertexing O2::DCAFitter O2Physics::ALICE3Core O2Physics::FastTracker
1515
COMPONENT_NAME Analysis)
1616

1717
o2physics_add_dpl_workflow(onthefly-tofpid
1818
SOURCES onTheFlyTofPid.cxx
19-
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core
19+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core O2Physics::FastTracker
2020
COMPONENT_NAME Analysis)
2121

2222
o2physics_add_dpl_workflow(onthefly-richpid
2323
SOURCES onTheFlyRichPid.cxx
24-
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core
24+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core O2Physics::FastTracker
2525
COMPONENT_NAME Analysis)
2626

2727
o2physics_add_dpl_workflow(on-the-fly-tracker-pid
2828
SOURCES onTheFlyTrackerPid.cxx
29-
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core
29+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core O2Physics::FastTracker
3030
COMPONENT_NAME Analysis)
3131

3232
o2physics_add_dpl_workflow(on-the-fly-detector-geometry-provider

ALICE3/TableProducer/OTF/onTheFlyDetectorGeometryProvider.cxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ struct OnTheFlyDetectorGeometryProvider {
6868
geometryContainer.addEntry(configFile);
6969
idx++;
7070
}
71+
72+
// First we check that the magnetic field is consistent
73+
const int nGeometries = geometryContainer.getNumberOfConfigurations();
74+
const float mMagneticField = geometryContainer.getFloatValue(0, "global", "magneticfield");
75+
for (int icfg = 0; icfg < nGeometries; ++icfg) {
76+
const float cfgBfield = geometryContainer.getFloatValue(icfg, "global", "magneticfield");
77+
if (std::abs(cfgBfield - mMagneticField) > 1e-3) {
78+
LOG(fatal) << "Inconsistent magnetic field values between configurations 0 and " << icfg << ": " << mMagneticField << " vs " << cfgBfield;
79+
}
80+
}
81+
7182
pc.services().get<o2::framework::ControlService>().endOfStream();
7283
pc.services().get<o2::framework::ControlService>().readyToQuit(o2::framework::QuitRequest::Me);
7384
}

ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
/// \since May 22, 2024
3131
///
3232

33-
#include "TableHelper.h"
34-
3533
#include "ALICE3/Core/DelphesO2TrackSmearer.h"
34+
#include "ALICE3/Core/FastTracker.h"
3635
#include "ALICE3/Core/TrackUtilities.h"
3736
#include "ALICE3/DataModel/OTFRICH.h"
37+
#include "ALICE3/DataModel/OTFTracks.h"
3838
#include "Common/Core/trackUtilities.h"
3939
#include "Common/DataModel/TrackSelectionTables.h"
4040

@@ -83,9 +83,6 @@ struct OnTheFlyRichPid {
8383
// Necessary for LUTs
8484
Service<o2::ccdb::BasicCCDBManager> ccdb;
8585

86-
// master setting: magnetic field
87-
Configurable<float> magneticField{"magneticField", 0, "magnetic field (kilogauss) if 0, taken from the tracker task"};
88-
8986
// add rich-specific configurables here
9087
Configurable<int> bRichNumberOfSectors{"bRichNumberOfSectors", 21, "barrel RICH number of sectors"};
9188
Configurable<float> bRichPhotodetectorCentralModuleHalfLength{"bRichPhotodetectorCentralModuleHalfLength", 18.4 / 2.0, "barrel RICH photodetector central module half length (cm)"};
@@ -132,11 +129,12 @@ struct OnTheFlyRichPid {
132129
Configurable<float> bRichRefractiveIndexSector20{"bRichRefractiveIndexSector20", 1.03, "barrel RICH refractive index central(s)-20 and central(s)+20"}; // central(s)-20 and central(s)+20
133130
Configurable<float> bRICHPixelSize{"bRICHPixelSize", 0.1, "barrel RICH pixel size (cm)"};
134131
Configurable<float> bRichGapRefractiveIndex{"bRichGapRefractiveIndex", 1.000283, "barrel RICH gap refractive index"};
132+
Configurable<bool> cleanLutWhenLoaded{"cleanLutWhenLoaded", true, "clean LUTs after being loaded to save disk space"};
135133

136134
o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE;
137135

138-
// Track smearer (here used to get relative pt and eta uncertainties)
139-
o2::delphes::DelphesO2TrackSmearer mSmearer;
136+
// Track smearer array, one per geometry
137+
std::vector<std::unique_ptr<o2::delphes::DelphesO2TrackSmearer>> mSmearer;
140138

141139
// needed: random number generator for smearing
142140
TRandom3 pRandomNumberGenerator;
@@ -286,40 +284,68 @@ struct OnTheFlyRichPid {
286284
// std::cout << std::endl << std::endl;
287285
}
288286

287+
// Configuration defined at init time
288+
o2::fastsim::GeometryContainer mGeoContainer;
289+
float mMagneticField = 0.0f;
289290
void init(o2::framework::InitContext& initContext)
290291
{
292+
mGeoContainer.init(initContext);
293+
294+
const int nGeometries = mGeoContainer.getNumberOfConfigurations();
295+
mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield");
296+
291297
pRandomNumberGenerator.SetSeed(0); // fully randomize
292298

293-
if (magneticField.value < o2::constants::math::Epsilon) {
294-
LOG(info) << "Getting the magnetic field from the on-the-fly tracker task";
295-
if (!getTaskOptionValue(initContext, "on-the-fly-tracker", magneticField, false)) {
296-
LOG(fatal) << "Could not get Bz from on-the-fly-tracker task";
297-
}
298-
LOG(info) << "Bz = " << magneticField.value << " T";
299-
}
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+
std::map<std::string, std::string> globalConfiguration = mGeoContainer.getConfiguration(icfg, "global");
305+
for (const auto& entry : globalConfiguration) {
306+
int pdg = 0;
307+
if (entry.first.find("lut") != 0) {
308+
continue;
309+
}
310+
if (entry.first.find("lutEl") != std::string::npos) {
311+
pdg = kElectron;
312+
} else if (entry.first.find("lutMu") != std::string::npos) {
313+
pdg = kMuonMinus;
314+
} else if (entry.first.find("lutPi") != std::string::npos) {
315+
pdg = kPiPlus;
316+
} else if (entry.first.find("lutKa") != std::string::npos) {
317+
pdg = kKPlus;
318+
} else if (entry.first.find("lutPr") != std::string::npos) {
319+
pdg = kProton;
320+
} else if (entry.first.find("lutDe") != std::string::npos) {
321+
pdg = o2::constants::physics::kDeuteron;
322+
} else if (entry.first.find("lutTr") != std::string::npos) {
323+
pdg = o2::constants::physics::kTriton;
324+
} else if (entry.first.find("lutHe3") != std::string::npos) {
325+
pdg = o2::constants::physics::kHelium3;
326+
} else if (entry.first.find("lutAl") != std::string::npos) {
327+
pdg = o2::constants::physics::kAlpha;
328+
}
300329

301-
// Load LUT for pt and eta smearing
302-
if (flagIncludeTrackAngularRes && flagRICHLoadDelphesLUTs) {
303-
mSmearer.setCcdbManager(ccdb.operator->());
304-
auto loadLUT = [&](int pdg, const std::string& cfgNameToInherit) {
305-
std::string lut = "none";
306-
if (!getTaskOptionValue(initContext, "on-the-fly-tracker", cfgNameToInherit, lut, false)) {
307-
LOG(fatal) << "Could not get " << cfgNameToInherit << " from on-the-fly-tracker task";
330+
std::string filename = entry.second;
331+
if (pdg == 0) {
332+
LOG(fatal) << "Unknown LUT entry " << entry.first << " for global configuration";
308333
}
309-
bool success = mSmearer.loadTable(pdg, lut.c_str());
310-
if (!success && !lut.empty()) {
311-
LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << lut;
334+
LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided file '" << filename << "'";
335+
if (filename.empty()) {
336+
LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping.";
312337
}
313-
};
314-
loadLUT(11, "lutEl");
315-
loadLUT(13, "lutMu");
316-
loadLUT(211, "lutPi");
317-
loadLUT(321, "lutKa");
318-
loadLUT(2212, "lutPr");
319-
loadLUT(1000010020, "lutDe");
320-
loadLUT(1000010030, "lutTr");
321-
loadLUT(1000020030, "lutHe3");
322-
loadLUT(1000020040, "lutAl");
338+
// strip from leading/trailing spaces
339+
filename.erase(0, filename.find_first_not_of(" "));
340+
filename.erase(filename.find_last_not_of(" ") + 1);
341+
if (filename.empty()) {
342+
LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping.";
343+
}
344+
bool success = mSmearer[icfg]->loadTable(pdg, filename.c_str());
345+
if (!success) {
346+
LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename;
347+
}
348+
}
323349
}
324350

325351
if (doQAplots) {
@@ -691,7 +717,7 @@ struct OnTheFlyRichPid {
691717
return trackAngularResolution;
692718
}
693719

694-
void process(soa::Join<aod::Collisions, aod::McCollisionLabels>::iterator const& collision,
720+
void process(soa::Join<aod::Collisions, aod::McCollisionLabels, aod::OTFLUTConfigId>::iterator const& collision,
695721
soa::Join<aod::Tracks, aod::TracksCov, aod::McTrackLabels> const& tracks,
696722
aod::McParticles const&,
697723
aod::McCollisions const&)
@@ -751,7 +777,7 @@ struct OnTheFlyRichPid {
751777
o2::track::TrackParCov o2track = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdg);
752778

753779
// float xPv = kErrorValue;
754-
if (o2track.propagateToDCA(mcPvVtx, magneticField)) {
780+
if (o2track.propagateToDCA(mcPvVtx, mMagneticField)) {
755781
// xPv = o2track.getX();
756782
}
757783

@@ -781,7 +807,7 @@ struct OnTheFlyRichPid {
781807
const float projectiveRadiatorRadius = radiusRipple(o2track.getEta(), iSecor);
782808
bool flagReachesRadiator = false;
783809
if (projectiveRadiatorRadius > kErrorValue + 1.) {
784-
flagReachesRadiator = checkMagfieldLimit(o2track, projectiveRadiatorRadius, magneticField);
810+
flagReachesRadiator = checkMagfieldLimit(o2track, projectiveRadiatorRadius, mMagneticField);
785811
}
786812
/// DISCLAIMER: Exact extrapolation of angular resolution would require track propagation
787813
/// to the RICH radiator (accounting sector inclination) in terms of (R,z).
@@ -794,7 +820,7 @@ struct OnTheFlyRichPid {
794820
// Now we calculate the expected Cherenkov angle following certain mass hypotheses
795821
// and the (imperfect!) reconstructed track parametrizations
796822
auto recoTrack = getTrackParCov(track);
797-
if (recoTrack.propagateToDCA(pvVtx, magneticField)) {
823+
if (recoTrack.propagateToDCA(pvVtx, mMagneticField)) {
798824
// xPv = recoTrack.getX();
799825
}
800826

@@ -844,9 +870,9 @@ struct OnTheFlyRichPid {
844870
double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(recoTrack.getSigma1Pt2());
845871
double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-recoTrack.getEta())))) * std::sqrt(recoTrack.getSigmaTgl2());
846872
if (flagRICHLoadDelphesLUTs) {
847-
if (mSmearer.hasTable(kParticlePdgs[ii])) {
848-
ptResolution = mSmearer.getAbsPtRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum);
849-
etaResolution = mSmearer.getAbsEtaRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum);
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);
850876
}
851877
}
852878
// cout << endl << "Pt resolution: " << ptResolution << ", Eta resolution: " << etaResolution << endl << endl;

0 commit comments

Comments
 (0)