Skip to content

Commit f2acadf

Browse files
authored
Merge branch 'master' into mc-sampling-fixes
2 parents d6524c8 + eb21dd9 commit f2acadf

182 files changed

Lines changed: 3393 additions & 2035 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ALICE3/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ o2physics_add_library(ALICE3Core
2020
o2physics_target_root_dictionary(ALICE3Core
2121
HEADERS TrackUtilities.h
2222
FlatLutEntry.h
23+
OTFParticle.h
2324
GeometryContainer.h
2425
LINKDEF ALICE3CoreLinkDef.h)
2526

ALICE3/Macros/drawFastTracker.C

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
// granted to it by virtue of its status as an Intergovernmental Organization
1010
// or submit itself to any jurisdiction.
1111

12+
/// \file drawFastTracker.C
13+
/// \author Nicolò Jacazio nicolo.jacazio@cern.ch
14+
/// \brief Draw FastTracker performace
15+
1216
#include "ALICE3/Core/FastTracker.h"
1317
#include "ALICE3/Core/TrackUtilities.h"
1418

@@ -26,6 +30,7 @@
2630
#include <TH1.h>
2731
#include <TLatex.h>
2832
#include <TLorentzVector.h>
33+
#include <TPDGCode.h>
2934
#include <TParticlePDG.h>
3035
#include <TString.h>
3136

@@ -34,67 +39,64 @@
3439
#include <cstddef>
3540
#include <vector>
3641

37-
void drawFastTracker(float magneticField = 5.f, // in units of kGauss
38-
const int nch = 100, // number of charged particles per unit rapidity
39-
const int pdg = 211) // PDG code of the particle to track
42+
void drawFastTracker(const float magneticField = 20.f, // in units of kGauss
43+
const int nch = 100, // number of charged particles per unit rapidity
44+
const int pdg = PDG_t::kPiPlus) // PDG code of the particle to track
4045
{
4146
TDatabasePDG* db = TDatabasePDG::Instance();
42-
TParticlePDG* p = 0;
47+
TParticlePDG* p = nullptr;
4348
p = db->GetParticle(pdg);
4449
if (!p) {
4550
LOG(fatal) << "Particle with PDG code " << pdg << " not found in TDatabasePDG";
4651
return;
4752
}
48-
const float mass = p->Mass(); // particle mass in GeV/c^2
49-
const float q = p->Charge() / 3.0; // charge in e
53+
const float mass = p->Mass(); // particle mass in GeV/c^2
54+
const int q = static_cast<int>(p->Charge() / 3); // charge in e
5055

5156
o2::parameters::GRPMagField grpmag;
5257
grpmag.setFieldUniformity(true);
5358
grpmag.setL3Current(30000.f * (magneticField / 5.0f));
54-
auto field = grpmag.getNominalL3Field();
59+
// auto field = grpmag.getNominalL3Field();
5560
o2::base::Propagator::initFieldFromGRP(&grpmag);
5661

5762
fair::Logger::SetVerbosity(fair::Verbosity::verylow);
5863
o2::fastsim::FastTracker fastTracker = o2::fastsim::FastTracker();
59-
if (0) {
60-
fastTracker.SetApplyEffCorrection(false);
61-
Double_t x0IB = 0.001;
62-
Double_t x0OB = 0.01;
63-
Double_t xrhoIB = 2.3292e-02; // 100 mum Si
64-
Double_t xrhoOB = 2.3292e-01; // 1000 mum Si
65-
Double_t resRPhiIB = 0.00025;
66-
Double_t resZIB = 0.00025;
67-
Double_t resRPhiOB = 0.00100;
68-
Double_t resZOB = 0.00100;
69-
Double_t eff = 0.98;
70-
// fastTracker.AddLayer("vertex", 0.0, 250, 0, 0); // dummy vertex for matrix calculation
71-
fastTracker.AddLayer("bpipe0", 0.48, 250, 0.00042, 2.772e-02); // 150 mum Be
72-
fastTracker.AddLayer("B00", 0.50, 250, x0IB, xrhoIB, resRPhiIB, resZIB, eff, 1);
73-
fastTracker.AddLayer("B01", 1.20, 250, x0IB, xrhoIB, resRPhiIB, resZIB, eff, 1);
74-
fastTracker.AddLayer("B02", 2.50, 250, x0IB, xrhoIB, resRPhiIB, resZIB, eff, 1);
75-
fastTracker.AddLayer("bpipe1", 3.7, 250, 0.0014, 9.24e-02); // 500 mum Be
76-
fastTracker.AddLayer("B03", 3.75, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
77-
fastTracker.AddLayer("B04", 7.00, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
78-
fastTracker.AddLayer("B05", 12.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
79-
fastTracker.AddLayer("B06", 20.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
80-
fastTracker.AddLayer("B07", 30.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
81-
fastTracker.AddLayer("B08", 45.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
82-
fastTracker.AddLayer("B09", 60.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
83-
fastTracker.AddLayer("B10", 80.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
84-
fastTracker.AddLayer("B11", 100., 250, x0OB, xrhoOB, resRPhiOB, resZOB, eff, 1);
85-
} else {
86-
std::vector<float> pixelRes{0.025, 0.025, 0.01, 0.01};
87-
// fastTracker.AddSiliconALICE3v4(pixelRes); // FIXME
88-
}
89-
90-
fastTracker.Print();
91-
fastTracker.SetMagneticField(magneticField);
64+
fastTracker.setApplyEffCorrection(false);
65+
Double_t x0IB = 0.001;
66+
Double_t x0OB = 0.01;
67+
Double_t xrhoIB = 2.3292e-02; // 100 mum Si
68+
Double_t xrhoOB = 2.3292e-01; // 1000 mum Si
69+
Double_t resRPhiIB = 0.00025;
70+
Double_t resZIB = 0.00025;
71+
Double_t resRPhiOB = 0.00100;
72+
Double_t resZOB = 0.00100;
73+
Double_t trackerEff = 0.98;
74+
// fastTracker.AddLayer("vertex", 0.0, 250, 0, 0); // dummy vertex for matrix calculation
75+
76+
// N.B. Tracker configuration outdated and is only meant to be used as a template
77+
fastTracker.addLayer("bpipe0", 0.48, 250, 0.00042, 2.772e-02); // 150 mum Be
78+
fastTracker.addLayer("B00", 0.50, 250, x0IB, xrhoIB, resRPhiIB, resZIB, trackerEff, 1);
79+
fastTracker.addLayer("B01", 1.20, 250, x0IB, xrhoIB, resRPhiIB, resZIB, trackerEff, 1);
80+
fastTracker.addLayer("B02", 2.50, 250, x0IB, xrhoIB, resRPhiIB, resZIB, trackerEff, 1);
81+
fastTracker.addLayer("bpipe1", 3.7, 250, 0.0014, 9.24e-02); // 500 mum Be
82+
fastTracker.addLayer("B03", 3.75, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
83+
fastTracker.addLayer("B04", 7.00, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
84+
fastTracker.addLayer("B05", 12.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
85+
fastTracker.addLayer("B06", 20.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
86+
fastTracker.addLayer("B07", 30.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
87+
fastTracker.addLayer("B08", 45.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
88+
fastTracker.addLayer("B09", 60.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
89+
fastTracker.addLayer("B10", 80.0, 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
90+
fastTracker.addLayer("B11", 100., 250, x0OB, xrhoOB, resRPhiOB, resZOB, trackerEff, 1);
91+
92+
fastTracker.print();
93+
fastTracker.setMagneticField(magneticField);
9294

9395
TAxis ptBinning(1000, 0., 10);
94-
TGraph* gPt = new TGraph();
96+
auto gPt = new TGraph();
9597
gPt->GetXaxis()->SetTitle("#it{p}_{T} (GeV/c)");
9698
gPt->GetYaxis()->SetTitle("Efficiency");
97-
TEfficiency* hEfficiency = new TEfficiency("hEfficiency", ";#it{p}_{T} (GeV/c);Efficiency", ptBinning.GetNbins(), ptBinning.GetBinLowEdge(1), ptBinning.GetBinUpEdge(ptBinning.GetNbins()));
99+
auto hEfficiency = new TEfficiency("hEfficiency", ";#it{p}_{T} (GeV/c);Efficiency", ptBinning.GetNbins(), ptBinning.GetBinLowEdge(1), ptBinning.GetBinUpEdge(ptBinning.GetNbins()));
98100
TH1F* hFastTrackerQA = new TH1F("hFastTrackerQA", ";#it{p}_{T} (GeV/c;Tracking code", ptBinning.GetNbins(), ptBinning.GetBinLowEdge(1), ptBinning.GetBinUpEdge(ptBinning.GetNbins()));
99101

100102
TLorentzVector tlv;
@@ -120,11 +122,12 @@ void drawFastTracker(float magneticField = 5.f, // in units of kGauss
120122
continue;
121123
}
122124

123-
for (int trial = 0; trial < 200; trial++) {
124-
hEfficiency->Fill(fastTracker.FastTrack(trkIn, trkOut, nch) > 0, pt);
125+
const int nTrials = 200;
126+
for (int trial = 0; trial < nTrials; trial++) {
127+
hEfficiency->Fill(fastTracker.fastTrack(trkIn, trkOut, nch) > 0, pt);
125128
}
126129
int status = 4;
127-
status = fastTracker.FastTrack(trkIn, trkOut, nch);
130+
status = fastTracker.fastTrack(trkIn, trkOut, nch);
128131
hFastTrackerQA->Fill(pt, status);
129132
if (status < 0) {
130133
LOG(debug) << " --- fatSolve: FastTrack failed with status " << status << " --- ";
@@ -134,12 +137,12 @@ void drawFastTracker(float magneticField = 5.f, // in units of kGauss
134137
}
135138
// define the efficiency
136139
float eff = 1.;
137-
for (size_t l = 1; l < fastTracker.GetNLayers(); ++l) {
138-
if (fastTracker.IsLayerInert(l)) {
140+
for (size_t l = 1; l < fastTracker.getNLayers(); ++l) {
141+
if (fastTracker.isLayerInert(l)) {
139142
continue; // skip inert layers
140143
}
141144
float igoodhit = 0.f;
142-
igoodhit = fastTracker.GetGoodHitProb(l);
145+
igoodhit = fastTracker.getGoodHitProb(l);
143146
if (igoodhit <= 0.) {
144147
continue;
145148
}

ALICE3/Macros/testFastTracker.C

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,34 @@
1414
/// \brief Test the FastTracker functionality
1515

1616
#include "ALICE3/Core/FastTracker.h"
17+
#include "ALICE3/Core/GeometryContainer.h"
1718

19+
#include <CCDB/BasicCCDBManager.h>
1820
#include <Framework/Logger.h>
1921

2022
#include <string>
2123

22-
void testFastTracker(const std::string& geometryFile = "a3geo.ini")
24+
void testFastTracker(const std::string& geometryFile = "Configuration/a3geo.ini")
2325
{
2426

2527
fair::Logger::SetConsoleSeverity(fair::Severity::debug);
2628

27-
// auto& ccdb = o2::ccdb::BasicCCDBManager::instance();
28-
// ccdb.setURL("http://alice-ccdb.cern.ch");
29-
o2::fastsim::FastTracker fastTracker;
30-
// fastTracker.AddGenericDetector(geometryFile); // FIXME
31-
// fastTracker.AddGenericDetector(geometryFile, &ccdb);
32-
fastTracker.Print();
29+
auto& ccdb = o2::ccdb::BasicCCDBManager::instance();
30+
ccdb.setURL("http://alice-ccdb.cern.ch");
31+
32+
o2::fastsim::GeometryContainer geometryContainer;
33+
geometryContainer.setCcdbManager(&ccdb);
34+
geometryContainer.addEntry(geometryFile);
35+
const int nGeometries = geometryContainer.getNumberOfConfigurations();
36+
const float magneticField = geometryContainer.getFloatValue(0, "global", "magneticfield");
37+
38+
for (int icfg = 0; icfg < nGeometries; ++icfg) {
39+
const o2::fastsim::GeometryEntry& geometry = geometryContainer.getEntry(icfg);
40+
o2::fastsim::FastTracker fastTracker;
41+
42+
fastTracker.setMagneticField(magneticField);
43+
fastTracker.addGenericDetector(geometry, &ccdb);
44+
45+
fastTracker.print();
46+
}
3347
}

Common/Core/TPCVDriftManager.h

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,18 @@ class TPCVDriftManager
3737
mCCDB = ccdb;
3838
}
3939

40+
// Use the TPC side flags (with legacy-data fallback) instead of the tgl-sign-based correction.
41+
// Off by default so that existing analyses see no change in results until this is explicitly
42+
// enabled for testing. Tasks using TPCVDriftManager can expose this via their own Configurable.
43+
void setUseSideBasedCorrection(bool value) noexcept
44+
{
45+
mUseSideBasedCorrection = value;
46+
}
47+
4048
void update(uint64_t timestamp) noexcept
4149
{
4250
// Keep the object we already have if it is still valid for this timestamp.
43-
// firstTime/lastTime are the first and last timestamps of the TFs the correction
51+
// firstTime/lastTime are the first and last timestamps of the TF the correction
4452
// was derived from, so the validity range is closed on both ends.
4553
if (mVD != nullptr && timestamp >= static_cast<uint64_t>(mVD->firstTime) && timestamp <= static_cast<uint64_t>(mVD->lastTime)) {
4654
return;
@@ -136,7 +144,7 @@ class TPCVDriftManager
136144
float dTime = tTB - trackExtra.trackTime();
137145
float dDrift = dTime * mTPCVDriftNS;
138146
float dDriftErr = tTBErr * mTPCVDriftNS;
139-
if (dDriftErr < 0.f || dDrift > 250.f) { // we cannot move a track outside the drift volume
147+
if (dDriftErr < 0.f || dDrift > mMaxDriftCm) { // we cannot move a track outside the drift volume
140148
if (mOutside < mWarningLimit) {
141149
LOGP(warn, "Skipping correction outside of tpc volume with dDrift={} +- {}", dDrift, dDriftErr);
142150
const auto trackBC = trackExtra.template collision_as<Collisions>().template foundBC_as<BCs>().globalBC();
@@ -152,7 +160,54 @@ class TPCVDriftManager
152160
}
153161

154162
// impose new Z coordinate
155-
track.setZ(track.getZ() + ((track.getTgl() < 0.) ? -dDrift : dDrift));
163+
float zShift = 0.f;
164+
if (!mUseSideBasedCorrection) {
165+
// Legacy behaviour (default): infer the side from tgl alone.
166+
zShift = (track.getTgl() < 0.f) ? -dDrift : dDrift;
167+
} else {
168+
const auto sides = (trackExtra.flags() & (o2::aod::track::TrackFlags::TPCSideA | o2::aod::track::TrackFlags::TPCSideC));
169+
if (sides == o2::aod::track::TrackFlags::TPCSideA) {
170+
zShift = dDrift;
171+
} else if (sides == o2::aod::track::TrackFlags::TPCSideC) {
172+
zShift = -dDrift;
173+
} else if (sides == 0) {
174+
// Fallback for datasets produced before the TPC side flags were introduced (Feb. 2026).
175+
o2::aod::track::extensions::TPCTimeErrEncoding tEnc;
176+
tEnc.encoding.timeErr = trackExtra.trackTimeRes();
177+
const float dFwd = tEnc.getDeltaTFwd();
178+
const float dBwd = tEnc.getDeltaTBwd();
179+
// Equal, small forward/backward margins mean the track is bounded on both ends,
180+
// i.e. it crosses the CE: it cannot be moved and is already corrected elsewhere.
181+
const bool crossesCE = (dFwd == dBwd) && (dFwd < mMaxCECrossingDeltaTNS);
182+
if (!crossesCE) {
183+
const bool zPositive = track.getZ() > 0.f;
184+
const bool tglPositive = track.getTgl() > 0.f;
185+
int side = 0; // +1 = A, -1 = C, 0 = undetermined -> leave uncorrected
186+
if (zPositive == tglPositive) {
187+
// Consistent sign: the track converges to Z=0 at the beamline by construction.
188+
side = tglPositive ? 1 : -1;
189+
} else if (dBwd == 0.f && dFwd > 0.f) {
190+
// Bounded backward at the CE with room forward: no clusters on the opposite
191+
// side, so trust the measured Z rather than the (here inverted) tgl.
192+
side = zPositive ? 1 : -1;
193+
} else if (dBwd > 0.f) {
194+
// Large tgl track bounded at the readout side instead: trust tgl.
195+
side = tglPositive ? 1 : -1;
196+
}
197+
// else: degenerate case, track touches both CE and readout -> cannot be deduced/moved.
198+
// (in practice unreachable here: dFwd==dBwd==0 would already satisfy crossesCE above,
199+
// since dFwd/dBwd are always >= 0; kept explicit to mirror the reference logic 1:1.)
200+
201+
if (side > 0) {
202+
zShift = dDrift;
203+
} else if (side < 0) {
204+
zShift = -dDrift;
205+
}
206+
}
207+
}
208+
// else: track has clusters on both sides (crossed the CE) and is already corrected elsewhere
209+
}
210+
track.setZ(track.getZ() + zShift);
156211
if constexpr (std::is_base_of_v<o2::track::TrackParCov, Track>) {
157212
track.setCov(track.getSigmaZ2() + dDriftErr * dDriftErr, o2::track::kSigZ2);
158213
}
@@ -169,6 +224,7 @@ class TPCVDriftManager
169224

170225
private:
171226
bool mValid{false};
227+
bool mUseSideBasedCorrection{false}; // off by default: preserves legacy tgl-sign behaviour
172228
// Factors
173229
float mTPCVDriftNS{0.f}; // drift velocity in cm/ns
174230

@@ -177,6 +233,8 @@ class TPCVDriftManager
177233
o2::ccdb::BasicCCDBManager* mCCDB{}; // reference to initialized ccdb manager
178234

179235
static constexpr unsigned int mWarningLimit{10};
236+
static constexpr float mMaxDriftCm{250.f}; // TPC drift volume half-length in cm
237+
static constexpr float mMaxCECrossingDeltaTNS{1000.f}; // ~1 us, ballpark forward/backward time margin of a CE-crossing track
180238

181239
// Counters
182240
unsigned int mCalls{0}; // total number of calls

0 commit comments

Comments
 (0)