Skip to content

Commit 0b7a081

Browse files
committed
Merge branch 'AliceO2Group:master' into jethadronBranch
2 parents 8331d11 + fe31180 commit 0b7a081

File tree

83 files changed

+6634
-2295
lines changed

Some content is hidden

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

83 files changed

+6634
-2295
lines changed

ALICE3/Core/FastTracker.cxx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa
442442
inputTrack.getXYZGlo(posIni);
443443
const float initialRadius = std::hypot(posIni[0], posIni[1]);
444444
const float kTrackingMargin = 0.1;
445-
const int kMaxNumberOfDetectors = 20;
446-
if (kMaxNumberOfDetectors < layers.size()) {
447-
LOG(fatal) << "Too many layers in FastTracker, increase kMaxNumberOfDetectors";
448-
return -1; // too many layers
449-
}
445+
450446
int firstActiveLayer = -1; // first layer that is not inert
451447
for (size_t i = 0; i < layers.size(); ++i) {
452448
if (!layers[i].isInert()) {
@@ -461,8 +457,12 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa
461457
const int xrhosteps = 100;
462458
const bool applyAngularCorrection = true;
463459

460+
// Delphes sets this to 20 instead of the number of layers,
461+
// but does not count all points in the tpc as layers which we do here
462+
// Loop over all the added layers to prevent crash when adding the tpc
463+
// Should not affect efficiency calculation
464464
goodHitProbability.clear();
465-
for (int i = 0; i < kMaxNumberOfDetectors; ++i) {
465+
for (size_t i = 0; i < layers.size(); ++i) {
466466
goodHitProbability.push_back(-1.);
467467
}
468468
goodHitProbability[0] = 1.; // we use layer zero to accumulate
@@ -650,7 +650,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa
650650

651651
// generate efficiency
652652
float eff = 1.;
653-
for (int i = 0; i < kMaxNumberOfDetectors; i++) {
653+
for (size_t i = 0; i < layers.size(); i++) {
654654
float iGoodHit = goodHitProbability[i];
655655
if (iGoodHit <= 0)
656656
continue;

ALICE3/DataModel/OTFMulticharm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ DECLARE_SOA_INDEX_COLUMN_FULL(XiCCPion, xiCCPion, int, Tracks, "_PiXiCC");
3636

3737
DECLARE_SOA_COLUMN(XicMass, xicMass, float);
3838
DECLARE_SOA_COLUMN(XiccMass, xiccMass, float);
39+
DECLARE_SOA_COLUMN(LUTConfigId, lutConfigId, int); //! Index for LUT configuration
3940

4041
// kine vars
4142
DECLARE_SOA_COLUMN(XiccPt, xiccPt, float);
@@ -155,7 +156,8 @@ DECLARE_SOA_TABLE(MCharmCores, "AOD", "MCharmCores",
155156
otfmulticharm::XiccProperLength,
156157
otfmulticharm::Pi1cPt,
157158
otfmulticharm::Pi2cPt,
158-
otfmulticharm::PiccPt);
159+
otfmulticharm::PiccPt,
160+
otfmulticharm::LUTConfigId);
159161

160162
DECLARE_SOA_TABLE(MCharmPID, "AOD", "MCharmPID",
161163
otfmulticharm::Pi1cTofDeltaInner,

ALICE3/DataModel/OTFTracks.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
///
13+
/// \file OTFTracks.h
14+
/// \author Jesper Karlsson Gumprecht
15+
/// \since 11/11/2025
16+
/// \brief Table to map track to LUT configuration
17+
///
18+
19+
#ifndef ALICE3_DATAMODEL_OTFTRACKS_H_
20+
#define ALICE3_DATAMODEL_OTFTRACKS_H_
21+
22+
// O2 includes
23+
#include "Framework/AnalysisDataModel.h"
24+
25+
namespace o2::aod
26+
{
27+
namespace otftracks
28+
{
29+
DECLARE_SOA_COLUMN(LUTConfigId, lutConfigId, int); //! Index for LUT configuration
30+
} // namespace otftracks
31+
32+
DECLARE_SOA_TABLE(OTFLUTConfigId, "AOD", "OTFLUTConfigId", otftracks::LUTConfigId);
33+
} // namespace o2::aod
34+
35+
#endif // ALICE3_DATAMODEL_OTFTRACKS_H_

ALICE3/TableProducer/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,8 @@ o2physics_add_dpl_workflow(alice3-correlatorddbar
4545
SOURCES alice3-correlatorDDbar.cxx
4646
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter
4747
COMPONENT_NAME Analysis)
48+
49+
o2physics_add_dpl_workflow(alice3-tracking-translator
50+
SOURCES alice3TrackingTranslator.cxx
51+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter
52+
COMPONENT_NAME Analysis)

ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx

Lines changed: 191 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ struct OnTheFlyTofPid {
9393
Configurable<bool> considerEventTime{"considerEventTime", true, "flag to consider event time"};
9494
Configurable<float> innerTOFRadius{"innerTOFRadius", 20, "barrel inner TOF radius (cm)"};
9595
Configurable<float> outerTOFRadius{"outerTOFRadius", 80, "barrel outer TOF radius (cm)"};
96+
Configurable<float> innerTOFLength{"innerTOFLength", 124, "barrel inner TOF length (cm)"};
97+
Configurable<float> outerTOFLength{"outerTOFLength", 250, "barrel outer TOF length (cm)"};
98+
Configurable<std::array<float, 2>> innerTOFPixelDimension{"innerTOFPixelDimension", {0.1, 0.1}, "barrel inner TOF pixel dimension in Z and RPhi (cm)"};
99+
Configurable<float> innerTOFFractionOfInactiveArea{"innerTOFFractionOfInactiveArea", 0.f, "barrel inner TOF fraction of inactive area"};
100+
Configurable<std::array<float, 2>> outerTOFPixelDimension{"outerTOFPixelDimension", {0.1, 0.1}, "barrel outer TOF pixel dimension in Z and RPhi (cm)"};
101+
Configurable<float> outerTOFFractionOfInactiveArea{"outerTOFFractionOfInactiveArea", 0.f, "barrel outer TOF fraction of inactive area"};
96102
Configurable<float> innerTOFTimeReso{"innerTOFTimeReso", 20, "barrel inner TOF time error (ps)"};
97103
Configurable<float> outerTOFTimeReso{"outerTOFTimeReso", 20, "barrel outer TOF time error (ps)"};
98104
Configurable<int> nStepsLIntegrator{"nStepsLIntegrator", 200, "number of steps in length integrator"};
@@ -196,12 +202,14 @@ struct OnTheFlyTofPid {
196202
histos.add("iTOF/h2dTrackLengthInnerVsPt", "h2dTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner});
197203
histos.add("iTOF/h2dTrackLengthInnerRecoVsPt", "h2dTrackLengthInnerRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner});
198204
histos.add("iTOF/h2dDeltaTrackLengthInnerVsPt", "h2dDeltaTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength});
205+
histos.add("iTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.innerTOFLength / 2, simConfig.innerTOFLength / 2}, {1000, 0, simConfig.innerTOFRadius * 2 * M_PI}});
199206

200207
histos.add("oTOF/h2dVelocityVsMomentumOuter", "h2dVelocityVsMomentumOuter", kTH2F, {axisMomentum, axisVelocity});
201208
histos.add("oTOF/h2dVelocityVsRigidityOuter", "h2dVelocityVsRigidityOuter", kTH2F, {axisRigidity, axisVelocity});
202209
histos.add("oTOF/h2dTrackLengthOuterVsPt", "h2dTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter});
203210
histos.add("oTOF/h2dTrackLengthOuterRecoVsPt", "h2dTrackLengthOuterRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter});
204211
histos.add("oTOF/h2dDeltaTrackLengthOuterVsPt", "h2dDeltaTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength});
212+
histos.add("oTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.outerTOFLength / 2, simConfig.outerTOFLength / 2}, {1000, 0, simConfig.outerTOFRadius * 2 * M_PI}});
205213

206214
const AxisSpec axisPt{static_cast<int>(plotsConfig.nBinsP), 0.0f, +4.0f, "#it{p}_{T} (GeV/#it{c})"};
207215
const AxisSpec axisEta{static_cast<int>(plotsConfig.nBinsEta), -2.0f, +2.0f, "#eta"};
@@ -244,11 +252,172 @@ struct OnTheFlyTofPid {
244252
}
245253
}
246254

255+
struct TOFLayerEfficiency {
256+
private:
257+
const float layerRadius;
258+
const float layerLength;
259+
const float pixelDimensionZ;
260+
const float pixelDimensionRPhi;
261+
const float fractionInactive;
262+
const float magField;
263+
264+
TAxis* axisZ = nullptr;
265+
TAxis* axisRPhi = nullptr;
266+
TAxis* axisInPixelZ = nullptr;
267+
TAxis* axisInPixelRPhi = nullptr;
268+
269+
TH2F* hHitMapInPixel = nullptr;
270+
TH2F* hHitMapInPixelBefore = nullptr;
271+
TH2F* hHitMap = nullptr;
272+
273+
public:
274+
~TOFLayerEfficiency()
275+
{
276+
hHitMap->SaveAs(Form("/tmp/%s.png", hHitMap->GetName()));
277+
hHitMapInPixel->SaveAs(Form("/tmp/%s.png", hHitMapInPixel->GetName()));
278+
hHitMapInPixelBefore->SaveAs(Form("/tmp/%s.png", hHitMapInPixelBefore->GetName()));
279+
280+
delete axisZ;
281+
delete axisRPhi;
282+
delete axisInPixelZ;
283+
delete axisInPixelRPhi;
284+
delete hHitMap;
285+
delete hHitMapInPixel;
286+
delete hHitMapInPixelBefore;
287+
}
288+
289+
TOFLayerEfficiency(float r, float l, std::array<float, 2> pDimensions, float fIA, float m)
290+
: layerRadius(r), layerLength(l), pixelDimensionZ(pDimensions[0]), pixelDimensionRPhi(pDimensions[1]), fractionInactive(fIA), magField(m)
291+
{
292+
// Assuming square pixels for simplicity
293+
const float circumference = 2.0f * M_PI * layerRadius;
294+
axisZ = new TAxis(static_cast<int>(layerLength / pixelDimensionZ), -layerLength / 2, layerLength);
295+
axisRPhi = new TAxis(static_cast<int>(circumference / pixelDimensionRPhi), 0.f, circumference);
296+
297+
const float inactiveBorderRPhi = pixelDimensionRPhi * std::sqrt(fractionInactive) / 2;
298+
const float inactiveBorderZ = pixelDimensionZ * std::sqrt(fractionInactive) / 2;
299+
const double arrayRPhi[4] = {-pixelDimensionRPhi / 2, -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2};
300+
for (int i = 0; i < 4; i++) {
301+
LOG(info) << "arrayRPhi[" << i << "] = " << arrayRPhi[i];
302+
}
303+
axisInPixelRPhi = new TAxis(3, arrayRPhi);
304+
const double arrayZ[4] = {-pixelDimensionZ / 2, -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2};
305+
for (int i = 0; i < 4; i++) {
306+
LOG(info) << "arrayZ[" << i << "] = " << arrayZ[i];
307+
}
308+
axisInPixelZ = new TAxis(3, arrayZ);
309+
310+
hHitMap = new TH2F(Form("hHitMap_R%.0f", layerRadius), "HitMap;z (cm); r#phi (cm)", 1000, -1000, 1000, 1000, -1000, 1000);
311+
hHitMapInPixel = new TH2F(Form("hHitMapInPixel_R%.0f", layerRadius), "HitMapInPixel;z (cm); r#phi (cm)", 1000, -10, 10, 1000, -10, 10);
312+
hHitMapInPixelBefore = new TH2F(Form("hHitMapInPixelBefore_R%.0f", layerRadius), "HitMapInPixel;z (cm); r#phi (cm)", 1000, -10, 10, 1000, -10, 10);
313+
}
314+
315+
bool isInTOFActiveArea(std::array<float, 3> hitPosition)
316+
{
317+
if (fractionInactive <= 0.0f) {
318+
return true;
319+
}
320+
if (fractionInactive >= 1.0f) {
321+
return false;
322+
}
323+
324+
// Convert 3D position to cylindrical coordinates for area calculation
325+
const float phi = std::atan2(hitPosition[1], hitPosition[0]);
326+
const float rphi = phi * layerRadius;
327+
const float z = hitPosition[2];
328+
const float r = std::sqrt(hitPosition[0] * hitPosition[0] + hitPosition[1] * hitPosition[1]);
329+
330+
// Check if hit is within layer geometric acceptance
331+
if (std::abs(layerRadius - r) > 10.f) {
332+
LOG(debug) << "Hit out of TOF layer acceptance: r=" << r << " cm with respect to the layer radius " << layerRadius;
333+
return false;
334+
}
335+
if (std::abs(z) > layerLength / 2.0f) {
336+
LOG(debug) << "Hit out of TOF layer acceptance: z=" << z << " cm with respect to the layer length " << layerLength;
337+
return false;
338+
}
339+
340+
const int pixelIndexPhi = axisRPhi->FindBin(rphi);
341+
const int pixelIndexZ = axisZ->FindBin(z);
342+
343+
// LOG(info) << "Hit pixel " << pixelIndexPhi << "/" << nPixelsRPhi << " and " << pixelIndexZ << "/" << nPixelsZ;
344+
345+
if (pixelIndexPhi <= 0 || pixelIndexPhi > axisRPhi->GetNbins() || pixelIndexZ <= 0 || pixelIndexZ > axisZ->GetNbins()) {
346+
// LOG(info) << "Hit out of TOF layer pixel range: pixelIndexPhi=" << pixelIndexPhi << ", pixelIndexZ=" << pixelIndexZ;
347+
return false;
348+
}
349+
// Calculate local position within the pixel
350+
const float localRPhi = (rphi - axisRPhi->GetBinCenter(pixelIndexPhi));
351+
const float localZ = (z - axisZ->GetBinCenter(pixelIndexZ));
352+
353+
// The difference between the hit and the pixel position cannot be greater than the size of the pixel
354+
if (std::abs(localRPhi - axisRPhi->GetBinCenter(pixelIndexPhi)) > axisRPhi->GetBinWidth(pixelIndexPhi)) {
355+
// LOG(warning) << "Local hit difference in phi is bigger than the pixel size";
356+
}
357+
if (std::abs(localZ - axisZ->GetBinCenter(pixelIndexZ)) > axisZ->GetBinWidth(pixelIndexZ)) {
358+
// LOG(warning) << "Local hit difference in z is bigger than the pixel size";
359+
}
360+
hHitMapInPixelBefore->Fill(localZ, localRPhi);
361+
switch (axisInPixelRPhi->FindBin(localRPhi)) {
362+
case 0:
363+
case 1:
364+
case 3:
365+
case 4:
366+
return false;
367+
}
368+
switch (axisInPixelZ->FindBin(localZ)) {
369+
case 0:
370+
case 1:
371+
case 3:
372+
case 4:
373+
return false;
374+
}
375+
hHitMapInPixel->Fill(localZ, localRPhi);
376+
hHitMap->Fill(z, rphi);
377+
return true;
378+
}
379+
380+
/// Check if a track hits the active area (convenience function)
381+
/// \param track the track parameters for automatic hit position calculation
382+
/// \return true if the hit is in the active area
383+
bool isTrackInActiveArea(const o2::track::TrackParCov& track)
384+
{
385+
if (fractionInactive <= 0.f) {
386+
return true;
387+
}
388+
float x, y, z;
389+
if (!track.getXatLabR(layerRadius, x, magField)) {
390+
LOG(debug) << "Could not propagate track to TOF layer at radius " << layerRadius << " cm";
391+
return false;
392+
}
393+
bool b;
394+
ROOT::Math::PositionVector3D hit = track.getXYZGloAt(x, magField, b);
395+
if (!b) {
396+
LOG(debug) << "Could not get hit position at radius " << layerRadius << " cm";
397+
return false;
398+
}
399+
hit.GetCoordinates(x, y, z);
400+
return isInTOFActiveArea(std::array<float, 3>{x, y, z});
401+
}
402+
};
403+
404+
bool isInInnerTOFActiveArea(const o2::track::TrackParCov& track)
405+
{
406+
static TOFLayerEfficiency innerTOFLayer(simConfig.innerTOFRadius, simConfig.innerTOFLength, simConfig.innerTOFPixelDimension, simConfig.innerTOFFractionOfInactiveArea, simConfig.magneticField);
407+
return innerTOFLayer.isTrackInActiveArea(track);
408+
}
409+
410+
bool isInOuterTOFActiveArea(const o2::track::TrackParCov& track)
411+
{
412+
static TOFLayerEfficiency outerTOFLayer(simConfig.outerTOFRadius, simConfig.outerTOFLength, simConfig.outerTOFPixelDimension, simConfig.outerTOFFractionOfInactiveArea, simConfig.magneticField);
413+
return outerTOFLayer.isTrackInActiveArea(track);
414+
}
415+
247416
/// function to calculate track length of this track up to a certain radius
248417
/// \param track the input track
249418
/// \param radius the radius of the layer you're calculating the length to
250419
/// \param magneticField the magnetic field to use when propagating
251-
float computeTrackLength(o2::track::TrackParCov track, float radius, float magneticField)
420+
static float computeTrackLength(o2::track::TrackParCov track, float radius, float magneticField)
252421
{
253422
// don't make use of the track parametrization
254423
float length = -100;
@@ -496,6 +665,25 @@ struct OnTheFlyTofPid {
496665
trackLengthOuterTOF = computeTrackLength(o2track, simConfig.outerTOFRadius, simConfig.magneticField);
497666
}
498667

668+
// Check if the track hit a sensitive area of the TOF
669+
const bool activeInnerTOF = isInInnerTOFActiveArea(o2track);
670+
if (!activeInnerTOF) {
671+
trackLengthInnerTOF = -999.f;
672+
} else {
673+
float x = 0.f;
674+
o2track.getXatLabR(simConfig.innerTOFRadius, x, simConfig.magneticField);
675+
histos.fill(HIST("iTOF/h2HitMap"), o2track.getZAt(x, simConfig.magneticField), simConfig.innerTOFRadius * o2track.getPhiAt(x, simConfig.magneticField));
676+
}
677+
678+
const bool activeOuterTOF = isInOuterTOFActiveArea(o2track);
679+
if (!activeOuterTOF) {
680+
trackLengthOuterTOF = -999.f;
681+
} else {
682+
float x = 0.f;
683+
o2track.getXatLabR(simConfig.outerTOFRadius, x, simConfig.magneticField);
684+
histos.fill(HIST("oTOF/h2HitMap"), o2track.getZAt(x, simConfig.magneticField), simConfig.outerTOFRadius * o2track.getPhiAt(x, simConfig.magneticField));
685+
}
686+
499687
// get mass to calculate velocity
500688
auto pdgInfo = pdg->GetParticle(mcParticle.pdgCode());
501689
if (pdgInfo == nullptr) {
@@ -504,8 +692,8 @@ struct OnTheFlyTofPid {
504692
continue;
505693
}
506694
const float v = computeParticleVelocity(o2track.getP(), pdgInfo->Mass());
507-
const float expectedTimeInnerTOF = trackLengthInnerTOF / v + eventCollisionTimePS; // arrival time to the Inner TOF in ps
508-
const float expectedTimeOuterTOF = trackLengthOuterTOF / v + eventCollisionTimePS; // arrival time to the Outer TOF in ps
695+
const float expectedTimeInnerTOF = trackLengthInnerTOF > 0 ? trackLengthInnerTOF / v + eventCollisionTimePS : -999.f; // arrival time to the Inner TOF in ps
696+
const float expectedTimeOuterTOF = trackLengthOuterTOF > 0 ? trackLengthOuterTOF / v + eventCollisionTimePS : -999.f; // arrival time to the Outer TOF in ps
509697
upgradeTofMC(expectedTimeInnerTOF, trackLengthInnerTOF, expectedTimeOuterTOF, trackLengthOuterTOF);
510698

511699
// Smear with expected resolutions

0 commit comments

Comments
 (0)