@@ -768,6 +768,28 @@ struct HadNucleiFemto {
768768 {" fraction/hDcaMotherPdgHad" , " Hadron DCA by exact direct-mother PDG; signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin;collision association;mother PDG sign;mother PDG high;mother PDG low" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40 , 0 .f , 100 .f }, {NDcaOrigins, -0 .5f , static_cast <float >(NDcaOrigins) - 0 .5f }, {NCollisionAssociations, -0 .5f , static_cast <float >(NCollisionAssociations) - 0 .5f }, {3 , -1 .5f , 1 .5f }, {MotherPdgHighMax + 1 , -0 .5f , static_cast <float >(MotherPdgHighMax) + 0 .5f }, {MotherPdgChunkBase, -0 .5f , static_cast <float >(MotherPdgChunkBase) - 0 .5f }}}},
769769 {" fraction/hDcaMotherPdgNu" , " Nucleus DCA by exact direct-mother PDG; signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin;collision association;mother PDG sign;mother PDG high;mother PDG low" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40 , 0 .f , 100 .f }, {NDcaOrigins, -0 .5f , static_cast <float >(NDcaOrigins) - 0 .5f }, {NCollisionAssociations, -0 .5f , static_cast <float >(NCollisionAssociations) - 0 .5f }, {3 , -1 .5f , 1 .5f }, {MotherPdgHighMax + 1 , -0 .5f , static_cast <float >(MotherPdgHighMax) + 0 .5f }, {MotherPdgChunkBase, -0 .5f , static_cast <float >(MotherPdgChunkBase) - 0 .5f }}}},
770770
771+ // Generator denominators and source-resolved response matrices for the
772+ // hypertriton-to-primary He3 and triton constraints. Generated momenta
773+ // are physical particle momenta and must never receive the reconstructed
774+ // He3-track x2 rigidity conversion. The two-body histograms are
775+ // conditional on their generated decay channel, so the physical
776+ // branching ratios remain independent offline inputs.
777+ {" fractionMCGen/hPrimaryHe3" , " Physical-primary generated He3 in selected MC collisions;signed generated p_{T}^{He3} (GeV/c);generated y^{He3};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
778+ {" fractionMCGen/hHypertriton" , " Physical-primary generated hypertritons in selected MC collisions;signed generated p_{T}^{hypertriton} (GeV/c);generated y^{hypertriton};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
779+ {" fractionMCGen/hHypertritonToHe3Pi" , " Physical-primary generated hypertritons in the He3-pion channel;signed generated p_{T}^{hypertriton} (GeV/c);generated y^{hypertriton};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
780+ {" fractionMCGen/hHypertritonDaughterHe3" , " Generated direct He3 daughters in the hypertriton-He3-pion channel;signed generated p_{T}^{He3} (GeV/c);generated y^{He3};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
781+ {" fractionMCGen/hHypertritonPtVsDaughterHe3Pt" , " Generated hypertriton-to-He3 decay mapping;signed generated p_{T}^{hypertriton} (GeV/c);signed generated p_{T}^{He3} (GeV/c);generated y^{hypertriton};generated y^{He3};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
782+ {" fractionMCGen/hPrimaryTriton" , " Physical-primary generated tritons in selected MC collisions;signed generated p_{T}^{triton} (GeV/c);generated y^{triton};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
783+ {" fractionMCGen/hHypertritonToTritonPi0" , " Physical-primary generated hypertritons in the triton-pi0 channel;signed generated p_{T}^{hypertriton} (GeV/c);generated y^{hypertriton};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
784+ {" fractionMCGen/hHypertritonDaughterTriton" , " Generated direct triton daughters in the hypertriton-triton-pi0 channel;signed generated p_{T}^{triton} (GeV/c);generated y^{triton};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
785+ {" fractionMCGen/hHypertritonPtVsDaughterTritonPt" , " Generated hypertriton-to-triton decay mapping;signed generated p_{T}^{hypertriton} (GeV/c);signed generated p_{T}^{triton} (GeV/c);generated y^{hypertriton};generated y^{triton};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
786+ {" fractionMCReco/hPrimaryHe3GenPtVsRecoPt" , " DCA-selected physical-primary He3 response;signed generated p_{T}^{He3} (GeV/c);signed physical reconstructed p_{T}^{He3} (GeV/c);generated y^{He3};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
787+ {" fractionMCReco/hHypertritonDaughterHe3GenPtVsRecoPt" , " DCA-selected hypertriton-daughter He3 response;signed generated p_{T}^{He3} (GeV/c);signed physical reconstructed p_{T}^{He3} (GeV/c);generated y^{He3};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
788+ {" fractionMCReco/hHypertritonParentPtVsDaughterRecoPt" , " DCA-selected hypertriton parent-to-He3 response;signed generated p_{T}^{hypertriton} (GeV/c);signed physical reconstructed p_{T}^{He3} (GeV/c);generated y^{hypertriton};generated y^{He3};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
789+ {" fractionMCReco/hPrimaryTritonGenPtVsRecoPt" , " DCA-selected physical-primary triton response;signed generated p_{T}^{triton} (GeV/c);signed physical reconstructed p_{T}^{triton} (GeV/c);generated y^{triton};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
790+ {" fractionMCReco/hHypertritonDaughterTritonGenPtVsRecoPt" , " DCA-selected hypertriton-daughter triton response;signed generated p_{T}^{triton} (GeV/c);signed physical reconstructed p_{T}^{triton} (GeV/c);generated y^{triton};centrality" , {HistType::kTHnSparseF , {{280 , -7 .f , 7 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
791+ {" fractionMCReco/hHypertritonParentPtVsDaughterTritonRecoPt" , " DCA-selected hypertriton parent-to-triton response;signed generated p_{T}^{hypertriton} (GeV/c);signed physical reconstructed p_{T}^{triton} (GeV/c);generated y^{hypertriton};generated y^{triton};centrality" , {HistType::kTHnSparseF , {{400 , -10 .f , 10 .f }, {280 , -7 .f , 7 .f }, {120 , -1 .5f , 1 .5f }, {120 , -1 .5f , 1 .5f }, {40 , 0 .f , 100 .f }}}},
792+
771793 // Hierarchical MC truth purity counters: all = correct species + mis-ID
772794 // + no label; correct species = correct collision + wrong collision;
773795 // correct collision = primary + weak + material.
@@ -3687,6 +3709,54 @@ struct HadNucleiFemto {
36873709 const float productionRadius = std::hypot (particle.vx (), particle.vy ());
36883710 const float signedPt = signedPhysicalPt (track, isNucleus);
36893711
3712+ // These response matrices use the relaxed DCA-fit selection under which
3713+ // this function is called. Keep only correct-collision He3 or triton so
3714+ // the reconstructed numerators match the selected-MC-collision generator
3715+ // denominators filled below. Hypertriton responses are conditional on the
3716+ // explicit He3-pion or triton-pi0 channel; physical branching ratios are
3717+ // deliberately not folded into these histograms.
3718+ const int absoluteParticlePdg = std::abs (particle.pdgCode ());
3719+ if (isNucleus && matchesRecoCollision && (absoluteParticlePdg == He3PDG || absoluteParticlePdg == TritonPDG)) {
3720+ const float signedGeneratedPt = particle.pdgCode () > 0 ? particle.pt () : -particle.pt ();
3721+ const float generatedRapidity = particle.y ();
3722+ if (origin == Primary) {
3723+ if (absoluteParticlePdg == He3PDG) {
3724+ mQaRegistry .fill (HIST (" fractionMCReco/hPrimaryHe3GenPtVsRecoPt" ), signedGeneratedPt, signedPt, generatedRapidity, centrality);
3725+ } else {
3726+ mQaRegistry .fill (HIST (" fractionMCReco/hPrimaryTritonGenPtVsRecoPt" ), signedGeneratedPt, signedPt, generatedRapidity, centrality);
3727+ }
3728+ } else if (origin == WeakDecay && particle.has_mothers ()) {
3729+ for (const auto & mother : particle.template mothers_as <aod::McParticles>()) {
3730+ if (std::abs (mother.pdgCode ()) != HyperTritonPDG || !mother.isPhysicalPrimary () ||
3731+ ((mother.pdgCode () > 0 ) != (particle.pdgCode () > 0 ))) {
3732+ continue ;
3733+ }
3734+ const int expectedPionPdg = absoluteParticlePdg == He3PDG
3735+ ? (mother.pdgCode () > 0 ? -PDG_t::kPiPlus : PDG_t::kPiPlus )
3736+ : PDG_t::kPi0 ;
3737+ bool hasExpectedPion = false ;
3738+ for (const auto & daughter : mother.template daughters_as <aod::McParticles>()) {
3739+ if (daughter.pdgCode () == expectedPionPdg) {
3740+ hasExpectedPion = true ;
3741+ break ;
3742+ }
3743+ }
3744+ if (!hasExpectedPion) {
3745+ continue ;
3746+ }
3747+ const float signedParentPt = mother.pdgCode () > 0 ? mother.pt () : -mother.pt ();
3748+ if (absoluteParticlePdg == He3PDG) {
3749+ mQaRegistry .fill (HIST (" fractionMCReco/hHypertritonDaughterHe3GenPtVsRecoPt" ), signedGeneratedPt, signedPt, generatedRapidity, centrality);
3750+ mQaRegistry .fill (HIST (" fractionMCReco/hHypertritonParentPtVsDaughterRecoPt" ), signedParentPt, signedPt, mother.y (), generatedRapidity, centrality);
3751+ } else {
3752+ mQaRegistry .fill (HIST (" fractionMCReco/hHypertritonDaughterTritonGenPtVsRecoPt" ), signedGeneratedPt, signedPt, generatedRapidity, centrality);
3753+ mQaRegistry .fill (HIST (" fractionMCReco/hHypertritonParentPtVsDaughterTritonRecoPt" ), signedParentPt, signedPt, mother.y (), generatedRapidity, centrality);
3754+ }
3755+ break ;
3756+ }
3757+ }
3758+ }
3759+
36903760 // The detailed histogram is always filled for a truth-PDG-matched track,
36913761 // including wrong-collision associations, so tighter choices can be made
36923762 // offline without rerunning the table producer.
@@ -3771,15 +3841,93 @@ struct HadNucleiFemto {
37713841 }
37723842 }
37733843
3844+ using SelectedMcCollisionInfo = std::unordered_map<int64_t , std::pair<int , float >>;
3845+
3846+ void fillMCGeneratorNucleiFeedDown (const aod::McParticles& mcParticles, const SelectedMcCollisionInfo& selectedMcCollisions)
3847+ {
3848+ for (const auto & particle : mcParticles) {
3849+ const auto collision = selectedMcCollisions.find (particle.mcCollisionId ());
3850+ if (collision == selectedMcCollisions.end ()) {
3851+ continue ;
3852+ }
3853+ const float centrality = collision->second .second ;
3854+ const int particlePdg = particle.pdgCode ();
3855+ const int absolutePdg = std::abs (particlePdg);
3856+ const float signedPt = particlePdg > 0 ? particle.pt () : -particle.pt ();
3857+
3858+ if (absolutePdg == He3PDG && particle.isPhysicalPrimary ()) {
3859+ mQaRegistry .fill (HIST (" fractionMCGen/hPrimaryHe3" ), signedPt, particle.y (), centrality);
3860+ continue ;
3861+ }
3862+ if (absolutePdg == TritonPDG && particle.isPhysicalPrimary ()) {
3863+ mQaRegistry .fill (HIST (" fractionMCGen/hPrimaryTriton" ), signedPt, particle.y (), centrality);
3864+ continue ;
3865+ }
3866+ if (absolutePdg != HyperTritonPDG || !particle.isPhysicalPrimary ()) {
3867+ continue ;
3868+ }
3869+
3870+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertriton" ), signedPt, particle.y (), centrality);
3871+
3872+ const int expectedHe3Pdg = particlePdg > 0 ? He3PDG : -He3PDG;
3873+ const int expectedTritonPdg = particlePdg > 0 ? TritonPDG : -TritonPDG;
3874+ const int expectedChargedPionPdg = particlePdg > 0 ? -PDG_t::kPiPlus : PDG_t::kPiPlus ;
3875+ bool hasExpectedHe3 = false ;
3876+ bool hasExpectedTriton = false ;
3877+ bool hasExpectedChargedPion = false ;
3878+ bool hasPi0 = false ;
3879+ float signedHe3Pt = 0 .f ;
3880+ float he3Rapidity = 0 .f ;
3881+ float signedTritonPt = 0 .f ;
3882+ float tritonRapidity = 0 .f ;
3883+ for (const auto & daughter : particle.template daughters_as <aod::McParticles>()) {
3884+ if (daughter.pdgCode () == expectedHe3Pdg) {
3885+ hasExpectedHe3 = true ;
3886+ signedHe3Pt = daughter.pdgCode () > 0 ? daughter.pt () : -daughter.pt ();
3887+ he3Rapidity = daughter.y ();
3888+ } else if (daughter.pdgCode () == expectedTritonPdg) {
3889+ hasExpectedTriton = true ;
3890+ signedTritonPt = daughter.pdgCode () > 0 ? daughter.pt () : -daughter.pt ();
3891+ tritonRapidity = daughter.y ();
3892+ } else if (daughter.pdgCode () == expectedChargedPionPdg) {
3893+ hasExpectedChargedPion = true ;
3894+ } else if (daughter.pdgCode () == PDG_t::kPi0 ) {
3895+ hasPi0 = true ;
3896+ }
3897+ }
3898+
3899+ if (hasExpectedHe3 && hasExpectedChargedPion) {
3900+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertritonToHe3Pi" ), signedPt, particle.y (), centrality);
3901+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertritonDaughterHe3" ), signedHe3Pt, he3Rapidity, centrality);
3902+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertritonPtVsDaughterHe3Pt" ), signedPt, signedHe3Pt, particle.y (), he3Rapidity, centrality);
3903+ }
3904+ if (hasExpectedTriton && hasPi0) {
3905+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertritonToTritonPi0" ), signedPt, particle.y (), centrality);
3906+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertritonDaughterTriton" ), signedTritonPt, tritonRapidity, centrality);
3907+ mQaRegistry .fill (HIST (" fractionMCGen/hHypertritonPtVsDaughterTritonPt" ), signedPt, signedTritonPt, particle.y (), tritonRapidity, centrality);
3908+ }
3909+ }
3910+ }
3911+
37743912 // MC DCA templates use the relaxed-DCA selection. MC purity uses the full
37753913 // nominal candidate selection, including its DCA requirement.
3776- void processDcaFractionPurityMC (const CollisionsFullMC& collisions, const TrackCandidatesMCDca& tracks, const aod::McParticles&, const aod::BCsWithTimestamps& bcs)
3914+ void processDcaFractionPurityMC (const CollisionsFullMC& collisions, const TrackCandidatesMCDca& tracks, const aod::McParticles& mcParticles , const aod::BCsWithTimestamps& bcs)
37773915 {
3916+ SelectedMcCollisionInfo selectedMcCollisions;
37783917 for (const auto & collision : collisions) {
37793918 if (!selectCollision</* isMC*/ true >(collision, bcs)) {
37803919 continue ;
37813920 }
37823921
3922+ if (collision.has_mcCollision ()) {
3923+ const int64_t mcCollisionId = collision.mcCollisionId ();
3924+ const int numberOfContributors = collision.numContrib ();
3925+ const auto storedCollision = selectedMcCollisions.find (mcCollisionId);
3926+ if (storedCollision == selectedMcCollisions.end () || numberOfContributors > storedCollision->second .first ) {
3927+ selectedMcCollisions[mcCollisionId] = {numberOfContributors, collision.centFT0C ()};
3928+ }
3929+ }
3930+
37833931 const uint64_t collIdx = collision.globalIndex ();
37843932 auto tracksThisCollision = tracks.sliceBy (mPerColMC , collIdx);
37853933 tracksThisCollision.bindExternalIndices (&tracks);
@@ -3840,6 +3988,7 @@ struct HadNucleiFemto {
38403988 }
38413989 }
38423990 }
3991+ fillMCGeneratorNucleiFeedDown (mcParticles, selectedMcCollisions);
38433992 }
38443993 PROCESS_SWITCH (HadNucleiFemto, processDcaFractionPurityMC, " Produce MC DCA templates and truth-purity counters" , false );
38453994
0 commit comments