Skip to content

Commit 3204913

Browse files
authored
[DPG] HMPID: new method to select primaries (#17248)
1 parent 4a82301 commit 3204913

1 file changed

Lines changed: 130 additions & 56 deletions

File tree

DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx

Lines changed: 130 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include <Framework/runDataProcessing.h>
3535

3636
#include <TGeoManager.h>
37+
#include <TMath.h>
38+
#include <TPDGCode.h>
3739

3840
#include <HMPIDBase/Param.h>
3941

@@ -73,6 +75,12 @@ struct HmpidTableProducer {
7375
Configurable<bool> requireTPC{"requireTPC", true, "Require TPC track"};
7476
Configurable<bool> requireTOF{"requireTOF", true, "Require TOF track"};
7577

78+
Configurable<bool> useInAbsorberGeomMethod{"useInAbsorberGeomMethod", false, "Use geometrical method to check if daughters are born in absorber"};
79+
80+
// (reference) 473 cm - was the legacy value in run2 simulation
81+
Configurable<float> survivalThresholdRich2{"survivalThresholdRich2", 437.5f, "survivalThresholdRich2"};
82+
Configurable<float> survivalThresholdRich4{"survivalThresholdRich4", 439.0f, "survivalThresholdRich4"};
83+
7684
using CollisionCandidates = o2::soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::CentFV0As>;
7785

7886
using TrackCandidates = soa::Join<aod::Tracks, aod::TracksExtra,
@@ -94,30 +102,9 @@ struct HmpidTableProducer {
94102

95103
static constexpr int Rich2 = 2, Rich4 = 4;
96104

97-
// -----------------------------------------------------------------------
98-
// HMPID absorber geometry (hardcoded from HMPIDSimulation/Detector.cxx,
99-
// Detector::ConstructGeometry / Detector::createAbsorber).
100-
// The experiment is finalised and this geometry will not change, so the
101-
// values are copied here instead of being re-derived from TGeoManager/CCDB
102-
// at runtime. If the detector geometry code is ever revisited, these
103-
// constants must be updated accordingly.
104-
//
105-
// Each absorber is a box (TGeoBBox) whose LOCAL->GLOBAL transform is built as:
106-
// pMatrix->SetTranslation(T);
107-
// pMatrix->RotateZ(theta);
108-
// which yields, for a local point p: p_glob = Rz(theta) * p_loc + T.
109-
// In particular the box CENTER in global coordinates is exactly T (the
110-
// rotation does not affect T, since it is applied to p_loc only, not to
111-
// the already-set translation). Only the box AXES are rotated by theta
112-
// with respect to the global x,y axes.
113-
//
114-
// To test whether a global point lies inside the box we invert the
115-
// transform: p_loc = Rz(-theta) * (p_glob - T), then compare component-wise
116-
// against the box half-widths.
117-
// -----------------------------------------------------------------------
105+
// (reference) HMPID Detector class in O2
118106
static constexpr double AbsThetaDeg = 33.5;
119-
const double mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad());
120-
const double mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad());
107+
double mAbsCosT = 0., mAbsSinT = 0.;
121108

122109
// Rich2 absorber: trans2 = {435.5, 0., -155.}, thickness 40mm -> halfX = 2cm
123110
static constexpr double AbsRich2CenterX = 435.5, AbsRich2CenterZ = -155.;
@@ -132,6 +119,9 @@ struct HmpidTableProducer {
132119

133120
void init(o2::framework::InitContext&)
134121
{
122+
mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad());
123+
mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad());
124+
135125
ccdb->setURL(ccdbConfig.ccdbUrl);
136126
ccdb->setCaching(true);
137127
ccdb->setLocalObjectValidityChecking();
@@ -159,6 +149,10 @@ struct HmpidTableProducer {
159149
kTH1F, {{4, -0.5, 3.5, ""}});
160150

161151
histos.add("hProdVertex", ";X (cm);Y (cm);Z (cm)", HistType::kTH3F, {{500, -500., 500.}, {500, -500., 500.}, {500, -500., 500.}});
152+
histos.add("hDaughterRCyl_Rich2", "hDaughterRCyl_Rich2", kTH1F, {{600, 0., 600.}});
153+
histos.add("hDaughterRCyl_Rich4", "hDaughterRCyl_Rich4", kTH1F, {{600, 0., 600.}});
154+
histos.add("hDaughterRSph_Rich2", "hDaughterRSph_Rich2", kTH1F, {{600, 0., 600.}});
155+
histos.add("hDaughterRSph_Rich4", "hDaughterRSph_Rich4", kTH1F, {{600, 0., 600.}});
162156
}
163157

164158
// -----------------------------------------------------------------------
@@ -274,8 +268,9 @@ struct HmpidTableProducer {
274268
(x[1] - planePoint[1]) * planeNormal[1] +
275269
(x[2] - planePoint[2]) * planeNormal[2];
276270

277-
if (std::abs(dist) >= std::abs(distPrev))
271+
if (std::abs(dist) >= std::abs(distPrev)) {
278272
return false;
273+
}
279274

280275
distPrev = dist;
281276
s -= dist;
@@ -318,14 +313,16 @@ struct HmpidTableProducer {
318313
// Intersection track - radiator plane
319314
std::array<double, 3> xRad{}, pAtRad{};
320315

321-
if (!intersectHelixPlane(bz, charge, x, p, pRad, nRad, xRad, pAtRad))
316+
if (!intersectHelixPlane(bz, charge, x, p, pRad, nRad, xRad, pAtRad)) {
322317
continue;
318+
}
323319

324320
// Intersection track - PC plane
325321
std::array<double, 3> xPc{}, pAtPc{};
326322

327-
if (!intersectHelixPlane(bz, charge, xRad, pAtRad, pPc, nPc, xPc, pAtPc))
323+
if (!intersectHelixPlane(bz, charge, xRad, pAtRad, pPc, nPc, xPc, pAtPc)) {
328324
continue;
325+
}
329326

330327
double theta = 0., phi = 0.;
331328
param->mars2LorsVec(ch, pAtRad.data(), theta, phi);
@@ -334,8 +331,9 @@ struct HmpidTableProducer {
334331
param->mars2Lors(ch, xPc.data(), xL, yL);
335332

336333
// Use isInside to check Chamber intersected
337-
if (param->isInside(xL, yL, param->distCut()))
334+
if (param->isInside(xL, yL, param->distCut())) {
338335
return ch;
336+
}
339337
}
340338

341339
// No chamber intersected
@@ -361,17 +359,32 @@ struct HmpidTableProducer {
361359
return false;
362360
}
363361

364-
// subtract the box center (translation is not rotated, see geometry block above)
365-
const double rx = vx * mAbsCosT + vy * mAbsSinT;
366-
const double ry = -vx * mAbsSinT + vy * mAbsCosT;
367-
const double rz = vz;
362+
// translate to box center
363+
const double lx = vx - centerX;
364+
const double ly = vy; // centerY = 0
365+
const double lz = vz - centerZ;
368366

369367
// rotate by -theta into the box local frame
370-
const double lx = rx - centerX;
371-
const double ly = ry; // centerY = 0
372-
const double lz = rz - centerZ;
368+
const double rx = lx * mAbsCosT + ly * mAbsSinT;
369+
const double ry = -lx * mAbsSinT + ly * mAbsCosT;
370+
const double rz = lz;
371+
372+
return std::abs(rx) <= halfX && std::abs(ry) <= AbsHalfY && std::abs(rz) <= AbsHalfZ;
373+
}
374+
375+
bool survivedAbsorber(double vx, double vy, int chamber)
376+
{
377+
float thresholdR = 0.;
378+
if (chamber == Rich2) {
379+
thresholdR = survivalThresholdRich2;
380+
} else if (chamber == Rich4) {
381+
thresholdR = survivalThresholdRich4;
382+
} else {
383+
return false;
384+
}
373385

374-
return std::abs(lx) <= halfX && std::abs(ly) <= AbsHalfY && std::abs(lz) <= AbsHalfZ;
386+
const float r = std::hypot(vx, vy);
387+
return r > thresholdR;
375388
}
376389

377390
void processEvent(CollisionCandidates::iterator const& col,
@@ -397,26 +410,30 @@ struct HmpidTableProducer {
397410

398411
const auto& globalTrack = t.template track_as<TTrackTable>();
399412

400-
if (!globalTrack.has_collision())
413+
if (!globalTrack.has_collision()) {
401414
continue;
415+
}
402416

403417
const auto& col = globalTrack.template collision_as<CollisionCandidates>();
404418
initCCDB(col.template bc_as<aod::BCsWithTimestamps>());
405419
uint32_t collId = col.globalIndex();
406420

407421
if ((requireITS && !globalTrack.hasITS()) ||
408422
(requireTPC && !globalTrack.hasTPC()) ||
409-
(requireTOF && !globalTrack.hasTOF()))
423+
(requireTOF && !globalTrack.hasTOF())) {
410424
continue;
425+
}
411426

412-
if (mCollisionsWithHmpid.insert(collId).second)
427+
if (mCollisionsWithHmpid.insert(collId).second) {
413428
histos.fill(HIST("eventsHmpid"), 0.5);
429+
}
414430

415431
// clusSize diagnostics
416432
histos.fill(HIST("hClusSize"), t.hmpidClusSize());
417433
bool isCorrupt = (t.hmpidClusSize() <= 0);
418-
if (isCorrupt)
434+
if (isCorrupt) {
419435
histos.fill(HIST("hClusSizeCorrupt"), t.hmpidClusSize());
436+
}
420437

421438
// --- M2: clusSize encoding ---
422439
int chamberM2 = t.hmpidClusSize() / 1000000;
@@ -464,20 +481,22 @@ struct HmpidTableProducer {
464481
// bin 2 = clusSize <= 0, M1 recovery (corrupt, M1 ok)
465482
// bin 3 = clusSize <= 0, M1 fails (corrupt, skipped)
466483

467-
if (!isCorrupt && chamberM3 >= 0)
484+
if (!isCorrupt && chamberM3 >= 0) {
468485
histos.fill(HIST("hChamberAssignment"), 0.);
469-
else if (!isCorrupt && chamberM3 < 0)
486+
} else if (!isCorrupt && chamberM3 < 0) {
470487
histos.fill(HIST("hChamberAssignment"), 1.);
471-
else if (isCorrupt && chamberM3 >= 0)
488+
} else if (isCorrupt && chamberM3 >= 0) {
472489
histos.fill(HIST("hChamberAssignment"), 2.);
473-
else
490+
} else {
474491
histos.fill(HIST("hChamberAssignment"), 3.);
492+
}
475493

476494
histos.fill(HIST("hChamberM3"), chamberM3);
477495
histos.fill(HIST("hChamberM3vsM2"), chamberM2, chamberM3);
478496

479-
if (chamberM3 < 0)
497+
if (chamberM3 < 0) {
480498
continue;
499+
}
481500

482501
std::vector<float> hmpidPhotsCharge2(o2::aod::kDimPhotonsCharge, 0.f);
483502

@@ -514,23 +533,78 @@ struct HmpidTableProducer {
514533

515534
if ((chamberM3 == Rich2 || chamberM3 == Rich4) && mc.has_daughters()) {
516535
auto dIds = mc.daughtersIds();
517-
518-
for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) {
519-
auto daughter = mcParticles.rawIteratorAt(idx);
520-
521-
histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz());
522-
523-
if (isInAbsorber(daughter.vx(), daughter.vy(), daughter.vz(), chamberM3)) {
524-
interactionInAbsorber = true;
525-
break;
526-
}
527-
} // end loop daughters
536+
bool foundRelevantDaughter = false; // true if at least one non-delta/photon daughter was examined
537+
538+
if (useInAbsorberGeomMethod) {
539+
for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) {
540+
auto daughter = mcParticles.rawIteratorAt(idx);
541+
542+
int absPdg = std::abs(daughter.pdgCode());
543+
if (absPdg == kElectron || absPdg == kGamma) {
544+
continue;
545+
}
546+
547+
foundRelevantDaughter = true;
548+
549+
// diagnostics on daughters distribution
550+
histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz());
551+
552+
double rCyl = std::hypot(daughter.vx(), daughter.vy());
553+
double rSph = std::hypot(daughter.vx(), daughter.vy(), daughter.vz());
554+
if (chamberM3 == Rich2) {
555+
histos.fill(HIST("hDaughterRCyl_Rich2"), rCyl);
556+
histos.fill(HIST("hDaughterRSph_Rich2"), rSph);
557+
} else {
558+
histos.fill(HIST("hDaughterRCyl_Rich4"), rCyl);
559+
histos.fill(HIST("hDaughterRSph_Rich4"), rSph);
560+
}
561+
562+
if (isInAbsorber(daughter.vx(), daughter.vy(), daughter.vz(), chamberM3)) {
563+
interactionInAbsorber = true;
564+
}
565+
} // end loop daughters
566+
} else {
567+
bool survived = false;
568+
for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) {
569+
auto daughter = mcParticles.rawIteratorAt(idx);
570+
571+
// skip delta rays (e-/e+), photons, and HMPID Cherenkov/feedback
572+
int absPdg = std::abs(daughter.pdgCode());
573+
if (absPdg == kElectron || absPdg == kGamma) {
574+
continue;
575+
}
576+
577+
foundRelevantDaughter = true;
578+
579+
histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz());
580+
581+
double rCyl = std::hypot(daughter.vx(), daughter.vy());
582+
double rSph = std::hypot(daughter.vx(), daughter.vy(), daughter.vz());
583+
if (chamberM3 == Rich2) {
584+
histos.fill(HIST("hDaughterRCyl_Rich2"), rCyl);
585+
histos.fill(HIST("hDaughterRSph_Rich2"), rSph);
586+
} else {
587+
histos.fill(HIST("hDaughterRCyl_Rich4"), rCyl);
588+
histos.fill(HIST("hDaughterRSph_Rich4"), rSph);
589+
}
590+
591+
if (survivedAbsorber(daughter.vx(), daughter.vy(), chamberM3)) {
592+
survived = true;
593+
}
594+
} // end loop daughters
595+
596+
// No relevant daughter found (only delta rays/photons, or no
597+
// daughters at all): no evidence of a genuine interaction -> treat
598+
// as primary/survived, consistent with the "no daughters" case.
599+
interactionInAbsorber = foundRelevantDaughter ? !survived : false;
600+
}
528601
} // end if has_daughters
529602

530603
hmpidAnalysisMC(mc.pdgCode(), mc.vx(), mc.vy(), mc.vz(),
531604
mc.isPhysicalPrimary(), mc.getProcess(), interactionInAbsorber);
532605
} else {
533-
hmpidAnalysisMC(-1, 0.f, 0.f, 0.f, false, -100, false);
606+
// No MC truth associated to this track
607+
hmpidAnalysisMC(-999, -999.f, -999.f, -999.f, false, -100, false);
534608
}
535609
} // end if constexpr (isMC)
536610

0 commit comments

Comments
 (0)