diff --git a/PWGCF/Femto/Core/closeTripletRejection.h b/PWGCF/Femto/Core/closeTripletRejection.h index 20a68f86cfe..3a2ad4c6847 100644 --- a/PWGCF/Femto/Core/closeTripletRejection.h +++ b/PWGCF/Femto/Core/closeTripletRejection.h @@ -29,10 +29,13 @@ namespace o2::analysis::femto::closetripletrejection constexpr const char PrefixCtrTrackTrackTrack[] = "CtrTrackTrackTrack"; constexpr const char PrefixCtrTrackTrackV0[] = "CtrTrackTrackV0"; constexpr const char PrefixCtrTrackTrackCascade[] = "CtrTrackTrackCascade"; +constexpr const char PrefixCtrMcParticleMcParticleMcParticle[] = "CtrMcParticleMcParticleMcParticle"; using ConfCtrTrackTrackTrack = closepairrejection::ConfCpr; using ConfCtrTrackTrackV0 = closepairrejection::ConfCpr; using ConfCtrTrackTrackCascade = closepairrejection::ConfCpr; +// generated particles, no cut by default (close triplet rejection corrects a detector effect) +using ConfCtrMcParticleMcParticleMcParticle = closepairrejection::ConfCpr; // directory names constexpr char PrefixTrack1Track2Se[] = "CPR_Track1Track2/SE/"; @@ -42,6 +45,13 @@ constexpr char PrefixTrack1Track2Me[] = "CPR_Track1Track2/ME/"; constexpr char PrefixTrack2Track3Me[] = "CPR_Track2Track3/ME/"; constexpr char PrefixTrack1Track3Me[] = "CPR_Track1Track3/ME/"; +constexpr char PrefixMcParticle1McParticle2Se[] = "CPR_McParticle1McParticle2/SE/"; +constexpr char PrefixMcParticle2McParticle3Se[] = "CPR_McParticle2McParticle3/SE/"; +constexpr char PrefixMcParticle1McParticle3Se[] = "CPR_McParticle1McParticle3/SE/"; +constexpr char PrefixMcParticle1McParticle2Me[] = "CPR_McParticle1McParticle2/ME/"; +constexpr char PrefixMcParticle2McParticle3Me[] = "CPR_McParticle2McParticle3/ME/"; +constexpr char PrefixMcParticle1McParticle3Me[] = "CPR_McParticle1McParticle3/ME/"; + constexpr char PrefixTrack1V0Se[] = "CPR_Track1V0/SE/"; constexpr char PrefixTrack2V0Se[] = "CPR_Track2V0/SE/"; constexpr char PrefixTrack1V0Me[] = "CPR_Track1V0/ME/"; @@ -205,5 +215,40 @@ class CloseTripletRejectionTrackTrackCascade closepairrejection::ClosePairRejectionTrackCascade mCtrTrack2Cascade; }; +// close triplet rejection for triplets of generated particles; checks all three constituent pairs +template +class CloseTripletRejectionMcParticleMcParticleMcParticle +{ + public: + CloseTripletRejectionMcParticleMcParticleMcParticle() = default; + ~CloseTripletRejectionMcParticleMcParticleMcParticle() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specs, + T const& confCpr) + { + mCtr12.init(registry, specs, confCpr); + mCtr23.init(registry, specs, confCpr); + mCtr13.init(registry, specs, confCpr); + } + + template + [[nodiscard]] bool isCloseTriplet(T1 const& particle1, T2 const& particle2, T3 const& particle3, T4 const& tripletHistManager) + { + bool isClose12 = mCtr12.isClosePair(particle1, particle2, tripletHistManager); + bool isClose23 = mCtr23.isClosePair(particle2, particle3, tripletHistManager); + bool isClose13 = mCtr13.isClosePair(particle1, particle3, tripletHistManager); + return isClose12 || isClose23 || isClose13; + } + + private: + closepairrejection::ClosePairRejectionMcParticleMcParticle mCtr12; + closepairrejection::ClosePairRejectionMcParticleMcParticle mCtr23; + closepairrejection::ClosePairRejectionMcParticleMcParticle mCtr13; +}; + } // namespace o2::analysis::femto::closetripletrejection #endif // PWGCF_FEMTO_CORE_CLOSETRIPLETREJECTION_H_ diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index e722e70d780..7935ebbb2ad 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -122,9 +122,11 @@ struct ConfMcParticleSelection : o2::framework::ConfigurableGroup { constexpr const char PrefixMcParticleSelection1[] = "McParticleSelection1"; constexpr const char PrefixMcParticleSelection2[] = "McParticleSelection2"; +constexpr const char PrefixMcParticleSelection3[] = "McParticleSelection3"; using ConfMcParticleSelection1 = ConfMcParticleSelection; using ConfMcParticleSelection2 = ConfMcParticleSelection; +using ConfMcParticleSelection3 = ConfMcParticleSelection; class McBuilder { diff --git a/PWGCF/Femto/Core/mcParticleHistManager.h b/PWGCF/Femto/Core/mcParticleHistManager.h index b226e10459a..641558589f5 100644 --- a/PWGCF/Femto/Core/mcParticleHistManager.h +++ b/PWGCF/Femto/Core/mcParticleHistManager.h @@ -84,9 +84,11 @@ struct ConfMcParticleBinning : o2::framework::ConfigurableGroup { constexpr const char PrefixMcParticleBinning1[] = "McParticleBinning1"; constexpr const char PrefixMcParticleBinning2[] = "McParticleBinning2"; +constexpr const char PrefixMcParticleBinning3[] = "McParticleBinning3"; using ConfMcParticleBinning1 = ConfMcParticleBinning; using ConfMcParticleBinning2 = ConfMcParticleBinning; +using ConfMcParticleBinning3 = ConfMcParticleBinning; // the enum gives the correct index in the array constexpr std::array, kMcParticleHistLast> @@ -144,6 +146,7 @@ auto makeMcParticleHistSpecMap(const T& confBinning) inline constexpr char PrefixMcParticle1[] = "McParticle1/"; inline constexpr char PrefixMcParticle2[] = "McParticle2/"; +inline constexpr char PrefixMcParticle3[] = "McParticle3/"; constexpr std::string_view McDir = "MC/"; diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 5f2a285f3ec..c2fef5d2659 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -760,6 +760,14 @@ class PairHistManager mTrueMinv = getMinv(mTrueParticle1, mTrueParticle2); mTrueKstar = getKstar(mTrueParticle1, mTrueParticle2); + // in the pure mc-truth path there is no reco counterpart, so the generated values are also + // stored in the reco members; they are used by getKinematic(), i.e. by the kinematic histograms + // of the pair cleaner and of the close pair rejection + mKt = mTrueKt; + mMt = mTrueMt; + mMassInv = mTrueMinv; + mKstar = mTrueKstar; + if (mPlotBertschPratt) { std::tie(mTrueQout, mTrueQside, mTrueQlong) = computeBertschPrattLCMS(mTrueParticle1, mTrueParticle2); } @@ -787,6 +795,20 @@ class PairHistManager mTrueCent = 0.5f * (col1.cent() + col2.cent()); } + /// pair cuts on the mc-truth values, for the pure mc-truth path (kMc without kReco), + /// where the reco values are never set + bool checkPairCutsMcTruth() const + { + return (!(mKstarMin > 0.f) || mTrueKstar > mKstarMin) && + (!(mKstarMax > 0.f) || mTrueKstar < mKstarMax) && + (!(mKtMin > 0.f) || mTrueKt > mKtMin) && + (!(mKtMax > 0.f) || mTrueKt < mKtMax) && + (!(mMtMin > 0.f) || mTrueMt > mMtMin) && + (!(mMtMax > 0.f) || mTrueMt < mMtMax) && + (!(mMassInvMin > 0.f) || mTrueMinv > mMassInvMin) && + (!(mMassInvMax > 0.f) || mTrueMinv < mMassInvMax); + } + bool checkPairCuts() const { return (!(mKstarMin > 0.f) || mKstar > mKstarMin) && diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index 0df4aa3853d..70c681c78a1 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -341,7 +341,7 @@ bool processSameEvent(T1 const& SliceParticle, if (CprManager.isClosePair(p1, p2, PairHistManager)) { continue; } - if (PairHistManager.checkPairCuts()) { + if (PairHistManager.checkPairCutsMcTruth()) { PairHistManager.template fill(); PairHistManager.trackParticlesPerEvent(p1, p2); foundPair = true; @@ -408,7 +408,7 @@ bool processSameEvent(T1 const& SliceParticle1, if (CprManager.isClosePair(p1, p2, PairHistManager)) { continue; } - if (PairHistManager.checkPairCuts()) { + if (PairHistManager.checkPairCutsMcTruth()) { PairHistManager.template fill(); PairHistManager.trackParticlesPerEvent(p1, p2); foundPair = true; @@ -714,7 +714,7 @@ void processMixedEvent(T1 const& Collisions, continue; } - if (PairHistManager.checkPairCuts()) { + if (PairHistManager.checkPairCutsMcTruth()) { hasValidPair = true; PairHistManager.trackParticlesPerEvent(p1, p2); PairHistManager.template fill(); diff --git a/PWGCF/Femto/Core/particleCleaner.h b/PWGCF/Femto/Core/particleCleaner.h index 57c61cd11ba..6c29b6ced89 100644 --- a/PWGCF/Femto/Core/particleCleaner.h +++ b/PWGCF/Femto/Core/particleCleaner.h @@ -85,8 +85,10 @@ using ConfOmegaCleaner2 = ConfParticleCleaner; constexpr const char PrefixMcParticleCleaner1[] = "McParticleCleaner1"; constexpr const char PrefixMcParticleCleaner2[] = "McParticleCleaner2"; +constexpr const char PrefixMcParticleCleaner3[] = "McParticleCleaner3"; using ConfMcParticleCleaner1 = ConfParticleCleaner; using ConfMcParticleCleaner2 = ConfParticleCleaner; +using ConfMcParticleCleaner3 = ConfParticleCleaner; class ParticleCleaner { diff --git a/PWGCF/Femto/Core/tripletBuilder.h b/PWGCF/Femto/Core/tripletBuilder.h index 048b60abd94..1f4c704a67b 100644 --- a/PWGCF/Femto/Core/tripletBuilder.h +++ b/PWGCF/Femto/Core/tripletBuilder.h @@ -19,6 +19,7 @@ #include "PWGCF/Femto/Core/cascadeHistManager.h" #include "PWGCF/Femto/Core/closeTripletRejection.h" #include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/mcParticleHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" @@ -962,6 +963,200 @@ class TripletTrackTrackCascadeBuilder std::uniform_int_distribution<> mDist; }; +// builder for triplets of generated particles (mc truth only, kMc without kReco) +// covers all triplet types, since e.g. a lambda is just another mc particle +template +class TripletMcParticleMcParticleMcParticleBuilder +{ + public: + TripletMcParticleMcParticleMcParticleBuilder() = default; + ~TripletMcParticleMcParticleMcParticleBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confCollisionBinning, + T2 const& confMcParticleSelection1, + T3 const& confMcParticleSelection2, + T4 const& confMcParticleSelection3, + T5 const& confMcParticleBinning1, + T6 const& confMcParticleBinning2, + T7 const& confMcParticleBinning3, + T8 const& confMcParticleCleaner1, + T9 const& confMcParticleCleaner2, + T10 const& confMcParticleCleaner3, + T11 const& confCtr, + T12 const& confMixing, + T13 const& confTripletBinning, + T14 const& confTripletCuts, + std::map> const& colHistSpec, + std::map> const& mcParticleHistSpec1, + std::map> const& mcParticleHistSpec2, + std::map> const& mcParticleHistSpec3, + std::map> const& tripletHistSpec, + std::map> const& ctrHistSpec, + std::map> const& tripletCleanerHistSpec) + { + mParticle1Particle2Particle3AreSameSpecies = confMixing.particle123AreSameSpecies.value; + mParticle1Particle2AreSameSpecies = confMixing.particle12AreSameSpecies.value; + if (mParticle1Particle2Particle3AreSameSpecies && mParticle1Particle2AreSameSpecies) { + LOG(fatal) << "Option Particle 1&2 are identical and Option Particle 1&2&3 are identical are activated. Breaking..."; + } + + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); + mTripletHistManagerSe.template init(registry, tripletHistSpec, confTripletBinning, confTripletCuts, confMixing); + mTripletHistManagerMe.template init(registry, tripletHistSpec, confTripletBinning, confTripletCuts, confMixing); + + mTcSe.template init(registry, tripletCleanerHistSpec, confTripletCuts); + mTcMe.template init(registry, tripletCleanerHistSpec, confTripletCuts); + + mCtrSe.init(registry, ctrHistSpec, confCtr); + mCtrMe.init(registry, ctrHistSpec, confCtr); + + // generated particles carry the true pt, so the charge is always 1 here + if (mParticle1Particle2Particle3AreSameSpecies) { + mMcParticleCleaner1.init(confMcParticleCleaner1); + mMcParticleHistManager1.init(registry, mcParticleHistSpec1, confMcParticleBinning1); + mTripletHistManagerSe.setMass(confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection1.pdgCodeAbs.value); + mTripletHistManagerMe.setMass(confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection1.pdgCodeAbs.value); + } else if (mParticle1Particle2AreSameSpecies) { + mMcParticleCleaner1.init(confMcParticleCleaner1); + mMcParticleCleaner3.init(confMcParticleCleaner3); + mMcParticleHistManager1.init(registry, mcParticleHistSpec1, confMcParticleBinning1); + mMcParticleHistManager3.init(registry, mcParticleHistSpec3, confMcParticleBinning3); + mTripletHistManagerSe.setMass(confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection3.pdgCodeAbs.value); + mTripletHistManagerMe.setMass(confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection3.pdgCodeAbs.value); + } else { + mMcParticleCleaner1.init(confMcParticleCleaner1); + mMcParticleCleaner2.init(confMcParticleCleaner2); + mMcParticleCleaner3.init(confMcParticleCleaner3); + mMcParticleHistManager1.init(registry, mcParticleHistSpec1, confMcParticleBinning1); + mMcParticleHistManager2.init(registry, mcParticleHistSpec2, confMcParticleBinning2); + mMcParticleHistManager3.init(registry, mcParticleHistSpec3, confMcParticleBinning3); + mTripletHistManagerSe.setMass(confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection2.pdgCodeAbs.value, confMcParticleSelection3.pdgCodeAbs.value); + mTripletHistManagerMe.setMass(confMcParticleSelection1.pdgCodeAbs.value, confMcParticleSelection2.pdgCodeAbs.value, confMcParticleSelection3.pdgCodeAbs.value); + } + mTripletHistManagerSe.setCharge(1, 1, 1); + mTripletHistManagerMe.setCharge(1, 1, 1); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + + // setup rng if necessary + if (confMixing.seed.value >= 0) { + uint64_t randomSeed = 0; + mMixIdenticalParticles = true; + if (confMixing.seed.value == 0) { + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } else { + randomSeed = static_cast(confMixing.seed.value); + } + mRng = std::mt19937(randomSeed); + mDist = std::uniform_int_distribution(static_cast(tripletprocesshelpers::kOrder123), static_cast(tripletprocesshelpers::kOrder321)); + } + } + + /// \return true if at least one triplet passed all triplet selections (usable as triplet trigger) + template + bool processSameEvent(T1 const& mcCol, T2 const& mcParticles, T3 const& mcMothers, T4 const& mcPartonicMothers, T5& partition1, T6& partition2, T7& partition3, T8& cache) + { + tripletprocesshelpers::TripletOrder tripletOrder = tripletprocesshelpers::kOrder123; + + if (mParticle1Particle2Particle3AreSameSpecies) { + auto mcParticleSlice1 = partition1->sliceByCached(o2::aod::femtomcparticle::fMcColId, mcCol.globalIndex(), cache); + if (mcParticleSlice1.size() < nLimitPartitionIdenticalParticles123) { + return false; + } + mColHistManager.template fill(mcCol); + if (mMixIdenticalParticles) { + tripletOrder = static_cast(mDist(mRng)); + } + return tripletprocesshelpers::processSameEventMcTruth(mcParticleSlice1, mcParticles, mcMothers, mcPartonicMothers, mcCol, mMcParticleHistManager1, mTripletHistManagerSe, mMcParticleCleaner1, mCtrSe, mTcSe, tripletOrder); + } + + if (mParticle1Particle2AreSameSpecies) { + auto mcParticleSlice1 = partition1->sliceByCached(o2::aod::femtomcparticle::fMcColId, mcCol.globalIndex(), cache); + auto mcParticleSlice3 = partition3->sliceByCached(o2::aod::femtomcparticle::fMcColId, mcCol.globalIndex(), cache); + if (mcParticleSlice1.size() < nLimitPartitionIdenticalParticles12 || mcParticleSlice3.size() < nLimitPartitionParticles) { + return false; + } + mColHistManager.template fill(mcCol); + if (mMixIdenticalParticles) { + tripletOrder = static_cast(mDist(mRng)); + } + return tripletprocesshelpers::processSameEventMcTruth(mcParticleSlice1, mcParticleSlice3, mcParticles, mcMothers, mcPartonicMothers, mcCol, mMcParticleHistManager1, mMcParticleHistManager3, mTripletHistManagerSe, mMcParticleCleaner1, mMcParticleCleaner3, mCtrSe, mTcSe, tripletOrder); + } + + auto mcParticleSlice1 = partition1->sliceByCached(o2::aod::femtomcparticle::fMcColId, mcCol.globalIndex(), cache); + auto mcParticleSlice2 = partition2->sliceByCached(o2::aod::femtomcparticle::fMcColId, mcCol.globalIndex(), cache); + auto mcParticleSlice3 = partition3->sliceByCached(o2::aod::femtomcparticle::fMcColId, mcCol.globalIndex(), cache); + if (mcParticleSlice1.size() < nLimitPartitionParticles || mcParticleSlice2.size() < nLimitPartitionParticles || mcParticleSlice3.size() < nLimitPartitionParticles) { + return false; + } + mColHistManager.template fill(mcCol); + return tripletprocesshelpers::processSameEventMcTruth(mcParticleSlice1, mcParticleSlice2, mcParticleSlice3, mcParticles, mcMothers, mcPartonicMothers, mcCol, mMcParticleHistManager1, mMcParticleHistManager2, mMcParticleHistManager3, mTripletHistManagerSe, mMcParticleCleaner1, mMcParticleCleaner2, mMcParticleCleaner3, mCtrSe, mTcSe); + } + + template + void processMixedEvent(T1 const& mcCols, T2 const& mcParticles, T3 const& mcMothers, T4 const& mcPartonicMothers, T5& partition1, T6& partition2, T7& partition3, T8& cache, T9& binsVtxMult, T10& binsVtxCent, T11& binsVtxMultCent) + { + // for identical species the same partition is used several times + auto& p2 = (mParticle1Particle2Particle3AreSameSpecies || mParticle1Particle2AreSameSpecies) ? partition1 : partition2; + auto& p3 = mParticle1Particle2Particle3AreSameSpecies ? partition1 : partition3; + auto& cleaner2 = (mParticle1Particle2Particle3AreSameSpecies || mParticle1Particle2AreSameSpecies) ? mMcParticleCleaner1 : mMcParticleCleaner2; + auto& cleaner3 = mParticle1Particle2Particle3AreSameSpecies ? mMcParticleCleaner1 : mMcParticleCleaner3; + + switch (mMixingPolicy) { + case triplethistmanager::MixingPolicy::kVtxMult: + tripletprocesshelpers::processMixedEventMcTruth(mcCols, partition1, p2, p3, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mMcParticleCleaner1, cleaner2, cleaner3, mCtrMe, mTcMe); + break; + case triplethistmanager::MixingPolicy::kVtxCent: + tripletprocesshelpers::processMixedEventMcTruth(mcCols, partition1, p2, p3, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mMcParticleCleaner1, cleaner2, cleaner3, mCtrMe, mTcMe); + break; + case triplethistmanager::MixingPolicy::kVtxMultCent: + tripletprocesshelpers::processMixedEventMcTruth(mcCols, partition1, p2, p3, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mMcParticleCleaner1, cleaner2, cleaner3, mCtrMe, mTcMe); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + mcparticlehistmanager::McParticleHistManager mMcParticleHistManager1; + mcparticlehistmanager::McParticleHistManager mMcParticleHistManager2; + mcparticlehistmanager::McParticleHistManager mMcParticleHistManager3; + triplethistmanager::TripletHistManager mTripletHistManagerSe; + triplethistmanager::TripletHistManager mTripletHistManagerMe; + closetripletrejection::CloseTripletRejectionMcParticleMcParticleMcParticle mCtrSe; + closetripletrejection::CloseTripletRejectionMcParticleMcParticleMcParticle mCtrMe; + tripletcleaner::McParticleMcParticleMcParticleTripletCleaner mTcSe; + tripletcleaner::McParticleMcParticleMcParticleTripletCleaner mTcMe; + particlecleaner::ParticleCleaner mMcParticleCleaner1; + particlecleaner::ParticleCleaner mMcParticleCleaner2; + particlecleaner::ParticleCleaner mMcParticleCleaner3; + triplethistmanager::MixingPolicy mMixingPolicy = triplethistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; + bool mParticle1Particle2Particle3AreSameSpecies = false; + bool mParticle1Particle2AreSameSpecies = false; + bool mMixIdenticalParticles = false; + std::mt19937 mRng; + std::uniform_int_distribution<> mDist; +}; + } // namespace o2::analysis::femto::tripletbuilder #endif // PWGCF_FEMTO_CORE_TRIPLETBUILDER_H_ diff --git a/PWGCF/Femto/Core/tripletCleaner.h b/PWGCF/Femto/Core/tripletCleaner.h index 1a1cb689968..85a89c77ff9 100644 --- a/PWGCF/Femto/Core/tripletCleaner.h +++ b/PWGCF/Femto/Core/tripletCleaner.h @@ -26,6 +26,8 @@ constexpr char PrefixTripletCleanerTrackTrackV0Se[] = "TrackTrackV0Cleaner/SE/"; constexpr char PrefixTripletCleanerTrackTrackV0Me[] = "TrackTrackV0Cleaner/ME/"; constexpr char PrefixTripletCleanerTrackTrackCascadeSe[] = "TrackTrackCascadeCleaner/SE/"; constexpr char PrefixTripletCleanerTrackTrackCascadeMe[] = "TrackTrackCascadeCleaner/ME/"; +constexpr char PrefixTripletCleanerMcParticleMcParticleMcParticleSe[] = "McParticleMcParticleMcParticleCleaner/SE/"; +constexpr char PrefixTripletCleanerMcParticleMcParticleMcParticleMe[] = "McParticleMcParticleMcParticleCleaner/ME/"; template class TrackTrackTrackTripletCleaner : public paircleaner::BasePairCleaner @@ -163,6 +165,50 @@ class TrackTrackCascadeTripletCleaner : public paircleaner::BasePairCleaner +class McParticleMcParticleMcParticleTripletCleaner : public paircleaner::BasePairCleaner +{ + public: + McParticleMcParticleMcParticleTripletCleaner() = default; + ~McParticleMcParticleMcParticleTripletCleaner() override = default; + + template + bool isCleanTriplet(T1 const& particle1, T2 const& particle2, T3 const& particle3, T4 const& tripletHistManager) const + { + this->fillAll(); + bool isClean = this->isCleanParticlePair(particle1, particle2) && + this->isCleanParticlePair(particle2, particle3) && + this->isCleanParticlePair(particle1, particle3); + if (!isClean) { + this->fillBlocked(tripletHistManager.getKinematic()); + } + return isClean; + } + + template + bool isCleanTriplet(T1 const& particle1, T2 const& particle2, T3 const& particle3, T4 const& partonicMothers, T5 const& tripletHistManager) const + { + if (!this->isCleanTriplet(particle1, particle2, particle3, tripletHistManager)) { + return false; + } + // triplet is clean + // no check if we require common or non-common ancestry + if (this->mMixPairsWithCommonAncestor) { + return this->mcPairHasCommonAncestor(particle1, particle2, partonicMothers) && + this->mcPairHasCommonAncestor(particle2, particle3, partonicMothers) && + this->mcPairHasCommonAncestor(particle1, particle3, partonicMothers); + } + if (this->mMixPairsWithNonCommonAncestor) { + return this->mcPairHasNonCommonAncestor(particle1, particle2, partonicMothers) && + this->mcPairHasNonCommonAncestor(particle2, particle3, partonicMothers) && + this->mcPairHasNonCommonAncestor(particle1, particle3, partonicMothers); + } + return true; + } +}; + } // namespace o2::analysis::femto::tripletcleaner #endif // PWGCF_FEMTO_CORE_TRIPLETCLEANER_H_ diff --git a/PWGCF/Femto/Core/tripletHistManager.h b/PWGCF/Femto/Core/tripletHistManager.h index ea15869bdd1..b11e38905d0 100644 --- a/PWGCF/Femto/Core/tripletHistManager.h +++ b/PWGCF/Femto/Core/tripletHistManager.h @@ -73,6 +73,18 @@ enum TripletHist { kTrueMtVsMt, kTrueMultVsMult, kTrueCentVsCent, + // mc truth (kMc without kReco), i.e. triplets of generated particles + kTrueQ3, + kTrueMt, + kTrueKstar12, + kTrueKstar13, + kTrueKstar23, + kTruePt1VsTrueQ3, + kTruePt2VsTrueQ3, + kTruePt3VsTrueQ3, + kTrueQ3VsTrueMt, + kTrueQ3VsTrueMult, + kTrueQ3VsTrueCent, // mixing qa kSeNpart1VsNpart2VsNpart3, // unique particles 1,2,3 in each same event @@ -173,6 +185,18 @@ constexpr std::array, kTripletHistogramLast> {kTrueMtVsMt, o2::framework::HistType::kTH2F, "hTrueMtVsMt", "m_{T,True} vs m_{T}; m_{T,True} (GeV/#it{c}^{2}); m_{T} (GeV/#it{c}^{2})"}, {kTrueMultVsMult, o2::framework::HistType::kTH2F, "hTrueMultVsMult", "Multiplicity_{True} vs Multiplicity; Multiplicity_{True} ; Multiplicity"}, {kTrueCentVsCent, o2::framework::HistType::kTH2F, "hTrueCentVsCent", "Centrality_{True} vs Centrality; Centrality_{True} (%); Centrality (%)"}, + // mc truth + {kTrueQ3, o2::framework::HistType::kTH1F, "hTrueQ3", "Q_{3,True}; Q_{3,True} (GeV/#it{c}); Entries"}, + {kTrueMt, o2::framework::HistType::kTH1F, "hTrueMt", "true transverse mass; m_{T,True} (GeV/#it{c}^{2}); Entries"}, + {kTrueKstar12, o2::framework::HistType::kTH1F, "hTrueKstar12", "true k* between particle 1 and particle 2; k*_{True} (GeV/#it{c}); Entries"}, + {kTrueKstar13, o2::framework::HistType::kTH1F, "hTrueKstar13", "true k* between particle 1 and particle 3; k*_{True} (GeV/#it{c}); Entries"}, + {kTrueKstar23, o2::framework::HistType::kTH1F, "hTrueKstar23", "true k* between particle 2 and particle 3; k*_{True} (GeV/#it{c}); Entries"}, + {kTruePt1VsTrueQ3, o2::framework::HistType::kTH2F, "hTruePt1VsTrueQ3", "p_{T,1,True} vs Q_{3,True}; p_{T,1,True} (GeV/#it{c}); Q_{3,True} (GeV/#it{c})"}, + {kTruePt2VsTrueQ3, o2::framework::HistType::kTH2F, "hTruePt2VsTrueQ3", "p_{T,2,True} vs Q_{3,True}; p_{T,2,True} (GeV/#it{c}); Q_{3,True} (GeV/#it{c})"}, + {kTruePt3VsTrueQ3, o2::framework::HistType::kTH2F, "hTruePt3VsTrueQ3", "p_{T,3,True} vs Q_{3,True}; p_{T,3,True} (GeV/#it{c}); Q_{3,True} (GeV/#it{c})"}, + {kTrueQ3VsTrueMt, o2::framework::HistType::kTH2F, "hTrueQ3VsTrueMt", "Q_{3,True} vs m_{T,True}; Q_{3,True} (GeV/#it{c}); m_{T,True} (GeV/#it{c}^{2})"}, + {kTrueQ3VsTrueMult, o2::framework::HistType::kTH2F, "hTrueQ3VsTrueMult", "Q_{3,True} vs Multiplicity_{True}; Q_{3,True} (GeV/#it{c}); Multiplicity_{True}"}, + {kTrueQ3VsTrueCent, o2::framework::HistType::kTH2F, "hTrueQ3VsTrueCent", "Q_{3,True} vs Centrality_{True}; Q_{3,True} (GeV/#it{c}); Centrality_{True} (%)"}, // mixing qa {kSeNpart1VsNpart2VsNpart3, o2::framework::HistType::kTHnSparseF, "hSeNpart1VsNpart2VsNpart3", "# unique particle 1 vs # unique particle 2 vs # unique particle 3 in each same event; # particle 1; # particle 2; # particle 3;"}, {kMeMixingWindowRaw, o2::framework::HistType::kTH1F, "hMeMixingWindowRaw", "Raw Mixing Window; Raw Mixing Window; Entries"}, @@ -182,30 +206,47 @@ constexpr std::array, kTripletHistogramLast> }}; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define TRIPLET_HIST_ANALYSIS_MAP(conf, confMixing) \ - {kQ3, {(conf).q3}}, \ - {kMt, {(conf).mt}}, \ - {kKstar12, {(conf).kstar}}, \ - {kKstar13, {(conf).kstar}}, \ - {kKstar23, {(conf).kstar}}, \ - {kPt1VsQ3, {(conf).pt1, (conf).q3}}, \ - {kPt2VsQ3, {(conf).pt2, (conf).q3}}, \ - {kPt3VsQ3, {(conf).pt3, (conf).q3}}, \ - {kQ3VsMt, {(conf).q3, (conf).mt}}, \ - {kQ3VsMult, {(conf).q3, (conf).multiplicity}}, \ - {kQ3VsCent, {(conf).q3, (conf).centrality}}, \ - {kPt1VsPt2VsPt3, {(conf).pt1, (conf).pt2, (conf).pt3}}, \ - {kQ3VsPt1VsPt2VsPt3, {(conf).q3, (conf).pt1, (conf).pt2, (conf).pt3}}, \ - {kQ3VsMtVsMult, {(conf).q3, (conf).mt, (conf).multiplicity}}, \ - {kQ3VsMtVsMultVsCent, {(conf).q3, (conf).mt, (conf).multiplicity, (conf).centrality}}, \ - {kQ3VsMtVsPt1VsPt2VsPt3VsMult, {(conf).q3, (conf).mt, (conf).pt1, (conf).pt2, (conf).pt3, (conf).multiplicity}}, \ - {kQ3VsMtVsPt1VsPt2VsPt3VsMultVsCent, {(conf).q3, (conf).mt, (conf).pt1, (conf).pt2, (conf).pt3, (conf).multiplicity, (conf).centrality}}, \ - {kSeNpart1VsNpart2VsNpart3, {(confMixing).particleBinning, (confMixing).particleBinning, (confMixing).particleBinning}}, \ - {kMeMixingWindowRaw, {(confMixing).particleBinning}}, \ - {kMeMixingWindowEffective, {(confMixing).particleBinning}}, \ - {kMeNpart1VsNpart2VsNpart3, {(confMixing).particleBinning, (confMixing).particleBinning, (confMixing).particleBinning}}, \ +#define TRIPLET_HIST_ANALYSIS_MAP(conf, confMixing) \ + {kQ3, {(conf).q3}}, \ + {kMt, {(conf).mt}}, \ + {kKstar12, {(conf).kstar}}, \ + {kKstar13, {(conf).kstar}}, \ + {kKstar23, {(conf).kstar}}, \ + {kPt1VsQ3, {(conf).pt1, (conf).q3}}, \ + {kPt2VsQ3, {(conf).pt2, (conf).q3}}, \ + {kPt3VsQ3, {(conf).pt3, (conf).q3}}, \ + {kQ3VsMt, {(conf).q3, (conf).mt}}, \ + {kQ3VsMult, {(conf).q3, (conf).multiplicity}}, \ + {kQ3VsCent, {(conf).q3, (conf).centrality}}, \ + {kPt1VsPt2VsPt3, {(conf).pt1, (conf).pt2, (conf).pt3}}, \ + {kQ3VsPt1VsPt2VsPt3, {(conf).q3, (conf).pt1, (conf).pt2, (conf).pt3}}, \ + {kQ3VsMtVsMult, {(conf).q3, (conf).mt, (conf).multiplicity}}, \ + {kQ3VsMtVsMultVsCent, {(conf).q3, (conf).mt, (conf).multiplicity, (conf).centrality}}, \ + {kQ3VsMtVsPt1VsPt2VsPt3VsMult, {(conf).q3, (conf).mt, (conf).pt1, (conf).pt2, (conf).pt3, (conf).multiplicity}}, \ + {kQ3VsMtVsPt1VsPt2VsPt3VsMultVsCent, {(conf).q3, (conf).mt, (conf).pt1, (conf).pt2, (conf).pt3, (conf).multiplicity, (conf).centrality}}, + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define TRIPLET_HIST_MIXING_QA_MAP(confMixing) \ + {kSeNpart1VsNpart2VsNpart3, {(confMixing).particleBinning, (confMixing).particleBinning, (confMixing).particleBinning}}, \ + {kMeMixingWindowRaw, {(confMixing).particleBinning}}, \ + {kMeMixingWindowEffective, {(confMixing).particleBinning}}, \ + {kMeNpart1VsNpart2VsNpart3, {(confMixing).particleBinning, (confMixing).particleBinning, (confMixing).particleBinning}}, \ {kMeVtz1VsMult1VsCent1VsVtz2VsMult2VsCent2VsVtz3VsMult3VsCent3, {(confMixing).vtxBins, (confMixing).multBins, (confMixing).centBins, (confMixing).vtxBins, (confMixing).multBins, (confMixing).centBins, (confMixing).vtxBins, (confMixing).multBins, (confMixing).centBins}}, +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define TRIPLET_HIST_MC_TRUTH_MAP(conf) \ + {kTrueQ3, {(conf).q3}}, \ + {kTrueMt, {(conf).mt}}, \ + {kTrueKstar12, {(conf).kstar}}, \ + {kTrueKstar13, {(conf).kstar}}, \ + {kTrueKstar23, {(conf).kstar}}, \ + {kTruePt1VsTrueQ3, {(conf).pt1, (conf).q3}}, \ + {kTruePt2VsTrueQ3, {(conf).pt2, (conf).q3}}, \ + {kTruePt3VsTrueQ3, {(conf).pt3, (conf).q3}}, \ + {kTrueQ3VsTrueMt, {(conf).q3, (conf).mt}}, \ + {kTrueQ3VsTrueMult, {(conf).q3, (conf).multiplicity}}, \ + {kTrueQ3VsTrueCent, {(conf).q3, (conf).centrality}}, + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TRIPLET_HIST_MC_MAP(conf) \ {kTrueQ3VsQ3, {(conf).q3, (conf).q3}}, \ @@ -217,7 +258,8 @@ template auto makeTripletHistSpecMap(T1 const& confPairBinning, T2 const& confMixing) { return std::map>{ - TRIPLET_HIST_ANALYSIS_MAP(confPairBinning, confMixing)}; + TRIPLET_HIST_ANALYSIS_MAP(confPairBinning, confMixing) + TRIPLET_HIST_MIXING_QA_MAP(confMixing)}; }; template @@ -225,11 +267,23 @@ auto makeTripletMcHistSpecMap(T1 const& confPairBinning, T2 const& confMixing) { return std::map>{ TRIPLET_HIST_ANALYSIS_MAP(confPairBinning, confMixing) - TRIPLET_HIST_MC_MAP(confPairBinning)}; + TRIPLET_HIST_MIXING_QA_MAP(confMixing) + TRIPLET_HIST_MC_MAP(confPairBinning)}; +}; + +/// triplets of generated particles only (kMc without kReco) +template +auto makeTripletMcTruthHistSpecMap(T1 const& confPairBinning, T2 const& confMixing) +{ + return std::map>{ + TRIPLET_HIST_MC_TRUTH_MAP(confPairBinning) + TRIPLET_HIST_MIXING_QA_MAP(confMixing)}; }; #undef TRIPLET_HIST_ANALYSIS_MAP +#undef TRIPLET_HIST_MIXING_QA_MAP #undef TRIPLET_HIST_MC_MAP +#undef TRIPLET_HIST_MC_TRUTH_MAP constexpr char PrefixTrackTrackTrackSe[] = "TrackTrackTrack/SE/"; constexpr char PrefixTrackTrackTrackMe[] = "TrackTrackTrack/ME/"; @@ -237,6 +291,9 @@ constexpr char PrefixTrackTrackTrackMe[] = "TrackTrackTrack/ME/"; constexpr char PrefixTrackTrackLambdaSe[] = "TrackTrackLambda/SE/"; constexpr char PrefixTrackTrackLambdaMe[] = "TrackTrackLambda/ME/"; +constexpr char PrefixMcParticleMcParticleMcParticleSe[] = "McParticleMcParticleMcParticle/SE/"; +constexpr char PrefixMcParticleMcParticleMcParticleMe[] = "McParticleMcParticleMcParticle/ME/"; + constexpr char PrefixTrackTrackCascadeSe[] = "TrackTrackCascade/SE/"; constexpr char PrefixTrackTrackCascadeMe[] = "TrackTrackCascade/ME/"; @@ -292,9 +349,12 @@ class TripletHistManager initAnalysis(Specs); } - if constexpr (isFlagSet(mode, modes::Mode::kMc)) { + if constexpr (isFlagSet(mode, modes::Mode::kReco) && isFlagSet(mode, modes::Mode::kMc)) { initMc(Specs); } + if constexpr (isFlagSet(mode, modes::Mode::kMc) && !isFlagSet(mode, modes::Mode::kReco)) { + initMcTruth(Specs); + } if constexpr (isFlagSet(mode, modes::Mode::kSe)) { initSeMixingQa(Specs); } @@ -365,6 +425,53 @@ class TripletHistManager mCent = (col1.cent() + col2.cent() + col3.cent()) / 3.f; // if mixing with centrality, should be in the same mixing bin } + // pure mc-truth triplet: the particles ARE the truth, there is no reco counterpart. + // The mass is always the PDG mass here, and the pt needs no charge rescaling, + // since generated particles store the true pt. + template + void setTripletMcTruth(T1 const& particle1, T2 const& particle2, T3 const& particle3) + { + mTrueParticle1 = ROOT::Math::PtEtaPhiMVector(particle1.pt(), particle1.eta(), particle1.phi(), mPdgMass1); + mTrueParticle2 = ROOT::Math::PtEtaPhiMVector(particle2.pt(), particle2.eta(), particle2.phi(), mPdgMass2); + mTrueParticle3 = ROOT::Math::PtEtaPhiMVector(particle3.pt(), particle3.eta(), particle3.phi(), mPdgMass3); + + mTrueMt = getMt(mTrueParticle1, mTrueParticle2, mTrueParticle3); + mTrueQ3 = getQ3(mTrueParticle1, mTrueParticle2, mTrueParticle3); + + // in the pure mc-truth path there is no reco counterpart, so the generated values are also + // stored in the reco members; they are used by getKinematic(), i.e. by the kinematic histograms + // of the triplet cleaner and of the close triplet rejection + mMt = mTrueMt; + mQ3 = mTrueQ3; + + if (mPlotKstar) { + mTrueKstar12 = getKstar(mTrueParticle1, mTrueParticle2); + mTrueKstar13 = getKstar(mTrueParticle1, mTrueParticle3); + mTrueKstar23 = getKstar(mTrueParticle2, mTrueParticle3); + mKstar12 = mTrueKstar12; + mKstar13 = mTrueKstar13; + mKstar23 = mTrueKstar23; + } + } + + // same event: one (truth) collision for true mult/cent + template + void setTripletMcTruth(T1 const& particle1, T2 const& particle2, T3 const& particle3, T4 const& col) + { + setTripletMcTruth(particle1, particle2, particle3); + mTrueMult = col.mult(); + mTrueCent = col.cent(); + } + + // mixed event: three (truth) collisions, averaged mult/cent (same convention as setTriplet) + template + void setTripletMcTruth(T1 const& particle1, T2 const& particle2, T3 const& particle3, T4 const& col1, T4 const& col2, T4 const& col3) + { + setTripletMcTruth(particle1, particle2, particle3); + mTrueMult = (col1.mult() + col2.mult() + col3.mult()) / 3.f; + mTrueCent = (col1.cent() + col2.cent() + col3.cent()) / 3.f; + } + template void setTripletMc(T1 const& particle1, T2 const& particle2, T3 const& particle3, const T4& /*mcParticles*/) { @@ -420,6 +527,16 @@ class TripletHistManager mTrueCent = (mcCol1.cent() + mcCol2.cent() + mcCol3.cent()) / 3.f; } + /// triplet cuts on the mc-truth values, for the pure mc-truth path (kMc without kReco), + /// where the reco values are never set + bool checkTripletCutsMcTruth() const + { + return (!(mQ3Min > 0.f) || mTrueQ3 > mQ3Min) && + (!(mQ3Max > 0.f) || mTrueQ3 < mQ3Max) && + (!(mMtMin > 0.f) || mTrueMt > mMtMin) && + (!(mMtMax > 0.f) || mTrueMt < mMtMax); + } + bool checkTripletCuts() const { return (!(mQ3Min > 0.f) || mQ3 > mQ3Min) && @@ -434,9 +551,12 @@ class TripletHistManager if constexpr (isFlagSet(mode, modes::Mode::kReco)) { fillAnalysis(); } - if constexpr (isFlagSet(mode, modes::Mode::kMc)) { + if constexpr (isFlagSet(mode, modes::Mode::kReco) && isFlagSet(mode, modes::Mode::kMc)) { fillMc(); } + if constexpr (isFlagSet(mode, modes::Mode::kMc) && !isFlagSet(mode, modes::Mode::kReco)) { + fillMcTruth(); + } } float getKinematic() const @@ -622,6 +742,51 @@ class TripletHistManager } } + // pure mc-truth triplet (kMc without kReco) — reuses the mPlot1d/mPlot2d/mPlotKstar flags, + // since these are histogram-content flags, not mode flags + void initMcTruth(std::map> const& Specs) + { + std::string mcDir = std::string(prefix) + std::string(McDir); + if (mPlot1d) { + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3, HistTable), getHistDesc(kTrueQ3, HistTable), getHistType(kTrueQ3, HistTable), {Specs.at(kTrueQ3)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueMt, HistTable), getHistDesc(kTrueMt, HistTable), getHistType(kTrueMt, HistTable), {Specs.at(kTrueMt)}); + } + if (mPlot2d) { + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePt1VsTrueQ3, HistTable), getHistDesc(kTruePt1VsTrueQ3, HistTable), getHistType(kTruePt1VsTrueQ3, HistTable), {Specs.at(kTruePt1VsTrueQ3)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePt2VsTrueQ3, HistTable), getHistDesc(kTruePt2VsTrueQ3, HistTable), getHistType(kTruePt2VsTrueQ3, HistTable), {Specs.at(kTruePt2VsTrueQ3)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePt3VsTrueQ3, HistTable), getHistDesc(kTruePt3VsTrueQ3, HistTable), getHistType(kTruePt3VsTrueQ3, HistTable), {Specs.at(kTruePt3VsTrueQ3)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3VsTrueMt, HistTable), getHistDesc(kTrueQ3VsTrueMt, HistTable), getHistType(kTrueQ3VsTrueMt, HistTable), {Specs.at(kTrueQ3VsTrueMt)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3VsTrueMult, HistTable), getHistDesc(kTrueQ3VsTrueMult, HistTable), getHistType(kTrueQ3VsTrueMult, HistTable), {Specs.at(kTrueQ3VsTrueMult)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3VsTrueCent, HistTable), getHistDesc(kTrueQ3VsTrueCent, HistTable), getHistType(kTrueQ3VsTrueCent, HistTable), {Specs.at(kTrueQ3VsTrueCent)}); + } + if (mPlotKstar) { + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar12, HistTable), getHistDesc(kTrueKstar12, HistTable), getHistType(kTrueKstar12, HistTable), {Specs.at(kTrueKstar12)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar13, HistTable), getHistDesc(kTrueKstar13, HistTable), getHistType(kTrueKstar13, HistTable), {Specs.at(kTrueKstar13)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar23, HistTable), getHistDesc(kTrueKstar23, HistTable), getHistType(kTrueKstar23, HistTable), {Specs.at(kTrueKstar23)}); + } + } + + void fillMcTruth() + { + if (mPlot1d) { + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3, HistTable)), mTrueQ3); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueMt, HistTable)), mTrueMt); + } + if (mPlot2d) { + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTruePt1VsTrueQ3, HistTable)), mTrueParticle1.Pt(), mTrueQ3); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTruePt2VsTrueQ3, HistTable)), mTrueParticle2.Pt(), mTrueQ3); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTruePt3VsTrueQ3, HistTable)), mTrueParticle3.Pt(), mTrueQ3); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3VsTrueMt, HistTable)), mTrueQ3, mTrueMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3VsTrueMult, HistTable)), mTrueQ3, mTrueMult); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3VsTrueCent, HistTable)), mTrueQ3, mTrueCent); + } + if (mPlotKstar) { + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar12, HistTable)), mTrueKstar12); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar13, HistTable)), mTrueKstar13); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar23, HistTable)), mTrueKstar23); + } + } + void fillAnalysis() { if (mPlot1d) { @@ -735,6 +900,9 @@ class TripletHistManager ROOT::Math::PtEtaPhiMVector mTrueParticle3; float mTrueQ3 = 0.f; float mTrueMt = 0.f; + float mTrueKstar12 = 0.f; + float mTrueKstar13 = 0.f; + float mTrueKstar23 = 0.f; float mTrueMult = 0.f; float mTrueCent = 0.f; diff --git a/PWGCF/Femto/Core/tripletProcessHelpers.h b/PWGCF/Femto/Core/tripletProcessHelpers.h index 41a73f57096..729ef2a9cc1 100644 --- a/PWGCF/Femto/Core/tripletProcessHelpers.h +++ b/PWGCF/Femto/Core/tripletProcessHelpers.h @@ -497,6 +497,237 @@ bool processSameEvent(T1 const& SliceParticle1, return foundTriplet; } +// --- mc truth only (kMc without kReco): triplets of generated particles --------------------------- +// These are named processSameEventMcTruth (not processSameEvent) on purpose: several of the reco +// overloads have the same number of arguments and every parameter is a template type, so the call +// would be ambiguous. +// The particles ARE the truth, so there is no track table, no reco counterpart and no charge rescaling. +// The close triplet rejection and the triplet cleaner take the table of mc particles where the reco +// helpers take the track table; both ignore it in the track-track-track case. + +// process same event for identical 3 mc particles +template +bool processSameEventMcTruth(T1 const& SliceParticle, + T2 const& /*mcParticles*/, + T3 const& mcMothers, + T4 const& mcPartonicMothers, + T5 const& Collision, + T6& ParticleHistManager, + T7& TripletHistManager, + T8& ParticleCleaner, + T9& CtrManager, + T10& TcManager, + TripletOrder tripletOrder) +{ + TripletHistManager.resetTrackedParticlesPerEvent(); + bool foundTriplet = false; + + for (auto const& part : SliceParticle) { + if (!ParticleCleaner.isClean(part, mcMothers, mcPartonicMothers)) { + continue; + } + ParticleHistManager.fill(part, mcMothers, mcPartonicMothers); + } + + for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle, SliceParticle, SliceParticle))) { + if (!ParticleCleaner.isClean(p1, mcMothers, mcPartonicMothers) || + !ParticleCleaner.isClean(p2, mcMothers, mcPartonicMothers) || + !ParticleCleaner.isClean(p3, mcMothers, mcPartonicMothers)) { + continue; + } + + // Randomize triplet order if enabled, then compute the kinematic (Q3) for this triplet + switch (tripletOrder) { + case kOrder213: + TripletHistManager.setTripletMcTruth(p2, p1, p3, Collision); + break; + case kOrder132: + TripletHistManager.setTripletMcTruth(p1, p3, p2, Collision); + break; + case kOrder321: + TripletHistManager.setTripletMcTruth(p3, p2, p1, Collision); + break; + case kOrder123: + default: + TripletHistManager.setTripletMcTruth(p1, p2, p3, Collision); + break; + } + + if (!TcManager.isCleanTriplet(p1, p2, p3, mcPartonicMothers, TripletHistManager)) { + continue; + } + + if (CtrManager.isCloseTriplet(p1, p2, p3, TripletHistManager)) { + continue; + } + + if (TripletHistManager.checkTripletCutsMcTruth()) { + TripletHistManager.template fill(); + TripletHistManager.trackParticlesPerEvent(p1, p2, p3); + foundTriplet = true; + } + } + + TripletHistManager.fillMixingQaSe(); + return foundTriplet; +} + +// process same event for 2 identical mc particles and 1 other mc particle +template +bool processSameEventMcTruth(T1 const& SliceParticle1, // 1&2 have same species + T2 const& SliceParticle3, + T3 const& /*mcParticles*/, + T4 const& mcMothers, + T5 const& mcPartonicMothers, + T6 const& Collision, + T7& ParticleHistManager1, + T8& ParticleHistManager3, + T9& TripletHistManager, + T10& ParticleCleaner1, + T11& ParticleCleaner3, + T12& CtrManager, + T13& TcManager, + TripletOrder tripletOrder) +{ + TripletHistManager.resetTrackedParticlesPerEvent(); + bool foundTriplet = false; + + for (auto const& part : SliceParticle1) { + if (!ParticleCleaner1.isClean(part, mcMothers, mcPartonicMothers)) { + continue; + } + ParticleHistManager1.fill(part, mcMothers, mcPartonicMothers); + } + for (auto const& part : SliceParticle3) { + if (!ParticleCleaner3.isClean(part, mcMothers, mcPartonicMothers)) { + continue; + } + ParticleHistManager3.fill(part, mcMothers, mcPartonicMothers); + } + + for (auto const& p3 : SliceParticle3) { + if (!ParticleCleaner3.isClean(p3, mcMothers, mcPartonicMothers)) { + continue; + } + for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle1, SliceParticle1))) { + if (!ParticleCleaner1.isClean(p1, mcMothers, mcPartonicMothers) || + !ParticleCleaner1.isClean(p2, mcMothers, mcPartonicMothers)) { + continue; + } + + switch (tripletOrder) { + case kOrder213: + TripletHistManager.setTripletMcTruth(p2, p1, p3, Collision); + break; + case kOrder123: + default: + TripletHistManager.setTripletMcTruth(p1, p2, p3, Collision); + break; + } + + if (!TcManager.isCleanTriplet(p1, p2, p3, mcPartonicMothers, TripletHistManager)) { + continue; + } + + if (CtrManager.isCloseTriplet(p1, p2, p3, TripletHistManager)) { + continue; + } + + if (TripletHistManager.checkTripletCutsMcTruth()) { + TripletHistManager.template fill(); + TripletHistManager.trackParticlesPerEvent(p1, p2, p3); + foundTriplet = true; + } + } + } + + TripletHistManager.fillMixingQaSe(); + return foundTriplet; +} + +// process same event for 3 different mc particles +template +bool processSameEventMcTruth(T1 const& SliceParticle1, + T2 const& SliceParticle2, + T3 const& SliceParticle3, + T4 const& /*mcParticles*/, + T5 const& mcMothers, + T6 const& mcPartonicMothers, + T7 const& Collision, + T8& ParticleHistManager1, + T9& ParticleHistManager2, + T10& ParticleHistManager3, + T11& TripletHistManager, + T12& ParticleCleaner1, + T13& ParticleCleaner2, + T14& ParticleCleaner3, + T15& CtrManager, + T16& TcManager) +{ + TripletHistManager.resetTrackedParticlesPerEvent(); + bool foundTriplet = false; + + for (auto const& part : SliceParticle1) { + if (!ParticleCleaner1.isClean(part, mcMothers, mcPartonicMothers)) { + continue; + } + ParticleHistManager1.fill(part, mcMothers, mcPartonicMothers); + } + for (auto const& part : SliceParticle2) { + if (!ParticleCleaner2.isClean(part, mcMothers, mcPartonicMothers)) { + continue; + } + ParticleHistManager2.fill(part, mcMothers, mcPartonicMothers); + } + for (auto const& part : SliceParticle3) { + if (!ParticleCleaner3.isClean(part, mcMothers, mcPartonicMothers)) { + continue; + } + ParticleHistManager3.fill(part, mcMothers, mcPartonicMothers); + } + + for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(SliceParticle1, SliceParticle2, SliceParticle3))) { + if (!ParticleCleaner1.isClean(p1, mcMothers, mcPartonicMothers) || + !ParticleCleaner2.isClean(p2, mcMothers, mcPartonicMothers) || + !ParticleCleaner3.isClean(p3, mcMothers, mcPartonicMothers)) { + continue; + } + + TripletHistManager.setTripletMcTruth(p1, p2, p3, Collision); + + if (!TcManager.isCleanTriplet(p1, p2, p3, mcPartonicMothers, TripletHistManager)) { + continue; + } + + if (CtrManager.isCloseTriplet(p1, p2, p3, TripletHistManager)) { + continue; + } + + if (TripletHistManager.checkTripletCutsMcTruth()) { + TripletHistManager.template fill(); + TripletHistManager.trackParticlesPerEvent(p1, p2, p3); + foundTriplet = true; + } + } + + TripletHistManager.fillMixingQaSe(); + return foundTriplet; +} + // process mixed event // (no cleaner here — ParticleCleaner only operates on MC info, see the mc overload below) template +void processMixedEventMcTruth(T1 const& McCollisions, + T2& Partition1, + T3& Partition2, + T4& Partition3, + T5 const& /*mcParticles*/, + T6 const& mcMothers, + T7 const& mcPartonicMothers, + T8& cache, + T9 const& policy, + T10 const& depth, + T11& TripletHistManager, + T12& ParticleCleaner1, + T13& ParticleCleaner2, + T14& ParticleCleaner3, + T15& CtrManager, + T16& TcManager) +{ + int64_t lastCollisionIndex1 = -1; + int64_t lastCollisionIndex2 = -1; + int windowSizeRaw = 0; + int windowSizeEffective = 0; + + std::optionalsliceByCached(o2::aod::femtomcparticle::fMcColId, 0, cache))> sliceParticle1; + std::optionalsliceByCached(o2::aod::femtomcparticle::fMcColId, 0, cache))> sliceParticle2; + + for (auto const& [collision1, collision2, collision3] : o2::soa::selfCombinations(policy, depth, -1, McCollisions, McCollisions, McCollisions)) { + + // outer window + if (collision1.globalIndex() != lastCollisionIndex1) { + if (lastCollisionIndex1 != -1) { + TripletHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective); + } + windowSizeRaw = 0; + windowSizeEffective = 0; + lastCollisionIndex1 = collision1.globalIndex(); + lastCollisionIndex2 = -1; // force sliceParticle2 to refresh below + sliceParticle1.emplace(Partition1->sliceByCached(o2::aod::femtomcparticle::fMcColId, collision1.globalIndex(), cache)); + } + + // inner sub-window + if (collision2.globalIndex() != lastCollisionIndex2) { + lastCollisionIndex2 = collision2.globalIndex(); + sliceParticle2.emplace(Partition2->sliceByCached(o2::aod::femtomcparticle::fMcColId, collision2.globalIndex(), cache)); + } + + ++windowSizeRaw; + + auto sliceParticle3 = Partition3->sliceByCached(o2::aod::femtomcparticle::fMcColId, collision3.globalIndex(), cache); + + TripletHistManager.resetTrackedParticlesPerEvent(); + + if (sliceParticle1->size() == 0 || sliceParticle2->size() == 0 || sliceParticle3.size() == 0) { + TripletHistManager.fillMixingQaMePerEvent(); + continue; + } + + bool hasValidTriplet = false; + TripletHistManager.fillMixingQaMe(collision1, collision2, collision3); + + for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(*sliceParticle1, *sliceParticle2, sliceParticle3))) { + + if (!ParticleCleaner1.isClean(p1, mcMothers, mcPartonicMothers) || + !ParticleCleaner2.isClean(p2, mcMothers, mcPartonicMothers) || + !ParticleCleaner3.isClean(p3, mcMothers, mcPartonicMothers)) { + continue; + } + + // compute the kinematic (Q3) for this triplet + TripletHistManager.setTripletMcTruth(p1, p2, p3, collision1, collision2, collision3); + + if (!TcManager.isCleanTriplet(p1, p2, p3, mcPartonicMothers, TripletHistManager)) { + continue; + } + + // Close triplet rejection; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TripletHistManager)) { + continue; + } + + if (TripletHistManager.checkTripletCutsMcTruth()) { + hasValidTriplet = true; + TripletHistManager.trackParticlesPerEvent(p1, p2, p3); + TripletHistManager.template fill(); + } + } + + if (hasValidTriplet) { + ++windowSizeEffective; + } + + TripletHistManager.fillMixingQaMePerEvent(); + } + + // final window + if (windowSizeRaw > 0) { + TripletHistManager.fillMixingQaMePerMixingBin(windowSizeRaw, windowSizeEffective); + } +} + } // namespace o2::analysis::femto::tripletprocesshelpers #endif // PWGCF_FEMTO_CORE_TRIPLETPROCESSHELPERS_H_ diff --git a/PWGCF/Femto/Tasks/CMakeLists.txt b/PWGCF/Femto/Tasks/CMakeLists.txt index b67a1bf5b19..0aa26cf38d7 100644 --- a/PWGCF/Femto/Tasks/CMakeLists.txt +++ b/PWGCF/Femto/Tasks/CMakeLists.txt @@ -94,11 +94,6 @@ o2physics_add_dpl_workflow(femto-pair-mc-particle-mc-particle PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(femto-pair-efficiency - SOURCES femtoPairEfficiency.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(femto-triplet-track-track-track SOURCES femtoTripletTrackTrackTrack.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -114,7 +109,22 @@ o2physics_add_dpl_workflow(femto-triplet-track-track-cascade PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-triplet-mc-particle-mc-particle-mc-particle + SOURCES femtoTripletMcParticleMcParticleMcParticle.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-dndeta-pair SOURCES femtoDndetaPair.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-dndeta-triplet + SOURCES femtoDndetaTriplet.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-efficiency + SOURCES femtoPairEfficiency.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/Tasks/femtoDndetaPair.cxx b/PWGCF/Femto/Tasks/femtoDndetaPair.cxx index eb70b544157..5e3545af380 100644 --- a/PWGCF/Femto/Tasks/femtoDndetaPair.cxx +++ b/PWGCF/Femto/Tasks/femtoDndetaPair.cxx @@ -72,7 +72,7 @@ struct FemtoDndetaPair { using FemtoMcParticles = o2::soa::Join; o2::framework::SliceCache cache; - o2::framework::Service pdg; + o2::framework::Service pdg = {}; // setup dndeta dndetabuilder::ConfDndeta confDndeta; diff --git a/PWGCF/Femto/Tasks/femtoDndetaTriplet.cxx b/PWGCF/Femto/Tasks/femtoDndetaTriplet.cxx new file mode 100644 index 00000000000..8bdf06a3459 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoDndetaTriplet.cxx @@ -0,0 +1,399 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file femtoDndetaTriplet.cxx +/// \brief charged-particle pseudorapidity density in events triggered on femto triplets +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// +/// An event is triggered if at least one triplet passes the particle selections, the triplet cleaner, +/// the close triplet rejection and the triplet cuts (e.g. TripletCuts.q3Max). +/// There is no generator-level triplet builder yet, so the event/signal loss is not conditioned on a generator-level trigger. +/// Needs a femto producer run in pass-through mode. + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/closeTripletRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/dndetaBuilder.h" +#include "PWGCF/Femto/Core/dndetaHistManager.h" +#include "PWGCF/Femto/Core/mcBuilder.h" +#include "PWGCF/Femto/Core/mcParticleHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairCleaner.h" +#include "PWGCF/Femto/Core/particleCleaner.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/tripletBuilder.h" +#include "PWGCF/Femto/Core/tripletHistManager.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGCF/Femto/Core/v0HistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoDndetaTriplet { + + // setup tables + // FCols provides the default centrality (FT0M in pp, FT0C in PbPb), FColMults the INEL>0 and correlation estimators + using FemtoCollisions = o2::soa::Join; + using FemtoCollision = FemtoCollisions::iterator; + using FemtoCollisionsWithLabel = o2::soa::Join; + + // same join as femtoTrackQa, the track histogram managers (QA) need mass, DCAs, extras and PID + using FemtoTracks = o2::soa::Join; + using FemtoTracksWithLabel = o2::soa::Join; + + using FemtoLambdas = o2::soa::Join; + using FemtoLambdasWithLabel = o2::soa::Join; + using FemtoK0shorts = o2::soa::Join; + + using FemtoMcParticles = o2::soa::Join; + + o2::framework::SliceCache cache; + o2::framework::Service pdg = {}; + + // setup dndeta + dndetabuilder::ConfDndeta confDndeta; + dndetabuilder::ConfDndetaAcceptance confDndetaAcceptance; + dndetahistmanager::ConfDndetaBinning confDndetaBinning; + dndetabuilder::DndetaBuilder dndetaBuilder; + + o2::framework::Preslice perMcColParticles = o2::aod::femtomcparticle::fMcColId; + + // setup collisions (applied in the dndeta builder, no filter, so the cutflow sees every collision) + collisionbuilder::ConfCollisionSelection collisionSelection; + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks for dndeta (bitmask with track quality bits only, see dndetaBuilder.h) + trackbuilder::ConfTrackSelectionDndetaGlobal confDndetaTracksGlobal; + trackhistmanager::ConfDndetaTrackGlobalBinning confDndetaTrackGlobalBinning; + trackhistmanager::ConfDndetaTrackGlobalQaBinning confDndetaTrackGlobalQaBinning; + + trackbuilder::ConfTrackSelectionDndetaItsOnly confDndetaTracksItsOnly; + trackhistmanager::ConfDndetaTrackItsOnlyBinning confDndetaTrackItsOnlyBinning; + trackhistmanager::ConfDndetaTrackItsOnlyQaBinning confDndetaTrackItsOnlyQaBinning; + + o2::framework::Partition dndetaTrackPartitionGlobal = MAKE_TRACK_PARTITION(confDndetaTracksGlobal); + o2::framework::Partition dndetaTrackPartitionItsOnly = MAKE_TRACK_PARTITION(confDndetaTracksItsOnly); + + o2::framework::Partition dndetaTrackWithLabelPartitionGlobal = MAKE_TRACK_PARTITION(confDndetaTracksGlobal); + o2::framework::Partition dndetaTrackWithLabelPartitionItsOnly = MAKE_TRACK_PARTITION(confDndetaTracksItsOnly); + + // setup tracks (trigger) + trackbuilder::ConfTrackSelection1 confTrackSelection1; + trackhistmanager::ConfTrackBinning1 confTrackBinning1; + particlecleaner::ConfTrackCleaner1 confTrackCleaner1; + + trackbuilder::ConfTrackSelection2 confTrackSelection2; + trackhistmanager::ConfTrackBinning2 confTrackBinning2; + particlecleaner::ConfTrackCleaner2 confTrackCleaner2; + + trackbuilder::ConfTrackSelection3 confTrackSelection3; + trackhistmanager::ConfTrackBinning3 confTrackBinning3; + particlecleaner::ConfTrackCleaner3 confTrackCleaner3; + + o2::framework::Partition trackPartition1 = MAKE_TRACK_PARTITION(confTrackSelection1); + o2::framework::Partition trackPartition2 = MAKE_TRACK_PARTITION(confTrackSelection2); + o2::framework::Partition trackPartition3 = MAKE_TRACK_PARTITION(confTrackSelection3); + + o2::framework::Partition trackWithLabelPartition1 = MAKE_TRACK_PARTITION(confTrackSelection1); + o2::framework::Partition trackWithLabelPartition2 = MAKE_TRACK_PARTITION(confTrackSelection2); + o2::framework::Partition trackWithLabelPartition3 = MAKE_TRACK_PARTITION(confTrackSelection3); + + // setup for daughters + trackhistmanager::ConfV01PosDauBinning confPosDauBinning; + trackhistmanager::ConfV01NegDauBinning confNegDauBinning; + + // setup lambdas (trigger) + v0builder::ConfLambdaSelection1 confLambdaSelection; + v0histmanager::ConfLambdaBinning1 confLambdaBinning; + particlecleaner::ConfLambdaCleaner1 confLambdaCleaner; + + o2::framework::Partition lambdaPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + o2::framework::Partition lambdaWithLabelPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + + // setup strangeness yields (dedicated selections, independent of the trigger) + v0builder::ConfLambdaSelectionStrangeness confStrangeLambdaSelection; + v0builder::ConfK0shortSelectionStrangeness confStrangeK0shortSelection; + + o2::framework::Partition strangeLambdaPartition = MAKE_LAMBDA_PARTITION(confStrangeLambdaSelection); + o2::framework::Partition strangeK0shortPartition = MAKE_K0SHORT_PARTITION(confStrangeK0shortSelection); + + // setup mc particles (generator-level trigger) + // FMcParticles also contains rows of reconstructed secondaries (created via labels), so set + // McParticleSelection1/2/3.requireOrigin = true (origin = 2, physical primary) for an unbiased generator-level trigger + mcbuilder::ConfMcParticleSelection1 confMcParticleSelection1; + mcparticlehistmanager::ConfMcParticleBinning1 confMcParticleBinning1; + particlecleaner::ConfMcParticleCleaner1 confMcParticleCleaner1; + + mcbuilder::ConfMcParticleSelection2 confMcParticleSelection2; + mcparticlehistmanager::ConfMcParticleBinning2 confMcParticleBinning2; + particlecleaner::ConfMcParticleCleaner2 confMcParticleCleaner2; + + mcbuilder::ConfMcParticleSelection3 confMcParticleSelection3; + mcparticlehistmanager::ConfMcParticleBinning3 confMcParticleBinning3; + particlecleaner::ConfMcParticleCleaner3 confMcParticleCleaner3; + + o2::framework::Partition mcParticlePartition1 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection1); + o2::framework::Partition mcParticlePartition2 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection2); + o2::framework::Partition mcParticlePartition3 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection3); + + // setup triplets + triplethistmanager::ConfTripletBinning confTripletBinning; + triplethistmanager::ConfTripletCuts confTripletCuts; + paircleaner::ConfPairCleanerBinning confTripletCleanerBinning; + triplethistmanager::ConfMixing confMixing; // only same event is processed, used for particle12(3)AreSameSpecies/seed + + closetripletrejection::ConfCtrTrackTrackTrack confCtrTrackTrackTrack; + closetripletrejection::ConfCtrTrackTrackV0 confCtrTrackTrackV0; + closetripletrejection::ConfCtrMcParticleMcParticleMcParticle confCtrMcParticleMcParticleMcParticle; // generator-level trigger, no cut by default + + tripletbuilder::TripletTrackTrackTrackBuilder< + trackhistmanager::PrefixTrack1, + trackhistmanager::PrefixTrack2, + trackhistmanager::PrefixTrack3, + triplethistmanager::PrefixTrackTrackTrackSe, + triplethistmanager::PrefixTrackTrackTrackMe, + closetripletrejection::PrefixTrack1Track2Se, + closetripletrejection::PrefixTrack2Track3Se, + closetripletrejection::PrefixTrack1Track3Se, + closetripletrejection::PrefixTrack1Track2Me, + closetripletrejection::PrefixTrack2Track3Me, + closetripletrejection::PrefixTrack1Track3Me> + tripletTrackTrackTrackBuilder; + + tripletbuilder::TripletTrackTrackV0Builder< + modes::V0::kLambda, + trackhistmanager::PrefixTrack1, + trackhistmanager::PrefixTrack2, + v0histmanager::PrefixLambda1, + trackhistmanager::PrefixV01PosDaughter, + trackhistmanager::PrefixV01NegDaughter, + triplethistmanager::PrefixTrackTrackLambdaSe, + triplethistmanager::PrefixTrackTrackLambdaMe, + closetripletrejection::PrefixTrack1Track2Se, + closetripletrejection::PrefixTrack1V0Se, + closetripletrejection::PrefixTrack2V0Se, + closetripletrejection::PrefixTrack1Track2Me, + closetripletrejection::PrefixTrack1V0Me, + closetripletrejection::PrefixTrack2V0Me> + tripletTrackTrackLambdaBuilder; + + tripletbuilder::TripletMcParticleMcParticleMcParticleBuilder< + mcparticlehistmanager::PrefixMcParticle1, + mcparticlehistmanager::PrefixMcParticle2, + mcparticlehistmanager::PrefixMcParticle3, + triplethistmanager::PrefixMcParticleMcParticleMcParticleSe, + triplethistmanager::PrefixMcParticleMcParticleMcParticleMe, + closetripletrejection::PrefixMcParticle1McParticle2Se, + closetripletrejection::PrefixMcParticle2McParticle3Se, + closetripletrejection::PrefixMcParticle1McParticle3Se, + closetripletrejection::PrefixMcParticle1McParticle2Me, + closetripletrejection::PrefixMcParticle2McParticle3Me, + closetripletrejection::PrefixMcParticle1McParticle3Me> + tripletMcParticleMcParticleMcParticleBuilder; + + // dndeta histograms and trigger QA are kept in separate registries, so the fixed histogram names of the builders cannot clash + o2::framework::HistogramRegistry hRegistry{"FemtoDndetaTriplet", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + o2::framework::HistogramRegistry hRegistryTrigger{"FemtoDndetaTripletTrigger", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + o2::framework::HistogramRegistry hRegistryGenTrigger{"FemtoDndetaTripletGenTrigger", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + const bool processDataWithStrangeness = doprocessTrackTrackTrackWithStrangeness || doprocessTrackTrackV0WithStrangeness; + const bool processMc = doprocessTrackTrackTrackMc || doprocessTrackTrackV0Mc; + const int nProcess = static_cast(doprocessTrackTrackTrack) + static_cast(doprocessTrackTrackV0) + + static_cast(doprocessTrackTrackTrackWithStrangeness) + static_cast(doprocessTrackTrackV0WithStrangeness) + + static_cast(doprocessTrackTrackTrackMc) + static_cast(doprocessTrackTrackV0Mc); + if (nProcess != 1) { + LOG(fatal) << "Exactly one process function has to be activated (found " << nProcess << "). Breaking..."; + } + + const modes::Trigger trigger = (doprocessTrackTrackTrack || doprocessTrackTrackTrackWithStrangeness || doprocessTrackTrackTrackMc) ? modes::Trigger::kTrackTrackTrack : modes::Trigger::kTrackTrackV0; + LOG(info) << "Trigger: " << modes::triggerToString(trigger); + + dndetaBuilder.init(&hRegistry, confDndeta, confDndetaAcceptance, collisionSelection, + confDndetaTracksGlobal, confDndetaTrackGlobalBinning, confDndetaTrackGlobalQaBinning, + confDndetaTracksItsOnly, confDndetaTrackItsOnlyBinning, confDndetaTrackItsOnlyQaBinning, + confDndetaBinning, processMc, processDataWithStrangeness); + if (dndetaBuilder.useGenTrigger() && !processMc) { + LOG(warn) << "Dndeta.useGenTrigger is only used for mc processing. Ignoring it."; + } + + // setup histogram specs + std::map> colHistSpec; + std::map> trackHistSpec1; + std::map> trackHistSpec2; + std::map> trackHistSpec3; + std::map> posDauSpec; + std::map> negDauSpec; + std::map> lambdaHistSpec; + std::map> tripletHistSpec; + std::map> tripletCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confTripletCleanerBinning); + + if (!processMc) { + colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + trackHistSpec1 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning1); + trackHistSpec2 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning2); + trackHistSpec3 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning3); + posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); + tripletHistSpec = triplethistmanager::makeTripletHistSpecMap(confTripletBinning, confMixing); + } else { + colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + trackHistSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning1); + trackHistSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning2); + trackHistSpec3 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning3); + posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); + tripletHistSpec = triplethistmanager::makeTripletMcHistSpecMap(confTripletBinning, confMixing); + } + + // only the builder of the active trigger is initialized + // only same event processing is used; the mixed event histograms are booked but stay empty + if (trigger == modes::Trigger::kTrackTrackTrack) { + std::map> ctrHistSpec = closepairrejection::makeCprHistSpecMap(confCtrTrackTrackTrack); + if (!processMc) { + tripletTrackTrackTrackBuilder.init(&hRegistryTrigger, confCollisionBinning, confTrackSelection1, confTrackSelection2, confTrackSelection3, confTrackCleaner1, confTrackCleaner2, confTrackCleaner3, confCtrTrackTrackTrack, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, trackHistSpec3, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); + } else { + tripletTrackTrackTrackBuilder.init(&hRegistryTrigger, confCollisionBinning, confTrackSelection1, confTrackSelection2, confTrackSelection3, confTrackCleaner1, confTrackCleaner2, confTrackCleaner3, confCtrTrackTrackTrack, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, trackHistSpec3, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); + } + } else { + std::map> ctrHistSpec = closepairrejection::makeCprHistSpecMap(confCtrTrackTrackV0); + if (!processMc) { + tripletTrackTrackLambdaBuilder.init(&hRegistryTrigger, confCollisionBinning, confTrackSelection1, confTrackSelection2, confLambdaSelection, confTrackCleaner1, confTrackCleaner2, confLambdaCleaner, confCtrTrackTrackV0, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, lambdaHistSpec, posDauSpec, negDauSpec, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); + } else { + tripletTrackTrackLambdaBuilder.init(&hRegistryTrigger, confCollisionBinning, confTrackSelection1, confTrackSelection2, confLambdaSelection, confTrackCleaner1, confTrackCleaner2, confLambdaCleaner, confCtrTrackTrackV0, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, lambdaHistSpec, posDauSpec, negDauSpec, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); + } + } + + // generator-level trigger; the species come from McParticleSelection1/2/3, so it covers + // both triplet triggers (a lambda is just another mc particle) + if (processMc && dndetaBuilder.useGenTrigger()) { + std::map> genColHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + std::map> mcParticleHistSpec1 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning1); + std::map> mcParticleHistSpec2 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning2); + std::map> mcParticleHistSpec3 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning3); + std::map> genTripletHistSpec = triplethistmanager::makeTripletMcTruthHistSpecMap(confTripletBinning, confMixing); + std::map> genCtrHistSpec = closepairrejection::makeCprHistSpecMap(confCtrMcParticleMcParticleMcParticle); + tripletMcParticleMcParticleMcParticleBuilder.init(&hRegistryGenTrigger, confCollisionBinning, confMcParticleSelection1, confMcParticleSelection2, confMcParticleSelection3, confMcParticleBinning1, confMcParticleBinning2, confMcParticleBinning3, confMcParticleCleaner1, confMcParticleCleaner2, confMcParticleCleaner3, confCtrMcParticleMcParticleMcParticle, confMixing, confTripletBinning, confTripletCuts, genColHistSpec, mcParticleHistSpec1, mcParticleHistSpec2, mcParticleHistSpec3, genTripletHistSpec, genCtrHistSpec, tripletCleanerHistSpec); + } + + hRegistry.print(); + hRegistryTrigger.print(); + hRegistryGenTrigger.print(); + }; + + /// generator-level triplet trigger, or always true if not configured + template + bool evaluateGenTrigger(T1 const& mcCol, T2 const& mcParticles, T3 const& mcMothers, T4 const& mcPartonicMothers) + { + if (!dndetaBuilder.useGenTrigger()) { + return true; + } + return tripletMcParticleMcParticleMcParticleBuilder.processSameEvent(mcCol, mcParticles, mcMothers, mcPartonicMothers, mcParticlePartition1, mcParticlePartition2, mcParticlePartition3, cache); + } + + template + void fillStrangeness(T const& col) + { + auto lambdas = strangeLambdaPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto k0shorts = strangeK0shortPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + dndetaBuilder.processStrangeness(col, lambdas, k0shorts); + } + + // data + void processTrackTrackTrack(FemtoCollision const& col, FemtoTracks const& tracks) + { + dndetaBuilder.processData(col, dndetaTrackPartitionGlobal, dndetaTrackPartitionItsOnly, cache, [&]() { + return tripletTrackTrackTrackBuilder.processSameEvent(col, tracks, trackPartition1, trackPartition2, trackPartition3, cache); + }); + } + PROCESS_SWITCH(FemtoDndetaTriplet, processTrackTrackTrack, "Data, track-track-track trigger", true); + + void processTrackTrackV0(FemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/) + { + dndetaBuilder.processData(col, dndetaTrackPartitionGlobal, dndetaTrackPartitionItsOnly, cache, [&]() { + return tripletTrackTrackLambdaBuilder.processSameEvent(col, tracks, trackPartition1, trackPartition2, lambdaPartition, cache); + }); + } + PROCESS_SWITCH(FemtoDndetaTriplet, processTrackTrackV0, "Data, track-track-lambda trigger", false); + + // data with strangeness yields + void processTrackTrackTrackWithStrangeness(FemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/, FemtoK0shorts const& /*k0shorts*/) + { + if (dndetaBuilder.processData(col, dndetaTrackPartitionGlobal, dndetaTrackPartitionItsOnly, cache, [&]() { + return tripletTrackTrackTrackBuilder.processSameEvent(col, tracks, trackPartition1, trackPartition2, trackPartition3, cache); + })) { + fillStrangeness(col); + } + } + PROCESS_SWITCH(FemtoDndetaTriplet, processTrackTrackTrackWithStrangeness, "Data with strangeness yields, track-track-track trigger", false); + + void processTrackTrackV0WithStrangeness(FemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/, FemtoK0shorts const& /*k0shorts*/) + { + if (dndetaBuilder.processData(col, dndetaTrackPartitionGlobal, dndetaTrackPartitionItsOnly, cache, [&]() { + return tripletTrackTrackLambdaBuilder.processSameEvent(col, tracks, trackPartition1, trackPartition2, lambdaPartition, cache); + })) { + fillStrangeness(col); + } + } + PROCESS_SWITCH(FemtoDndetaTriplet, processTrackTrackV0WithStrangeness, "Data with strangeness yields, track-track-lambda trigger", false); + + // mc + void processTrackTrackTrackMc(FemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + dndetaBuilder.processMc( + cols, mcCols, dndetaTrackWithLabelPartitionGlobal, dndetaTrackWithLabelPartitionItsOnly, cache, mcParticles, mcMothers, perMcColParticles, pdg, + [&](auto const& col) { + return tripletTrackTrackTrackBuilder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition1, trackWithLabelPartition2, trackWithLabelPartition3, mcParticles, mcMothers, mcPartonicMothers, cache); + }, + [&](auto const& mcCol) { return evaluateGenTrigger(mcCol, mcParticles, mcMothers, mcPartonicMothers); }); + } + PROCESS_SWITCH(FemtoDndetaTriplet, processTrackTrackTrackMc, "MC, track-track-track trigger", false); + + void processTrackTrackV0Mc(FemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + dndetaBuilder.processMc( + cols, mcCols, dndetaTrackWithLabelPartitionGlobal, dndetaTrackWithLabelPartitionItsOnly, cache, mcParticles, mcMothers, perMcColParticles, pdg, + [&](auto const& col) { + return tripletTrackTrackLambdaBuilder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition1, trackWithLabelPartition2, lambdaWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + }, + [&](auto const& mcCol) { return evaluateGenTrigger(mcCol, mcParticles, mcMothers, mcPartonicMothers); }); + } + PROCESS_SWITCH(FemtoDndetaTriplet, processTrackTrackV0Mc, "MC, track-track-lambda trigger", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoTripletMcParticleMcParticleMcParticle.cxx b/PWGCF/Femto/Tasks/femtoTripletMcParticleMcParticleMcParticle.cxx new file mode 100644 index 00000000000..fc4c36b8ed6 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoTripletMcParticleMcParticleMcParticle.cxx @@ -0,0 +1,152 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file femtoTripletMcParticleMcParticleMcParticle.cxx +/// \brief Task for triplets of generated particles (mc truth only) +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/closeTripletRejection.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/mcBuilder.h" +#include "PWGCF/Femto/Core/mcParticleHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairCleaner.h" +#include "PWGCF/Femto/Core/particleCleaner.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/tripletBuilder.h" +#include "PWGCF/Femto/Core/tripletHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoTripletMcParticleMcParticleMcParticle { + + // setup tables + using FemtoMcCollisions = o2::aod::FMcCols; + using FilteredFemtoMcCollisions = o2::soa::Filtered; + using FilteredFemtoMcCollision = FilteredFemtoMcCollisions::iterator; + + using FemtoMcParticles = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup collisions + mcbuilder::ConfMcCollisionFilters collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_MC_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup mc particles + mcbuilder::ConfMcParticleSelection1 confMcParticleSelection1; + mcparticlehistmanager::ConfMcParticleBinning1 confMcParticleBinning1; + particlecleaner::ConfMcParticleCleaner1 confMcParticleCleaner1; + + mcbuilder::ConfMcParticleSelection2 confMcParticleSelection2; + mcparticlehistmanager::ConfMcParticleBinning2 confMcParticleBinning2; + particlecleaner::ConfMcParticleCleaner2 confMcParticleCleaner2; + + mcbuilder::ConfMcParticleSelection3 confMcParticleSelection3; + mcparticlehistmanager::ConfMcParticleBinning3 confMcParticleBinning3; + particlecleaner::ConfMcParticleCleaner3 confMcParticleCleaner3; + + o2::framework::Partition mcParticlesPartition1 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection1); + o2::framework::Partition mcParticlesPartition2 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection2); + o2::framework::Partition mcParticlesPartition3 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection3); + + // setup triplets + triplethistmanager::ConfTripletBinning confTripletBinning; + triplethistmanager::ConfTripletCuts confTripletCuts; + paircleaner::ConfPairCleanerBinning confTripletCleanerBinning; + + closetripletrejection::ConfCtrMcParticleMcParticleMcParticle confCtr; + + tripletbuilder::TripletMcParticleMcParticleMcParticleBuilder< + mcparticlehistmanager::PrefixMcParticle1, + mcparticlehistmanager::PrefixMcParticle2, + mcparticlehistmanager::PrefixMcParticle3, + triplethistmanager::PrefixMcParticleMcParticleMcParticleSe, + triplethistmanager::PrefixMcParticleMcParticleMcParticleMe, + closetripletrejection::PrefixMcParticle1McParticle2Se, + closetripletrejection::PrefixMcParticle2McParticle3Se, + closetripletrejection::PrefixMcParticle1McParticle3Se, + closetripletrejection::PrefixMcParticle1McParticle2Me, + closetripletrejection::PrefixMcParticle2McParticle3Me, + closetripletrejection::PrefixMcParticle1McParticle3Me> + tripletMcParticleMcParticleMcParticleBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + o2::framework::ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + triplethistmanager::ConfMixing confMixing; + + o2::framework::HistogramRegistry hRegistry{"FemtoMcParticleMcParticleMcParticle", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histogram specs + std::map> colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + std::map> mcParticleHistSpec1 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning1); + std::map> mcParticleHistSpec2 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning2); + std::map> mcParticleHistSpec3 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning3); + std::map> tripletHistSpec = triplethistmanager::makeTripletMcTruthHistSpecMap(confTripletBinning, confMixing); + std::map> ctrHistSpec = closepairrejection::makeCprHistSpecMap(confCtr); + std::map> tripletCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confTripletCleanerBinning); + + tripletMcParticleMcParticleMcParticleBuilder.init(&hRegistry, confCollisionBinning, confMcParticleSelection1, confMcParticleSelection2, confMcParticleSelection3, confMcParticleBinning1, confMcParticleBinning2, confMcParticleBinning3, confMcParticleCleaner1, confMcParticleCleaner2, confMcParticleCleaner3, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, mcParticleHistSpec1, mcParticleHistSpec2, mcParticleHistSpec3, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); + + hRegistry.print(); + }; + + void processSameEvent(FilteredFemtoMcCollision const& col, FemtoMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + tripletMcParticleMcParticleMcParticleBuilder.processSameEvent(col, mcParticles, mcMothers, mcPartonicMothers, mcParticlesPartition1, mcParticlesPartition2, mcParticlesPartition3, cache); + } + PROCESS_SWITCH(FemtoTripletMcParticleMcParticleMcParticle, processSameEvent, "Enable processing same event processing", true); + + void processMixedEvent(FilteredFemtoMcCollisions const& cols, FemtoMcParticles const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + tripletMcParticleMcParticleMcParticleBuilder.processMixedEvent(cols, mcParticles, mcMothers, mcPartonicMothers, mcParticlesPartition1, mcParticlesPartition2, mcParticlesPartition3, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoTripletMcParticleMcParticleMcParticle, processMixedEvent, "Enable processing mixed event processing", true); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +}