Skip to content

Commit 453095e

Browse files
authored
[ALICE3] A3TOF: add dead chip areas (#13356)
1 parent f2083b3 commit 453095e

File tree

2 files changed

+193
-3
lines changed

2 files changed

+193
-3
lines changed

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

ALICE3/TableProducer/OTF/onTheFlyTracker.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ struct OnTheFlyTracker {
304304
hCovMatOK->GetXaxis()->SetBinLabel(2, "OK");
305305

306306
histos.add("hPtGenerated", "hPtGenerated", kTH1F, {axes.axisMomentum});
307+
histos.add("hPhiGenerated", "hPhiGenerated", kTH1F, {{100, 0.0f, 2 * M_PI, "#phi (rad)"}});
307308
histos.add("hPtGeneratedEl", "hPtGeneratedEl", kTH1F, {axes.axisMomentum});
308309
histos.add("hPtGeneratedPi", "hPtGeneratedPi", kTH1F, {axes.axisMomentum});
309310
histos.add("hPtGeneratedKa", "hPtGeneratedKa", kTH1F, {axes.axisMomentum});
@@ -614,6 +615,7 @@ struct OnTheFlyTracker {
614615
}
615616

616617
histos.fill(HIST("hPtGenerated"), mcParticle.pt());
618+
histos.fill(HIST("hPhiGenerated"), mcParticle.phi());
617619
if (std::abs(mcParticle.pdgCode()) == kElectron)
618620
histos.fill(HIST("hPtGeneratedEl"), mcParticle.pt());
619621
if (std::abs(mcParticle.pdgCode()) == kPiPlus)

0 commit comments

Comments
 (0)