@@ -2550,6 +2550,12 @@ struct HStrangeCorrelation {
25502550 }
25512551 }
25522552 if (doprocessClosureTest) {
2553+ histos.add (" ClosureTest/PairLossK0/Truth/sameEvent/K0Short" , " truth h-K0 pairs with the processPairLossK0MC selections" , kTHnF , {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2554+ histos.add (" ClosureTest/PairLossK0/AnyTrack/sameEvent/K0Short" , " truth h-K0 pairs whose truth trigger has a reconstructed-track match in any associated collision" , kTHnF , {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2555+ histos.add (" ClosureTest/PairLossK0/Truth/hTrigger" , " truth triggers with the processPairLossK0MC selections;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}" , kTH3F , {axesConfigurations.axisPtQA , axesConfigurations.axisEta , axesConfigurations.axisPhi });
2556+ histos.add (" ClosureTest/PairLossK0/Truth/hK0Short" , " truth K0s with the processPairLossK0MC selections;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}" , kTH3F , {axesConfigurations.axisPtQA , axesConfigurations.axisEta , axesConfigurations.axisPhi });
2557+ histos.add (" ClosureTest/PairLossK0/AnyTrack/hTrigger" , " truth triggers with a reconstructed-track match in any associated collision;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}" , kTH3F , {axesConfigurations.axisPtQA , axesConfigurations.axisEta , axesConfigurations.axisPhi });
2558+ histos.add (" ClosureTest/PairLossK0/AnyTrack/hK0Short" , " truth K0s; unchanged at the any-track trigger stage;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}" , kTH3F , {axesConfigurations.axisPtQA , axesConfigurations.axisEta , axesConfigurations.axisPhi });
25532559 for (int i = 0 ; i < AssocParticleTypes; i++) {
25542560 if (TESTBIT (doCorrelation, i)) {
25552561 histos.add (fmt::format (" ClosureTest/sameEvent/{}" , Particlenames[i]).c_str (), " " , kTHnF , {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
@@ -4254,6 +4260,150 @@ struct HStrangeCorrelation {
42544260 TracksCompleteMC const & tracks)
42554261 {
42564262
4263+ // Reproduce the first two processPairLossK0MC trigger stages without changing
4264+ // the selections or output of the pre-existing closure-test analysis below.
4265+ // Both histograms remain anchored to the same truth h-K0 pair. "AnyTrack"
4266+ // changes only the trigger requirement: at least one reconstructed track in
4267+ // any reconstructed collision associated with this MC collision must point
4268+ // back to the truth trigger through its MC label.
4269+ auto fillPairLossK0TruthAndAnyTrack = [&]() {
4270+ if (recCollisions.size () == 0 ) {
4271+ return ;
4272+ }
4273+
4274+ int64_t pairLossBestCollisionId = -1 ;
4275+ int pairLossLargestNContributors = -1 ;
4276+ for (auto const & collision : recCollisions) {
4277+ if (collision.numContrib () > pairLossLargestNContributors) {
4278+ pairLossLargestNContributors = collision.numContrib ();
4279+ pairLossBestCollisionId = collision.globalIndex ();
4280+ }
4281+ }
4282+ if (pairLossBestCollisionId < 0 ) {
4283+ return ;
4284+ }
4285+
4286+ std::unordered_set<int64_t > pairLossAnyTrackMcParticleIds;
4287+ for (auto const & collision : recCollisions) {
4288+ const auto trackSlice = tracks.sliceBy (pairLossTracksPerCollision, collision.globalIndex ());
4289+ for (auto const & track : trackSlice) {
4290+ if (track.has_mcParticle ()) {
4291+ pairLossAnyTrackMcParticleIds.insert (track.mcParticleId ());
4292+ }
4293+ }
4294+ }
4295+
4296+ for (auto const & collision : recCollisions) {
4297+ if (static_cast <int64_t >(collision.globalIndex ()) != pairLossBestCollisionId) {
4298+ continue ;
4299+ }
4300+
4301+ const bool collisionSelected = !pairLossK0Configurations.applyRecoEventSelection ||
4302+ (masterConfigurations.doPPAnalysis ? isCollisionSelected (collision) : isCollisionSelectedPbPb (collision, false ));
4303+ if (!collisionSelected) {
4304+ return ;
4305+ }
4306+
4307+ const float pairLossBestCollisionVtxZ = collision.posZ ();
4308+ const float pairLossBestCollisionMultiplicity = masterConfigurations.doPPAnalysis ? collision.centFT0M () : collision.centFT0C ();
4309+ std::vector<PairLossTruthTrackInfo> pairLossTruthTriggers;
4310+ std::vector<PairLossTruthK0Info> pairLossTruthK0s;
4311+
4312+ for (auto const & mcParticle : mcParticles) {
4313+ if (isPairLossTriggerPdg (mcParticle.pdgCode ()) && std::abs (mcParticle.eta ()) <= etaSel &&
4314+ mcParticle.pt () >= axisRanges[3 ][0 ] && mcParticle.pt () <= axisRanges[3 ][1 ] &&
4315+ (!masterConfigurations.doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary ())) {
4316+ auto const * pdgParticle = pdgDB->GetParticle (mcParticle.pdgCode ());
4317+ const double charge = pdgParticle != nullptr ? pdgParticle->Charge () : 0.0 ;
4318+ const int sign = charge > 0.0 ? 1 : (charge < 0.0 ? -1 : 0 );
4319+ if (!((triggerParticleCharge > 0 && sign < 0 ) || (triggerParticleCharge < 0 && sign > 0 ) || sign == 0 )) {
4320+ pairLossTruthTriggers.push_back (PairLossTruthTrackInfo{
4321+ .globalIndex = static_cast <int64_t >(mcParticle.globalIndex ()),
4322+ .pt = mcParticle.pt (),
4323+ .eta = mcParticle.eta (),
4324+ .phi = mcParticle.phi (),
4325+ .sign = sign});
4326+ }
4327+ }
4328+
4329+ if (mcParticle.pdgCode () != PDG_t::kK0Short || std::abs (mcParticle.eta ()) > etaSel ||
4330+ mcParticle.pt () < axisRanges[2 ][0 ] || mcParticle.pt () > axisRanges[2 ][1 ] ||
4331+ (doAssocPhysicalPrimary && !mcParticle.isPhysicalPrimary ())) {
4332+ continue ;
4333+ }
4334+
4335+ PairLossTruthK0Info truthK0{
4336+ .globalIndex = static_cast <int64_t >(mcParticle.globalIndex ()),
4337+ .pt = mcParticle.pt (),
4338+ .eta = mcParticle.eta (),
4339+ .phi = mcParticle.phi (),
4340+ .decayRadius = -1 .0f ,
4341+ .findable = false ,
4342+ .positiveDaughter = {},
4343+ .negativeDaughter = {}};
4344+ for (auto const & daughter : mcParticle.daughters_as <aod::McParticles>()) {
4345+ PairLossTruthTrackInfo daughterInfo{
4346+ .globalIndex = static_cast <int64_t >(daughter.globalIndex ()),
4347+ .pt = daughter.pt (),
4348+ .eta = daughter.eta (),
4349+ .phi = daughter.phi (),
4350+ .sign = daughter.pdgCode () > 0 ? 1 : -1 };
4351+ if (daughter.pdgCode () == PDG_t::kPiPlus ) {
4352+ truthK0.positiveDaughter = daughterInfo;
4353+ } else if (daughter.pdgCode () == -PDG_t::kPiPlus ) {
4354+ truthK0.negativeDaughter = daughterInfo;
4355+ }
4356+ }
4357+ pairLossTruthK0s.push_back (truthK0);
4358+ }
4359+
4360+ if (useTheLeadingParticleAsTrigger && pairLossTruthTriggers.size () > 1 ) {
4361+ const auto leadingTrigger = std::max_element (pairLossTruthTriggers.begin (), pairLossTruthTriggers.end (), [](auto const & lhs, auto const & rhs) { return lhs.pt < rhs.pt ; });
4362+ const auto leadingTriggerCopy = *leadingTrigger;
4363+ pairLossTruthTriggers.clear ();
4364+ pairLossTruthTriggers.push_back (leadingTriggerCopy);
4365+ }
4366+
4367+ for (auto const & truthTrigger : pairLossTruthTriggers) {
4368+ histos.fill (HIST (" ClosureTest/PairLossK0/Truth/hTrigger" ), truthTrigger.pt , truthTrigger.eta , truthTrigger.phi );
4369+ if (pairLossAnyTrackMcParticleIds.find (truthTrigger.globalIndex ) != pairLossAnyTrackMcParticleIds.end ()) {
4370+ histos.fill (HIST (" ClosureTest/PairLossK0/AnyTrack/hTrigger" ), truthTrigger.pt , truthTrigger.eta , truthTrigger.phi );
4371+ }
4372+ }
4373+ for (auto const & truthK0 : pairLossTruthK0s) {
4374+ // The any-track stage adds no K0 requirement, so its object-level K0
4375+ // spectrum is intentionally identical to the truth-stage spectrum.
4376+ histos.fill (HIST (" ClosureTest/PairLossK0/Truth/hK0Short" ), truthK0.pt , truthK0.eta , truthK0.phi );
4377+ histos.fill (HIST (" ClosureTest/PairLossK0/AnyTrack/hK0Short" ), truthK0.pt , truthK0.eta , truthK0.phi );
4378+ }
4379+
4380+ for (auto const & truthTrigger : pairLossTruthTriggers) {
4381+ const bool triggerHasAnyTrack = pairLossAnyTrackMcParticleIds.find (truthTrigger.globalIndex ) != pairLossAnyTrackMcParticleIds.end ();
4382+ for (auto const & truthK0 : pairLossTruthK0s) {
4383+ if (truthTrigger.globalIndex == truthK0.positiveDaughter .globalIndex || truthTrigger.globalIndex == truthK0.negativeDaughter .globalIndex ) {
4384+ continue ;
4385+ }
4386+ const float truthDeltaPhi = computeDeltaPhi (truthTrigger.phi , truthK0.phi );
4387+ float truthDeltaEta = truthTrigger.eta - truthK0.eta ;
4388+ if (masterConfigurations.doMirroringInDelataEta ) {
4389+ truthDeltaEta = std::abs (truthDeltaEta);
4390+ }
4391+ if (truthDeltaPhi < axisRanges[0 ][0 ] || truthDeltaPhi > axisRanges[0 ][1 ] ||
4392+ truthDeltaEta < axisRanges[1 ][0 ] || truthDeltaEta > axisRanges[1 ][1 ]) {
4393+ continue ;
4394+ }
4395+
4396+ histos.fill (HIST (" ClosureTest/PairLossK0/Truth/sameEvent/K0Short" ), truthDeltaPhi, truthDeltaEta, truthK0.pt , truthTrigger.pt , pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity);
4397+ if (triggerHasAnyTrack) {
4398+ histos.fill (HIST (" ClosureTest/PairLossK0/AnyTrack/sameEvent/K0Short" ), truthDeltaPhi, truthDeltaEta, truthK0.pt , truthTrigger.pt , pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity);
4399+ }
4400+ }
4401+ }
4402+ return ;
4403+ }
4404+ };
4405+ fillPairLossK0TruthAndAnyTrack ();
4406+
42574407 std::vector<uint32_t > triggerIndices;
42584408 std::vector<std::vector<uint32_t >> associatedIndices;
42594409 std::vector<uint32_t > assocHadronIndices;
0 commit comments