@@ -129,6 +129,7 @@ struct HStrangeCorrelation {
129129 Configurable<bool > selectINELgtONE{" selectINELgtONE" , false , " select INEL>1 events (at least 2 charged particles in |eta| < 1)" };
130130 Configurable<float > zVertexCut{" zVertexCut" , 10 , " Cut on PV position" };
131131 Configurable<bool > requireAllGoodITSLayers{" requireAllGoodITSLayers" , false , " require that in the event all ITS are good" };
132+ Configurable<bool > rejectSameBunchPileup{" rejectSameBunchPileup" , false , " reject collisions associated with the same found-by-T0 bunch crossing" };
132133 Configurable<bool > requireGoodTriggerTVX{" requireGoodTriggerTVX" , false , " require acceptable FT0C-FT0A time difference" };
133134 Configurable<bool > requireGoodZvtxFT0vsPV{" requireGoodZvtxFT0vsPV" , false , " require small difference between z-vertex from PV and from FT0" };
134135 Configurable<bool > skipUnderOverflowInTHn{" skipUnderOverflowInTHn" , false , " skip under/overflow in THns" };
@@ -3227,6 +3228,10 @@ struct HStrangeCorrelation {
32273228 if (!collision.sel8 ()) {
32283229 return false ;
32293230 }
3231+ if (!collision.selection_bit (aod::evsel::kIsTriggerTVX ) && masterConfigurations.requireGoodTriggerTVX ) {
3232+ // FT0 vertex (acceptable FT0C-FT0A time difference) collisions
3233+ return false ;
3234+ }
32303235 if (std::abs (collision.posZ ()) > masterConfigurations.zVertexCut ) {
32313236 return false ;
32323237 }
@@ -3242,6 +3247,15 @@ struct HStrangeCorrelation {
32423247 if (!collision.selection_bit (aod::evsel::kIsGoodITSLayersAll ) && masterConfigurations.requireAllGoodITSLayers ) {
32433248 return false ;
32443249 }
3250+ if (!collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV ) && masterConfigurations.requireGoodZvtxFT0vsPV ) {
3251+ // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference
3252+ // use this cut at low multiplicities with caution
3253+ return false ;
3254+ }
3255+ if (!collision.selection_bit (o2::aod::evsel::kNoSameBunchPileup ) && masterConfigurations.rejectSameBunchPileup ) {
3256+ // rejects collisions which are associated with the same "found-by-T0" bunch crossing
3257+ return false ;
3258+ }
32453259 if (zorroMask.value != " " ) {
32463260 auto bc = collision.template bc_as <aod::BCsWithTimestamps>();
32473261 initZorro (bc);
@@ -4195,6 +4209,9 @@ struct HStrangeCorrelation {
41954209 bool bestCollisionSel8 = false ;
41964210 bool bestCollisionINELgtZERO = false ;
41974211 bool bestCollisionINELgtONE = false ;
4212+ bool bestCollisionNoSameBunchPileup = false ;
4213+ bool bestCollisionGoodTriggerTVX = false ;
4214+ bool bestCollisionGoodZvtxFT0vsPV = false ;
41984215 bool isCollisionSelect = false ;
41994216 uint32_t bestCollisionTriggerPresenceMap = 0 ;
42004217
@@ -4211,6 +4228,9 @@ struct HStrangeCorrelation {
42114228 bestCollisionVtxZ = collision.posZ ();
42124229 bestCollisionINELgtZERO = collision.isInelGt0 ();
42134230 bestCollisionINELgtONE = collision.isInelGt1 ();
4231+ bestCollisionNoSameBunchPileup = collision.selection_bit (o2::aod::evsel::kNoSameBunchPileup );
4232+ bestCollisionGoodTriggerTVX = collision.selection_bit (aod::evsel::kIsTriggerTVX );
4233+ bestCollisionGoodZvtxFT0vsPV = collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV );
42144234 }
42154235 if (triggerPresenceMap.size () > 0 ) {
42164236 bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex ()];
@@ -4262,6 +4282,15 @@ struct HStrangeCorrelation {
42624282 if (masterConfigurations.selectINELgtONE && !bestCollisionINELgtONE) {
42634283 return ;
42644284 }
4285+ if (masterConfigurations.rejectSameBunchPileup && !bestCollisionNoSameBunchPileup) {
4286+ return ;
4287+ }
4288+ if (masterConfigurations.requireGoodTriggerTVX && !bestCollisionGoodTriggerTVX) {
4289+ return ;
4290+ }
4291+ if (masterConfigurations.requireGoodZvtxFT0vsPV && !bestCollisionGoodZvtxFT0vsPV) {
4292+ return ;
4293+ }
42654294 }
42664295
42674296 histos.fill (HIST (" hClosureTestEventCounter" ), 3 .5f );
@@ -4706,6 +4735,9 @@ struct HStrangeCorrelation {
47064735 bool genBestCollisionSel8 = false ;
47074736 bool genBestCollisionINELgtZERO = false ;
47084737 bool genBestCollisionINELgtONE = false ;
4738+ bool genBestCollisionNoSameBunchPileup = false ;
4739+ bool genBestCollisionGoodTriggerTVX = false ;
4740+ bool genBestCollisionGoodZvtxFT0vsPV = false ;
47094741 bool genCollisionSelected = false ;
47104742 int genLargestNContributors = -1 ;
47114743 uint32_t genBestCollisionTriggerPresenceMap = 0 ;
@@ -4723,6 +4755,9 @@ struct HStrangeCorrelation {
47234755 genBestCollisionVtxZ = recCollision.posZ ();
47244756 genBestCollisionINELgtZERO = recCollision.isInelGt0 ();
47254757 genBestCollisionINELgtONE = recCollision.isInelGt1 ();
4758+ genBestCollisionNoSameBunchPileup = recCollision.selection_bit (o2::aod::evsel::kNoSameBunchPileup );
4759+ genBestCollisionGoodTriggerTVX = recCollision.selection_bit (aod::evsel::kIsTriggerTVX );
4760+ genBestCollisionGoodZvtxFT0vsPV = recCollision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV );
47264761 }
47274762 if (triggerPresenceMap.size () > 0 ) {
47284763 genBestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex ()];
@@ -4734,6 +4769,9 @@ struct HStrangeCorrelation {
47344769 } else if (masterConfigurations.doGenEventSelection ) {
47354770 genEventSelected = genEventSelected && genBestCollisionSel8 && std::abs (genBestCollisionVtxZ) <= masterConfigurations.zVertexCut &&
47364771 genBestCollisionINELgtZERO && (!masterConfigurations.selectINELgtONE || genBestCollisionINELgtONE) &&
4772+ (!masterConfigurations.rejectSameBunchPileup || genBestCollisionNoSameBunchPileup) &&
4773+ (!masterConfigurations.requireGoodTriggerTVX || genBestCollisionGoodTriggerTVX) &&
4774+ (!masterConfigurations.requireGoodZvtxFT0vsPV || genBestCollisionGoodZvtxFT0vsPV) &&
47374775 genBestCollisionMultiplicity >= axisRanges[5 ][0 ] && genBestCollisionMultiplicity <= axisRanges[5 ][1 ];
47384776 }
47394777
@@ -5660,21 +5698,19 @@ struct HStrangeCorrelation {
56605698 // recomputed from raw tracks so that this stage cannot drift away from the
56615699 // reconstructed analysis it exists to be compared against.
56625700 //
5663- // The sets are built per reconstructed collision and a pair is required to be
5664- // final within one and the same collision: the reconstructed same-event
5665- // correlation only ever pairs a trigger with a V0 sitting in the same vertex,
5666- // so a pair split across two reconstructed vertices of one MC collision must
5667- // not count as final here either.
5668- //
5669- // N.B.: the reconstructed autocorrelation rejection (trigger track identical
5670- // to a V0 daughter track) is deliberately not replicated. It is a no-op as
5671- // soon as the trigger is required to be a physical primary, because
5672- // mcTrue(IndexK0) forces the daughters to be genuine -- hence secondary --
5673- // K0 decay products.
5674- std::vector<std::pair<std::unordered_set<int64_t >, std::unordered_set<int64_t >>> pairLossFinalPerCollision;
5701+ // The stage is restricted to the best reconstructed collision and keeps the
5702+ // reconstructed kinematics of every matched object, so that the pair test below
5703+ // can also impose the reconstructed-coordinate angular range and the
5704+ // reconstructed autocorrelation rejection. Both are conditions the reconstructed
5705+ // same-event correlation imposes as well, so this Final stage is by construction
5706+ // the same object as PairLossK0/Comparison/Final: the truth pairs that really do
5707+ // end up in the reconstructed correlation.
5708+ PairLossTrackMap pairLossFinalTriggers;
5709+ PairLossV0Map pairLossFinalV0s;
56755710 for (auto const & collision : recCollisions) {
5676- std::unordered_set<int64_t > finalTriggerMcIds;
5677- std::unordered_set<int64_t > finalK0McIds;
5711+ if (static_cast <int64_t >(collision.globalIndex ()) != pairLossBestCollisionId) {
5712+ continue ;
5713+ }
56785714
56795715 const auto finalTriggerSlice = triggerTracks.sliceBy (collisionSliceTracks, collision.globalIndex ());
56805716 for (auto const & triggerEntry : finalTriggerSlice) {
@@ -5691,7 +5727,7 @@ struct HStrangeCorrelation {
56915727 if (masterConfigurations.doTriggPhysicalPrimary && !triggerEntry.mcPhysicalPrimary ()) {
56925728 continue ;
56935729 }
5694- finalTriggerMcIds. insert ( track.mcParticleId ());
5730+ pairLossFinalTriggers[ track.mcParticleId ()]. push_back ( makePairLossTrackInfo (track ));
56955731 }
56965732
56975733 const auto finalV0Slice = associatedV0s.sliceBy (collisionSliceV0s, collision.globalIndex ());
@@ -5735,34 +5771,54 @@ struct HStrangeCorrelation {
57355771 if (!passesFinalSelection) {
57365772 continue ;
57375773 }
5738- finalK0McIds.insert (v0MC.particleIdMC ());
5774+ pairLossFinalV0s[v0MC.particleIdMC ()].push_back (PairLossV0Info{
5775+ .globalIndex = static_cast <int64_t >(v0.globalIndex ()),
5776+ .positiveTrackId = static_cast <int64_t >(positiveTrack.globalIndex ()),
5777+ .negativeTrackId = static_cast <int64_t >(negativeTrack.globalIndex ()),
5778+ .pt = v0.pt (),
5779+ .eta = v0.eta (),
5780+ .phi = v0.phi (),
5781+ .radius = v0.v0radius (),
5782+ .cosPA = v0.v0cosPA (),
5783+ .dcaDaughters = v0.dcaV0daughters (),
5784+ .massNSigma = assocEntry.invMassNSigma (IndexK0)});
57395785 }
5740-
5741- pairLossFinalPerCollision.emplace_back (std::move (finalTriggerMcIds), std::move (finalK0McIds));
57425786 }
57435787
5744- // Object-level membership, used only for the single-particle spectra: at
5745- // least one collision in which the object is fully selected. The pair
5746- // histogram uses pairLossHasFinalPair() instead, which is stricter.
5788+ // Object-level membership, used only for the single-particle spectra: the object
5789+ // has a fully selected reconstructed counterpart in the best collision. The pair
5790+ // histogram uses pairLossHasFinalPair() instead, which is stricter: it also
5791+ // requires the reconstructed pair itself to fall in the reconstructed angular
5792+ // range and to survive the reconstructed autocorrelation rejection.
57475793 auto pairLossHasFinalTrigger = [&](int64_t mcId) {
5748- for (auto const & perCollision : pairLossFinalPerCollision) {
5749- if (perCollision.first .count (mcId) > 0 ) {
5750- return true ;
5751- }
5752- }
5753- return false ;
5794+ return pairLossFinalTriggers.find (mcId) != pairLossFinalTriggers.end ();
57545795 };
57555796 auto pairLossHasFinalK0 = [&](int64_t mcId) {
5756- for (auto const & perCollision : pairLossFinalPerCollision) {
5757- if (perCollision.second .count (mcId) > 0 ) {
5758- return true ;
5759- }
5760- }
5761- return false ;
5797+ return pairLossFinalV0s.find (mcId) != pairLossFinalV0s.end ();
57625798 };
57635799 auto pairLossHasFinalPair = [&](int64_t triggerMcId, int64_t k0McId) {
5764- for (auto const & perCollision : pairLossFinalPerCollision) {
5765- if (perCollision.first .count (triggerMcId) > 0 && perCollision.second .count (k0McId) > 0 ) {
5800+ const auto triggerMatches = pairLossFinalTriggers.find (triggerMcId);
5801+ if (triggerMatches == pairLossFinalTriggers.end ()) {
5802+ return false ;
5803+ }
5804+ const auto v0Matches = pairLossFinalV0s.find (k0McId);
5805+ if (v0Matches == pairLossFinalV0s.end ()) {
5806+ return false ;
5807+ }
5808+ for (auto const & reconstructedTrigger : triggerMatches->second ) {
5809+ for (auto const & reconstructedV0 : v0Matches->second ) {
5810+ float reconstructedDeltaEta = reconstructedTrigger.eta - reconstructedV0.eta ;
5811+ if (masterConfigurations.doMirroringInDelataEta ) {
5812+ reconstructedDeltaEta = std::abs (reconstructedDeltaEta);
5813+ }
5814+ const float reconstructedDeltaPhi = computeDeltaPhi (reconstructedTrigger.phi , reconstructedV0.phi );
5815+ if (reconstructedDeltaPhi < axisRanges[0 ][0 ] || reconstructedDeltaPhi > axisRanges[0 ][1 ] ||
5816+ reconstructedDeltaEta < axisRanges[1 ][0 ] || reconstructedDeltaEta > axisRanges[1 ][1 ]) {
5817+ continue ;
5818+ }
5819+ if (doAutocorrelationRejection && (reconstructedTrigger.globalIndex == reconstructedV0.positiveTrackId || reconstructedTrigger.globalIndex == reconstructedV0.negativeTrackId )) {
5820+ continue ;
5821+ }
57665822 return true ;
57675823 }
57685824 }
@@ -5960,6 +6016,9 @@ struct HStrangeCorrelation {
59606016 bool bestCollisionSel8 = false ;
59616017 bool bestCollisionINELgtZERO = false ;
59626018 bool bestCollisionINELgtONE = false ;
6019+ bool bestCollisionNoSameBunchPileup = false ;
6020+ bool bestCollisionGoodTriggerTVX = false ;
6021+ bool bestCollisionGoodZvtxFT0vsPV = false ;
59636022 bool isCollisionSelect = false ;
59646023 int biggestNContribs = -1 ;
59656024 uint32_t bestCollisionTriggerPresenceMap = 0 ;
@@ -5975,6 +6034,9 @@ struct HStrangeCorrelation {
59756034 bestCollisionVtxZ = recCollision.posZ ();
59766035 bestCollisionINELgtZERO = recCollision.isInelGt0 ();
59776036 bestCollisionINELgtONE = recCollision.isInelGt1 ();
6037+ bestCollisionNoSameBunchPileup = recCollision.selection_bit (o2::aod::evsel::kNoSameBunchPileup );
6038+ bestCollisionGoodTriggerTVX = recCollision.selection_bit (aod::evsel::kIsTriggerTVX );
6039+ bestCollisionGoodZvtxFT0vsPV = recCollision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV );
59786040 }
59796041 if (triggerPresenceMap.size () > 0 ) {
59806042 bestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex ()];
@@ -6005,6 +6067,15 @@ struct HStrangeCorrelation {
60056067 if (masterConfigurations.selectINELgtONE && !bestCollisionINELgtONE) {
60066068 return ;
60076069 }
6070+ if (masterConfigurations.rejectSameBunchPileup && !bestCollisionNoSameBunchPileup) {
6071+ return ;
6072+ }
6073+ if (masterConfigurations.requireGoodTriggerTVX && !bestCollisionGoodTriggerTVX) {
6074+ return ;
6075+ }
6076+ if (masterConfigurations.requireGoodZvtxFT0vsPV && !bestCollisionGoodZvtxFT0vsPV) {
6077+ return ;
6078+ }
60086079 if (bestCollisionCentpercentile > axisRanges[5 ][1 ] || bestCollisionCentpercentile < axisRanges[5 ][0 ]) {
60096080 return ;
60106081 }
0 commit comments