3434#include < Framework/runDataProcessing.h>
3535
3636#include < TGeoManager.h>
37+ #include < TPDGCode.h>
3738
3839#include < HMPIDBase/Param.h>
3940
@@ -73,6 +74,12 @@ struct HmpidTableProducer {
7374 Configurable<bool > requireTPC{" requireTPC" , true , " Require TPC track" };
7475 Configurable<bool > requireTOF{" requireTOF" , true , " Require TOF track" };
7576
77+ Configurable<bool > useInAbsorberGeomMethod{" useInAbsorberGeomMethod" , false , " Use geometrical method to check if daughters are born in absorber" };
78+
79+ // (reference) 473 cm - was the legacy value in run2 simulation
80+ Configurable<float > survivalThresholdRich2{" survivalThresholdRich2" , 437 .5f , " survivalThresholdRich2" };
81+ Configurable<float > survivalThresholdRich4{" survivalThresholdRich4" , 439 .0f , " survivalThresholdRich4" };
82+
7683 using CollisionCandidates = o2::soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::CentFV0As>;
7784
7885 using TrackCandidates = soa::Join<aod::Tracks, aod::TracksExtra,
@@ -94,27 +101,7 @@ struct HmpidTableProducer {
94101
95102 static constexpr int Rich2 = 2 , Rich4 = 4 ;
96103
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- // -----------------------------------------------------------------------
104+ // (reference) HMPID Detector class in O2
118105 static constexpr double AbsThetaDeg = 33.5 ;
119106 const double mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad ());
120107 const double mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad ());
@@ -159,6 +146,10 @@ struct HmpidTableProducer {
159146 kTH1F , {{4 , -0.5 , 3.5 , " " }});
160147
161148 histos.add (" hProdVertex" , " ;X (cm);Y (cm);Z (cm)" , HistType::kTH3F , {{500 , -500 ., 500 .}, {500 , -500 ., 500 .}, {500 , -500 ., 500 .}});
149+ histos.add (" hDaughterRCyl_Rich2" , " hDaughterRCyl_Rich2" , kTH1F , {{600 , 0 ., 600 .}});
150+ histos.add (" hDaughterRCyl_Rich4" , " hDaughterRCyl_Rich4" , kTH1F , {{600 , 0 ., 600 .}});
151+ histos.add (" hDaughterRSph_Rich2" , " hDaughterRSph_Rich2" , kTH1F , {{600 , 0 ., 600 .}});
152+ histos.add (" hDaughterRSph_Rich4" , " hDaughterRSph_Rich4" , kTH1F , {{600 , 0 ., 600 .}});
162153 }
163154
164155 // -----------------------------------------------------------------------
@@ -361,17 +352,32 @@ struct HmpidTableProducer {
361352 return false ;
362353 }
363354
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;
355+ // translate to box center
356+ const double lx = vx - centerX ;
357+ const double ly = vy; // centerY = 0
358+ const double lz = vz - centerZ ;
368359
369360 // 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;
361+ const double rx = lx * mAbsCosT + ly * mAbsSinT ;
362+ const double ry = -lx * mAbsSinT + ly * mAbsCosT ;
363+ const double rz = lz;
364+
365+ return std::abs (rx) <= halfX && std::abs (ry) <= AbsHalfY && std::abs (rz) <= AbsHalfZ;
366+ }
367+
368+ bool survivedAbsorber (double vx, double vy, int chamber)
369+ {
370+ float thresholdR = 0 .;
371+ if (chamber == Rich2) {
372+ thresholdR = survivalThresholdRich2;
373+ } else if (chamber == Rich4) {
374+ thresholdR = survivalThresholdRich4;
375+ } else {
376+ return false ;
377+ }
373378
374- return std::abs (lx) <= halfX && std::abs (ly) <= AbsHalfY && std::abs (lz) <= AbsHalfZ;
379+ const float r = std::hypot (vx, vy);
380+ return r > thresholdR;
375381 }
376382
377383 void processEvent (CollisionCandidates::iterator const & col,
@@ -514,23 +520,76 @@ struct HmpidTableProducer {
514520
515521 if ((chamberM3 == Rich2 || chamberM3 == Rich4) && mc.has_daughters ()) {
516522 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
523+ bool foundRelevantDaughter = false ; // true if at least one non-delta/photon daughter was examined
524+
525+ if (useInAbsorberGeomMethod) {
526+ for (int32_t idx = dIds.front (); idx <= dIds.back (); ++idx) {
527+ auto daughter = mcParticles.rawIteratorAt (idx);
528+
529+ int absPdg = std::abs (daughter.pdgCode ());
530+ if (absPdg == kElectron || absPdg == kGamma )
531+ continue ;
532+
533+ foundRelevantDaughter = true ;
534+
535+ // diagnostics on daughters distribution
536+ histos.fill (HIST (" hProdVertex" ), daughter.vx (), daughter.vy (), daughter.vz ());
537+
538+ double rCyl = std::hypot (daughter.vx (), daughter.vy ());
539+ double rSph = std::hypot (daughter.vx (), daughter.vy (), daughter.vz ());
540+ if (chamberM3 == Rich2) {
541+ histos.fill (HIST (" hDaughterRCyl_Rich2" ), rCyl);
542+ histos.fill (HIST (" hDaughterRSph_Rich2" ), rSph);
543+ } else {
544+ histos.fill (HIST (" hDaughterRCyl_Rich4" ), rCyl);
545+ histos.fill (HIST (" hDaughterRSph_Rich4" ), rSph);
546+ }
547+
548+ if (isInAbsorber (daughter.vx (), daughter.vy (), daughter.vz (), chamberM3)) {
549+ interactionInAbsorber = true ;
550+ }
551+ } // end loop daughters
552+ } else {
553+ bool survived = false ;
554+ for (int32_t idx = dIds.front (); idx <= dIds.back (); ++idx) {
555+ auto daughter = mcParticles.rawIteratorAt (idx);
556+
557+ // skip delta rays (e-/e+), photons, and HMPID Cherenkov/feedback
558+ int absPdg = std::abs (daughter.pdgCode ());
559+ if (absPdg == kElectron || absPdg == kGamma )
560+ continue ;
561+
562+ foundRelevantDaughter = true ;
563+
564+ histos.fill (HIST (" hProdVertex" ), daughter.vx (), daughter.vy (), daughter.vz ());
565+
566+ double rCyl = std::hypot (daughter.vx (), daughter.vy ());
567+ double rSph = std::hypot (daughter.vx (), daughter.vy (), daughter.vz ());
568+ if (chamberM3 == Rich2) {
569+ histos.fill (HIST (" hDaughterRCyl_Rich2" ), rCyl);
570+ histos.fill (HIST (" hDaughterRSph_Rich2" ), rSph);
571+ } else {
572+ histos.fill (HIST (" hDaughterRCyl_Rich4" ), rCyl);
573+ histos.fill (HIST (" hDaughterRSph_Rich4" ), rSph);
574+ }
575+
576+ if (survivedAbsorber (daughter.vx (), daughter.vy (), chamberM3)) {
577+ survived = true ;
578+ }
579+ } // end loop daughters
580+
581+ // No relevant daughter found (only delta rays/photons, or no
582+ // daughters at all): no evidence of a genuine interaction -> treat
583+ // as primary/survived, consistent with the "no daughters" case.
584+ interactionInAbsorber = foundRelevantDaughter ? !survived : false ;
585+ }
528586 } // end if has_daughters
529587
530588 hmpidAnalysisMC (mc.pdgCode (), mc.vx (), mc.vy (), mc.vz (),
531589 mc.isPhysicalPrimary (), mc.getProcess (), interactionInAbsorber);
532590 } else {
533- hmpidAnalysisMC (-1 , 0 .f , 0 .f , 0 .f , false , -100 , false );
591+ // No MC truth associated to this track
592+ hmpidAnalysisMC (-999 , -999 .f , -999 .f , -999 .f , false , -100 , false );
534593 }
535594 } // end if constexpr (isMC)
536595
0 commit comments