diff --git a/ALICE3/Core/Decayer.h b/ALICE3/Core/Decayer.h index 52ca0a75adb..8f88e4e311b 100644 --- a/ALICE3/Core/Decayer.h +++ b/ALICE3/Core/Decayer.h @@ -31,13 +31,12 @@ #include #include +#include #include #include #include -namespace o2 -{ -namespace upgrade +namespace o2::upgrade { class Decayer @@ -47,44 +46,27 @@ class Decayer Decayer() = default; template - std::vector decayParticle(const TDatabase& pdgDB, const OTFParticle& particle) + std::vector decayParticle(const OTFParticle& particle, const TDatabase& pdgDB) { - const auto& particleInfo = pdgDB->GetParticle(particle.pdgCode()); + auto particleInfo = pdgDB->GetParticle(particle.pdgCode()); if (!particleInfo) { return {}; } const int charge = particleInfo->Charge() / 3; const double mass = particleInfo->Mass(); - - const double u = mRand3.Uniform(0.001, 0.999); - const double ctau = o2::constants::physics::LightSpeedCm2S * particleInfo->Lifetime(); // cm - const double betaGamma = particle.p() / mass; - const double rxyz = -betaGamma * ctau * std::log(1 - u); - double px, py, e; + std::array decayVtx = generateDecayVertex(particle, pdgDB); + mVx = decayVtx[0]; + mVy = decayVtx[1]; + mVz = decayVtx[2]; + double px{}, py{}, e{}; if (!charge) { - mVx = particle.vx() + rxyz * (particle.px() / particle.p()); - mVy = particle.vy() + rxyz * (particle.py() / particle.p()); - mVz = particle.vz() + rxyz * (particle.pz() / particle.p()); px = particle.px(); py = particle.py(); } else { - o2::track::TrackParCov track; - o2::math_utils::CircleXYf_t circle; - o2::upgrade::convertOTFParticleToO2Track(particle, track, pdgDB); - - float sna{}, csa{}; - track.getCircleParams(mBz, circle, sna, csa); - const double rxy = rxyz / std::sqrt(1. + track.getTgl() * track.getTgl()); - const double theta = rxy / circle.rC; - - mVx = ((particle.vx() - circle.xC) * std::cos(theta) - (particle.vy() - circle.yC) * std::sin(theta)) + circle.xC; - mVy = ((particle.vy() - circle.yC) * std::cos(theta) + (particle.vx() - circle.xC) * std::sin(theta)) + circle.yC; - mVz = particle.vz() + rxyz * (particle.pz() / track.getP()); - - px = particle.px() * std::cos(theta) - particle.py() * std::sin(theta); - py = particle.py() * std::cos(theta) + particle.px() * std::sin(theta); + px = particle.px() * std::cos(mTheta) - particle.py() * std::sin(mTheta); + py = particle.py() * std::cos(mTheta) + particle.px() * std::sin(mTheta); } double brTotal = 0.; @@ -133,6 +115,42 @@ class Decayer return decayProducts; } + template + std::array generateDecayVertex(const TParticle& particle, const TDatabase& pdgDB) + { + std::array decayVertex{}; + auto particleInfo = pdgDB->GetParticle(particle.pdgCode()); + if (!particleInfo) { + return {}; + } + + const int charge = particleInfo->Charge() / 3; + const double mass = particleInfo->Mass(); + const double u = mRand3.Uniform(0.001, 0.999); + const double ctau = o2::constants::physics::LightSpeedCm2S * particleInfo->Lifetime(); // cm + const double betaGamma = particle.p() / mass; + const double rxyz = -betaGamma * ctau * std::log(1 - u); + + if (!charge) { + decayVertex[0] = particle.vx() + rxyz * (particle.px() / particle.p()); + decayVertex[1] = particle.vy() + rxyz * (particle.py() / particle.p()); + decayVertex[2] = particle.vz() + rxyz * (particle.pz() / particle.p()); + } else { + o2::math_utils::CircleXYf_t circle; + o2::track::TrackParCov track = o2::upgrade::convertMCParticleToO2Track(particle, pdgDB); + + float sna{}, csa{}; + track.getCircleParams(mBz, circle, sna, csa); + const double rxy = rxyz / std::sqrt(1. + track.getTgl() * track.getTgl()); + mTheta = rxy / circle.rC; + + decayVertex[0] = ((particle.vx() - circle.xC) * std::cos(mTheta) - (particle.vy() - circle.yC) * std::sin(mTheta)) + circle.xC; + decayVertex[1] = ((particle.vy() - circle.yC) * std::cos(mTheta) + (particle.vx() - circle.xC) * std::sin(mTheta)) + circle.yC; + decayVertex[2] = particle.vz() + rxyz * (particle.pz() / track.getP()); + } + return decayVertex; + } + // Setters void setBField(const double b) { mBz = b; } void setSeed(const int seed) @@ -142,18 +160,18 @@ class Decayer } // Getters - float getSecondaryVertexX() const { return static_cast(mVx); } - float getSecondaryVertexY() const { return static_cast(mVy); } - float getSecondaryVertexZ() const { return static_cast(mVz); } - float getDecayRadius() const { return static_cast(std::hypot(mVx, mVy)); } + [[nodiscard]] float getSecondaryVertexX() const { return static_cast(mVx); } + [[nodiscard]] float getSecondaryVertexY() const { return static_cast(mVy); } + [[nodiscard]] float getSecondaryVertexZ() const { return static_cast(mVz); } + [[nodiscard]] float getDecayRadius() const { return static_cast(std::hypot(mVx, mVy)); } private: double mBz{20.}; // kG double mVx{-1.}, mVy{-1.}, mVz{-1.}; - TRandom3 mRand3{}; + double mTheta{}; + TRandom3 mRand3; }; -} // namespace upgrade -} // namespace o2 +} // namespace o2::upgrade #endif // ALICE3_CORE_DECAYER_H_ diff --git a/ALICE3/DataModel/OTFTOF.h b/ALICE3/DataModel/OTFTOF.h index b4bf1f26670..8643abc959c 100644 --- a/ALICE3/DataModel/OTFTOF.h +++ b/ALICE3/DataModel/OTFTOF.h @@ -150,6 +150,26 @@ DECLARE_SOA_DYNAMIC_COLUMN(NSigmaOuterTOF, nSigmaOuterTOF, //! General function } }); +DECLARE_SOA_COLUMN(NSigmaSplusInnerTOF, nSigmaSplusInnerTOF, float); //! NSigma Sigma plus InnerTOF +DECLARE_SOA_COLUMN(NSigmaSminusInnerTOF, nSigmaSminusInnerTOF, float); //! NSigma Sigma minus InnerTOF +DECLARE_SOA_COLUMN(NSigmaXiInnerTOF, nSigmaXiInnerTOF, float); //! NSigma Xi InnerTOF +DECLARE_SOA_COLUMN(NSigmaOmegaInnerTOF, nSigmaOmegaInnerTOF, float); //! NSigma Omega InnerTOF + +DECLARE_SOA_COLUMN(NSigmaSplusOuterTOF, nSigmaSplusOuterTOF, float); //! NSigma Sigma plus OuterTOF +DECLARE_SOA_COLUMN(NSigmaSminusOuterTOF, nSigmaSminusOuterTOF, float); //! NSigma Sigma minus OuterTOF +DECLARE_SOA_COLUMN(NSigmaXiOuterTOF, nSigmaXiOuterTOF, float); //! NSigma Xi OuterTOF +DECLARE_SOA_COLUMN(NSigmaOmegaOuterTOF, nSigmaOmegaOuterTOF, float); //! NSigma Omega OuterTOF + +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeSp, innerTOFExpectedTimeSp, float); //! Reconstructed expected time at the InnerTOF for the Sigma plus mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeSm, innerTOFExpectedTimeSm, float); //! Reconstructed expected time at the InnerTOF for the Sigma minus mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeXi, innerTOFExpectedTimeXi, float); //! Reconstructed expected time at the InnerTOF for the Xi mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeOm, innerTOFExpectedTimeOm, float); //! Reconstructed expected time at the InnerTOF for the Omega mass hypotheses + +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeSp, outerTOFExpectedTimeSp, float); //! Reconstructed expected time at the OuterTOF for the Sigma plus mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeSm, outerTOFExpectedTimeSm, float); //! Reconstructed expected time at the OuterTOF for the Sigma minus mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeXi, outerTOFExpectedTimeXi, float); //! Reconstructed expected time at the OuterTOF for the Xi mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeOm, outerTOFExpectedTimeOm, float); //! Reconstructed expected time at the OuterTOF for the Omega mass hypotheses + } // namespace upgrade_tof DECLARE_SOA_TABLE(UpgradeTofMCs, "AOD", "UPGRADETOFMC", @@ -222,9 +242,28 @@ DECLARE_SOA_TABLE(UpgradeTofExpectedTimes, "AOD", "UPGRADETOFEXPT", upgrade_tof::OuterTOFExpectedTimeHe3, upgrade_tof::OuterTOFExpectedTimeAl); +DECLARE_SOA_TABLE(UpgradeTofShortLiveds, "AOD", "UPGRTOFSHRTLVD", + upgrade_tof::NSigmaSplusInnerTOF, + upgrade_tof::NSigmaSminusInnerTOF, + upgrade_tof::NSigmaXiInnerTOF, + upgrade_tof::NSigmaOmegaInnerTOF, + upgrade_tof::NSigmaSplusOuterTOF, + upgrade_tof::NSigmaSminusOuterTOF, + upgrade_tof::NSigmaXiOuterTOF, + upgrade_tof::NSigmaOmegaOuterTOF, + upgrade_tof::InnerTOFExpectedTimeSp, + upgrade_tof::InnerTOFExpectedTimeSm, + upgrade_tof::InnerTOFExpectedTimeXi, + upgrade_tof::InnerTOFExpectedTimeOm, + upgrade_tof::OuterTOFExpectedTimeSp, + upgrade_tof::OuterTOFExpectedTimeSm, + upgrade_tof::OuterTOFExpectedTimeXi, + upgrade_tof::OuterTOFExpectedTimeOm); + using UpgradeTofMC = UpgradeTofMCs::iterator; using UpgradeTof = UpgradeTofs::iterator; using UpgradeTofExpectedTime = UpgradeTofExpectedTimes::iterator; +using UpgradeTofShortLived = UpgradeTofShortLiveds::iterator; } // namespace o2::aod diff --git a/ALICE3/DataModel/ReducedTablesAlice3.h b/ALICE3/DataModel/ReducedTablesAlice3.h index f11becd0945..363ba50842f 100644 --- a/ALICE3/DataModel/ReducedTablesAlice3.h +++ b/ALICE3/DataModel/ReducedTablesAlice3.h @@ -39,9 +39,9 @@ namespace o2::aod namespace reducedeventalice3 { DECLARE_SOA_COLUMN(MultDensity, multDensity, float); -DECLARE_SOA_COLUMN(MCPosX, mcPosX, float); //! MC event position X -DECLARE_SOA_COLUMN(MCPosY, mcPosY, float); //! MC event position Y -DECLARE_SOA_COLUMN(MCPosZ, mcPosZ, float); //! MC event position Z +DECLARE_SOA_COLUMN(McPosX, mcPosX, float); //! MC event position X +DECLARE_SOA_COLUMN(McPosY, mcPosY, float); //! MC event position Y +DECLARE_SOA_COLUMN(McPosZ, mcPosZ, float); //! MC event position Z } // namespace reducedeventalice3 DECLARE_SOA_TABLE_STAGED(ReA3Events, "REA3EVENT", //! Main event information table @@ -63,7 +63,7 @@ DECLARE_SOA_TABLE(ReducedA3EventsInfo, "AOD", "REA3EVENTINFO", //! Main event DECLARE_SOA_TABLE(ReA3MCEvents, "AOD", "REA3MCEVENT", //! Event level MC truth information o2::soa::Index<>, - mccollision::GeneratorsID, reducedeventalice3::MCPosX, reducedeventalice3::MCPosY, reducedeventalice3::MCPosZ, + mccollision::GeneratorsID, reducedeventalice3::McPosX, reducedeventalice3::McPosY, reducedeventalice3::McPosZ, mccollision::T, mccollision::Weight, mccollision::ImpactParameter, mcmult_alice3::MultMC, mcmult_alice3::MultMC25, mcmult_alice3::MultMC125, mcmult_alice3::MultMC09); @@ -73,7 +73,7 @@ using ReA3Event = ReA3Events::iterator; namespace reducedtrackalice3 { // basic track information -DECLARE_SOA_INDEX_COLUMN(ReA3Event, rea3event); //! +DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3Event); //! DECLARE_SOA_INDEX_COLUMN(Track, track); //! // ---- flags reserved for storing various information during filtering DECLARE_SOA_BITMAP_COLUMN(FilteringFlags, filteringFlags, 64); //! @@ -124,7 +124,7 @@ DECLARE_SOA_TABLE(ReducedA3TracksBarrelCov, "AOD", "REA3BARRELCOV", //! track::CSnpSnp, track::CTglY, track::CTglZ, track::CTglSnp, track::CTglTgl, track::C1PtY, track::C1PtZ, track::C1PtSnp, track::C1PtTgl, track::C1Pt21Pt2); -namespace reducedA3trackMC +namespace reduceda3trackmc { DECLARE_SOA_INDEX_COLUMN(ReA3MCEvent, reA3MCEvent); //! DECLARE_SOA_COLUMN(McReducedFlags, mcReducedFlags, uint16_t); //! Flags to hold compressed MC selection information @@ -151,27 +151,26 @@ DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity float pz = pt * std::sinh(eta); if ((e - pz) > static_cast(1e-7)) { return 0.5f * std::log((e + pz) / (e - pz)); - } else { - return -999.0f; } + return -999.0f; }); -} // namespace reducedA3trackMC +} // namespace reduceda3trackmc // NOTE: This table is nearly identical to the one from Framework (except that it points to the event ID, not the BC id) // This table contains all MC truth tracks (both barrel and muon) DECLARE_SOA_TABLE(ReA3MCTracks, "AOD", "REA3MCTRACK", //! MC track information (on disk) - o2::soa::Index<>, reducedA3trackMC::ReA3MCEventId, + o2::soa::Index<>, reduceda3trackmc::ReA3MCEventId, mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, - reducedA3trackMC::MothersIds, reducedA3trackMC::DaughtersIdSlice, + reduceda3trackmc::MothersIds, reduceda3trackmc::DaughtersIdSlice, mcparticle::Weight, - reducedA3trackMC::Pt, reducedA3trackMC::Eta, reducedA3trackMC::Phi, reducedA3trackMC::E, + reduceda3trackmc::Pt, reduceda3trackmc::Eta, reduceda3trackmc::Phi, reduceda3trackmc::E, mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, - reducedA3trackMC::McReducedFlags, - reducedA3trackMC::Px, - reducedA3trackMC::Py, - reducedA3trackMC::Pz, - reducedA3trackMC::P, - reducedA3trackMC::Y, + reduceda3trackmc::McReducedFlags, + reduceda3trackmc::Px, + reduceda3trackmc::Py, + reduceda3trackmc::Pz, + reduceda3trackmc::P, + reduceda3trackmc::Y, mcparticle::ProducedByGenerator, mcparticle::FromBackgroundEvent, mcparticle::GetGenStatusCode, @@ -190,7 +189,7 @@ DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); // NOTE: MC labels. This table has one entry for each reconstructed track (joinable with the track tables) // The McParticleId points to the position of the MC truth track from the ReducedTracksMC table DECLARE_SOA_TABLE(ReducedA3TracksBarrelLabels, "AOD", "REA3BARLA", //! - reduceda3barreltracklabel::ReA3MCTrackId, reduceda3barreltracklabel::McMask, reducedA3trackMC::McReducedFlags); + reduceda3barreltracklabel::ReA3MCTrackId, reduceda3barreltracklabel::McMask, reduceda3trackmc::McReducedFlags); using ReducedA3TrackBarrelLabel = ReducedA3TracksBarrelLabels::iterator; @@ -222,15 +221,15 @@ DECLARE_SOA_TABLE(ReducedA3MCEventLabels, "AOD", "REA3MCCOLLBL", //! Table joine using ReducedA3MCEventLabel = ReducedA3MCEventLabels::iterator; -namespace reducedA3track_association +namespace reduceda3trackassociation { -DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3event); //! ReducedEvent index -DECLARE_SOA_INDEX_COLUMN(ReA3Track, reA3track); //! ReducedTrack index -} // namespace reducedA3track_association +DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3Event); //! ReducedEvent index +DECLARE_SOA_INDEX_COLUMN(ReA3Track, reA3Track); //! ReducedTrack index +} // namespace reduceda3trackassociation DECLARE_SOA_TABLE(ReducedA3TracksAssoc, "AOD", "REA3ASSOC", //! Table for reducedtrack-to-reducedcollision association - reducedA3track_association::ReA3EventId, - reducedA3track_association::ReA3TrackId); + reduceda3trackassociation::ReA3EventId, + reduceda3trackassociation::ReA3TrackId); DECLARE_SOA_TABLE(ReducedA3PIDTOF, "AOD", "REA3PIDTOF", upgrade_tof::TOFEventTime, diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index c03447ecb75..2c8c4dea0c9 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -152,7 +152,7 @@ struct OnTheFlyDecayer { } particle.setBitOff(o2::upgrade::DecayerBits::IsAlive); - std::vector decayStack = decayer.decayParticle(pdgDB, particle); + std::vector decayStack = decayer.decayParticle(particle, pdgDB); if (decayStack.empty()) { continue; } diff --git a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx index 13f70c2980c..15d68e1306b 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx @@ -83,6 +83,7 @@ struct OnTheFlyTofPid { Produces upgradeTofMC; Produces upgradeTof; Produces upgradeTofExpectedTime; + Produces upgradeTofShortLived; // necessary for particle charges Service pdg; @@ -132,6 +133,7 @@ struct OnTheFlyTofPid { Configurable nBinsEta{"nBinsEta", 400, "number of bins plot relative eta error"}; Configurable nBinsMult{"nBinsMult", 200, "number of bins in multiplicity"}; Configurable maxMultRange{"maxMultRange", 1000.f, "upper limit in multiplicity plots"}; + Configurable> particlesForQa{"particlesForQa", {11, 13, 211, 321, 2212}, "pdgCodes for QA plots"}; } plotsConfig; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; @@ -145,13 +147,64 @@ struct OnTheFlyTofPid { // for handling basic QA histograms if requested HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; OutputObj listEfficiency{"efficiency"}; - static constexpr int kParticles = 9; + + enum ParticleType : int { El = 0, // electron + Mu, // muon + Pi, // pion + Ka, // kaon + Pr, // proton + Sp, // sigma plus + Sm, // sigma minus + Xi, // xi + Om, // omega + De, // deuteron + Tr, // triton + He, // helium 3 + Al, // alpha + NParticles }; + + struct ParticleInfo { + const char* texName; + const char* name; + ParticleType type; + int pdgCode; + double mass; + float charge; + }; + + static constexpr ParticleInfo Particles[NParticles] = { + {"#it{e}", "Elec", El, PDG_t::kElectron, o2::constants::physics::MassElectron, 1.f}, + {"#it{#mu}", "Muon", Mu, PDG_t::kMuonMinus, o2::constants::physics::MassMuon, 1.f}, + {"#it{#pi}", "Pion", Pi, PDG_t::kPiPlus, o2::constants::physics::MassPionCharged, 1.f}, + {"#it{K}", "Kaon", Ka, PDG_t::kKPlus, o2::constants::physics::MassKaonCharged, 1.f}, + {"#it{p}", "Prot", Pr, PDG_t::kProton, o2::constants::physics::MassProton, 1.f}, + {"#it{#SigmaPlus}", "Sigp", Sp, PDG_t::kSigmaPlus, o2::constants::physics::MassSigmaPlus, 1.f}, + {"#it{#SigmaMinus}", "Sigm", Sm, PDG_t::kSigmaMinus, o2::constants::physics::MassSigmaMinus, 1.f}, + {"#it{#Xi}", "Xi", Xi, PDG_t::kXiMinus, o2::constants::physics::MassXiMinus, 1.f}, + {"#it{#Omega}", "Omeg", Om, PDG_t::kOmegaMinus, o2::constants::physics::MassOmegaMinus, 1.f}, + {"#it{d}", "Deut", De, o2::constants::physics::kDeuteron, o2::constants::physics::MassDeuteron, 1.f}, + {"#it{t}", "Trit", Tr, o2::constants::physics::kTriton, o2::constants::physics::MassTriton, 1.f}, + {"^{3}He", "He", He, o2::constants::physics::kHelium3, o2::constants::physics::MassHelium3, 2.f}, + {"#it{#alpha}", "Al", Al, o2::constants::physics::kAlpha, o2::constants::physics::MassAlpha, 2.f}, + }; + + bool doQaForParticle(const int pdgCode) + { + return std::find(plotsConfig.particlesForQa.value.begin(), plotsConfig.particlesForQa.value.end(), std::abs(pdgCode)) != plotsConfig.particlesForQa.value.end(); + } // Configuration defined at init time o2::fastsim::GeometryContainer mGeoContainer; float mMagneticField = 0.0f; void init(o2::framework::InitContext& initContext) { + // Check Particles: every row's declared type must match its array position. + for (int i = 0; i < NParticles; ++i) { + if (Particles[i].type != i) { + LOG(fatal) << "Particles in ParticleInfo not ordered according to enum!"; + } + } + mGeoContainer.setCcdbManager(ccdb.operator->()); mGeoContainer.init(initContext); @@ -236,14 +289,14 @@ struct OnTheFlyTofPid { histos.add("iTOF/h2dTrackLengthInnerVsPt", "h2dTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); histos.add("iTOF/h2dTrackLengthInnerRecoVsPt", "h2dTrackLengthInnerRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); histos.add("iTOF/h2dDeltaTrackLengthInnerVsPt", "h2dDeltaTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); - histos.add("iTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.innerTOFLength / 2, simConfig.innerTOFLength / 2}, {1000, 0, simConfig.innerTOFRadius * 2 * M_PI}}); + histos.add("iTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.innerTOFLength / 2, simConfig.innerTOFLength / 2}, {1000, 0, simConfig.innerTOFRadius * o2::constants::math::TwoPI}}); histos.add("oTOF/h2dVelocityVsMomentumOuter", "h2dVelocityVsMomentumOuter", kTH2F, {axisMomentum, axisVelocity}); histos.add("oTOF/h2dVelocityVsRigidityOuter", "h2dVelocityVsRigidityOuter", kTH2F, {axisRigidity, axisVelocity}); histos.add("oTOF/h2dTrackLengthOuterVsPt", "h2dTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); histos.add("oTOF/h2dTrackLengthOuterRecoVsPt", "h2dTrackLengthOuterRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); histos.add("oTOF/h2dDeltaTrackLengthOuterVsPt", "h2dDeltaTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); - histos.add("oTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.outerTOFLength / 2, simConfig.outerTOFLength / 2}, {1000, 0, simConfig.outerTOFRadius * 2 * M_PI}}); + histos.add("oTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.outerTOFLength / 2, simConfig.outerTOFLength / 2}, {1000, 0, simConfig.outerTOFRadius * o2::constants::math::TwoPI}}); const AxisSpec axisPt{static_cast(plotsConfig.nBinsP), 0.0f, +4.0f, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisEta{static_cast(plotsConfig.nBinsEta), -2.0f, +2.0f, "#eta"}; @@ -252,35 +305,41 @@ struct OnTheFlyTofPid { histos.add("h2dRelativePtResolution", "h2dRelativePtResolution", kTH2F, {axisPt, axisRelativePt}); histos.add("h2dRelativeEtaResolution", "h2dRelativeEtaResolution", kTH2F, {axisEta, axisRelativeEta}); - std::string particleNames[kParticles] = {"#it{e}", "#it{#mu}", "#it{#pi}", "#it{K}", "#it{p}", "#it{d}", "#it{t}", "^{3}He", "#it{#alpha}"}; - std::string particleNames2[kParticles] = {"Elec", "Muon", "Pion", "Kaon", "Prot", "Deut", "Trit", "He3", "Al"}; - for (int iTrue = 0; iTrue < kParticles; iTrue++) { + for (int iTrue = 0; iTrue < NParticles; iTrue++) { + if (!doQaForParticle(Particles[iTrue].pdgCode)) { + continue; + } + auto addHistogram = [&](const std::string& name, const AxisSpec& axis) { return histos.add(name, "", kTH2F, {axisMomentum, axis}); }; - const AxisSpec axisTrackTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, "Track time resolution - " + particleNames[iTrue] + " (ps)"}; - h2dInnerTimeResTrack[iTrue] = addHistogram("iTOF/res/h2dInnerTimeResTrack" + particleNames2[iTrue] + "VsP", axisTrackTimeRes); - h2dOuterTimeResTrack[iTrue] = addHistogram("oTOF/res/h2dOuterTimeResTrack" + particleNames2[iTrue] + "VsP", axisTrackTimeRes); - const AxisSpec axisTotalTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, "Total time resolution - " + particleNames[iTrue] + " (ps)"}; - h2dInnerTimeResTotal[iTrue] = addHistogram("iTOF/res/h2dInnerTimeResTotal" + particleNames2[iTrue] + "VsP", axisTotalTimeRes); - h2dOuterTimeResTotal[iTrue] = addHistogram("oTOF/res/h2dOuterTimeResTotal" + particleNames2[iTrue] + "VsP", axisTotalTimeRes); - for (int iHyp = 0; iHyp < kParticles; iHyp++) { - std::string nameTitleInner = "h2dInnerNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; - std::string nameTitleOuter = "h2dOuterNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; - std::string nameTitleInnerDelta = "h2dInnerDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; - std::string nameTitleOuterDelta = "h2dOuterDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + const AxisSpec axisTrackTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, std::string("Track time resolution - ") + Particles[iTrue].texName + " (ps)"}; + h2dInnerTimeResTrack[iTrue] = addHistogram(std::string("iTOF/res/h2dInnerTimeResTrack") + Particles[iTrue].name + "VsP", axisTrackTimeRes); + h2dOuterTimeResTrack[iTrue] = addHistogram(std::string("oTOF/res/h2dOuterTimeResTrack") + Particles[iTrue].name + "VsP", axisTrackTimeRes); + const AxisSpec axisTotalTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, std::string("Total time resolution - ") + Particles[iTrue].texName + " (ps)"}; + h2dInnerTimeResTotal[iTrue] = addHistogram(std::string("iTOF/res/h2dInnerTimeResTotal") + Particles[iTrue].name + "VsP", axisTotalTimeRes); + h2dOuterTimeResTotal[iTrue] = addHistogram(std::string("oTOF/res/h2dOuterTimeResTotal") + Particles[iTrue].name + "VsP", axisTotalTimeRes); + for (int iHyp = 0; iHyp < NParticles; iHyp++) { + if (!doQaForParticle(Particles[iHyp].pdgCode)) { + continue; + } + + std::string nameTitleInner = std::string("h2dInnerNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; + std::string nameTitleOuter = std::string("h2dOuterNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; + std::string nameTitleInnerDelta = std::string("h2dInnerDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; + std::string nameTitleOuterDelta = std::string("h2dOuterDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; const AxisSpec axisX{plotsConfig.doSeparationVsPt.value ? axisPt : axisMomentum}; - const AxisSpec axisNsigmaCorrect{plotsConfig.nBinsNsigmaCorrectSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, "N#sigma - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; - const AxisSpec axisDeltaCorrect{plotsConfig.nBinsDeltaCorrectSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, "#Delta - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; - const AxisSpec axisNsigmaWrong{plotsConfig.nBinsNsigmaWrongSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, "N#sigma - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; - const AxisSpec axisDeltaWrong{plotsConfig.nBinsDeltaWrongSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, "#Delta - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; + const AxisSpec axisNsigmaCorrect{plotsConfig.nBinsNsigmaCorrectSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, std::string("N#sigma - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; + const AxisSpec axisDeltaCorrect{plotsConfig.nBinsDeltaCorrectSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, std::string("#Delta - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; + const AxisSpec axisNsigmaWrong{plotsConfig.nBinsNsigmaWrongSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, std::string("N#sigma - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; + const AxisSpec axisDeltaWrong{plotsConfig.nBinsDeltaWrongSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, std::string("#Delta - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; const AxisSpec axisNSigma{iTrue == iHyp ? axisNsigmaCorrect : axisNsigmaWrong}; const AxisSpec axisDelta{iTrue == iHyp ? axisDeltaCorrect : axisDeltaWrong}; - h2dInnerNsigmaTrue[iTrue][iHyp] = histos.add("iTOF/nsigma/h2dInnerNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisNSigma}); - h2dOuterNsigmaTrue[iTrue][iHyp] = histos.add("oTOF/nsigma/h2dOuterNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisNSigma}); - h2dInnerDeltaTrue[iTrue][iHyp] = histos.add("iTOF/delta/h2dInnerDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisDelta}); - h2dOuterDeltaTrue[iTrue][iHyp] = histos.add("oTOF/delta/h2dOuterDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisDelta}); + h2dInnerNsigmaTrue[iTrue][iHyp] = histos.add(std::string("iTOF/nsigma/h2dInnerNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleInner.c_str(), kTH2F, {axisX, axisNSigma}); + h2dOuterNsigmaTrue[iTrue][iHyp] = histos.add(std::string("oTOF/nsigma/h2dOuterNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleOuter.c_str(), kTH2F, {axisX, axisNSigma}); + h2dInnerDeltaTrue[iTrue][iHyp] = histos.add(std::string("iTOF/delta/h2dInnerDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleInnerDelta.c_str(), kTH2F, {axisX, axisDelta}); + h2dOuterDeltaTrue[iTrue][iHyp] = histos.add(std::string("oTOF/delta/h2dOuterDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleOuterDelta.c_str(), kTH2F, {axisX, axisDelta}); } } } @@ -326,19 +385,20 @@ struct OnTheFlyTofPid { : layerRadius(r), layerLength(l), pixelDimensionZ(pDimensions[0]), pixelDimensionRPhi(pDimensions[1]), fractionInactive(fIA), magField(m) { // Assuming square pixels for simplicity - const float circumference = 2.0f * M_PI * layerRadius; + const float circumference = o2::constants::math::TwoPI * layerRadius; axisZ = new TAxis(static_cast(layerLength / pixelDimensionZ), -layerLength / 2, layerLength); axisRPhi = new TAxis(static_cast(circumference / pixelDimensionRPhi), 0.f, circumference); const float inactiveBorderRPhi = pixelDimensionRPhi * std::sqrt(fractionInactive) / 2; const float inactiveBorderZ = pixelDimensionZ * std::sqrt(fractionInactive) / 2; - const double arrayRPhi[4] = {-pixelDimensionRPhi / 2, -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2}; - for (int i = 0; i < 4; i++) { + static constexpr int NDimBorderArray = 4; + const double arrayRPhi[NDimBorderArray] = {-pixelDimensionRPhi / 2, -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2}; + for (int i = 0; i < NDimBorderArray; i++) { LOG(info) << "arrayRPhi[" << i << "] = " << arrayRPhi[i]; } axisInPixelRPhi = new TAxis(3, arrayRPhi); - const double arrayZ[4] = {-pixelDimensionZ / 2, -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2}; - for (int i = 0; i < 4; i++) { + const double arrayZ[NDimBorderArray] = {-pixelDimensionZ / 2, -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2}; + for (int i = 0; i < NDimBorderArray; i++) { LOG(info) << "arrayZ[" << i << "] = " << arrayZ[i]; } axisInPixelZ = new TAxis(3, arrayZ); @@ -364,7 +424,8 @@ struct OnTheFlyTofPid { const float r = std::sqrt(hitPosition[0] * hitPosition[0] + hitPosition[1] * hitPosition[1]); // Check if hit is within layer geometric acceptance - if (std::abs(layerRadius - r) > 10.f) { + static constexpr float LayerGeometricAcceptance = 10.f; + if (std::abs(layerRadius - r) > LayerGeometricAcceptance) { LOG(debug) << "Hit out of TOF layer acceptance: r=" << r << " cm with respect to the layer radius " << layerRadius; return false; } @@ -516,10 +577,10 @@ struct OnTheFlyTofPid { sumw += w; } - static constexpr float kMaxEventTimeResolution = 200.f; - if (sumw <= 0. || tracks.size() <= 1 || std::sqrt(1. / sumw) > kMaxEventTimeResolution) { - tzero[0] = 0.; // [ps] - tzero[1] = kMaxEventTimeResolution; // [ps] + static constexpr float MaxEventTimeResolution = 200.f; + if (sumw <= 0. || tracks.size() <= 1 || std::sqrt(1. / sumw) > MaxEventTimeResolution) { + tzero[0] = 0.; // [ps] + tzero[1] = MaxEventTimeResolution; // [ps] return false; } @@ -616,12 +677,12 @@ struct OnTheFlyTofPid { o2::track::TrackParCov o2track = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdg); float xPv = -100.f; - static constexpr float kTrkXThreshold = -99.f; // Threshold to consider a good propagation of the track + static constexpr float TrkXThreshold = -99.f; // Threshold to consider a good propagation of the track if (o2track.propagateToDCA(mcPvVtx, mMagneticField)) { xPv = o2track.getX(); } float trackLengthInnerTOF = -1, trackLengthOuterTOF = -1; - if (xPv > kTrkXThreshold) { + if (xPv > TrkXThreshold) { trackLengthInnerTOF = o2::upgrade::computeTrackLength(o2track, simConfig.innerTOFRadius, mMagneticField); trackLengthOuterTOF = o2::upgrade::computeTrackLength(o2track, simConfig.outerTOFRadius, mMagneticField); } @@ -673,7 +734,7 @@ struct OnTheFlyTofPid { if (recoTrack.propagateToDCA(pvVtx, mMagneticField)) { xPv = recoTrack.getX(); } - if (xPv > kTrkXThreshold) { + if (xPv > TrkXThreshold) { trackLengthRecoInnerTOF = o2::upgrade::computeTrackLength(recoTrack, simConfig.innerTOFRadius, mMagneticField); trackLengthRecoOuterTOF = o2::upgrade::computeTrackLength(recoTrack, simConfig.outerTOFRadius, mMagneticField); } @@ -733,30 +794,10 @@ struct OnTheFlyTofPid { const float noSmearingPt = trkWithTime.mNoSmearingPt; // Straight to Nsigma - static std::array expectedTimeInnerTOF, expectedTimeOuterTOF; - static std::array deltaTimeInnerTOF, deltaTimeOuterTOF; - static std::array nSigmaInnerTOF, nSigmaOuterTOF; - static constexpr int kParticlePdgs[kParticles] = {kElectron, - kMuonMinus, - kPiPlus, - kKPlus, - kProton, - o2::constants::physics::kDeuteron, - o2::constants::physics::kTriton, - o2::constants::physics::kHelium3, - o2::constants::physics::kAlpha}; - static constexpr float kParticleMasses[kParticles] = {o2::constants::physics::MassElectron, - o2::constants::physics::MassMuon, - o2::constants::physics::MassPionCharged, - o2::constants::physics::MassKaonCharged, - o2::constants::physics::MassProton, - o2::constants::physics::MassDeuteron, - o2::constants::physics::MassTriton, - o2::constants::physics::MassHelium3, - o2::constants::physics::MassAlpha}; - static constexpr float kParticleCharges[kParticles] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 2.f, 2.f}; - float momentumHypotheses[kParticles]; // Store momentum hypothesis for each particle - + static std::array expectedTimeInnerTOF, expectedTimeOuterTOF; + static std::array deltaTimeInnerTOF, deltaTimeOuterTOF; + static std::array nSigmaInnerTOF, nSigmaOuterTOF; + float momentumHypotheses[NParticles]; // Store momentum hypothesis for each particle auto truePdgInfo = pdg->GetParticle(mcParticle.pdgCode()); float rigidity = momentum; // fallback to momentum if charge unknown @@ -787,7 +828,7 @@ struct OnTheFlyTofPid { } // For every mass hypothesis compute the expected time, the delta with respect to it and the nsigma - for (int ii = 0; ii < kParticles; ii++) { + for (int ii = 0; ii < NParticles; ii++) { expectedTimeInnerTOF[ii] = -100; expectedTimeOuterTOF[ii] = -100; deltaTimeInnerTOF[ii] = -100; @@ -795,8 +836,8 @@ struct OnTheFlyTofPid { nSigmaInnerTOF[ii] = -100; nSigmaOuterTOF[ii] = -100; - momentumHypotheses[ii] = rigidity * kParticleCharges[ii]; // Total momentum for this hypothesis - const float v = o2::upgrade::computeParticleVelocity(momentumHypotheses[ii], kParticleMasses[ii]); + momentumHypotheses[ii] = rigidity * Particles[ii].charge; // Total momentum for this hypothesis + const float v = o2::upgrade::computeParticleVelocity(momentumHypotheses[ii], Particles[ii].mass); expectedTimeInnerTOF[ii] = trackLengthInnerTOF / v; expectedTimeOuterTOF[ii] = trackLengthOuterTOF / v; @@ -812,18 +853,18 @@ struct OnTheFlyTofPid { double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(trkWithTime.mMomentum.second); double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-pseudorapidity)))) * std::sqrt(trkWithTime.mPseudorapidity.second); if (simConfig.flagTOFLoadDelphesLUTs) { - if (mSmearer[collision.lutConfigId()]->hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded - ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); - etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); + if (mSmearer[collision.lutConfigId()]->hasTable(Particles[ii].pdgCode)) { // Only if the LUT for this particle was loaded + ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(Particles[ii].pdgCode, dNdEta, pseudorapidity, transverseMomentum); + etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(Particles[ii].pdgCode, dNdEta, pseudorapidity, transverseMomentum); } } - const float innerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.innerTOFRadius, mMagneticField); - const float outerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.outerTOFRadius, mMagneticField); + const float innerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, Particles[ii].mass, simConfig.innerTOFRadius, mMagneticField); + const float outerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, Particles[ii].mass, simConfig.outerTOFRadius, mMagneticField); innerTotalTimeReso = std::hypot(simConfig.innerTOFTimeReso, innerTrackTimeReso); outerTotalTimeReso = std::hypot(simConfig.outerTOFTimeReso, outerTrackTimeReso); if (plotsConfig.doQAplots) { - if (std::fabs(mcParticle.pdgCode()) == kParticlePdgs[ii]) { + if (doQaForParticle(Particles[ii].pdgCode) && std::fabs(mcParticle.pdgCode()) == Particles[ii].pdgCode) { if (trackLengthRecoInnerTOF > 0) { h2dInnerTimeResTrack[ii]->Fill(momentumHypotheses[ii], innerTrackTimeReso); h2dInnerTimeResTotal[ii]->Fill(momentumHypotheses[ii], innerTotalTimeReso); @@ -831,8 +872,7 @@ struct OnTheFlyTofPid { if (trackLengthRecoOuterTOF > 0) { h2dOuterTimeResTrack[ii]->Fill(momentumHypotheses[ii], outerTrackTimeReso); h2dOuterTimeResTotal[ii]->Fill(momentumHypotheses[ii], outerTotalTimeReso); - static constexpr int kIdPion = 2; - if (ii == kIdPion) { + if (ii == Pi) { histos.fill(HIST("h2dRelativePtResolution"), transverseMomentum, 100.0 * ptResolution / transverseMomentum); histos.fill(HIST("h2dRelativeEtaResolution"), pseudorapidity, 100.0 * etaResolution / (std::fabs(pseudorapidity) + 1e-6)); } @@ -844,25 +884,33 @@ struct OnTheFlyTofPid { // Fixme: assumes dominant resolution effect is the TOF resolution // and not the tracking itself. It's *probably* a fair assumption // but it should be tested further! --> FIXED IN THIS VERSION - if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) + if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) { nSigmaInnerTOF[ii] = deltaTimeInnerTOF[ii] / std::sqrt(innerTotalTimeReso * innerTotalTimeReso + tzero[1] * tzero[1]); - if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) + } + if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) { nSigmaOuterTOF[ii] = deltaTimeOuterTOF[ii] / std::sqrt(outerTotalTimeReso * outerTotalTimeReso + tzero[1] * tzero[1]); + } } if (plotsConfig.doQAplots) { - for (int ii = 0; ii < kParticles; ii++) { - if (std::fabs(mcParticle.pdgCode()) != pdg->GetParticle(kParticlePdgs[ii])->PdgCode()) { + for (int ii = 0; ii < NParticles; ii++) { + if (!doQaForParticle(Particles[ii].pdgCode) || std::fabs(mcParticle.pdgCode()) != pdg->GetParticle(Particles[ii].pdgCode)->PdgCode()) { continue; } if (trackLengthRecoInnerTOF > 0) { - for (int iii = 0; iii < kParticles; iii++) { + for (int iii = 0; iii < NParticles; iii++) { + if (!doQaForParticle(Particles[iii].pdgCode)) { + continue; + } h2dInnerNsigmaTrue[ii][iii]->Fill(momentumHypotheses[ii], nSigmaInnerTOF[iii]); h2dInnerDeltaTrue[ii][iii]->Fill(momentumHypotheses[ii], deltaTimeInnerTOF[iii]); } } if (trackLengthRecoOuterTOF > 0) { - for (int iii = 0; iii < kParticles; iii++) { + for (int iii = 0; iii < NParticles; iii++) { + if (!doQaForParticle(Particles[iii].pdgCode)) { + continue; + } h2dOuterNsigmaTrue[ii][iii]->Fill(momentumHypotheses[ii], nSigmaOuterTOF[iii]); h2dOuterDeltaTrue[ii][iii]->Fill(momentumHypotheses[ii], deltaTimeOuterTOF[iii]); } @@ -881,12 +929,16 @@ struct OnTheFlyTofPid { // Sigmas have been fully calculated. Please populate the NSigma helper table (once per track) upgradeTof(tzero[0], tzero[1], - nSigmaInnerTOF[0], nSigmaInnerTOF[1], nSigmaInnerTOF[2], nSigmaInnerTOF[3], nSigmaInnerTOF[4], nSigmaInnerTOF[5], nSigmaInnerTOF[6], nSigmaInnerTOF[7], nSigmaInnerTOF[8], + nSigmaInnerTOF[El], nSigmaInnerTOF[Mu], nSigmaInnerTOF[Pi], nSigmaInnerTOF[Ka], nSigmaInnerTOF[Pr], nSigmaInnerTOF[De], nSigmaInnerTOF[Tr], nSigmaInnerTOF[He], nSigmaInnerTOF[Al], measuredTimeInnerTOF, trackLengthRecoInnerTOF, - nSigmaOuterTOF[0], nSigmaOuterTOF[1], nSigmaOuterTOF[2], nSigmaOuterTOF[3], nSigmaOuterTOF[4], nSigmaOuterTOF[5], nSigmaOuterTOF[6], nSigmaOuterTOF[7], nSigmaOuterTOF[8], + nSigmaOuterTOF[El], nSigmaOuterTOF[Mu], nSigmaOuterTOF[Pi], nSigmaOuterTOF[Ka], nSigmaOuterTOF[Pr], nSigmaOuterTOF[De], nSigmaOuterTOF[Tr], nSigmaOuterTOF[He], nSigmaOuterTOF[Al], measuredTimeOuterTOF, trackLengthRecoOuterTOF); - upgradeTofExpectedTime(expectedTimeInnerTOF[0], expectedTimeInnerTOF[1], expectedTimeInnerTOF[2], expectedTimeInnerTOF[3], expectedTimeInnerTOF[4], expectedTimeInnerTOF[5], expectedTimeInnerTOF[6], expectedTimeInnerTOF[7], expectedTimeInnerTOF[8], - expectedTimeOuterTOF[0], expectedTimeOuterTOF[1], expectedTimeOuterTOF[2], expectedTimeOuterTOF[3], expectedTimeOuterTOF[4], expectedTimeOuterTOF[5], expectedTimeOuterTOF[6], expectedTimeOuterTOF[7], expectedTimeOuterTOF[8]); + upgradeTofExpectedTime(expectedTimeInnerTOF[El], expectedTimeInnerTOF[Mu], expectedTimeInnerTOF[Pi], expectedTimeInnerTOF[Ka], expectedTimeInnerTOF[Pr], expectedTimeInnerTOF[De], expectedTimeInnerTOF[Tr], expectedTimeInnerTOF[He], expectedTimeInnerTOF[Al], + expectedTimeOuterTOF[El], expectedTimeOuterTOF[Mu], expectedTimeOuterTOF[Pi], expectedTimeOuterTOF[Ka], expectedTimeOuterTOF[Pr], expectedTimeOuterTOF[De], expectedTimeOuterTOF[Tr], expectedTimeOuterTOF[He], expectedTimeOuterTOF[Al]); + upgradeTofShortLived(nSigmaInnerTOF[Sp], nSigmaInnerTOF[Sm], nSigmaInnerTOF[Xi], nSigmaInnerTOF[Om], + nSigmaOuterTOF[Sp], nSigmaOuterTOF[Sm], nSigmaOuterTOF[Xi], nSigmaOuterTOF[Om], + expectedTimeInnerTOF[Sp], expectedTimeInnerTOF[Sm], expectedTimeInnerTOF[Xi], expectedTimeInnerTOF[Om], + expectedTimeOuterTOF[Sp], expectedTimeOuterTOF[Sm], expectedTimeOuterTOF[Xi], expectedTimeOuterTOF[Om]); } if (trackWithTimeIndex != tracks.size()) { diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index b2d55f13015..949d707928d 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -23,6 +23,7 @@ /// \author Roberto Preghenella preghenella@bo.infn.it /// +#include "ALICE3/Core/Decayer.h" #include "ALICE3/Core/DetLayer.h" #include "ALICE3/Core/FastTracker.h" #include "ALICE3/Core/FlatTrackSmearer.h" @@ -378,6 +379,9 @@ struct OnTheFlyTracker { // Track smearer array, one per geometry std::vector> mSmearer; + // Configuration defined at init time + o2::fastsim::GeometryContainer mGeoContainer; + float mMagneticField = 0.0f; // For processing and vertexing std::vector recoPrimaries; @@ -395,10 +399,8 @@ struct OnTheFlyTracker { // For TGenPhaseSpace seed TRandom3 rand; Service ccdb{}; + o2::upgrade::Decayer decayer; - // Configuration defined at init time - o2::fastsim::GeometryContainer mGeoContainer; - float mMagneticField = 0.0f; // Time resolution constants static constexpr float timeResolutionNs = 100.f; // ns static constexpr float nsToMus = 1e-3f; @@ -438,6 +440,7 @@ struct OnTheFlyTracker { const int nGeometries = mGeoContainer.getNumberOfConfigurations(); mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); + decayer.setBField(mMagneticField); for (int icfg = 0; icfg < nGeometries; ++icfg) { const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; mSmearer.emplace_back(std::make_unique()); @@ -1910,7 +1913,6 @@ struct OnTheFlyTracker { uint32_t multiplicityCounter = 0; // Now that the multiplicity is known, we can process the particles to smear them for (const auto& mcParticle : mcParticles) { - if (!mcParticle.isPhysicalPrimary()) { continue; } @@ -1950,15 +1952,24 @@ struct OnTheFlyTracker { bool reconstructed = true; int nTrkHits = 0; if (enablePrimarySmearing) { - if (fastPrimaryTrackerSettings.fastTrackPrimaries || fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { - o2::track::TrackParCov perfectTrackParCov; - o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); + if (fastPrimaryTrackerSettings.fastTrackPrimaries && longLivedToBeHandled) { + o2::track::TrackParCov perfectTrackParCov = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdgDB); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { reconstructed = false; } + } else if (fastPrimaryTrackerSettings.fastTrackShortLivedParticles && shortLivedToBeHandled) { + o2::track::TrackParCov perfectTrackParCov = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdgDB); + perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); + computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); + const std::array decayVtx = decayer.generateDecayVertex(mcParticle, pdgDB); + const float decayRadius2D = std::hypot(decayVtx[0], decayVtx[1]); + nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta, decayRadius2D); + if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { + reconstructed = false; + } } else { o2::upgrade::convertMCParticleToO2Track(mcParticle, trackParCov, pdgDB); computeBremsstrahlungLoss(icfg, mcParticle, trackParCov); @@ -2155,8 +2166,7 @@ struct OnTheFlyTracker { computeBremsstrahlungLoss(icfg, mcParticle, trackParCov); reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); } else if (shortLivedToBeHandled && fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { - o2::track::TrackParCov perfectTrackParCov; - o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); + o2::track::TrackParCov perfectTrackParCov = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdgDB); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta, mcParticle.decayRadius()); diff --git a/ALICE3/TableProducer/alice3DqTableMaker.cxx b/ALICE3/TableProducer/alice3DqTableMaker.cxx index 075873899e3..041fc71ebfe 100644 --- a/ALICE3/TableProducer/alice3DqTableMaker.cxx +++ b/ALICE3/TableProducer/alice3DqTableMaker.cxx @@ -28,7 +28,9 @@ #include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -141,8 +143,9 @@ struct Alice3DqTableMaker { { bool isProcessSkimmingEnabled = context.mOptions.get("processSkimming"); - if (!isProcessSkimmingEnabled) + if (!isProcessSkimmingEnabled) { LOG(fatal) << "No process function was enabled ALICE 3 TableMaker"; + } VarManager::SetDefaultVarNames(); // Important that this is called before defineCuts() !!! @@ -310,7 +313,7 @@ struct Alice3DqTableMaker { fStatsList->Add(histEvents); // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) - TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); + TH1I* histTracks = new TH1I("TrackStats", "Track statistics", static_cast(fTrackCuts.size() + 5.0), -0.5, fTrackCuts.size() - 0.5 + 5.0); ibX = 1; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ibX++) { histTracks->GetXaxis()->SetBinLabel(ibX, (*cut)->GetName()); @@ -623,8 +626,9 @@ struct Alice3DqTableMaker { skimCollisions(collisions); - if (fCollIndexMap.empty()) + if (fCollIndexMap.empty()) { return; + } skimMCParticles(mcParticles, mcCollisions); diff --git a/ALICE3/TableProducer/alice3MulticharmFinder.cxx b/ALICE3/TableProducer/alice3MulticharmFinder.cxx index 1543db72315..b3efa1fe9b8 100644 --- a/ALICE3/TableProducer/alice3MulticharmFinder.cxx +++ b/ALICE3/TableProducer/alice3MulticharmFinder.cxx @@ -516,12 +516,13 @@ struct Alice3MulticharmFinder { fitter.setBz(cfgMagneticField); fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); + // initialize O2 3-prong fitter (only once) fitter3.setPropagateToPCA(cfgFitter.propagateToPCA); fitter3.setMaxR(cfgFitter.maxR); fitter3.setMinParamChange(cfgFitter.minParamChange); fitter3.setMinRelChi2Change(cfgFitter.minRelChi2Change); fitter3.setMaxDZIni(cfgFitter.maxDZIni); - fitter3.setMaxDZIni(cfgFitter.maxDXYIni); + fitter3.setMaxDXYIni(cfgFitter.maxDXYIni); fitter3.setMaxChi2(cfgFitter.maxVtxChi2); fitter3.setUseAbsDCA(cfgFitter.useAbsDCA); fitter3.setWeightedFinalPCA(cfgFitter.useWeightedFinalPCA); @@ -1000,7 +1001,7 @@ struct Alice3MulticharmFinder { continue; } - if (selFlags.applyLaMaxDauDCA && xiCand.v0radius() < selVals.laMinDecayRadius) { + if (selFlags.applyLaMinDecayRadius && xiCand.v0radius() < selVals.laMinDecayRadius) { continue; } @@ -1036,7 +1037,7 @@ struct Alice3MulticharmFinder { continue; } - if (xiCand.cascradius() < selVals.xiMinDecayRadius) { + if (selFlags.applyXiMinDecayRadius && xiCand.cascradius() < selVals.xiMinDecayRadius) { continue; } diff --git a/ALICE3/TableProducer/alice3TrackingTranslator.cxx b/ALICE3/TableProducer/alice3TrackingTranslator.cxx index 70e0dca3bd6..58e2b2893d3 100644 --- a/ALICE3/TableProducer/alice3TrackingTranslator.cxx +++ b/ALICE3/TableProducer/alice3TrackingTranslator.cxx @@ -66,8 +66,6 @@ namespace using Key = std::array; // barcode (vp, vs, particle, gen, sub) Key keyOf(std::uint32_t vp, std::uint32_t vs, std::uint32_t pa, std::uint32_t ge, std::uint32_t sp) { return Key{vp, vs, pa, ge, sp}; } -// struct ParticleTruthInfo { int pdg; float px, py, pz, m; }; -// struct Seg { double px, py, pz, p; }; } // namespace struct Alice3TrackingTranslator { @@ -102,10 +100,6 @@ struct Alice3TrackingTranslator { { // Initialization if needed LOG(info) << "Alice3TrackingTranslator init called"; - - histos.add("hPx", "Px distribution;Px [GeV/c];Entries", kTH1F, {{100, -5.0, 5.0}}); - histos.add("hPy", "Py distribution;Py [GeV/c];Entries", kTH1F, {{100, -5.0, 5.0}}); - histos.add("hPz", "Pz distribution;Pz [GeV/c];Entries", kTH1F, {{100, -5.0, 5.0}}); } #define SETADDRESS(branchname, branchvar) \ @@ -226,30 +220,47 @@ struct Alice3TrackingTranslator { SETADDRESS("nHoles", m_nHoles); SETADDRESS("chi2Sum", m_chi2Sum); SETADDRESS("NDF", m_NDF); - SETADDRESS("eLOC0_fit", m_eLOC0_fit); - SETADDRESS("eLOC1_fit", m_eLOC1_fit); - SETADDRESS("ePHI_fit", m_ePHI_fit); - SETADDRESS("eTHETA_fit", m_eTHETA_fit); - SETADDRESS("eQOP_fit", m_eQOP_fit); - SETADDRESS("eT_fit", m_eT_fit); SETADDRESS("nMajorityHits", m_nMajorityHits); SETADDRESS("t_charge", m_t_charge); SETADDRESS("t_vx", m_t_vx); SETADDRESS("t_vy", m_t_vy); SETADDRESS("t_vz", m_t_vz); - SETADDRESS("t_time", m_t_time); SETADDRESS("t_px", m_t_px); SETADDRESS("t_py", m_t_py); SETADDRESS("t_pz", m_t_pz); - SETADDRESS("t_theta", m_t_theta); - SETADDRESS("t_phi", m_t_phi); - SETADDRESS("t_pT", m_t_pT); - SETADDRESS("t_eta", m_t_eta); SETADDRESS("majorityParticleId_vertex_primary", m_majorityParticleId_vertex_primary); SETADDRESS("majorityParticleId_vertex_secondary", m_majorityParticleId_vertex_secondary); SETADDRESS("majorityParticleId_generation", m_majorityParticleId_generation); SETADDRESS("majorityParticleId_sub_particle", m_majorityParticleId_sub_particle); SETADDRESS("majorityParticleId_particle", m_majorityParticleId_particle); + SETADDRESS("eQOP_fit", m_eQOP_fit); + SETADDRESS("eX_fit", m_eX_fit); + SETADDRESS("eY_fit", m_eY_fit); + SETADDRESS("eZ_fit", m_eZ_fit); + SETADDRESS("ePX_fit", m_ePX_fit); + SETADDRESS("ePY_fit", m_ePY_fit); + SETADDRESS("ePZ_fit", m_ePZ_fit); + SETADDRESS("cov_eX_eX", m_cov_eX_eX); + // SETADDRESS("cov_eY_eY", m_cov_eY_eY); + SETADDRESS("cov_eZ_eZ", m_cov_eZ_eZ); + SETADDRESS("cov_ePX_ePX", m_cov_ePX_ePX); + SETADDRESS("cov_ePY_ePY", m_cov_ePY_ePY); + SETADDRESS("cov_ePZ_ePZ", m_cov_ePZ_ePZ); + SETADDRESS("cov_eX_ePX", m_cov_eX_ePX); + SETADDRESS("cov_eY_ePY", m_cov_eY_ePY); + SETADDRESS("cov_eZ_ePZ", m_cov_eZ_ePZ); + SETADDRESS("cov_eX_eY", m_cov_eX_eY); + SETADDRESS("cov_eX_eZ", m_cov_eX_eZ); + SETADDRESS("cov_eY_eZ", m_cov_eY_eZ); + SETADDRESS("cov_ePX_ePY", m_cov_ePX_ePY); + SETADDRESS("cov_ePX_ePZ", m_cov_ePX_ePZ); + SETADDRESS("cov_ePY_ePZ", m_cov_ePY_ePZ); + SETADDRESS("cov_eX_ePY", m_cov_eX_ePY); + SETADDRESS("cov_eX_ePZ", m_cov_eX_ePZ); + SETADDRESS("cov_eY_ePX", m_cov_eY_ePX); + SETADDRESS("cov_eY_ePZ", m_cov_eY_ePZ); + SETADDRESS("cov_eZ_ePX", m_cov_eZ_ePX); + SETADDRESS("cov_eZ_ePY", m_cov_eZ_ePY); } // Define track-related members here UInt_t* m_event_nr = nullptr; @@ -259,12 +270,37 @@ struct Alice3TrackingTranslator { std::vector* m_chi2Sum = nullptr; std::vector* m_NDF = nullptr; // Fitted track parameters - std::vector* m_eLOC0_fit = nullptr; // local position 0 (typically y in local frame) - std::vector* m_eLOC1_fit = nullptr; // local position 1 (typically z in local frame) - std::vector* m_ePHI_fit = nullptr; // azimuthal angle - std::vector* m_eTHETA_fit = nullptr; // polar angle - std::vector* m_eQOP_fit = nullptr; // q/m_p (charge over momentum) - std::vector* m_eT_fit = nullptr; // time + std::vector* m_eQOP_fit = nullptr; // q/m_p (charge over momentum) + + std::vector* m_eX_fit = nullptr; // global position x + std::vector* m_eY_fit = nullptr; // global position y + std::vector* m_eZ_fit = nullptr; // global position z + std::vector* m_ePX_fit = nullptr; // global momentum px + std::vector* m_ePY_fit = nullptr; // global momentum py + std::vector* m_ePZ_fit = nullptr; // global momentum pz + + // covariance matrices for fitted track parameters (if available) + std::vector* m_cov_eX_eX = nullptr; // covariance of global position x + // std::vector* m_cov_eY_eY = nullptr; // covariance of global position y + std::vector* m_cov_eZ_eZ = nullptr; // covariance of global position z + std::vector* m_cov_ePX_ePX = nullptr; // covariance of global momentum px + std::vector* m_cov_ePY_ePY = nullptr; // covariance of global momentum py + std::vector* m_cov_ePZ_ePZ = nullptr; // covariance of global momentum pz + std::vector* m_cov_eX_ePX = nullptr; // covariance between global position x and momentum px + std::vector* m_cov_eY_ePY = nullptr; // covariance between global position y and momentum py + std::vector* m_cov_eZ_ePZ = nullptr; // covariance between global position z and momentum pz + std::vector* m_cov_eX_eY = nullptr; // covariance between global position x and y + std::vector* m_cov_eX_eZ = nullptr; // covariance between global position x and z + std::vector* m_cov_eY_eZ = nullptr; // covariance between global position y and z + std::vector* m_cov_ePX_ePY = nullptr; // covariance between global momentum px and py + std::vector* m_cov_ePX_ePZ = nullptr; // covariance between global momentum px and pz + std::vector* m_cov_ePY_ePZ = nullptr; // covariance between global momentum py and pz + std::vector* m_cov_eX_ePY = nullptr; // covariance between global position x and momentum py + std::vector* m_cov_eX_ePZ = nullptr; // covariance between global position x and momentum pz + std::vector* m_cov_eY_ePX = nullptr; // covariance between global position y and momentum px + std::vector* m_cov_eY_ePZ = nullptr; // covariance between global position y and momentum pz + std::vector* m_cov_eZ_ePX = nullptr; // covariance between global position z and momentum px + std::vector* m_cov_eZ_ePY = nullptr; // covariance between global position z and momentum py // The majority truth particle info std::vector* m_nMajorityHits = nullptr; /// The number of hits from majority particle @@ -276,10 +312,6 @@ struct Alice3TrackingTranslator { std::vector* m_t_px = nullptr; /// Initial momenta m_px of majority particle std::vector* m_t_py = nullptr; /// Initial momenta m_py of majority particle std::vector* m_t_pz = nullptr; /// Initial momenta m_pz of majority particle - std::vector* m_t_theta = nullptr; /// Initial momenta theta of majority particle - std::vector* m_t_phi = nullptr; /// Initial momenta phi of majority particle - std::vector* m_t_pT = nullptr; /// Initial momenta pT of majority particle - std::vector* m_t_eta = nullptr; /// Initial momenta eta of majority particle std::vector* m_majorityParticleId_vertex_primary = nullptr; std::vector* m_majorityParticleId_vertex_secondary = nullptr; @@ -354,33 +386,21 @@ struct Alice3TrackingTranslator { files[justFilename.Data()] = filename; } LOG(info) << "All files loaded successfully"; - // Now open the files to translate and read the trees - // ParticleStruct fileParticles(files["particles.root"], "particles"); - // LOG(info) << "Particles loaded successfully"; ParticleStruct fileParticlesSim(files["particles_simulation.root"], "particles"); LOG(info) << "Particles Sim loaded successfully"; - // std::string daughterFileName = addDaughterInfo ? "particles_decay.root" : "particles_simulation.root"; - // ParticleStruct fileDaughterParticles(files[daughterFileName], "particles"); - // LOG(info) << "Daughter particles loaded successfully from file " << daughterFileName; // FileStruct fileVertices(files["performance_vertexing.root"], "vertexing"); TrackStruct fileTracksummary(files["tracksummary_ambi-tracks-merged.root"], "tracksummary"); - // HitsStruct fileHits(files["hits.root"], "hits"); VertexStruct fileVertices(files["vertices_gen_and_geant.root"], "vertices"); LOG(info) << "Tracks loaded successfully"; const Long64_t kEvents = fileParticlesSim.getEntries(); - // int indexOfLastParticleAfterEvent = -1; for (Long64_t iEvent = 0; iEvent < kEvents; ++iEvent) { if (iEvent > 0 && maxCollisions.value > 0 && (iEvent % maxCollisions) == 0) { LOG(info) << "Stopping at event " << iEvent << "/" << kEvents; break; } - // fileParticles.setEventEntry(iEvent); fileVertices.setEventEntry(iEvent); fileTracksummary.setEventEntry(iEvent); - // fileHits.setEventEntry(iEvent); - // if (addDaughterInfo) - // fileDaughterParticles.setEventEntry(iEvent); fileParticlesSim.setEventEntry(iEvent); LOG(info) << "Processing event " << iEvent << "/" << kEvents; @@ -399,10 +419,8 @@ struct Alice3TrackingTranslator { int collisionId = tableCollisions.lastIndex() + 1; // Convert tracks from ACTS to ALICE format - // const size_t nParticlesGen = fileParticles.m_vx->size(); const size_t nParticlesSim = fileParticlesSim.m_vx->size(); - // const size_t nDaughterParticles = fileDaughterParticles.m_vx->size(); - const size_t nTracks = fileTracksummary.m_eLOC0_fit->size(); + const size_t nTracks = fileTracksummary.m_ePX_fit->size(); std::vector idMCparticles; // local index k within this event -> global AO2D index @@ -469,7 +487,6 @@ struct Alice3TrackingTranslator { } } } - // int idPrimary = -1; for (size_t iPart = 0; iPart < nParticlesSim; ++iPart) { int globalIdx = firstIdxThisEvent + (int)iPart; int motherIdx = -1; @@ -495,20 +512,7 @@ struct Alice3TrackingTranslator { collisionY = fileVertices.m_y->at(iPart); collisionZ = fileVertices.m_z->at(iPart); flags |= o2::aod::mcparticle::enums::PhysicalPrimary; - // idPrimary += 1; } - // if(motherIdx==-1 && std::abs(fileParticlesSim.m_particle_type->at(iPart)) == 211) { - std::cout << "Adding MC particle " << iPart << ", with globalIdx " << globalIdx << ", with motherIdx " << motherIdx << ", firstDaughter " << firstDaughter << ", secondDaughter " << secondDaughter << ", pdg " << fileParticlesSim.m_particle_type->at(iPart) << std::endl; - // std::cout << "PV: " << fileVertices.m_x->at(iPart) << ", " << fileVertices.m_y->at(iPart) << ", " << fileVertices.m_z->at(iPart) << std::endl; - // std::cout << "Daughter info: "; - // if(firstDaughter != -1){ - // std::cout << "firstDaughter pdg " << fileParticlesSim.m_particle_type->at(firstDaughter) << " "; - // } - // if(secondDaughter != -1){ - // std::cout << "secondDaughter pdg " << fileParticlesSim.m_particle_type->at(secondDaughter) << " "; - // } - // std::cout << std::endl; - // } GlobalIdxToPDGCode[globalIdx] = fileParticlesSim.m_particle_type->at(iPart); GlobalToLocalIdx[globalIdx] = iPart; addMCParticle(tableMcCollisions.lastIndex(), fileParticlesSim, iPart, flags, motherIdx, firstDaughter, secondDaughter, fileParticlesSim.m_number_of_hits->at(iPart)); @@ -550,65 +554,30 @@ struct Alice3TrackingTranslator { if (iterator != barcodeToGlobalIdx.end()) { mcParticleIdx = iterator->second; } - std::cout << "Track " << iTrack << " is associated with MC particle index " << mcParticleIdx << std::endl; // Extract ACTS track parameters - float phi = fileTracksummary.m_ePHI_fit->at(iTrack); - float theta = fileTracksummary.m_eTHETA_fit->at(iTrack); float qOverP = fileTracksummary.m_eQOP_fit->at(iTrack); - float loc0 = fileTracksummary.m_eLOC0_fit->at(iTrack); - float loc1 = fileTracksummary.m_eLOC1_fit->at(iTrack); - float vx = loc0; - float vy = loc1; - float vz = 0.0f; - // auto iteratorVz = barcodeToVertexPosition.find(key); - // if (iteratorVz != barcodeToVertexPosition.end()){ - // vx = iteratorVz->second[0]; - // vy = iteratorVz->second[1]; - // vz = iteratorVz->second[2]; - // } + float x = fileTracksummary.m_eX_fit->at(iTrack); + float y = fileTracksummary.m_eY_fit->at(iTrack); + float z = fileTracksummary.m_eZ_fit->at(iTrack); + float px = fileTracksummary.m_ePX_fit->at(iTrack); + float py = fileTracksummary.m_ePY_fit->at(iTrack); + float pz = fileTracksummary.m_ePZ_fit->at(iTrack); + int localIdx = GlobalToLocalIdx[mcParticleIdx]; if (useTrueInfoForRecoTracks) { if (mcParticleIdx != -1) { - int localIdx = GlobalToLocalIdx[mcParticleIdx]; - float p = fileParticlesSim.m_p->at(localIdx); - // float m = fileParticlesSim.m_m->at(localIdx); - float pt = std::hypot(fileParticlesSim.m_px->at(localIdx), fileParticlesSim.m_py->at(localIdx)); - phi = std::acos(fileParticlesSim.m_px->at(localIdx) / pt); - theta = std::acos(fileParticlesSim.m_pz->at(localIdx) / p); - qOverP = (fileParticlesSim.m_q->at(localIdx) != 0) ? (fileParticlesSim.m_q->at(localIdx) / p) : 0.0f; - loc0 = fileParticlesSim.m_vx->at(localIdx); - loc1 = fileParticlesSim.m_vy->at(localIdx); + px = fileParticlesSim.m_px->at(localIdx); + py = fileParticlesSim.m_py->at(localIdx); + pz = fileParticlesSim.m_pz->at(localIdx); + x = fileParticlesSim.m_vx->at(localIdx); + y = fileParticlesSim.m_vy->at(localIdx); + z = fileParticlesSim.m_vz->at(localIdx); } } - - std::cout << "Track parameters: phi=" << phi << ", theta=" << theta << ", qOverP=" << qOverP << ", loc0=" << loc0 << ", loc1=" << loc1 << std::endl; - std::cout << "vx= " << vx << ", vy= " << vy << ", vz= " << vz << std::endl; // Convert to ALICE track parameters - // ALICE uses: alpha, x, y, z, snp, tgl, signed1Pt - float alpha = phi - M_PI / 2; // Track angle in global frame - float x = vx; // Local x position - float y = vy; // Local y position - float z = vz; // Will be set from DCA or collision vertex - - // Calculate snp (sin of track momentum azimuthal angle) - float snp = o2::constants::math::Almost1; // std::sin(phi);// - - // Calculate tgl (tangent of track momentum dip angle) - float tgl = 1.0f / std::tan(theta); - - // Calculate signed1Pt (charge/pt) - const float m_p = (qOverP != 0) ? std::abs(1.0f / qOverP) : 0.0f; - const float px = m_p * std::cos(phi) * std::sin(theta); - const float py = m_p * std::sin(phi) * std::sin(theta); - const float pz = m_p * std::cos(theta); - const float pt = m_p * std::sin(theta); int8_t charge = (qOverP > 0) ? 1 : -1; - const float signed1Pt = (pt != 0) ? charge / pt : 0.0f; - - if (charge > 0) { - histos.fill(HIST("hPx"), px); - histos.fill(HIST("hPy"), py); - histos.fill(HIST("hPz"), pz); + if (qOverP == 0) { + charge = 0; } // Track quality @@ -616,30 +585,34 @@ struct Alice3TrackingTranslator { uint32_t m_nMeasurements = fileTracksummary.m_nMeasurements->at(iTrack); uint32_t m_NDF = fileTracksummary.m_NDF->at(iTrack); - // Fill covariance matrices (simplified - should be extracted from ACTS if available) - float cYY = 0.1f; - float cZY = 0.0f; - float cZZ = 0.1f; - float cSnpY = 0.0f; - float cSnpZ = 0.0f; - float cSnpSnp = 0.001f; - float cTglY = 0.0f; - float cTglZ = 0.0f; - float cTglSnp = 0.0f; - float cTglTgl = 0.001f; - float c1PtY = 0.0f; - float c1PtZ = 0.0f; - float c1PtSnp = 0.0f; - float c1PtTgl = 0.0f; - float c1Pt21Pt2 = 0.001f * signed1Pt * signed1Pt; - - // Create TrackParCov object with dummy covariance matrix - std::array trackParams = {y, z, snp, tgl, signed1Pt}; - std::array trackCov = {cYY, cZY, cZZ, cSnpY, cSnpZ, cSnpSnp, - cTglY, cTglZ, cTglSnp, cTglTgl, - c1PtY, c1PtZ, c1PtSnp, c1PtTgl, c1Pt21Pt2}; - o2::track::TrackParCov trackParCov(x, alpha, trackParams, trackCov, charge); - std::cout << "TrackParCov created with parameters:" << std::endl; + // Fill covariance matrices + float cxx = fileTracksummary.m_cov_eX_eX->at(iTrack); + float cyy = cxx; // fileTracksummary.cov_eY_eY->at(iTrack); + float czz = fileTracksummary.m_cov_eZ_eZ->at(iTrack); + float cxy = fileTracksummary.m_cov_eX_eY->at(iTrack); + float cxz = fileTracksummary.m_cov_eX_eZ->at(iTrack); + float cyz = fileTracksummary.m_cov_eY_eZ->at(iTrack); + float cpxpx = fileTracksummary.m_cov_ePX_ePX->at(iTrack); + float cpypy = fileTracksummary.m_cov_ePY_ePY->at(iTrack); + float cpzpz = fileTracksummary.m_cov_ePZ_ePZ->at(iTrack); + float cpxpy = fileTracksummary.m_cov_ePX_ePY->at(iTrack); + float cpxpz = fileTracksummary.m_cov_ePX_ePZ->at(iTrack); + float cpypz = fileTracksummary.m_cov_ePY_ePZ->at(iTrack); + float cxpx = fileTracksummary.m_cov_eX_ePX->at(iTrack); + float cxpy = fileTracksummary.m_cov_eX_ePY->at(iTrack); + float cxpz = fileTracksummary.m_cov_eX_ePZ->at(iTrack); + float cypx = fileTracksummary.m_cov_eY_ePX->at(iTrack); + float cypy = fileTracksummary.m_cov_eY_ePY->at(iTrack); + float cypz = fileTracksummary.m_cov_eY_ePZ->at(iTrack); + float czpx = fileTracksummary.m_cov_eZ_ePX->at(iTrack); + float czpy = fileTracksummary.m_cov_eZ_ePY->at(iTrack); + float czpz = fileTracksummary.m_cov_eZ_ePZ->at(iTrack); + // Create TrackParCov object with covariance matrix + std::array position = {x, y, z}; + std::array momentum = {px, py, pz}; + std::array trackCov = {cxx, cxy, cyy, cxz, cyz, czz, cxpx, cypx, czpx, cpxpx, cxpy, cypy, czpy, cpxpy, cpypy, cxpz, cypz, czpz, cpxpz, cpypz, cpzpz}; + o2::track::TrackParCov trackParCov(position, momentum, trackCov, charge); + // Fill StoredTracks table (basic track parameters) tableStoredTracks(collisionId, // collisionId o2::aod::track::TrackTypeEnum::Track, // trackType @@ -650,13 +623,11 @@ struct Alice3TrackingTranslator { trackParCov.getSnp(), // snp trackParCov.getTgl(), // tgl trackParCov.getQ2Pt()); // signed1Pt - std::cout << "Filling StoredTracks table" << std::endl; // Fill TracksExtension table tableTracksExtension(trackParCov.getPt(), trackParCov.getP(), trackParCov.getEta(), trackParCov.getPhi()); - std::cout << "Filling TracksExtension table" << std::endl; tableStoredTracksCov(std::sqrt(trackParCov.getSigmaY2()), // SigmaY std::sqrt(trackParCov.getSigmaZ2()), // SigmaZ std::sqrt(trackParCov.getSigmaSnp2()), // SigmaSnp @@ -672,7 +643,6 @@ struct Alice3TrackingTranslator { 0, // Rho1PtZ 0, // Rho1PtSnp 0); // Rho1PtTgl - std::cout << "Filling StoredTracksCov table" << std::endl; // covariance matrix at collision vertex tableTracksCovExtension(trackParCov.getSigmaY2(), // sigmaY2 trackParCov.getSigmaZY(), // sigmaZY @@ -689,31 +659,25 @@ struct Alice3TrackingTranslator { trackParCov.getSigma1PtSnp(), // sigma1PtSnp trackParCov.getSigma1PtTgl(), // sigma1PtTgl trackParCov.getSigma1Pt2()); // sigma1Pt - std::cout << "Filling TracksCovExtension table" << std::endl; // Fill MC label tableMcTrackLabels(mcParticleIdx, // McParticleId 0); // mcMask - std::cout << "Filling McTrackLabels table" << std::endl; - // Fill DCA info (simplified - should be calculated properly) - tableTracksDCA(0.0f, // dcaXY - 0.0f); // dcaZ - std::cout << "Filling TracksDCA table" << std::endl; + // Fill DCA info TODO: should be calculated properly + tableTracksDCA(0.0f, // dcaXY + 0.0f); // dcaZ tableTracksDCACov(0.0f, // sigmaDcaXY2 0.0f); // sigmaDcaZ2 - std::cout << "Filling TracksDCACov table" << std::endl; // Fill ALICE3 specific tables tableTracksAlice3(true); // isReconstructed - std::cout << GlobalIdxToPDGCode[mcParticleIdx] << std::endl; if (mcParticleIdx > 0) tableTracksAlice3Pdg(GlobalIdxToPDGCode[mcParticleIdx]); // PdgCode to the linked MC truth particle else tableTracksAlice3Pdg(0); // No linked MC truth particle - std::cout << "Filling TracksAlice3 and TracksAlice3Pdg tables" << std::endl; + tableTracksExtraA3(m_nMeasurements, // nSiliconHits (using m_nMeasurements as proxy) 0, // nTPCHits 0, // trackType false); // isPVContributor - std::cout << "Filling TracksExtraA3 table" << std::endl; // Fill extra track info tableStoredTracksExtra(0.f, // TPCInnerParam static_cast(0), // Flags @@ -736,16 +700,14 @@ struct Alice3TrackingTranslator { 0.f, // TrackPhiEMCAL 0.f, // TrackTime 0.f); // TrackTimeRes - std::cout << "Filling StoredTracksExtra table" << std::endl; // Fill track selection - tableTrackSelection(false, // IsGlobalTrackSDD, - false, // TrackCutFlag, - false, // TrackCutFlagFb1, - false, // TrackCutFlagFb2, - false, // TrackCutFlagFb3, - false, // TrackCutFlagFb4, - false); // TrackCutFlagFb5, - std::cout << "Filling TrackSelection table" << std::endl; + tableTrackSelection(false, // IsGlobalTrackSDD, + false, // TrackCutFlag, + false, // TrackCutFlagFb1, + false, // TrackCutFlagFb2, + false, // TrackCutFlagFb3, + false, // TrackCutFlagFb4, + false); // TrackCutFlagFb5, tableTrackSelectionExtension(false, // PassedTrackType, false, // PassedPtRange, false, // PassedEtaRange, @@ -763,177 +725,7 @@ struct Alice3TrackingTranslator { false, // PassedDCAz, false, // PassedITSHitsFB1, false); // PassedITSHitsFB2 - std::cout << "Filling TrackSelectionExtension table" << std::endl; } - - // for (size_t iTrack = 0; iTrack < nTracks; ++iTrack) { - // LOG(info) << "Processing track " << iTrack << "/" << nTracks << " (nParticlesSim=" << nParticlesSim << ") nParticlesGen=" << nParticlesGen; - // const size_t iParticle = iTrack; - - // if (iParticle == 0) { - // tableMcCollisions(0, // mccollision::BCId, - // 0, // mccollision::GeneratorsID, - // fileParticles.m_vx->at(iParticle), // mccollision::PosX, - // fileParticles.m_vy->at(iParticle), // mccollision::PosY, - // fileParticles.m_vz->at(iParticle), // mccollision::PosZ - // fileParticles.m_vt->at(iParticle), // mccollision::T - // 1.0f, // mccollision::Weight - // 0.0f, // mccollision::ImpactParameter, - // 0.f); // mccollision::EventPlaneAngle, - // } - // uint8_t flags = 0; - - // Key majorityVertexInfo = keyOf(fileTracksummary.m_majorityParticleId_vertex_primary->at(iTrack), fileTracksummary.m_majorityParticleId_vertex_secondary->at(iTrack), (*ouPa)[j][d], - // (*ouGe)[j][d], (*ouSp)[j][d]); - - // // ULong64_t idMCTrueParticle = fileTracksummary.m_majorityParticleId->at(iParticle); - // // int32_t mcParticleId = -1; - // // int pdgCode = -1; - - // // for (size_t iMC = 0; iMC < nParticlesGen; ++iMC) { - // // if (fileParticles.m_particleId->at(iMC) == idMCTrueParticle) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileParticles.m_particleId->at(iMC)) > 0) { - // // continue; - // // } - // // idMCparticles.push_back(fileParticles.m_particleId->at(iMC)); - // // flags |= o2::aod::mcparticle::enums::PhysicalPrimary; - // // int nHits = 0; - // // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // // if (fileParticlesSim.m_particleId->at(iPartSim) == fileParticles.m_particleId->at(iMC)) { - // // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // // break; - // // } - // // } - // // addMCParticle(tableMcCollisions.lastIndex(), fileParticles, iMC, flags, -1, -1, nHits); - // // mcParticleId = tableStoredMcParticles.lastIndex(); - // // pdgCode = fileParticles.m_particle_type->at(iMC); - // // break; - // // } - // // } - // // if (addDaughterInfo) { - // // for (size_t iMC = 0; iMC < nParticlesSim; ++iMC) { - // // if (fileDaughterParticles.m_particleId->at(iMC) == idMCTrueParticle) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_particleId->at(iMC)) > 0) { - // // break; - // // } - - // // int nHits = 0; - // // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // // if (fileParticlesSim.m_particleId->at(iPartSim) == fileDaughterParticles.m_particleId->at(iMC)) { - // // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // // break; - // // } - // // } - // // for (size_t iMother = 0; iMother < nParticlesGen; ++iMother) { - // // if (fileDaughterParticles.m_motherId->at(iMC) == fileParticles.m_particleId->at(iMother)) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileParticles.m_particleId->at(iMother)) > 0) { - // // break; - // // } - // // idMCparticles.push_back(fileParticles.m_particleId->at(iMother)); - // // uint8_t flagsMother = o2::aod::mcparticle::enums::PhysicalPrimary; - // // addMCParticle(tableMcCollisions.lastIndex(), fileParticles, iMother, flagsMother, -1, tableStoredMcParticles.lastIndex() + 2, 0); - // // break; - // // } - // // } - // // int motherId = -1; - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iMC)) > 0) { - // // auto it = find(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iMC)); - // // motherId = it - idMCparticles.begin() + indexOfLastParticleAfterEvent + 1; - // // } - // // idMCparticles.push_back(fileDaughterParticles.m_particleId->at(iMC)); - // // addMCParticle(tableMcCollisions.lastIndex(), fileDaughterParticles, iMC, flags, motherId, -1, nHits); - // // mcParticleId = tableStoredMcParticles.lastIndex(); - // // pdgCode = fileDaughterParticles.m_particle_type->at(iMC); - // // break; - // // } - // // } - // // } - // - - // - - // - - // // Fill MC track labels - // // Get particle linkage from hits using the majority hit index - // // if (fileTracksummary.nMajorityHits && iTrack < fileTracksummary.nMajorityHits->size()) { - // // unsigned int hitIndex = fileTracksummary.nMajorityHits->at(iTrack); - // // if (fileHits.barcode && hitIndex < fileHits.barcode->size()) { - // // mcParticleId = static_cast(fileHits.barcode->at(hitIndex)); - // // LOG(debug) << "Track " << iTrack << " linked to MC particle " << mcParticleId - // // << " via hit index " << hitIndex; - // // } else { - // // LOG(warning) << "Hit index " << hitIndex << " out of range for track " << iTrack - // // << " (barcode vector size: " << (fileHits.barcode ? fileHits.barcode->size() : 0) << ")"; - // // } - // // } else { - // // LOG(warning) << "No majority hit information available for track " << iTrack; - // // } - // // for ( const auto &vv : fileTracksummary.majorityParticleId->at(iTrack) ){ - // // LOG(info) << vv; - // // } - // - // } - - // for (size_t iParticle = 0; iParticle < nParticlesGen; ++iParticle) { - // if (iParticle == 0 && nTracks == 0) { - // tableMcCollisions(0, // mccollision::BCId, - // 0, // mccollision::GeneratorsID, - // fileParticles.m_vx->at(iParticle), // mccollision::PosX, - // fileParticles.m_vy->at(iParticle), // mccollision::PosY, - // fileParticles.m_vz->at(iParticle), // mccollision::PosZ - // fileParticles.m_vt->at(iParticle), // mccollision::T - // 1.0f, // mccollision::Weight - // 0.0f, // mccollision::ImpactParameter, - // 0.f); // mccollision::EventPlaneAngle, - // } - // if (idMCparticles.end() != std::find(idMCparticles.begin(), idMCparticles.end(), fileParticles.m_particleId->at(iParticle))) { - // // Already added via track - // continue; - // } - // uint8_t flags = 0; - // flags |= o2::aod::mcparticle::enums::PhysicalPrimary; - - // int nHits = 0; - // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // if (fileParticlesSim.m_particleId->at(iPartSim) == fileParticles.m_particleId->at(iParticle)) { - // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // break; - // } - // } - // addMCParticle(tableMcCollisions.lastIndex(), fileParticles, iParticle, flags, -1, -1, nHits); - // idMCparticles.push_back(fileParticles.m_particleId->at(iParticle)); - // } - // // if (addDaughterInfo) { - // // for (size_t iParticle = 0; iParticle < nDaughterParticles; ++iParticle) { - // // if (idMCparticles.end() != std::find(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_particleId->at(iParticle))) { - // // // Already added via track - // // continue; - // // } - // // uint8_t flags = 0; - // // int nHits = 0; - // // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // // if (fileParticlesSim.m_particleId->at(iPartSim) == fileDaughterParticles.m_particleId->at(iParticle)) { - // // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // // break; - // // } - // // } - // // int motherId = -1; - // // for (size_t iMother = 0; iMother < nParticlesGen; ++iMother) { - // // if (fileDaughterParticles.m_motherId->at(iParticle) == fileParticles.m_particleId->at(iMother)) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iParticle)) > 0) { - // // auto it = find(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iParticle)); - // // motherId = it - idMCparticles.begin() + indexOfLastParticleAfterEvent + 1; - // // } - // // } - // // } - // // addMCParticle(tableMcCollisions.lastIndex(), fileDaughterParticles, iParticle, flags, motherId, -1, nHits); - // // } - // // } - - // LOG(info) << "Event " << iEvent << ": has " << nTracks << " tracks, " << nParticlesGen << " particles " << nDaughterParticles << " daughter particles, " << nParticlesSim << " propagated particles."; - // LOG(info) << "Total numbers of stored MC particles: " << tableStoredMcParticles.lastIndex() + 1; - // indexOfLastParticleAfterEvent = tableStoredMcParticles.lastIndex(); } } }; diff --git a/ALICE3/Tasks/alice3-dilepton.cxx b/ALICE3/Tasks/alice3-dilepton.cxx index d76b8a6f8c2..396b2df25bd 100644 --- a/ALICE3/Tasks/alice3-dilepton.cxx +++ b/ALICE3/Tasks/alice3-dilepton.cxx @@ -55,13 +55,14 @@ struct Alice3Lepton { kCe = 0, kBe = 1, kBCe = 2, - kPPi0 = 4, + kPPi0 = 3, + kHFE = 4, }; Service inspdg; Configurable pdg{"pdg", 11, "pdg code for analysis. dielectron:11, dimuon:13"}; - Configurable requireHFE{"requireHFE", -1, "-1: no selection, 0: charm, 1: direct beauty, 2: beauty->charm->e, 3: HFE, 4: promptPi0"}; + Configurable requireHFE{"requireHFE", -1, "-1: no selection, 0: charm, 1: direct beauty, 2: beauty->charm->e, 3: promptPi0, 4: HFE"}; Configurable ptMin{"ptMin", 0.f, "Lower limit in pT"}; Configurable ptMax{"ptMax", 5.f, "Upper limit in pT"}; Configurable etaMin{"etaMin", -5.f, "Lower limit in eta"}; @@ -92,7 +93,7 @@ struct Alice3Lepton { const AxisSpec axisTrackLengthOuterTOF{300, 0., 300., "Track length (cm)"}; const AxisSpec axisEta{1000, -5, 5, "#it{#eta}"}; const AxisSpec axisDCAxysigma{1000, -20, 20, "DCA_{xy} (#sigma)"}; - const AxisSpec axisDCAxy{1000, -1000, 1000, "DCA_{xy} (#micro m)"}; + const AxisSpec axisDCAxy{1200, -300, 300, "DCA_{xy} (#micro m)"}; const AxisSpec axisPhi{360, 0, TMath::TwoPi(), "#it{#varphi} (rad.)"}; const AxisSpec axisProdx{2000, -100, 100, "Prod. Vertex X (cm)"}; const AxisSpec axisPrody{2000, -100, 100, "Prod. Vertex Y (cm)"}; @@ -162,8 +163,9 @@ struct Alice3Lepton { template int IsHF(TMCParticle1 const& p1, TMCParticles const& mcparticles) { - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return HFType::kUndef; + } int motherid_p1 = p1.mothersIds()[0]; if (motherid_p1 > -1) { @@ -285,15 +287,12 @@ struct Alice3Lepton { continue; } } - if (std::abs(mcParticle.pdgCode()) != pdg) { - continue; - } if (requireHFE > -1) { int typehfe = IsHF(mcParticle, mcParticles); - if (requireHFE < 3 && typehfe != requireHFE) { + if (requireHFE < HFType::kHFE && typehfe != requireHFE) { continue; } - if (requireHFE == 3 && typehfe == HFType::kUndef) { + if (requireHFE == HFType::kHFE && (typehfe == HFType::kUndef || typehfe == kPPi0)) { continue; } } @@ -431,10 +430,10 @@ struct Alice3Lepton { } if (requireHFE > -1) { int typehfe = IsHF(mcParticle, mcParticles); - if (requireHFE < 3 && typehfe != requireHFE) { + if (requireHFE < HFType::kHFE && typehfe != requireHFE) { continue; } - if (requireHFE == 3 && typehfe == HFType::kUndef) { + if (requireHFE == HFType::kHFE && (typehfe == HFType::kUndef || typehfe == kPPi0)) { continue; } } @@ -528,7 +527,8 @@ struct Alice3Dilepton { SliceCache cache_rec; Configurable pdg{"pdg", 11, "pdg code for analysis. dielectron:11, dimuon:13"}; - Configurable requireHFEid{"requireHFEid", true, "Require HFE identification for both leptons"}; + Configurable requireHFEid{"requireHFEid", true, "Require HFE identification"}; + Configurable contamination{"contamination", false, "Fill only pairs with one misidentifixed electrons"}; Configurable ptMin{"ptMin", 0.f, "Lower limit in pT"}; Configurable ptMax{"ptMax", 5.f, "Upper limit in pT"}; Configurable etaMin{"etaMin", -5.f, "Lower limit in eta"}; @@ -629,13 +629,40 @@ struct Alice3Dilepton { } } + template + bool IsHF(TTrack const& track, TMCParticles const& mcparticles) + { + if (!track.has_mcParticle()) { + return false; + } + const auto p1 = track.template mcParticle_as(); + if (!p1.has_mothers()) { + return false; + } + int motherId = p1.mothersIds()[0]; + while (motherId > -1) { + auto mp = mcparticles.rawIteratorAt(motherId); + if (((500 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 599) || (5000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 5999)) || ((400 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 499) || (4000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 4999))) { + return true; + } + if (mp.has_mothers()) { + motherId = mp.mothersIds()[0]; + } else { + motherId = -999; + } + } + return false; + } + template int IsSameMother(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcparticles) { - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return -1; - if (!p2.has_mothers()) + } + if (!p2.has_mothers()) { return -1; + } int motherid1 = p1.mothersIds()[0]; auto mother1 = mcparticles.iteratorAt(motherid1); @@ -645,10 +672,12 @@ struct Alice3Dilepton { auto mother2 = mcparticles.iteratorAt(motherid2); int mother2_pdg = mother2.pdgCode(); - if (motherid1 != motherid2) + if (motherid1 != motherid2) { return -1; - if (mother1_pdg != mother2_pdg) + } + if (mother1_pdg != mother2_pdg) { return -1; + } if (std::abs(mother1_pdg) != PDG_t::kGamma // photon && std::abs(mother1_pdg) != PDG_t::kPi0 // pi0 @@ -674,10 +703,12 @@ struct Alice3Dilepton { // 1. b->e- and bbar->e+ (different b and bbar) // 2. b->c->e+ and bbar->cbar->e- (different b and bbar) // 3. b->c->e+ and b->e- (1 same b (or bbar)) - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return HFllType::kUndef; - if (!p2.has_mothers()) + } + if (!p2.has_mothers()) { return HFllType::kUndef; + } int motherid_p1 = p1.mothersIds()[0]; int motherid_p2 = p2.mothersIds()[0]; @@ -727,10 +758,12 @@ struct Alice3Dilepton { { // in total, 1 case for LS pairs // 4. b->c->e+ and bbar->e+ - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return HFllType::kUndef; - if (!p2.has_mothers()) + } + if (!p2.has_mothers()) { return HFllType::kUndef; + } int motherid_p1 = p1.mothersIds()[0]; int motherid_p2 = p2.mothersIds()[0]; @@ -788,13 +821,27 @@ struct Alice3Dilepton { } template - void FillPairRecAll(TTracks const& tracks1, TTracks const& tracks2) + void FillPairRecAll(TTracks const& tracks1, TTracks const& tracks2, const aod::McParticles& mcParticles) { if constexpr (pairtype == PairType::kULS) { for (const auto& [t1, t2] : combinations(soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { if (!IsInAcceptance(t1) || !IsInAcceptance(t2)) { continue; } + if (contamination) { + if (t1.has_mcParticle() && t2.has_mcParticle()) { + auto mct1 = t1.template mcParticle_as(); + auto mct2 = t2.template mcParticle_as(); + if (std::abs(mct1.pdgCode()) == pdg && std::abs(mct2.pdgCode()) == pdg) { + continue; + } + } + } + if (requireHFEid) { + if (!IsHF(t1, mcParticles) && !IsHF(t2, mcParticles)) { + continue; + } + } float pair_dca_xy = 999.f; ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); @@ -811,6 +858,20 @@ struct Alice3Dilepton { if (!IsInAcceptance(t1) || !IsInAcceptance(t2)) { continue; } + if (contamination) { + if (t1.has_mcParticle() && t2.has_mcParticle()) { + auto mct1 = t1.template mcParticle_as(); + auto mct2 = t2.template mcParticle_as(); + if (std::abs(mct1.pdgCode()) == pdg && std::abs(mct2.pdgCode()) == pdg) { + continue; + } + } + } + if (requireHFEid) { + if (!IsHF(t1, mcParticles) && !IsHF(t2, mcParticles)) { + continue; + } + } float pair_dca_xy = 999.f; ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); @@ -1084,7 +1145,7 @@ struct Alice3Dilepton { void processRecAll(MyFilteredAlice3Collision const& collisions, MyFilteredTracksMC const&, - const aod::McParticles&) + const aod::McParticles& mcParticles) { for (const auto& collision : collisions) { registry.fill(HIST("Reconstructed/Event/VtxZ"), collision.posZ()); @@ -1125,9 +1186,9 @@ struct Alice3Dilepton { registry.fill(HIST("Reconstructed/Track/Pre"), track.isTrackPrefilter()); } - FillPairRecAll(negTracks_coll, posTracks_coll); - FillPairRecAll(posTracks_coll, posTracks_coll); - FillPairRecAll(negTracks_coll, negTracks_coll); + FillPairRecAll(negTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(posTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(negTracks_coll, negTracks_coll, mcParticles); } // end of collision loop } // end of processRec @@ -1150,7 +1211,7 @@ struct Alice3Dilepton { void processRecAllWithSmearing(MyFilteredAlice3Collision const& collisions, MyFilteredTracksWithSmearing const&, - const aod::McParticles&) + const aod::McParticles& mcParticles) { for (const auto& collision : collisions) { registry.fill(HIST("Reconstructed/Event/VtxZ"), collision.posZ()); @@ -1191,9 +1252,9 @@ struct Alice3Dilepton { registry.fill(HIST("Reconstructed/Track/Pre"), track.isTrackPrefilter()); } - FillPairRecAll(negTracks_coll, posTracks_coll); - FillPairRecAll(posTracks_coll, posTracks_coll); - FillPairRecAll(negTracks_coll, negTracks_coll); + FillPairRecAll(negTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(posTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(negTracks_coll, negTracks_coll, mcParticles); } // end of collision loop } // end of processRec diff --git a/ALICE3/Tasks/alice3DqEfficiency.cxx b/ALICE3/Tasks/alice3DqEfficiency.cxx index f276a8803b5..5d6929b6927 100644 --- a/ALICE3/Tasks/alice3DqEfficiency.cxx +++ b/ALICE3/Tasks/alice3DqEfficiency.cxx @@ -303,7 +303,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { Configurable cfgTrackMCsignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; HistogramManager* fHistMan = nullptr; - std::vector fTrackCuts; + std::vector fTrackCuts; std::vector fMCSignals; // list of signals to be checked std::vector fHistNamesReco; std::vector fHistNamesMCMatched; @@ -330,7 +330,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (const auto& t : addTrackCuts) { - fTrackCuts.push_back(static_cast(t)); + fTrackCuts.push_back(t); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill @@ -401,7 +401,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { // Loop over associations for (const auto& assoc : assocs) { - auto event = assoc.template reA3event_as(); + auto event = assoc.template reA3Event_as(); if (!event.isEventSelected_bit(0)) { trackSel(0); continue; @@ -414,7 +414,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { VarManager::FillEventAlice3(event.reA3MCEvent()); } - auto track = assoc.template reA3track_as(); + auto track = assoc.template reA3Track_as(); VarManager::FillTrackAlice3(track); // compute quantities which depend on the associated collision, such as DCA VarManager::FillTrackCollision(track, event); @@ -563,7 +563,7 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { uint32_t fPrefilterMask = 0; int fPrefilterCutBit = -1; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; void init(o2::framework::InitContext& context) { @@ -650,8 +650,8 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { } for (const auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { - auto track1 = assoc1.template reA3track_as(); - auto track2 = assoc2.template reA3track_as(); + auto track1 = assoc1.template reA3Track_as(); + auto track2 = assoc2.template reA3Track_as(); // NOTE: here we restrict to just pairs of opposite sign (conversions), but in principle this can be made // a configurable and check also same-sign pairs (track splitting) @@ -707,7 +707,7 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { } else { for (const auto& assoc : assocs) { // TODO: just use the index from the assoc (no need to cast the whole track) - auto track = assoc.template reA3track_as(); + auto track = assoc.template reA3Track_as(); mymap = -1; if (!fPrefilterMap.contains(track.globalIndex())) { // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else @@ -735,12 +735,6 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { // The task implements also process functions for running event mixing struct Alice3DqEfficiencyAnalysisSameEventPairing { - Produces dielectronList; - Produces dielectronsExtraList; - Produces dielectronAllList; - Produces mcTruthTableEffi; - - o2::base::MatLayerCylSet* fLUT = nullptr; OutputObj fOutputList{"output"}; struct : ConfigurableGroup { @@ -794,7 +788,7 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { bool fEnableBarrelHistos = false; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; void init(o2::framework::InitContext& context) { @@ -1020,27 +1014,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { bool isCorrectAssocLeg1 = false; bool isCorrectAssocLeg2 = false; - int64_t reserveSize = 0; - for (auto const& event : events) { - if (event.isEventSelected_bit(0)) { - auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); - size_t nGood = 0; - for (auto const& t : groupedAssocs) { - if (t.isBarrelSelected_raw() > 0u) { - nGood++; - } - } - reserveSize += nGood * (nGood - 1) / 2; - } - } - - dielectronList.reserve(reserveSize); - dielectronsExtraList.reserve(reserveSize); - - if (fConfigOptions.cfgFlatTables.value) { - dielectronAllList.reserve(reserveSize); - } - for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -1063,8 +1036,8 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { continue; } - auto t1 = a1.template reA3track_as(); - auto t2 = a2.template reA3track_as(); + auto t1 = a1.template reA3Track_as(); + auto t2 = a2.template reA3Track_as(); sign1 = t1.sign(); sign2 = t2.sign(); // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter @@ -1102,11 +1075,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { } VarManager::FillPairVertexingAlice3(event, t1, t2, fConfigOptions.cfgPropToPCA); - if (!fConfigMC.cfgSkimSignalOnly || mcDecision > 0) { - dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, mcDecision); - } // Fill histograms bool isAmbiInBunch = false; @@ -1208,7 +1176,7 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { } // end loop over events } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reduceda3trackmc::reA3MCEventId; void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { @@ -1253,7 +1221,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, trackRaw)) { fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); - mcTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); } } } @@ -1324,7 +1291,7 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { runMCGenWithGrouping(events, mcEvents, mcTracks); } - PresliceUnsorted perReducedMcGenEvent = aod::reducedA3trackMC::reA3MCEventId; + PresliceUnsorted perReducedMcGenEvent = aod::reduceda3trackmc::reA3MCEventId; void processMCGen(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { @@ -1360,7 +1327,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, trackRaw)) { fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); - mcTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); } } } @@ -1446,7 +1412,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, trackRaw)) { fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); - mcTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); } } } @@ -1509,9 +1474,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { struct Alice3DqEfficiencyAnalysisAsymmetricPairing { - Produces ditrackList; - Produces ditrackExtraList; - // Output objects OutputObj fOutputList{"output"}; @@ -1538,7 +1500,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { HistogramManager* fHistMan = nullptr; - std::vector fPairCuts; + std::vector fPairCuts; int fNPairHistPrefixes = 0; std::vector fRecMCSignals; @@ -1568,8 +1530,8 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; - // PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; + // PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; // Partitions for triplets and asymmetric pairs Partition legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & cfgLegAFilterMask) > static_cast(0); @@ -1609,7 +1571,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { if (addPairCutsStr != "") { std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (const auto& t : addPairCuts) { - fPairCuts.push_back(static_cast(t)); + fPairCuts.push_back(t); pairCutNamesStr += Form(",%s", t->GetName()); } } @@ -1920,7 +1882,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { } // Function to run same event pairing with asymmetric pairs (e.g. kaon-pion) - void runAsymmetricPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocs const& assocs, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/) + void runAsymmetricPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocs const& /*assocs*/, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/) { fPairCount.clear(); @@ -1928,23 +1890,6 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { int sign2 = 0; uint32_t mcDecision = 0; - int64_t reserveSize = 0; - for (auto const& event : events) { - if (event.isEventSelected_bit(0)) { - auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); - size_t nGood = 0; - for (auto const& t : groupedAssocs) { - if (t.isBarrelSelected_raw() > 0u) { - nGood++; - } - } - reserveSize += nGood * (nGood - 1) / 2; - } - } - - ditrackList.reserve(reserveSize); - ditrackExtraList.reserve(reserveSize); - for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -1965,8 +1910,8 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { for (const auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { uint32_t twoTrackFilter = 0; uint32_t twoTrackCommonFilter = 0; - uint32_t pairFilter = 0; bool isPairIdWrong = false; + for (int icut = 0; icut < fNLegCuts; ++icut) { // Find leg pair definitions both candidates participate in if (((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) != 0u) && ((a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) != 0u)) { @@ -1987,8 +1932,8 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { // Find common track cuts both candidates pass twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reA3track_as(); - auto t2 = a2.template reA3track_as(); + auto t1 = a1.template reA3Track_as(); + auto t2 = a2.template reA3Track_as(); // Avoid self-pairs if (t1.globalIndex() == t2.globalIndex()) { @@ -2117,7 +2062,6 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { if (!((*cut)->IsSelected(dqefficiency_helpers::varValues()))) { // apply pair cuts continue; } - pairFilter |= (static_cast(1) << iPairCut); // Histograms with pair cuts if (sign1 * sign2 < 0) { fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); @@ -2171,9 +2115,6 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { } // end loop (pair cuts) } } // end loop (cuts) - ditrackList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, pairFilter, twoTrackCommonFilter); } // end inner assoc loop (leg A) } // end event loop } @@ -2256,9 +2197,9 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { // Find common track cuts all candidates pass threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reA3track_as(); - auto t2 = a2.template reA3track_as(); - auto t3 = a3.template reA3track_as(); + auto t1 = a1.template reA3Track_as(); + auto t2 = a2.template reA3Track_as(); + auto t3 = a3.template reA3Track_as(); // Avoid self-pairs if (t1 == t2 || t1 == t3 || t2 == t3) { @@ -2383,7 +2324,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { { // loop over mc stack and fill histograms for pure MC truth signals // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedA3trackMC::reA3MCEventId, event.reducedMCevent().globalIndex()); + // auto groupedMCTracks = tracksMC.sliceBy(aod::reduceda3trackmc::reA3MCEventId, event.reducedMCevent().globalIndex()); for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -2398,7 +2339,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { } } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reduceda3trackmc::reA3MCEventId; void processMCGenWithEventSelection(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) diff --git a/Common/Core/TPCVDriftManager.h b/Common/Core/TPCVDriftManager.h index 18c02b016b9..d7c5b25be19 100644 --- a/Common/Core/TPCVDriftManager.h +++ b/Common/Core/TPCVDriftManager.h @@ -46,7 +46,7 @@ class TPCVDriftManager return; } - // Update Obj + // Update Object mVD = mCCDB->getForTimeStamp("TPC/Calib/VDriftTgl", timestamp); if (mVD == nullptr || mVD->firstTime < 0 || mVD->lastTime < 0) { LOGP(error, "Got invalid VDriftCorrFact for {}", timestamp); @@ -60,7 +60,7 @@ class TPCVDriftManager mTPCVDriftNS = mVD->refVDrift * mVD->corrFact * 1e-3; mValid = true; - LOGP(info, "Updated VDrift for timestamp {} with vdrift={:.7f} (cm/ns)", mVD->creationTime, mTPCVDriftNS); + LOGP(debug, "Updated VDrift for timestamp {} with vdrift={:.7f} (cm/ns)", mVD->creationTime, mTPCVDriftNS); } template diff --git a/Common/Core/fwdtrackUtilities.h b/Common/Core/fwdtrackUtilities.h index 29a9db2c194..932a77d9ae3 100644 --- a/Common/Core/fwdtrackUtilities.h +++ b/Common/Core/fwdtrackUtilities.h @@ -108,16 +108,16 @@ o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float z return getTrackParCovFwd3DShift(track, 0.f, 0.f, zshift, covOpt...); } -inline o2::track::TrackParCovFwd getTrackParCovFwdShiftManual( +inline o2::track::TrackParCovFwd getTrackParCovFwd3DShiftManual( const double x, const double y, const double phi, const double tgl, const double signed1Pt, const double cXX, const double cXY, const double cYY, const double cPhiX, const double cPhiY, const double cPhiPhi, const double cTglX, const double cTglY, const double cTglPhi, const double cTglTgl, const double c1PtX, const double c1PtY, const double c1PtPhi, const double c1PtTgl, const double c1Pt21Pt2, - const float z, const float zshift, const float chi2) + const float z, const float xshift, const float yshift, const float zshift, const float chi2) { - SMatrix5 tpars(x, y, phi, tgl, signed1Pt); + SMatrix5 tpars(x + xshift, y + yshift, phi, tgl, signed1Pt); SMatrix55 tcovs; std::vector v1{ @@ -164,15 +164,15 @@ o2::track::TrackParCovFwd getTrackParCovFwd(TFwdTrack const& track, TFwdTrackCov /// propagate fwdtrack to a certain point. template -o2::dataformats::GlobalFwdTrack propagateMuon(TFwdTrack const& muon, TFwdTrackCov const& cov, TCollision const& collision, const propagationPoint endPoint, const float matchingZ, const float bzkG, const float zshift = 0.f) +o2::dataformats::GlobalFwdTrack propagateMuon(TFwdTrack const& muon, TFwdTrackCov const& cov, TCollision const& collision, const propagationPoint endPoint, const float matchingZ, const float bzkG, const float xshift = 0.f, const float yshift = 0.f, const float zshift = 0.f) { o2::track::TrackParCovFwd trackParCovFwd; if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - trackParCovFwd = getTrackParCovFwdShift(muon, zshift, cov); + trackParCovFwd = getTrackParCovFwd3DShift(muon, xshift, yshift, zshift, cov); } else if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - trackParCovFwd = getTrackParCovFwdShift(muon, zshift, muon); + trackParCovFwd = getTrackParCovFwd3DShift(muon, xshift, yshift, zshift, muon); } else { - trackParCovFwd = getTrackParCovFwdShift(muon, zshift, muon); + trackParCovFwd = getTrackParCovFwd3DShift(muon, xshift, yshift, zshift, muon); } o2::dataformats::GlobalFwdTrack propmuon = propagateTrackParCovFwd(trackParCovFwd, muon.trackType(), collision, endPoint, matchingZ, bzkG); @@ -340,7 +340,7 @@ float getFwdChi2IP(TTrackParCovFwd const& inputTrk, TCollision const& collision, } template -float getFwdChi2IP(const TFullFwdTrack& fwdtrack, const TCollision& collision, const float bz, const float zShift) +float getFwdChi2IP(const TFullFwdTrack& fwdtrack, const TCollision& collision, const float bz, const float xShift, const float yShift, const float zShift) { // this function returns imcompatibility of fwdtrack respect to a given PV. // fwdtracks are never PV contributors in ALICE. @@ -348,7 +348,7 @@ float getFwdChi2IP(const TFullFwdTrack& fwdtrack, const TCollision& collision, c // chi2IP cannot be used to decide the best fwdtrack-to-collision match or MFT-MCH match, because it gives biases toward small muon impact parameter. // chi2IP should be used only after the best fwdtrack-to-collision association and the best MFT-MCH match are defined. - o2::track::TrackParCovFwd trk = getTrackParCovFwdShift(fwdtrack, zShift, fwdtrack); + o2::track::TrackParCovFwd trk = getTrackParCovFwd3DShift(fwdtrack, xShift, yShift, zShift, fwdtrack); if (std::abs(bz) < 1e-12) { trk.propagateToZlinear(collision.posZ()); diff --git a/Common/Tools/Multiplicity/MultModule.h b/Common/Tools/Multiplicity/MultModule.h index beb1274b7a4..9687c52b20c 100644 --- a/Common/Tools/Multiplicity/MultModule.h +++ b/Common/Tools/Multiplicity/MultModule.h @@ -11,7 +11,7 @@ /// \file MultModule.h /// \brief combined multiplicity + centrality module with autodetect features -/// \author ALICE +/// \author ALICE Collaboration #ifndef COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ #define COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ @@ -1198,13 +1198,13 @@ class MultModule LOGF(info, "centrality loading procedure for timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); // capture the need for PYTHIA calibration in Pb-Pb runs - if (metadataInfo.isMC() && mRunNumber >= 544013 && mRunNumber <= 545367) { + if (metadataInfo.isMC() && mRunNumber >= 544013 && mRunNumber <= 545367 && internalOpts.generatorName.value.empty()) { LOGF(info, "This is MC for Pb-Pb. Setting generatorName automatically to PYTHIA"); internalOpts.generatorName.value = "PYTHIA"; } // capture the need for PYTHIA calibration in light ion runs automatically - if (metadataInfo.isMC() && mRunNumber >= 564250 && mRunNumber <= 564472) { + if (metadataInfo.isMC() && mRunNumber >= 564250 && mRunNumber <= 564472 && internalOpts.generatorName.value.empty()) { LOGF(info, "This is MC for light ion runs. Setting generatorName automatically to PYTHIA"); internalOpts.generatorName.value = "PYTHIA"; } diff --git a/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx index a79bd82a5c3..5e6cffea36d 100644 --- a/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx +++ b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx @@ -779,8 +779,8 @@ struct DetectorOccupancyQaTask { if (!col.selection_bit(kNoITSROFrameBorder)) continue; - std::vector vCollsAssocToGivenColl = vCollsInTimeWin[colIndex]; - std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + const std::vector& vCollsAssocToGivenColl = vCollsInTimeWin[colIndex]; + const std::vector& vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; LOGP(debug, " >> vCollsAssocToGivenColl.size={}", vCollsAssocToGivenColl.size()); diff --git a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx index b9789edaab8..13278810e0c 100644 --- a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx +++ b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx @@ -1415,7 +1415,7 @@ struct EventSelectionQaTask { bool isVertexUPC = flags & dataformats::Vertex>::Flags::UPCMode; // is vertex with UPC settings // the second collision in ROF - std::vector vAssocToSameROF = vCollsInSameITSROF[colIndex]; + const std::vector& vAssocToSameROF = vCollsInSameITSROF[colIndex]; int thisColIndex = vAssocToSameROF[0]; float vZassoc = vCollVz[thisColIndex]; // vZ of the second collision in the same ROF float nPVassoc = vTracksITS567perColl[thisColIndex]; // n PV tracks of the second collision in the same ROF diff --git a/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx b/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx index c9658dce198..40cd2429928 100644 --- a/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx +++ b/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx @@ -754,7 +754,7 @@ struct RofOccupancyQaTask { // LOGP(info, "#### starting new coll: bc={} bcInTF={} bcInITSROF={} rofId={}; noROFborder={}; rofOffset={} rofLength={}", vFoundGlobalBC[colIndex], bcInTF, bcInITSROF, rofId, bc.selection_bit(kNoITSROFrameBorder), rofOffset, rofLength); // LOGP(info, "#### starting new coll: bcInTF={} bcInITSROF={} rofIdInTF={}; noROFborder={}, vZ={} mult={}; rofOffset={} rofLength={}", bcInTF, bcInITSROF, rofIdInTF, bc.selection_bit(kNoITSROFrameBorder), vZ, vTracksITS567perColl[colIndex], rofOffset, rofLength); - std::vector vAssocToSameROF = vCollsInSameITSROF[colIndex]; + const std::vector& vAssocToSameROF = vCollsInSameITSROF[colIndex]; int nITS567tracksForRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF float nSumAmplFT0CforRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF // int nITS567tracksForRofVetoStandard = 0; // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold @@ -836,8 +836,8 @@ struct RofOccupancyQaTask { vArrNoCollInSameRofWithCloseVz.push_back(vVzCutThisColl); continue; } - std::vector vAssocToThisCol = vCollsInTimeWin[colIndex]; - std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + const std::vector& vAssocToThisCol = vCollsInTimeWin[colIndex]; + const std::vector& vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; int nITS567tracksInFullTimeWindow = 0; int sumAmpFT0CInFullTimeWindow = 0; int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx index bbe18f83730..bb6afc2a437 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx @@ -379,7 +379,7 @@ struct tofPidQa { int evtimeflag = 0; if constexpr (fillHistograms) { - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.hasTOF()) { // Skipping tracks without TOF continue; } @@ -529,7 +529,7 @@ struct tofPidQa { soa::Filtered const& tracks) { isEventSelected(collision, tracks); - for (auto t : tracks) { + for (const auto& t : tracks) { isTrackSelected(collision, t); } } @@ -543,7 +543,7 @@ struct tofPidQa { return; } - for (auto t : tracks) { + for (const auto& t : tracks) { if (!isTrackSelected(collision, t)) { continue; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx index e526840e19f..bec2f335512 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx @@ -401,7 +401,7 @@ struct tofPidQaDynamic { int evtimeflag = 0; if constexpr (fillHistograms) { - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.hasTOF()) { // Skipping tracks without TOF continue; } @@ -554,7 +554,7 @@ struct tofPidQaDynamic { tofResponse->processSetup(collision.bc_as()); isEventSelected(collision, tracks); - for (auto t : tracks) { + for (const auto& t : tracks) { isTrackSelected(collision, t); } } @@ -568,7 +568,7 @@ struct tofPidQaDynamic { return; } - for (auto t : tracks) { + for (const auto& t : tracks) { if (!isTrackSelected(collision, t)) { continue; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx index 35c33cb64fa..f9b6f0c620a 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx @@ -167,7 +167,7 @@ struct tofPidCollisionTimeQa { } listEfficiency.setObject(new THashList); - auto makeEfficiency = [&](TString effname, TString efftitle) { + auto makeEfficiency = [&](const TString& effname, const TString& efftitle) { listEfficiency->Add(new TEfficiency(effname, efftitle + ";TOF multiplicity;Efficiency", nBinsMultiplicity, 0, rangeMultiplicity)); }; diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index aa2f13ba744..dac01d5f092 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -345,7 +345,7 @@ struct perfK0sResolution { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) diff --git a/DPG/Tasks/AOTTrack/qaEfficiency.cxx b/DPG/Tasks/AOTTrack/qaEfficiency.cxx index b8b5bc4631e..6a998053a8a 100644 --- a/DPG/Tasks/AOTTrack/qaEfficiency.cxx +++ b/DPG/Tasks/AOTTrack/qaEfficiency.cxx @@ -500,7 +500,7 @@ struct QaEfficiency { subList->SetName(partName); listEfficiencyMC->Add(subList); - auto makeEfficiency = [&](const TString effname, auto h) { // 1D efficiencies + auto makeEfficiency = [&](const TString& effname, const auto& h) { // 1D efficiencies LOG(debug) << " Making 1D TEfficiency " << effname << " from " << h->GetName(); const TAxis* axis = h->GetXaxis(); TString efftitle = h->GetTitle(); @@ -563,7 +563,7 @@ struct QaEfficiency { makeEfficiency("ITS-TPC_vsPhi_Prm_Trk", hPhiTrkItsTpcPrm[histogramIndex]); makeEfficiency("ITS-TPC-TOF_vsPhi_Prm", hPhiItsTpcTofPrm[histogramIndex]); - auto makeEfficiency2D = [&](const TString effname, auto h) { // 2D efficiencies + auto makeEfficiency2D = [&](const TString& effname, const auto& h) { // 2D efficiencies LOG(debug) << " Making 2D TEfficiency " << effname << " from " << h->GetName(); const TAxis* axisX = h->GetXaxis(); const TAxis* axisY = h->GetYaxis(); @@ -898,7 +898,7 @@ struct QaEfficiency { listEfficiencyData.setObject(new THashList); if (makeEff) { LOG(debug) << "Making TEfficiency for Data"; - auto makeEfficiency = [&](TString effname, TString efftitle, auto templateHisto, TEfficiency*& eff) { + auto makeEfficiency = [&](const TString& effname, const TString& efftitle, auto templateHisto, TEfficiency*& eff) { TAxis* axis = histos.get(templateHisto)->GetXaxis(); if (axis->IsVariableBinSize()) { eff = new TEfficiency(effname, efftitle, axis->GetNbins(), axis->GetXbins()->GetArray()); @@ -927,7 +927,7 @@ struct QaEfficiency { "TPC-TOF M.E. in data " + tagPhi + ";#it{#varphi} (rad);Efficiency", HIST("Data/pos/phi/its_tpc_tof"), effTPCTOFMatchingVsPhi); - auto makeEfficiency2D = [&](TString effname, TString efftitle, auto templateHistoX, auto templateHistoY, TEfficiency*& eff) { + auto makeEfficiency2D = [&](const TString& effname, const TString& efftitle, auto templateHistoX, auto templateHistoY, TEfficiency*& eff) { TAxis* axisX = histos.get(templateHistoX)->GetXaxis(); TAxis* axisY = histos.get(templateHistoY)->GetYaxis(); if (axisX->IsVariableBinSize() || axisY->IsVariableBinSize()) { @@ -1366,7 +1366,7 @@ struct QaEfficiency { } // Filling 1D efficiencies - auto doFillEfficiency = [&](const TString effname, auto num, auto den) { + auto doFillEfficiency = [&](const TString& effname, const auto& num, const auto& den) { TEfficiency* eff = static_cast(subList->FindObject(effname)); if (!eff) { LOG(warning) << "Cannot find TEfficiency " << effname; @@ -1436,7 +1436,7 @@ struct QaEfficiency { } // Filling 2D efficiencies - auto fillEfficiency2D = [&](const TString effname, auto num, auto den) { + auto fillEfficiency2D = [&](const TString& effname, const auto& num, const auto& den) { TEfficiency* eff = static_cast(subList->FindObject(effname)); if (!eff) { LOG(warning) << "Cannot find TEfficiency " << effname; diff --git a/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx b/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx index 34373a3e1ad..dc1f2bed237 100644 --- a/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx +++ b/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx @@ -154,7 +154,7 @@ struct qaEventTrackLite { /// return initBBok ? mMip * o2::common::BetheBlochAleph(x[0] / par[0], mBetheBlockAleph[0], mBetheBlockAleph[1], mBetheBlockAleph[2], mBetheBlockAleph[3], mBetheBlockAleph[4]) * std::pow(par[1], mChargeFactor) : 0.; } - void setUpBetheBlockAleph(std::string str_case) + void setUpBetheBlockAleph(const std::string& str_case) { if (str_case.find("LHC22c") != std::string::npos) { // From A. Kalteyer (2022 Jul 18) @@ -418,7 +418,7 @@ struct qaEventTrackLite { histos.fill(HIST("Tracks/TPC/dEdxvsP"), p, track.tpcSignal()); histos.fill(HIST("Tracks/TPC/dEdxvsPvsEta"), p, track.eta(), track.tpcSignal()); if (betheBlock.initBBok) { - auto tpcdEdxRes = [&](TF1 func) { return track.tpcSignal() - func.Eval(p); }; + auto tpcdEdxRes = [&](const TF1& func) { return track.tpcSignal() - func.Eval(p); }; if (b_tpcResProton) { histos.fill(HIST("Tracks/TPC/dEdxvsPproton"), p, tpcdEdxRes(funcBBproton)); histos.fill(HIST("Tracks/TPC/dEdxvsPprotonvsEta"), p, track.eta(), tpcdEdxRes(funcBBproton)); diff --git a/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx index 680cb819b34..08d433103f1 100644 --- a/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx +++ b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include using namespace o2; @@ -134,10 +135,11 @@ struct qaTrackSplitting { if (!collision.sel8()) { return; } - typedef std::shared_ptr trkType; + using TrackType = const TrackCandidatesMC::iterator; + using TrackTypePtr = std::shared_ptr; - std::map> particleUsageCounter; - for (auto track : tracks) { + std::map> particleUsageCounter; + for (const auto& track : tracks) { histos.fill(HIST("tracks"), 0); if (!track.has_mcParticle()) { continue; @@ -156,7 +158,7 @@ struct qaTrackSplitting { continue; } histos.fill(HIST("tracks"), 4); - particleUsageCounter[track.mcParticleId()].push_back(std::make_shared(track)); + particleUsageCounter[track.mcParticleId()].push_back(std::make_shared(track)); } for (const auto& [mcId, tracksMatched] : particleUsageCounter) { histos.fill(HIST("numberOfRecoed"), tracksMatched.size()); diff --git a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx index 842f167d7d2..7fbc609af28 100644 --- a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx +++ b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx @@ -1296,7 +1296,7 @@ struct ProbeThirdTrack { } template - void loopOverThirdTrack(TTrackIndices const& groupedTrackThirdIndices, TTracks const& /*tracks*/, TTrack const& trackFirst, TTrack const& trackSecond, PParticles const mcParticles, const int motherIdxTag, const float radius) + void loopOverThirdTrack(TTrackIndices const& groupedTrackThirdIndices, TTracks const& /*tracks*/, TTrack const& trackFirst, TTrack const& trackSecond, PParticles const& mcParticles, const int motherIdxTag, const float radius) { for (const auto& trackIndex : groupedTrackThirdIndices) { auto trackThird = trackIndex.template track_as(); diff --git a/DPG/Tasks/ITS/filterTracks.cxx b/DPG/Tasks/ITS/filterTracks.cxx index 6a9ee148142..9af02996211 100644 --- a/DPG/Tasks/ITS/filterTracks.cxx +++ b/DPG/Tasks/ITS/filterTracks.cxx @@ -225,7 +225,7 @@ struct FilterTracks { { } - void fillTableData(auto track) + void fillTableData(const auto& track) { filteredTracksCollIdx(track.collisionId()); @@ -235,7 +235,7 @@ struct FilterTracks { filteredTracksTableExtraDet(track.itsClusterSizes(), track.itsChi2NCl(), track.tpcChi2NCl(), track.tpcNClsFound(), track.trackTime()); } - void fillTableDataMC(auto track, aod::McParticles const& mcParticles) + void fillTableDataMC(const auto& track, aod::McParticles const& mcParticles) { fillTableData(track); diff --git a/EventFiltering/PWGEM/globalDimuonFilter.cxx b/EventFiltering/PWGEM/globalDimuonFilter.cxx index 48cf5515f5c..4b18d831504 100644 --- a/EventFiltering/PWGEM/globalDimuonFilter.cxx +++ b/EventFiltering/PWGEM/globalDimuonFilter.cxx @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -56,10 +57,6 @@ #include #include -#include - -// #include - struct globalDimuonFilter { o2::framework::Produces tags; @@ -147,14 +144,24 @@ struct globalDimuonFilter { // for z shift for propagation o2::framework::Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; o2::framework::Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - o2::framework::Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualXShiftMFTtop{"cfgManualXShiftMFTtop", 0, "manual x shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualYShiftMFTtop{"cfgManualYShiftMFTtop", 0, "manual y shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualZShiftMFTtop{"cfgManualZShiftMFTtop", 0, "manual z shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualXShiftMFTbottom{"cfgManualXShiftMFTbottom", 0, "manual x shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualYShiftMFTbottom{"cfgManualYShiftMFTbottom", 0, "manual y shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualZShiftMFTbottom{"cfgManualZShiftMFTbottom", 0, "manual z shift for propagation of global muon to PV"}; o2::framework::HistogramRegistry fRegistry{"output", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject, false, false}; o2::ccdb::CcdbApi ccdbApi; o2::framework::Service ccdb; int mRunNumber = 0; float mBz = 0; - float mZShift = 0; + float mXShiftMFTtop = 0; + float mYShiftMFTtop = 0; + float mZShiftMFTtop = 0; + float mXShiftMFTbottom = 0; + float mYShiftMFTbottom = 0; + float mZShiftMFTbottom = 0; void init(o2::framework::InitContext&) { @@ -165,7 +172,12 @@ struct globalDimuonFilter { ccdbApi.init(ccdburl); mRunNumber = 0; mBz = 0; - mZShift = 0; + mXShiftMFTtop = 0; + mYShiftMFTtop = 0; + mZShiftMFTtop = 0; + mXShiftMFTbottom = 0; + mYShiftMFTbottom = 0; + mZShiftMFTbottom = 0; addHistograms(); } @@ -196,14 +208,26 @@ struct globalDimuonFilter { auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); if (zShift != nullptr && !zShift->empty()) { LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); - mZShift = (*zShift)[0]; + mZShiftMFTtop = (*zShift)[0]; + mZShiftMFTbottom = (*zShift)[0]; } else { LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); - mZShift = 0; + mZShiftMFTtop = 0; + mZShiftMFTbottom = 0; } } else { - LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); - mZShift = cfgManualZShift; + LOGF(info, "X shift for MFT top is manually set to %f cm", cfgManualXShiftMFTtop.value); + LOGF(info, "X shift for MFT bottom is manually set to %f cm", cfgManualXShiftMFTbottom.value); + LOGF(info, "Y shift for MFT top is manually set to %f cm", cfgManualYShiftMFTtop.value); + LOGF(info, "Y shift for MFT bottom is manually set to %f cm", cfgManualYShiftMFTbottom.value); + LOGF(info, "Z shift for MFT top is manually set to %f cm", cfgManualZShiftMFTtop.value); + LOGF(info, "Z shift for MFT bottom is manually set to %f cm", cfgManualZShiftMFTbottom.value); + mXShiftMFTtop = cfgManualXShiftMFTtop; + mYShiftMFTtop = cfgManualYShiftMFTtop; + mZShiftMFTtop = cfgManualZShiftMFTtop; + mXShiftMFTbottom = cfgManualXShiftMFTbottom; + mYShiftMFTbottom = cfgManualYShiftMFTbottom; + mZShiftMFTbottom = cfgManualZShiftMFTbottom; } } @@ -224,9 +248,9 @@ struct globalDimuonFilter { fRegistry.add("Vertex/MB/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::HistType::kTH1D, {{40, -20, +20}}, false); fRegistry.add("Vertex/MB/hChi2vsNContrib", "vertex #chi^{2}/N_{contrib} vs. N_{contrib};N_{contrib};#chi^{2}/N_{contrib}", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {100, 0, 10}}, false); - fRegistry.add("Vertex/MB/hSigmaX", "vertex #sigma_{X} vs. N_{contrib};N_{contrib};#sigma_{X} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {2000, 0, 200}}, false); - fRegistry.add("Vertex/MB/hSigmaY", "vertex #sigma_{Y} vs. N_{contrib};N_{contrib};#sigma_{Y} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {2000, 0, 200}}, false); - fRegistry.add("Vertex/MB/hSigmaZ", "vertex #sigma_{Z} vs. N_{contrib};N_{contrib};#sigma_{Z} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {2000, 0, 200}}, false); + fRegistry.add("Vertex/MB/hSigmaX", "vertex #sigma_{X} vs. N_{contrib};N_{contrib};#sigma_{X} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/MB/hSigmaY", "vertex #sigma_{Y} vs. N_{contrib};N_{contrib};#sigma_{Y} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/MB/hSigmaZ", "vertex #sigma_{Z} vs. N_{contrib};N_{contrib};#sigma_{Z} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {1000, 0, 100}}, false); fRegistry.addClone("Vertex/MB/", "Vertex/Triggered/"); fRegistry.add("MFTMCHMID/positive/hPt", "pT;p_{T} (GeV/c)", o2::framework::HistType::kTH1D, {{200, 0.0f, 10}}, false); @@ -245,7 +269,7 @@ struct globalDimuonFilter { fRegistry.add("MFTMCHMID/positive/hChi2MatchMCHMFT_Pt", "chi2 match MCH-MFT;p_{T,#mu} (GeV/c);matching #chi^{2}/ndf between MFT-MCH", o2::framework::HistType::kTH2D, {{200, 0, 10}, {100, 0.0f, 100}}, false); fRegistry.add("MFTMCHMID/positive/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2D, {{400, -1, 1}, {400, -1, +1}}, false); fRegistry.add("MFTMCHMID/positive/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2D, {{200, -10, 10}, {200, -10, +10}}, false); - fRegistry.add("MFTMCHMID/positive/hDCAxy", "DCAxy;DCA_{xy} (cm);", o2::framework::HistType::kTH1D, {{100, 0, 1}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxy", "DCAxy;DCA_{xy} (cm);", o2::framework::HistType::kTH1D, {{1000, 0, 1}}, false); fRegistry.add("MFTMCHMID/positive/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", o2::framework::HistType::kTH1D, {{100, 0, 10}}, false); fRegistry.add("MFTMCHMID/positive/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", o2::framework::HistType::kTH1D, {{1000, -5, 5}}, false); fRegistry.add("MFTMCHMID/positive/hDCAxResolutionvsPt", "DCA_{x} resolution vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", o2::framework::HistType::kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); @@ -418,12 +442,12 @@ struct globalDimuonFilter { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); phiMatchedMCHMID = RecoDecay::constrainAngle(phiMatchedMCHMID, 0, 1U); - o2::dataformats::GlobalFwdTrack propmuonAtPV = o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); pt = propmuonAtPV.getPt(); eta = propmuonAtPV.getEta(); phi = propmuonAtPV.getPhi(); @@ -440,7 +464,7 @@ struct globalDimuonFilter { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtDCA = o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtDCA = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); float dcaX = propmuonAtDCA.getX() - collision.posX(); float dcaY = propmuonAtDCA.getY() - collision.posY(); float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); @@ -474,7 +498,7 @@ struct globalDimuonFilter { } float sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2.f); - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); @@ -488,7 +512,7 @@ struct globalDimuonFilter { return false; } - float chi2IP = o2::aod::fwdtrackutils::getFwdChi2IP(fwdtrack, collision, mBz, mZShift); + float chi2IP = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); if constexpr (fillHistograms) { if (fwdtrack.sign() > 0) { @@ -605,12 +629,12 @@ struct globalDimuonFilter { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); phiMatchedMCHMID = RecoDecay::constrainAngle(phiMatchedMCHMID, 0, 1U); - o2::dataformats::GlobalFwdTrack propmuonAtPV = o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); pt = propmuonAtPV.getPt(); eta = propmuonAtPV.getEta(); phi = propmuonAtPV.getPhi(); @@ -693,12 +717,12 @@ struct globalDimuonFilter { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); phiMatchedMCHMID = RecoDecay::constrainAngle(phiMatchedMCHMID, 0, 1U); - o2::dataformats::GlobalFwdTrack propmuonAtPV = o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); pt = propmuonAtPV.getPt(); eta = propmuonAtPV.getEta(); phi = propmuonAtPV.getPhi(); @@ -722,7 +746,7 @@ struct globalDimuonFilter { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, probeMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, probeMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); @@ -880,7 +904,7 @@ struct globalDimuonFilter { } // end end of negative muon loop } // end end of positive muon loop - for (const auto pos1 : posMuons) { + for (const auto& pos1 : posMuons) { auto fwdtrack1 = fwdtracks.rawIteratorAt(pos1); if (!isBestMatch(collision, fwdtrack1, fwdtracks, mfttracks)) { continue; @@ -891,7 +915,7 @@ struct globalDimuonFilter { } ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, o2::constants::physics::MassMuon); - for (const auto pos2 : posMuons) { + for (const auto& pos2 : posMuons) { auto fwdtrack2 = fwdtracks.rawIteratorAt(pos2); if (pos1 == pos2) { continue; @@ -913,7 +937,7 @@ struct globalDimuonFilter { } // end end of positive muon loop } // end end of positive muon loop - for (const auto neg1 : negMuons) { + for (const auto& neg1 : negMuons) { auto fwdtrack1 = fwdtracks.rawIteratorAt(neg1); if (!isBestMatch(collision, fwdtrack1, fwdtracks, mfttracks)) { continue; @@ -924,7 +948,7 @@ struct globalDimuonFilter { } ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, o2::constants::physics::MassMuon); - for (const auto neg2 : negMuons) { + for (const auto& neg2 : negMuons) { auto fwdtrack2 = fwdtracks.rawIteratorAt(neg2); if (neg1 == neg2) { continue; diff --git a/PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx index e087f5a38c2..6181d4a8b3f 100644 --- a/PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx @@ -88,6 +88,7 @@ struct MeanptFluctuations { Configurable cfgEvSelkNoTimeFrameBorder{"cfgEvSelkNoTimeFrameBorder", true, "TimeFrame border event selection cut"}; Configurable cfgEvSelUseGoodZvtxFT0vsPV{"cfgEvSelUseGoodZvtxFT0vsPV", true, "GoodZvertex and FT0 vs PV cut"}; Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 1, "Centrlaity estimatore choice: 1-->FT0C, 2-->FT0A; 3-->FT0M, 4-->FV0A"}; + Configurable cfgUseParticlePDGsInProcessMcReco{"cfgUseParticlePDGsInProcessMcReco", true, "Check partcile PDG codes in reco"}; // pT dep DCAxy and DCAz cuts Configurable cfgUsePtDepDCAxy{"cfgUsePtDepDCAxy", true, "Use pt-dependent DCAxy cut"}; @@ -224,6 +225,7 @@ struct MeanptFluctuations { histos.add("AnalysisProfiles/Prof_skew_t1", "", {HistType::kTProfile2D, {centAxis, multAxis}}); histos.add("AnalysisProfiles/Prof_kurt_t1", "", {HistType::kTProfile2D, {centAxis, multAxis}}); histos.add("AnalysisProfiles/Hist2D_Nch_centrality", "", {HistType::kTH2D, {centAxis, multAxis}}); + histos.add("AnalysisProfiles/Hist2D_Ngen_centrality", "", {HistType::kTH2D, {centAxis, multAxis}}); histos.add("AnalysisProfiles/Hist2D_meanpt_centrality", "", {HistType::kTH2D, {centAxis, meanpTAxis}}); // Analysis Profiles for error (reconstructed data) @@ -349,7 +351,7 @@ struct MeanptFluctuations { } //! end init function template - bool eventSelected(TCollision const& collision, const int& multTrk, const float& centrality) + bool eventSelected(TCollision const& collision, const int multTrk, const float centrality) { if (collision.alias_bit(kTVXinTRD)) { // TRD triggered @@ -658,6 +660,54 @@ struct MeanptFluctuations { return; // this generated event was never reconstructed at all } + histos.fill(HIST("MCGenerated/hMC"), 6.5); + + std::vector selectedEvents(collisions.size()); + int nevts = 0; + + for (const auto& collision : collisions) { + if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + continue; + } + if (cfgUseGoodITSLayerAllCut && !(collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (cfgEvSelkNoSameBunchPileup && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (cfgEvSelkNoITSROFrameBorder && !(collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (cfgEvSelkNoTimeFrameBorder && !(collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (cfgEvSelUseGoodZvtxFT0vsPV && !(collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + + auto rectrackspart = tracks.sliceBy(perCollision, collision.globalIndex()); + auto cent = collision.centFT0C(); + + fillMultCorrPlotsBeforeSel(collision, rectrackspart); + + if (cfgUseSmallIonAdditionalEventCutInMC && !eventSelectedSmallion(collision, rectrackspart.size(), cent)) { + continue; + } + + if (cfgUseSmallIonAdditionalEventCutInMC) { + fillMultCorrPlotsAfterSel(collision, rectrackspart); + } + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + histos.fill(HIST("MCGenerated/hMC"), 7.5); + auto bestColl = collisions.begin(); bool foundValidColl = false; for (auto const& coll : collisions) { @@ -669,38 +719,12 @@ struct MeanptFluctuations { if (!foundValidColl) { return; } + histos.fill(HIST("MCGenerated/hMC"), 8.5); if (!bestColl.has_mcCollision()) { return; } - histos.fill(HIST("MCGenerated/hMC"), 6.5); - - if (std::abs(bestColl.posZ()) >= cfgCutVertex) { - return; - } - if (!eventSelectionDefaultCuts(bestColl)) { - return; - } - histos.fill(HIST("MCGenerated/hMC"), 7.5); - - auto tracksThisCollision = tracks.sliceBy(perCollision, bestColl.globalIndex()); - - fillMultCorrPlotsBeforeSel(bestColl, tracksThisCollision); - - const auto centralityFT0C = bestColl.centFT0C(); - if (cfgUse22sEventCut && !eventSelected(bestColl, tracksThisCollision.size(), centralityFT0C)) { - return; - } - if (cfgUseSmallIonAdditionalEventCut && !eventSelectedSmallion(bestColl, tracksThisCollision.size(), centralityFT0C)) { - return; - } - - if (cfgUseSmallIonAdditionalEventCut) { - fillMultCorrPlotsAfterSel(bestColl, tracksThisCollision); - } - - histos.fill(HIST("MCGenerated/hMC"), 8.5); - histos.fill(HIST("hZvtx_after_sel"), bestColl.posZ()); + histos.fill(HIST("MCGenerated/hMC"), 9.5); double cent = 0.0; int centChoiceFT0C = 1; @@ -718,16 +742,15 @@ struct MeanptFluctuations { } histos.fill(HIST("hCentrality"), cent); + histos.fill(HIST("hZvtx_after_sel"), bestColl.posZ()); + auto tracksThisCollision = tracks.sliceBy(perCollision, bestColl.globalIndex()); histos.fill(HIST("Hist2D_globalTracks_PVTracks"), bestColl.multNTracksPV(), tracksThisCollision.size()); - histos.fill(HIST("Hist2D_cent_nch"), tracksThisCollision.size(), centralityFT0C); + histos.fill(HIST("Hist2D_cent_nch"), tracksThisCollision.size(), cent); // Calculating generated no of particles for the collision event double noGen = 0.0; - // Slice particles belonging only to this MC collision - auto particlesThisEvent = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); - - for (const auto& mcParticle : particlesThisEvent) { + for (const auto& mcParticle : mcParticles) { if (!mcParticle.has_mcCollision()) { continue; } @@ -754,7 +777,6 @@ struct MeanptFluctuations { // variables double pTsum = 0.0; double nN = 0.0; - float q1 = 0.0; float q2 = 0.0; float q3 = 0.0; @@ -775,6 +797,21 @@ struct MeanptFluctuations { continue; } + if (particle.mcCollisionId() != mcCollision.globalIndex()) { // reject tracks whose true particle belongs to a DIFFERENT generated collision (pileup contamination in bestColl) + continue; + } + + if (cfgUseParticlePDGsInProcessMcReco) { + auto pdgPart = std::abs(particle.pdgCode()); + if (pdgPart != PDG_t::kPiPlus && + pdgPart != PDG_t::kKPlus && + pdgPart != PDG_t::kProton && + pdgPart != PDG_t::kElectron && + pdgPart != PDG_t::kMuonMinus) { + continue; // skip this track + } + } + if (!track.isPVContributor()) { continue; } @@ -848,6 +885,7 @@ struct MeanptFluctuations { histos.get(HIST("AnalysisProfilesV2/Prof_var_t1"))->Fill(noGen, nCh, varianceTerm1); histos.get(HIST("AnalysisProfilesV2/Prof_skew_t1"))->Fill(noGen, nCh, skewnessTerm1); histos.get(HIST("AnalysisProfilesV2/Prof_kurt_t1"))->Fill(noGen, nCh, kurtosisTerm1); + histos.fill(HIST("AnalysisProfiles/Hist2D_Ngen_centrality"), cent, noGen); // selecting subsample and filling profiles float lRandom = fRndm->Rndm(); diff --git a/PWGCF/GenericFramework/Core/FlowContainer.cxx b/PWGCF/GenericFramework/Core/FlowContainer.cxx index daa553374f2..b038eea0e11 100644 --- a/PWGCF/GenericFramework/Core/FlowContainer.cxx +++ b/PWGCF/GenericFramework/Core/FlowContainer.cxx @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FlowContainer.cxx +/// \brief Container class to store and calculate multi-particle azimuthal correlations and cumulants +/// \author Emil Gorm Dahlbæk Nielsen + #include "FlowContainer.h" #include "PWGCF/GenericFramework/Core/ProfileSubset.h" @@ -30,7 +34,8 @@ #include #include -#include +#include +#include #include ClassImp(FlowContainer); @@ -73,15 +78,15 @@ void FlowContainer::Initialize(TObjArray* inputList, const o2::framework::AxisSp if (nMultiBins <= 0) nMultiBins = multiBins.size() - 1; if (nMultiBins <= 0) { - printf("Multiplicity axis does not exist"); + LOGF(error, "Multiplicity axis does not exist"); return; } if (!inputList) { - printf("Input list not specified\n"); + LOGF(warning, "Input list not specified"); return; } if (inputList->GetEntries() < 1) { - printf("Input list empty!\n"); + LOGF(warning, "Input list empty!"); return; } fProf = new TProfile2D(Form("%s_CorrProfile", this->GetName()), "CorrProfile", nMultiBins, &multiBins[0], inputList->GetEntries(), 0.5, inputList->GetEntries() + 0.5); @@ -101,11 +106,11 @@ void FlowContainer::Initialize(TObjArray* inputList, const o2::framework::AxisSp void FlowContainer::Initialize(TObjArray* inputList, int nMultiBins, double MultiMin, double MultiMax, int nRandom) { if (!inputList) { - printf("Input list not specified\n"); + LOGF(warning, "Input list not specified"); return; } if (inputList->GetEntries() < 1) { - printf("Input list empty!\n"); + LOGF(warning, "Input list empty!"); return; } fProf = new TProfile2D(Form("%s_CorrProfile", this->GetName()), "CorrProfile", nMultiBins, MultiMin, MultiMax, inputList->GetEntries(), 0.5, inputList->GetEntries() + 0.5); @@ -138,7 +143,7 @@ void FlowContainer::SetXAxis(TAxis* inax) fXAxis = dynamic_cast(inax->Clone("pTAxis")); bool success = CreateBinsFromAxis(fXAxis); if (!success) - printf("Something went wrong setting the x axis!\n"); + LOGF(warning, "Something went wrong setting the x axis!"); } void FlowContainer::SetXAxis() { @@ -161,7 +166,7 @@ int FlowContainer::FillProfile(const char* hname, double multi, double corr, dou return -1; int yin = fProf->GetYaxis()->FindBin(hname); if (!yin) { - printf("Could not find bin %s\n", hname); + LOGF(info, "Could not find bin %s\n", hname); return -1; } fProf->Fill(multi, yin, corr, w); @@ -176,23 +181,23 @@ void FlowContainer::OverrideProfileErrors(TProfile2D* inpf) int nBinsX = fProf->GetNbinsX(); int nBinsY = fProf->GetNbinsY(); if ((inpf->GetNbinsX() != nBinsX) || (inpf->GetNbinsY() != nBinsY)) { - printf("Number of bins in two profiles do not match, not doing anything\n"); + LOGF(info, "Number of bins in two profiles do not match, not doing anything\n"); return; } if (!inpf->GetBinSumw2()->fArray) { - printf("Input profile has no BinSumw2()! Returning\n"); + LOGF(info, "Input profile has no BinSumw2()! Returning\n"); return; } if (!fProf->GetBinSumw2()->fArray) fProf->Sumw2(); double* sumw2Prof = fProf->GetSumw2()->fArray; - double* sumw2Targ = inpf->GetSumw2()->fArray; + const double* sumw2Targ = inpf->GetSumw2()->fArray; double* binsw2Prof = fProf->GetBinSumw2()->fArray; - double* binsw2Targ = inpf->GetBinSumw2()->fArray; + const double* binsw2Targ = inpf->GetBinSumw2()->fArray; double* farrProf = fProf->fArray; for (int ix = 1; ix <= nBinsX; ix++) { double xval = fProf->GetXaxis()->GetBinCenter(ix); - printf("Processing x-bin %i\n", ix); + LOGF(info, "Processing x-bin %i\n", ix); for (int iy = 1; iy <= nBinsY; iy++) { double yval = fProf->GetYaxis()->GetBinCenter(iy); int binno = fProf->FindBin(xval, yval); @@ -244,34 +249,38 @@ Long64_t FlowContainer::Merge(TCollection* collist) void FlowContainer::ReadAndMerge(const char* filelist) { - FILE* flist = fopen(filelist, "r"); - char str[150]; - int nFiles = 0; - while (fscanf(flist, "%s\n", str) == 1) - nFiles++; - rewind(flist); - if (nFiles == 0) { - printf("No files to read!\n"); + if (!filelist) { + LOGF(error, "File list path is null!"); + return; + } + std::ifstream input(filelist); + if (!input) { + LOGF(error, "Could not open file list %s!", filelist); return; } - for (int i = 0; i < nFiles; i++) { - auto retVal = fscanf(flist, "%s\n", str); - (void)retVal; - TFile* tf = new TFile(str, "READ"); - if (tf->IsZombie()) { - printf("Could not open file %s!\n", str); - tf->Close(); + + std::string filename; + bool hasFiles = false; + while (input >> filename) { + hasFiles = true; + TFile tf(filename.c_str(), "READ"); + if (tf.IsZombie()) { + LOGF(info, "Could not open file %s!", filename.c_str()); continue; } - PickAndMerge(tf); - tf->Close(); + PickAndMerge(&tf); + } + if (input.bad()) { + LOGF(error, "Error reading file list %s!", filelist); + } else if (!hasFiles) { + LOGF(info, "No files to read!"); } } void FlowContainer::PickAndMerge(TFile* tfi) { FlowContainer* lfc = dynamic_cast(tfi->Get(this->GetName())); if (!lfc) { - printf("Could not pick up the %s from %s\n", this->GetName(), tfi->GetName()); + LOGF(info, "Could not pick up the %s from %s", this->GetName(), tfi->GetName()); return; } TProfile2D* spro = lfc->GetProfile(); @@ -313,13 +322,13 @@ bool FlowContainer::OverrideBinsWithZero(int xb1, int yb1, int xb2, int yb2) bool FlowContainer::OverrideMainWithSub(int ind, bool ExcludeChosen) { if (!fProfRand) { - printf("Cannot override main profile with a randomized one. Random profile array does not exist.\n"); + LOGF(info, "Cannot override main profile with a randomized one. Random profile array does not exist."); return kFALSE; } if (!ExcludeChosen) { TProfile2D* tarprof = dynamic_cast(fProfRand->At(ind)); if (!tarprof) { - printf("Target random histogram does not exist.\n"); + LOGF(info, "Target random histogram does not exist."); return kFALSE; } TString ts(fProf->GetName()); @@ -345,7 +354,7 @@ bool FlowContainer::OverrideMainWithSub(int ind, bool ExcludeChosen) bool FlowContainer::RandomizeProfile(int nSubsets) { if (!fProfRand) { - printf("Cannot randomize profile, random array does not exist.\n"); + LOGF(info, "Cannot randomize profile, random array does not exist."); return kFALSE; } int l_Subsets = nSubsets ? nSubsets : fProfRand->GetEntries(); @@ -393,7 +402,7 @@ TProfile* FlowContainer::GetCorrXXVsMulti(const char* order, int l_pti) const char* ybinlab = Form("%s%s%s", l_name.Data(), order, ptpf); int ybinno = fProf->GetYaxis()->FindBin(ybinlab); if (ybinno < 0) { - printf("Could not find %s!\n", ybinlab); + LOGF(info, "Could not find %s!", ybinlab); return 0; } TProfile* rethist = dynamic_cast(fProf->ProfileX("temp_prof", ybinno, ybinno)); @@ -426,7 +435,6 @@ TH1D* FlowContainer::GetCorrXXVsPt(const char* order, double lminmulti, double l } if (lmaxmulti > lminmulti) maxm = fProf->GetXaxis()->FindBin(lmaxmulti - 0.001); - ProfileSubset* rhProfSub = new ProfileSubset(*fProf); TString l_name(""); Ssiz_t l_pos = 0; while (fIDName.Tokenize(l_name, l_pos)) { @@ -435,20 +443,19 @@ TH1D* FlowContainer::GetCorrXXVsPt(const char* order, double lminmulti, double l int ybn1 = fProf->GetYaxis()->FindBin(ybl1.Data()); int ybn2 = fProf->GetYaxis()->FindBin(ybl2.Data()); if (fNbinsPt != (ybn2 - ybn1 + 1)) { - printf("fNbinsPt is not matching the num of found histograms"); + LOGF(info, "fNbinsPt is not matching the num of found histograms"); return nullptr; } - TProfile* profY = rhProfSub->ProfileY("profY", minm, maxm); + const TString temporaryTag = Form("%s_%s_%.3f_%.3f", fIDName.Data(), order, lminmulti, lmaxmulti); + TProfile* profY = fProf->ProfileY(Form("profY_%s", temporaryTag.Data()), minm, maxm); TH1D* histY = ProfToHist(profY); - TH1D* hist = new TH1D("temphist", "temphist", fNbinsPt, fbinsPt); + delete profY; + TH1D* hist = new TH1D(Form("temphist_%s", temporaryTag.Data()), "temphist", fNbinsPt, fbinsPt); for (int ibin = 1; ibin <= hist->GetNbinsX(); ibin++) { - TString bLabel = rhProfSub->GetYaxis()->GetBinLabel(ibin + ybn1 - 1); - hist->GetXaxis()->SetBinLabel(ibin, bLabel.Data()); hist->SetBinContent(ibin, histY->GetBinContent(ibin + ybn1 - 1)); hist->SetBinError(ibin, histY->GetBinError(ibin + ybn1 - 1)); } delete histY; - delete rhProfSub; return hist; } return nullptr; @@ -479,7 +486,7 @@ TH1D* FlowContainer::GetHistCorrXXVsPt(const char* order, double lminmulti, doub { TH1D* rethist = GetCorrXXVsPt(order, lminmulti, lmaxmulti); if (!rethist) { - printf("GetCorrXXVsPt return nullptr!"); + LOGF(info, "GetCorrXXVsPt return nullptr!"); return nullptr; } TProfile* refflow = GetRefFlowProfile(order, lminmulti, lmaxmulti); @@ -890,23 +897,24 @@ TH1D* FlowContainer::GetVN8VsX(int n, bool onPt, double arg1, double arg2) } return rethist; } + TH1D* FlowContainer::GetCNN(int n, int c, bool onPt, double arg1, double arg2) { - if (c == 8) + if (c == kEightParticleOrder) return GetCN8VsX(n, onPt, arg1, arg2); - if (c == 6) + if (c == kSixParticleOrder) return GetCN6VsX(n, onPt, arg1, arg2); - if (c == 4) + if (c == kFourParticleOrder) return GetCN4VsX(n, onPt, arg1, arg2); return GetCN2VsX(n, onPt, arg1, arg2); }; TH1D* FlowContainer::GetVNN(int n, int c, bool onPt, double arg1, double arg2) { - if (c == 8) + if (c == kEightParticleOrder) return GetVN8VsX(n, onPt, arg1, arg2); - if (c == 6) + if (c == kSixParticleOrder) return GetVN6VsX(n, onPt, arg1, arg2); - if (c == 4) + if (c == kFourParticleOrder) return GetVN4VsX(n, onPt, arg1, arg2); return GetVN2VsX(n, onPt, arg1, arg2); }; @@ -1051,12 +1059,14 @@ double FlowContainer::CN6Error(double cor6e, double cor4, double cor4e, double c { if (!fPropagateErrors) return 0; - double inters[3]; + + constexpr int kCN6Terms = 3; + double inters[kCN6Terms]; inters[0] = cor6e; inters[1] = -9 * cor2 * cor4e; inters[2] = (-9 * cor4 + 36 * cor2 * cor2) * cor2e; double sum = 0; - for (int i = 0; i < 3; i++) + for (int i = 0; i < kCN6Terms; i++) sum += (inters[i] * inters[i]); return TMath::Sqrt(sum); }; @@ -1070,14 +1080,15 @@ double FlowContainer::DN6Error(double d6e, double d4, double d4e, double d2, { if (!fPropagateErrors) return 0; - double inters[5]; + constexpr int kDN6Terms = 5; + double inters[kDN6Terms]; inters[0] = d6e; inters[1] = -6 * c2 * d4e; inters[2] = (-3 * c4 + 12 * c2 * c2) * d2e; inters[3] = -3 * d2 * c4e; inters[4] = (-6 * d4 + 24 * d2 * c2) * c2e; double sum = 0; - for (int i = 0; i < 5; i++) + for (int i = 0; i < kDN6Terms; i++) sum += (inters[i] * inters[i]); return TMath::Sqrt(sum); }; @@ -1126,13 +1137,14 @@ double FlowContainer::CN8Error(double cor8e, double cor6, double cor6e, { if (!fPropagateErrors) return 0; - double parts[4]; + constexpr int kCN8Terms = 4; + double parts[kCN8Terms]; parts[0] = cor8e; parts[1] = -16 * cor2 * cor6e; parts[2] = (-36 * cor4 + 144 * cor2 * cor2) * cor4e; parts[3] = (-16 * cor6 + 288 * cor4 * cor2 + 576 * cor2 * cor2 * cor2) * cor2e; double retval = 0; - for (int i = 0; i < 4; i++) + for (int i = 0; i < kCN8Terms; i++) retval += TMath::Power(parts[i], 2); return TMath::Sqrt(retval); }; @@ -1147,7 +1159,8 @@ double FlowContainer::DN8Error(double d8e, double d6, double d6e, double d4, { if (!fPropagateErrors) return 0; - double parts[7]; + constexpr int kDN8Terms = 7; + double parts[kDN8Terms]; parts[0] = d8e; // d/d8' parts[1] = -12 * c2 * d6e; // d/d6' parts[2] = -4 * d2 * c6e; // d/d6 @@ -1156,7 +1169,7 @@ double FlowContainer::DN8Error(double d8e, double d6, double d6e, double d4, parts[5] = (-4 * c6 + 72 * c4 * c2 - 144 * c2 * c2 * c2) * d2e; parts[6] = (-12 * d6 + 144 * d4 * c2 + 72 * c4 * d2 - 432 * d2 * c2 * c2) * c2e; double retval = 0; - for (int i = 0; i < 7; i++) + for (int i = 0; i < kDN8Terms; i++) retval += TMath::Power(parts[i], 2); return TMath::Sqrt(retval); }; @@ -1197,26 +1210,6 @@ void FlowContainer::SetPtRebin(int nbins, double* binedges) { fPtRebin = nbins; fPtRebinEdges = binedges; - return; - int fPtRebin = 0; - // double *lPtRebinEdges=binedges; - if (!fbinsPt) - SetXAxis(); - for (int i = 0; i < nbins; i++) - if (binedges[i] < fbinsPt[0] || binedges[i] > fbinsPt[fNbinsPt - 1]) - continue; - else - fPtRebin++; - if (fPtRebinEdges) - delete[] fPtRebinEdges; - fPtRebinEdges = new double[fPtRebin]; - fPtRebin = 0; - for (int i = 0; i < nbins; i++) - if (binedges[i] < fbinsPt[0] || binedges[i] > fbinsPt[fNbinsPt]) - continue; - else - fPtRebinEdges[fPtRebin++] = binedges[i]; - // fPtRebin--; } void FlowContainer::SetMultiRebin(int nbins, double* binedges) { diff --git a/PWGCF/GenericFramework/Core/FlowContainer.h b/PWGCF/GenericFramework/Core/FlowContainer.h index 941442a941e..6d3da46f2e9 100644 --- a/PWGCF/GenericFramework/Core/FlowContainer.h +++ b/PWGCF/GenericFramework/Core/FlowContainer.h @@ -165,6 +165,12 @@ class FlowContainer : public TNamed double* fbinsPt; //! Do not store; stored in fXAxis bool fPropagateErrors; //! do not store TProfile* GetRefFlowProfile(const char* order, double m1 = -1, double m2 = -1); + + private: + static constexpr int kTwoParticleOrder = 2; + static constexpr int kFourParticleOrder = 4; + static constexpr int kSixParticleOrder = 6; + static constexpr int kEightParticleOrder = 8; ClassDef(FlowContainer, 2); }; diff --git a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx index 0a7c0dc5479..db3767664e9 100644 --- a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -506,16 +507,18 @@ struct FlowGfwV02 { registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kMultCuts, "after Mult cuts"); registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kTrackCent, "has track + within cent"); - if (gfwMemberCache.regions.GetSize() < 0) + if (gfwMemberCache.regions.GetSize() < 0) { LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + } for (auto i(0); i < gfwMemberCache.regions.GetSize(); ++i) { fGFW->AddRegion(gfwMemberCache.regions.GetNames()[i], gfwMemberCache.regions.GetEtaMin()[i], gfwMemberCache.regions.GetEtaMax()[i], (gfwMemberCache.regions.GetpTDifs()[i] != 0) ? ptbins + 1 : 1, gfwMemberCache.regions.GetBitmasks()[i]); } for (auto i = 0; i < gfwMemberCache.configs.GetSize(); ++i) { corrconfigs.push_back(fGFW->GetCorrelatorConfig(gfwMemberCache.configs.GetCorrs()[i], gfwMemberCache.configs.GetHeads()[i], gfwMemberCache.configs.GetpTDifs()[i] != 0)); } - if (corrconfigs.empty()) + if (corrconfigs.empty()) { LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); + } fGFW->CreateRegions(); auto* oba = new TObjArray(); oba->SetOwner(kTRUE); @@ -642,8 +645,9 @@ struct FlowGfwV02 { void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) { uint64_t timestamp = bc.timestamp(); - if (cfg.correctionsLoaded) + if (cfg.correctionsLoaded) { return; + } if (!cfgAcceptance.value.empty()) { cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance.value, timestamp); } @@ -670,8 +674,9 @@ struct FlowGfwV02 { void loadCorrections(int runnumber) { - if (cfg.correctionsLoaded) + if (cfg.correctionsLoaded) { return; + } if (!cfgAcceptance.value.empty()) { cfg.mAcceptance = ccdb->getForRun(cfgAcceptance.value, runnumber); } @@ -685,8 +690,9 @@ struct FlowGfwV02 { double getJTrackAcceptance(TTrack const& track) { double wacc = 1; - if constexpr (requires { track.weightNUA(); }) + if constexpr (requires { track.weightNUA(); }) { wacc = 1. / track.weightNUA(); + } return wacc; } @@ -694,8 +700,9 @@ struct FlowGfwV02 { double getJTrackEfficiency(TTrack const& track) { double eff = 1.; - if constexpr (requires { track.weightEff(); }) + if constexpr (requires { track.weightEff(); }) { eff = track.weightEff(); + } return eff; } @@ -703,8 +710,9 @@ struct FlowGfwV02 { double getAcceptance(TTrack const& track, const double& vtxz) { double wacc = 1; - if (cfg.mAcceptance) + if (cfg.mAcceptance) { wacc = cfg.mAcceptance->getNUA(track.phi(), track.eta(), vtxz); + } return wacc; } @@ -712,10 +720,12 @@ struct FlowGfwV02 { double getEfficiency(TTrack const& track, const int& pid = PidCharged) { double eff = 1.; - if (cfg.mEfficiency[pid]) + if (cfg.mEfficiency[pid]) { eff = cfg.mEfficiency[pid]->GetBinContent(cfg.mEfficiency[pid]->FindBin(track.pt())); - if (eff == 0) + } + if (eff == 0) { return -1.; + } return 1. / eff; } @@ -805,25 +815,32 @@ struct FlowGfwV02 { float zRes = std::sqrt(collision.covZZ()); float minZRes = 0.25; int minNContrib = 20; - if (zRes > minZRes && collision.numContrib() < minNContrib) + if (zRes > minZRes && collision.numContrib() < minNContrib) { vtxz = -999; + } } auto multNTracksPV = collision.multNTracksPV(); - if (vtxz > gfwMemberCache.vtxZup || vtxz < gfwMemberCache.vtxZlow) + if (vtxz > gfwMemberCache.vtxZup || vtxz < gfwMemberCache.vtxZlow) { return 0; + } if (cfgMultCut) { - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { return 0; - if (multTrk < fMultCutLow->Eval(centrality)) + } + if (multTrk < fMultCutLow->Eval(centrality)) { return 0; - if (multTrk > fMultCutHigh->Eval(centrality)) + } + if (multTrk > fMultCutHigh->Eval(centrality)) { return 0; - if (multTrk > fMultPVGlobalCutHigh->Eval(collision.multNTracksPV())) + } + if (multTrk > fMultPVGlobalCutHigh->Eval(collision.multNTracksPV())) { return 0; + } registry.fill(HIST("eventQA/eventSel"), kMultCuts); } return 1; @@ -837,19 +854,23 @@ struct FlowGfwV02 { int getPIDIndex(const std::string& corrconfig) { - if (!boost::ifind_first(corrconfig, "pi").empty()) + if (!boost::ifind_first(corrconfig, "pi").empty()) { return PidPions; - if (!boost::ifind_first(corrconfig, "ka").empty()) + } + if (!boost::ifind_first(corrconfig, "ka").empty()) { return PidKaons; - if (!boost::ifind_first(corrconfig, "pr").empty()) + } + if (!boost::ifind_first(corrconfig, "pr").empty()) { return PidProtons; + } return PidCharged; } template void fillOutputContainers(const float& centmult) { - double threshold = 1.01; + constexpr double threshold = 1.01; + constexpr double minDnxAB = 1e-8; // skip events with vanishing V22 weight int bootstrap = fRndm->Integer(gfwMemberCache.nBootstrap); // Calculate V02 @@ -859,7 +880,7 @@ struct FlowGfwV02 { double ptFractionMid = 0.; double dnxAB = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); // V22 weight for AB auto valAB = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnxAB; - if (std::abs(valAB) > threshold) { + if (std::abs(valAB) > threshold || std::isnan(valAB) || std::isinf(valAB) || dnxAB < minDnxAB) { return; } double v22pt = valAB * ptMeanMid; @@ -1030,12 +1051,15 @@ struct FlowGfwV02 { void processCollision(TCollision const& collision, TTracks const& tracks, const XAxis& xaxis) { float vtxz = collision.posZ(); - if (tracks.size() < 1) + if (tracks.size() < 1) { return; - if (xaxis.centrality >= 0 && (xaxis.centrality < gfwMemberCache.centbinning.front() || xaxis.centrality > gfwMemberCache.centbinning.back())) + } + if (xaxis.centrality >= 0 && (xaxis.centrality < gfwMemberCache.centbinning.front() || xaxis.centrality > gfwMemberCache.centbinning.back())) { return; - if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) + } + if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) { return; + } fGFW->Clear(); pidStates.hPtMid[PidCharged]->Reset(); pidStates.hPtMid[PidPions]->Reset(); @@ -1054,45 +1078,59 @@ struct FlowGfwV02 { AcceptedTracks acceptedTracks{.nPos = 0, .nNeg = 0, .nFull = 0, .nMid = 0}; for (const auto& track : tracks) { processTrack(track, vtxz, xaxis.multiplicity, acceptedTracks); - if (track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) + if (track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) { pidStates.hPtMid[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); - if (track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) // add mean pT + } + if (track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) { // add mean pT pidStates.hPtBackward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); - if (track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) // add mean pT + } + if (track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) { // add mean pT pidStates.hPtForward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); + } // If PID is identified, fill pt spectrum for the corresponding particle int pidInd = getNsigmaPID(track); if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) { - if (cfgPIDEfficiency) + if (cfgPIDEfficiency) { pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); - else + } else { pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) { - if (cfgPIDEfficiency) + if (cfgPIDEfficiency) { pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); - else + } else { pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) { - if (cfgPIDEfficiency) + if (cfgPIDEfficiency) { pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); - else + } else { pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } } - if (cfgConsistentEventFlag & 1) - if (!acceptedTracks.nPos || !acceptedTracks.nNeg) + if (cfgConsistentEventFlag & 1) { + if (!acceptedTracks.nPos || !acceptedTracks.nNeg) { return; - if (cfgConsistentEventFlag & 2) - if (acceptedTracks.nFull < 4) // o2-linter: disable=magic-number (at least four tracks in full acceptance) + } + } + if (cfgConsistentEventFlag & 2) { + if (acceptedTracks.nFull < 4) { // o2-linter: disable=magic-number (at least four tracks in full acceptance) return; - if (cfgConsistentEventFlag & 4) - if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in each subevent) + } + } + if (cfgConsistentEventFlag & 4) { + if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) { // o2-linter: disable=magic-number (at least two tracks in each subevent) return; - if (cfgConsistentEventFlag & 8) - if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in all three subevents) + } + } + if (cfgConsistentEventFlag & 8) { + if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) { // o2-linter: disable=magic-number (at least two tracks in all three subevents) return; + } + } // Fill output containers fillOutputContainers
(xaxis.centrality); } @@ -1100,21 +1138,26 @@ struct FlowGfwV02 { template void fillAcceptedTracks(TTrack const& track, AcceptedTracks& acceptedTracks) { - if (posRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[posRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[posRegionIndex]) + if (posRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[posRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[posRegionIndex]) { ++acceptedTracks.nPos; - if (negRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[negRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[negRegionIndex]) + } + if (negRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[negRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[negRegionIndex]) { ++acceptedTracks.nNeg; - if (fullRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[fullRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[fullRegionIndex]) + } + if (fullRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[fullRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[fullRegionIndex]) { ++acceptedTracks.nFull; - if (midRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[midRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[midRegionIndex]) + } + if (midRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[midRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[midRegionIndex]) { ++acceptedTracks.nMid; + } } template bool trackSelected(TTrack const& track) { - if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) + if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) { return false; + } return ((track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgNTPCXrows) && (track.tpcNClsFound() >= cfgTrackCuts.cfgNTPCCls) && (track.itsNCls() >= cfgTrackCuts.cfgMinNITSCls)); } @@ -1150,11 +1193,13 @@ struct FlowGfwV02 { registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); } - if (cfgGetNsigmaQA) + if (cfgGetNsigmaQA) { fillPidQA(track, getNsigmaPID(track)); + } - if (!trackSelected(track)) + if (!trackSelected(track)) { return; + } fillGFW(track, vtxz); // Fill GFW fillAcceptedTracks(track, acceptedTracks); // Fill accepted tracks @@ -1163,8 +1208,9 @@ struct FlowGfwV02 { registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); } - if (cfgGetNsigmaQA) + if (cfgGetNsigmaQA) { fillPidQA(track, getNsigmaPID(track)); + } } template @@ -1175,24 +1221,30 @@ struct FlowGfwV02 { bool withinPtRef = (track.pt() > gfwMemberCache.ptreflow && track.pt() < gfwMemberCache.ptrefup); bool withinPtPOI = (track.pt() > gfwMemberCache.ptpoilow && track.pt() < gfwMemberCache.ptpoiup); - if (!withinPtPOI && !withinPtRef) + if (!withinPtPOI && !withinPtRef) { return; + } double weff = getEfficiency(track, PidCharged); - if (weff < 0) + if (weff < 0) { return; + } double wacc = getAcceptance(track, vtxz); // Fill cumulants for different particles // ***Need to add proper weights for each particle!*** - if (withinPtRef) + if (withinPtRef) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); - if (withinPtPOI && pidInd == PidPions) + } + if (withinPtPOI && pidInd == PidPions) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidPions + 1); - if (withinPtPOI && pidInd == PidKaons) + } + if (withinPtPOI && pidInd == PidKaons) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidKaons + 1); - if (withinPtPOI && pidInd == PidProtons) + } + if (withinPtPOI && pidInd == PidProtons) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidProtons + 1); + } } template @@ -1310,8 +1362,9 @@ struct FlowGfwV02 { loadCorrections(bc); registry.fill(HIST("eventQA/eventSel"), kFilteredEvent); - if (!collision.sel8()) + if (!collision.sel8()) { return; + } registry.fill(HIST("eventQA/eventSel"), kSel8); registry.fill(HIST("eventQA/eventSel"), kOccupancy); // Add occupancy selection later @@ -1321,10 +1374,12 @@ struct FlowGfwV02 { registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/before/multiplicity"), xaxis.multiplicity); } - if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality)) + if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality)) { return; - if (cfgFillQA) + } + if (cfgFillQA) { fillEventQA(collision, xaxis); + } registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); diff --git a/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx b/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx index 0c1927d9579..bbf74ac53da 100644 --- a/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx @@ -125,6 +125,19 @@ void FlowJSPCAnalysis::calculateCorrelators(const int fCentBin) correlationDenom = 0.; weightCorrelationDenom = 0.; } + + // N_m = Re(Q_{0,1}); weight M_m. 3SPC → fN3, 4SPC → fN4. + if (mHistRegistry && qvecs) { + const double nSel = qvecs->QvectorQC[0][1].Re(); + const float centX = static_cast(fCentBin) + 0.5f; + if (nSel > 0.0 && std::isfinite(nSel)) { + if (mWhichSPC == 0 && fCorrelDenoms[2] > 0.0) { + mHistRegistry->fill(HIST("fN3"), centX, nSel, fCorrelDenoms[2]); + } else if (mWhichSPC == 1 && fCorrelDenoms[3] > 0.0) { + mHistRegistry->fill(HIST("fN4"), centX, nSel, fCorrelDenoms[3]); + } + } + } } void FlowJSPCAnalysis::fillHistograms(const int fCentBin, int ind, double cNum, double cDenom, double wNum, double wDenom) diff --git a/PWGCF/JCorran/Core/FlowJSPCAnalysis.h b/PWGCF/JCorran/Core/FlowJSPCAnalysis.h index 59a677dccd7..97ddedc1af2 100644 --- a/PWGCF/JCorran/Core/FlowJSPCAnalysis.h +++ b/PWGCF/JCorran/Core/FlowJSPCAnalysis.h @@ -29,6 +29,7 @@ #include +#include #include #include #include @@ -42,6 +43,27 @@ class FlowJSPCAnalysis int getCentBin(float cValue); using JQVectorsT = JQVectors; + /// Fill-grid size for Q_{n,p}: (v8 * nPartDen)+1 harmonics, nPartDen+1 powers. + static constexpr uint32_t Nh3p = 49; // 3-particle SPC, 6-particle denominator + static constexpr uint32_t Nk3p = 7; + static constexpr uint32_t Nh4p = 65; // 4-particle SPC, 8-particle denominator + static constexpr uint32_t Nk4p = 9; + static constexpr uint32_t NhFull = 113; + static constexpr uint32_t NkFull = 15; + void qVectorGrid(int whichSPC, uint32_t& nhUse, uint32_t& nkUse) + { + mWhichSPC = whichSPC; + if (whichSPC == 0) { + nhUse = Nh3p; + nkUse = Nk3p; + } else if (whichSPC == 1) { + nhUse = Nh4p; + nkUse = Nk4p; + } else { + nhUse = NhFull; + nkUse = NkFull; + } + } inline void setQvectors(const JQVectorsT* _qvecs) { qvecs = _qvecs; } void correlation(int c_nPart, int c_nHarmo, int* harmo, double* correlData); void calculateCorrelators(const int fCentBin); @@ -57,6 +79,9 @@ class FlowJSPCAnalysis return; } mHistRegistry->add("FullCentrality", "FullCentrality", o2::framework::HistType::kTH1D, {{100, 0., 100.}}, true); + // Effective N_m per centrality class, weighted by M_m (arXiv:2606.10258 c0). + mHistRegistry->add("fN3", "Effective N_{3};centrality class;N_{3}", {o2::framework::HistType::kTProfile, {{9, 0., 9.}}}, true); + mHistRegistry->add("fN4", "Effective N_{4};centrality class;N_{4}", {o2::framework::HistType::kTProfile, {{9, 0., 9.}}}, true); mHistRegistry->add("Centrality_0/fResults", "Numerators and denominators", {o2::framework::HistType::kTProfile, {{24, 0., 24.}}}, true); mHistRegistry->add("Centrality_0/fCovResults", "Covariance N*D", {o2::framework::HistType::kTProfile, {{48, 0., 48.}}}, true); mHistRegistry->add("Centrality_0/phiBefore", "Phi before", {o2::framework::HistType::kTH1D, {{100, 0., o2::constants::math::TwoPI}}}, true); @@ -67,13 +92,13 @@ class FlowJSPCAnalysis } } - void setCorrSet(int obsInd, int harmo[8]) + void setCorrSet(int obsInd, int const harmo[8]) { for (int i = 0; i < 8; i++) { fHarmosArray[obsInd][i] = harmo[i]; } } - void setFullCorrSet(int harmo[12][8]) + void setFullCorrSet(int const harmo[12][8]) { memcpy(fHarmosArray, harmo, sizeof(int) * 12 * 8); } @@ -92,13 +117,14 @@ class FlowJSPCAnalysis private: const int mNqHarmos = 113; ///< Highest harmo for Q(n,p): (v8*14part)+1. const int mNqPowers = 15; ///< Max power for Q(n,p): 14part+1. - const JQVectorsT* qvecs; + const JQVectorsT* qvecs = nullptr; o2::framework::HistogramRegistry* mHistRegistry = nullptr; - int fHarmosArray[12][8]; + int fHarmosArray[12][8] = {{0}}; - double fCorrelDenoms[14]; + double fCorrelDenoms[14] = {0}; + int mWhichSPC = 0; ClassDefNV(FlowJSPCAnalysis, 1); }; diff --git a/PWGCF/JCorran/Core/FlowJSPCObservables.h b/PWGCF/JCorran/Core/FlowJSPCObservables.h index 440d70c8bf2..e5db30a94e7 100644 --- a/PWGCF/JCorran/Core/FlowJSPCObservables.h +++ b/PWGCF/JCorran/Core/FlowJSPCObservables.h @@ -38,42 +38,53 @@ class FlowJSPCObservables switch (index) { case 0: { LOGF(info, "Computing three harmonic SPC"); - int harmonicArray01[maxNrComb][8] = { - {3, 6, -3, -3, 0, 0, 0, 0}, - {3, 4, -2, -2, 0, 0, 0, 0}, + // fResults slot j: num at 2j+0.5, denom at 2j+1.5. arXiv:2606.10258 nonflow refs in unused slots. + int const harmonicArray01[maxNrComb][8] = { + {3, 6, -3, -3, 0, 0, 0, 0}, // 0: C633 = + {3, 4, -2, -2, 0, 0, 0, 0}, // 1: C422 = {3, 8, -4, -4, 0, 0, 0, 0}, - {3, 2, 4, -6, 0, 0, 0, 0}, - {3, 2, 3, -5, 0, 0, 0, 0}, + {3, 2, 4, -6, 0, 0, 0, 0}, // 3: C246 = + {3, 2, 3, -5, 0, 0, 0, 0}, // 4: C235 = {3, 3, 4, -7, 0, 0, 0, 0}, // These are three harmonic SPC!! {3, 2, 5, -7, 0, 0, 0, 0}, // These are three harmonic SPC!! {3, 3, 5, -8, 0, 0, 0, 0}, // These are three harmonic SPC!! - {0, 6, -2, -2, -2, 0, 0, 0}, - {0, 2, -3, -4, 5, 0, 0, 0}, - {0, 2, -3, -3, 4, 0, 0, 0}, - {0, 3, 3, -2, -2, -2, 0, 0}}; + // {0, 6, -2, -2, -2, 0, 0, 0}, + // {0, 2, -3, -4, 5, 0, 0, 0}, + // {0, 2, -3, -3, 4, 0, 0, 0}, + // {0, 3, 3, -2, -2, -2, 0, 0}, + {3, 1, 1, -2, 0, 0, 0, 0}, // 8: C112 = , Eqs. (IV.7), (IV.18) + {3, 1, 2, -3, 0, 0, 0, 0}, // 9: C123 = , Eqs. (IV.8), (IV.18) + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}}; memcpy(harmonicArray, harmonicArray01, sizeof(int) * maxNrComb * 8); } break; case 1: { LOGF(info, "Computing four harmonic SPC"); - int harmonicArray02[maxNrComb][8] = { - {4, 6, -2, -2, -2, 0, 0, 0}, + // fResults slot j: num at 2j+0.5, denom at 2j+1.5. arXiv:2606.10258: c1{4}=<<4>>-2<<2>>^2 after averaging, Eq. (IV.6). + int const harmonicArray02[maxNrComb][8] = { + {4, 6, -2, -2, -2, 0, 0, 0}, // 0: C6222 = {4, 2, -3, -4, 5, 0, 0, 0}, {4, 2, -3, -3, 4, 0, 0, 0}, {4, 2, 2, 3, -7, 0, 0, 0}, // These are three harmonic SPC!! {4, 2, 2, 4, -8, 0, 0, 0}, // These are three harmonic SPC!! {4, 2, 7, -4, -5, 0, 0, 0}, {4, 3, -4, -4, 5, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 0}, + {4, 1, 1, -1, -1, 0, 0, 0}, // 7: <<4>>_{1,1,-1,-1} for c1{4} + {2, 1, -1, 0, 0, 0, 0, 0}, // 8: <<2>>_{1,-1} = + {3, 1, 1, -2, 0, 0, 0, 0}, // 9: C112 on the 4-particle sample (mixed-order Eq. (IV.19)) {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}; memcpy(harmonicArray, harmonicArray02, sizeof(int) * maxNrComb * 8); } break; case 2: { LOGF(info, "Computing five and six harmonic SPC"); - int harmonicArray03[maxNrComb][8] = { + int const harmonicArray03[maxNrComb][8] = { {5, 3, 3, -2, -2, -2, 0, 0}, {5, 2, 2, -3, 4, -5, 0, 0}, {5, 2, 3, 3, -4, -4, 0, 0}, @@ -90,7 +101,7 @@ class FlowJSPCObservables } break; case 3: { LOGF(info, "Computing slected five harmonic SPC"); - int harmonicArray04[maxNrComb][8] = { + int const harmonicArray04[maxNrComb][8] = { {5, 3, 3, -2, -2, -2, 0, 0}, {0, 2, 2, -3, 4, -5, 0, 0}, {5, 2, 3, 3, -4, -4, 0, 0}, diff --git a/PWGCF/JCorran/Core/JQVectors.h b/PWGCF/JCorran/Core/JQVectors.h index d0ba705c32f..aadb821fc2b 100644 --- a/PWGCF/JCorran/Core/JQVectors.h +++ b/PWGCF/JCorran/Core/JQVectors.h @@ -19,6 +19,8 @@ #include +#include +#include #include #include @@ -52,11 +54,16 @@ class JQVectors : public std::conditional_t, JQ using hasInvMass = decltype(std::declval().invMass()); template - inline void Calculate(JInputClass& inputInst, float etamin, float etamax, float massMin = 0.0f, float massMax = 999.9f) + inline void Calculate(JInputClass& inputInst, float etamin, float etamax, float massMin = 0.0f, float massMax = 999.9f, + uint32_t nhUse = nh, uint32_t nkUse = nk) { + // nhUse/nkUse limit the filled (harmonic, power) grid. Defaults keep the full template size. + const uint32_t nH = std::min(nhUse, nh); + const uint32_t nK = std::min(nkUse, nk); + // calculate Q-vector for QC method ( no subgroup ) - for (UInt_t ih = 0; ih < nh; ++ih) { - for (UInt_t ik = 0; ik < nk; ++ik) { + for (UInt_t ih = 0; ih < nH; ++ih) { + for (UInt_t ik = 0; ik < nK; ++ik) { QvectorQC[ih][ik] = Q(0, 0); if constexpr (gap) { for (UInt_t isub = 0; isub < 2; ++isub) @@ -64,7 +71,7 @@ class JQVectors : public std::conditional_t, JQ } } } - for (auto& track : inputInst) { + for (auto const& track : inputInst) { if (track.eta() < -etamax || track.eta() > etamax) continue; using JInputClassIter = typename JInputClass::iterator; @@ -74,10 +81,15 @@ class JQVectors : public std::conditional_t, JQ } UInt_t isub = (UInt_t)(track.eta() > 0.0); - for (UInt_t ih = 0; ih < nh; ++ih) { + const Double_t phi = track.phi(); + const Double_t c1 = TMath::Cos(phi); + const Double_t s1 = TMath::Sin(phi); + Double_t cn = 1.0; // cos(ih * phi), ih = 0 + Double_t sn = 0.0; // sin(ih * phi) + for (UInt_t ih = 0; ih < nH; ++ih) { Double_t tf = 1.0; - for (UInt_t ik = 0; ik < nk; ++ik) { - Q q(tf * TMath::Cos(ih * track.phi()), tf * TMath::Sin(ih * track.phi())); + for (UInt_t ik = 0; ik < nK; ++ik) { + Q q(tf * cn, tf * sn); QvectorQC[ih][ik] += q; if constexpr (gap) { @@ -90,6 +102,10 @@ class JQVectors : public std::conditional_t, JQ if constexpr (std::experimental::is_detected::value) tf *= track.weightEff(); } + const Double_t cnNext = cn * c1 - sn * s1; + const Double_t snNext = cn * s1 + sn * c1; + cn = cnNext; + sn = snNext; } } } diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 6892ab58658..cfe7f931a39 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -109,6 +109,8 @@ struct flowJSPCAnalysis { std::unique_ptr multCutFormula; std::array multCutFormulaParamIndex; + uint32_t mNhUse = FlowJSPCAnalysis::NhFull; + uint32_t mNkUse = FlowJSPCAnalysis::NkFull; void init(InitContext const&) { @@ -118,6 +120,8 @@ struct flowJSPCAnalysis { spcObservables.setSPCObservables(cfgWhichSPC); spcAnalysis.setFullCorrSet(spcObservables.harmonicArray); + spcAnalysis.qVectorGrid(cfgWhichSPC, mNhUse, mNkUse); + LOGF(info, "Q-vector fill grid: nh=%u nk=%u (cfgWhichSPC=%d)", mNhUse, mNkUse, cfgWhichSPC.value); histManager.setHistRegistryQA(&qaHistRegistry); histManager.setDebugLog(false); @@ -186,7 +190,7 @@ struct flowJSPCAnalysis { if (cfgFillQA) histManager.fillEventQA<1>(collision, cBin, cent, nTracks); - jqvecs.Calculate(tracks, 0.0, cfgTrackCuts.cfgEtaMax); + jqvecs.Calculate(tracks, 0.0, cfgTrackCuts.cfgEtaMax, 0.0f, 999.9f, mNhUse, mNkUse); spcAnalysis.setQvectors(&jqvecs); spcAnalysis.calculateCorrelators(cBin); } diff --git a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt index aa98d11a997..a20000206b2 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -33,3 +33,8 @@ o2physics_add_dpl_workflow(multiparticle-cumulants SOURCES multiparticleCumulants.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(multiparticle-correlations-mei + SOURCES multiparticleCorrelationsMei.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsMei.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsMei.cxx new file mode 100644 index 00000000000..69f167f3e8a --- /dev/null +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsMei.cxx @@ -0,0 +1,950 @@ +// Copyright 2019-2020 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 multiparticleCorrelationsMei.cxx +/// \brief Multiparticle correlation in O2 Framework +/// \author yuanjun.mei@cern.ch + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::constants; +using namespace std; + +// Definitions of join tables for Run 3 analysis: +using EventSelection = soa::Join; +using CollisionRec = soa::Join::iterator; // use in json "isMC": "true" for "event-selection-task" +using CollisionRecSim = soa::Join::iterator; +using CollisionSim = aod::McCollision; +using TracksRec = soa::Join; +using TrackRec = soa::Join::iterator; +using TracksRecSim = soa::Join; // + use in json "isMC" : "true" +using TrackRecSim = soa::Join::iterator; +using TracksSim = aod::McParticles; +using TrackSim = aod::McParticles::iterator; + +// *) Define enums: +enum ECentralityEstimator { + EFT0C = 0, + EFT0M, + EFV0A, + ENTPV +}; + +enum EMultiplicityTables { + EMultTPC = 0, + EMultFV0M, + EMultFT0C, + EMultFT0M, + EMultNTracksPV +}; + +enum ERecSim { + ERec = 0, + ESim, + ERecAndSim +}; + +enum ECuts { + ENoCuts = 0, + EWithCuts +}; + +enum EProcess { + EProcessRec = 0, // Run 3, only reconstructed + EProcessRecSim, // Run 3, both reconstructed and simulated + EProcessSim, // Run 3, only simulated + EProcess_N +}; + +enum EParticlEHistograms { + EParticlEHistogramsList = 0, + EHistPt, + EHistPhi, + EHistEta, + EParticlEHistograms_N +}; + +enum EEventHistograms { + EHistCentrality = 0, + EHistMultiplicity, + EHistVertexX, + EHistVertexY, + EHistVertexZ, + EHistImpactParameter, + EHistReferencEMultiplicity, + EEventHistograms_N +}; + +enum EExternalHistograms { + EHistWeights = 0, + EExternalHistograms_N +}; + +// *) Main task: +struct MultiparticleCorrelationsMei // this name is used in lower-case format to name the TDirectoryFile in AnalysisResults.root +{ + // *) Base TList to hold all output objects: + TString sBaseListName = "Default list name"; // yes, I declare it separately, because I need it also later in BailOut() function + OutputObj fBaseList{sBaseListName.Data(), + OutputObjHandlingPolicy::AnalysisObject, + OutputObjSourceType::OutputObjSource}; + + // *) CCDB: + Service ccdb; // support for offline callibration data base, not needed for the time being... + + // *) Define configurables: + Configurable centralityEstimator{"centralityEstimator", 0, "centrality estimator: 0=FT0C, 1=FT0M, 2=FV0A, 3=NTPV"}; + Configurable multiplicityTables{"multiplicityTables", 0, "multiplicity tables: 0=multTPC, 1=multFV0M, 2=multFT0C, 3=multFT0M, 4=multNTracksPV"}; + Configurable cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"}; + + // external root files + Configurable cfFileWithWeights{"cfFileWithWeights", "/scratch3/go97loy/O2challenge/C5/weights.root", "path to external ROOT file which holds all particle weights"}; + + // binnings + Configurable> cfPtBins{"cfPtBins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; // example for an array + Configurable> cfPhiBins{"cfPhiBins", {100, 0., math::TwoPI}, "nPhiBins, phiMin, phiMax"}; // example for an array + Configurable> cfEtaBins{"cfEtaBins", {100, 0., 10.}, "nEtaBins, etaMin, etaMax"}; // example for an array + + Configurable> cfMultBinsRec{"cfMultBinsRec", {200, 0., 10000.}, "nMultBins, multMin, multMax"}; + Configurable> cfMultBinsRef{"cfMultBinsRef", {200, 0., 10000.}, "nMultBins, multMin, multMax"}; + Configurable> cfMultBinsSim{"cfMultBinsSim", {100, 0., 1000.}, "nMultBins, multMin, multMax"}; + Configurable> cfVxBins{"cfVxBins", {100, -10., 10.}, "nVxBins, vxMin, vxMax"}; + Configurable> cfVyBins{"cfVyBins", {100, -10., 10.}, "nVyBins, vyMin, vyMax"}; + Configurable> cfVzBins{"cfVzBins", {200, -20., 20.}, "nVzBins, vzMin, vzMax"}; + Configurable> cfCentBins{"cfCentBins", {100, 0., 100.}, "nCentBins, centMin, centMax"}; + Configurable> cfIpBins{"cfIpBins", {100, 0., 20.}, "nIPBins, ipMin, ipMax"}; + + // Cuts + Configurable cfVertexZSwitch{"cfVertexZSwitch", false, "switch to apply vertex z position cut"}; + Configurable> cfVertexZ{"cfVertexZ", {-10, 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; + Configurable cfPtSwitch{"cfPtSwitch", false, "switch to apply pt cut"}; + Configurable> cfPt{"cfPt", {0.2, 5.}, "pt range: {min, max}, with convention: min <= Vz < max"}; + + // misc + Configurable sigmaInel{"sigmaInel", 7.71, "inelastic cross section in mb"}; + Configurable qualityAssurance{"qualityAssurance", false, "quality assurance"}; + + // *) Define and initialize all data members to be called in the main process* functions: + // **) Task configuration: + struct TaskConfiguration { + bool fProcess[EProcess_N] = {false}; // Set what to process. See enum EProcess for full description. Set via implicit variables within a PROCESS_SWITCH clause. + bool fDryRun = false; // book all histos and run without filling and calculating anything + } tc; // you have to prepend "tc." for all objects name in this group later in the code + + // **) Particle histograms: + struct ParticlEHistograms { + TList* fParticlEHistogramsList = NULL; //!Get("hist-name"). + + // Usage: TH1D *hist = (TH1D*) getObjectFromList("some-valid-TList-pointer","some-object-name"); + + // Insanity checks: + if (!list) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (!objectName) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (0 == list->GetEntries()) { + return NULL; + } + + // The object is in the current base list: + TObject* objectFinal = list->FindObject(objectName); // the final object I am after + if (objectFinal) { + return objectFinal; + } + + // Otherwise, search for the object recursively in the nested lists: + TObject* objectIter; // iterator object in the loop below + TIter next(list); + while ((objectIter = next())) // double round braces are to silence the warnings + { + if (TString(objectIter->ClassName()).EqualTo("TList")) { + objectFinal = getObjectFromList(reinterpret_cast(objectIter), objectName); + if (objectFinal) + return objectFinal; + } + } // while(objectIter = next()) + + return NULL; + } // TObject* getObjectFromList(TList *list, char *objectName) + + TH1D* getHistogramWithWeights(const char* filePath, const char* runNumber) + { + // *) Return value: + TH1D* hist = NULL; + TList* baseList = NULL; // base top-level list in the TFile, e.g. named "ccdb_object" + TList* listWithRuns = NULL; // nested list with run-wise TList's holding run-specific weights + + // *) Determine from filePath if the file is on a local machine, or in home dir AliEn, or in CCDB: + // Algorithm: If filePath begins with "/alice/cern.ch/" then it's in the home dir AliEn; + // If filePath begins with "/alice-ccdb.cern.ch/" then it's in CCDB. Therefore, files in AliEn and CCDB must be specified with abs path; + // for local files both abs and relative paths are just fine. + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; + + std::string path(cfFileWithWeights); + + if (path.starts_with("/alice/cern.ch/")) { + bFileIsInAliEn = true; + } else if (path.starts_with("/alice-ccdb.cern.ch/")) { + bFileIsInCCDB = true; + } + + if (bFileIsInAliEn) { + // File you want to access is in your home dir in AliEn: + const TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); // do not forget to add #include to the preamble of your analysis task + if (!alien) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + TFile* weightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); // yes, ROOT can open a file transparently, even if it's sitting in AliEn, with this specific syntax + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + weightsFile->GetObject("ccdb_object", baseList); + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Finally, from the top-level TList, get the desired nested TList => the technical problem here is that it can be nested at any level, + // for that there is a helper utility function getObjectFromList(...) , see its implementation further below + listWithRuns = reinterpret_cast(getObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(getObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + // OK, we got the desired TList with efficiency corrections, after that we can use the common code for all 3 cases (local, AliEn, CCDB, that common code is below) + + } else if (bFileIsInCCDB) { + // File you want to access is in your home dir in CCDB: + // Remember that here I do not access the file; instead, I directly access the object in that file. + // My home dir in CCDB: https://alice-ccdb.cern.ch/browse/Users/a/abilandz/ => adapt for your case + ccdb->setURL("https://alice-ccdb.cern.ch"); // to be able to use "ccdb" this object in your analysis task, see 4b/ below + baseList = dynamic_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = reinterpret_cast(getObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(getObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + // OK, we got the desired TList with efficiency corrections, after that we + // can use the common code for all 3 cases (local, AliEn, CCDB, that + // common code is below) + } else { + // this is the local case: + // Check if the external ROOT file exists at the specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + weightsFile->GetObject("ccdb_object", baseList); + + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = reinterpret_cast(getObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(getObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + // baseList->ls(); + // LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__, tc.fRunNumber.Data()); + } + } + } + + // Here comes the common code for all three cases, where from "listWithRuns" you fetch the desired histogram with efficiency corrections: + // listWithRuns->ls(); + + if (!listWithRuns) { + LOGF(fatal, + "\033[1;31m%s: listWithRuns is null for run %s\033[0m", + __FUNCTION__, runNumber); + } + + hist = dynamic_cast(listWithRuns->FindObject("h_invert")); + if (!hist) { + LOGF(fatal, "%s: histogram 'hist1' not found in run list", __FUNCTION__); + } + hist->SetDirectory(0); + auto histClone = dynamic_cast(hist->Clone()); + histClone->SetDirectory(0); + + delete baseList; // release back the memory + + return histClone; + } + + // templates + template + bool eventCuts(T1 const& collision) + { + if constexpr (rs == ERec || rs == ERecAndSim) { + if (cfVertexZSwitch) // Vertex Z cuts for Rec + { + if (collision.posZ() > cfVertexZ.value[1] || collision.posZ() < cfVertexZ.value[0]) { + return false; + } + if constexpr (rs == ERecAndSim) // Vertex Z cuts for Sim + { + if (!collision.has_mcCollision()) { + return false; + } + auto mcCollision = collision.mcCollision(); // corresponding MC truth simulated particle + if (mcCollision.posZ() > cfVertexZ.value[1] || mcCollision.posZ() < cfVertexZ.value[0]) { + return false; + } + } + } + } + + return true; + } + + template + void eventHistFill(T1 const& collision, T2 const& tracks) + { + auto thisCent = collision.centFT0C(); // use auto to determine the type + switch (centralityEstimator) { + case EFT0C: + thisCent = collision.centFT0C(); + break; + case EFT0M: + thisCent = collision.centFT0M(); + break; + case EFV0A: + thisCent = collision.centFV0A(); + break; + case ENTPV: + thisCent = collision.centNTPV(); + break; + } + + auto thisRefMult = collision.multTPC(); // use auto to determine the type + switch (multiplicityTables) { + case EMultTPC: + thisRefMult = collision.multTPC(); + break; + case EMultFV0M: + thisRefMult = collision.multFV0M(); + break; + case EMultFT0C: + thisRefMult = collision.multFT0C(); + break; + case EMultFT0M: + thisRefMult = collision.multFT0M(); + break; + case EMultNTracksPV: + thisRefMult = collision.multNTracksPV(); + break; + } + + if constexpr (rs == ERec || rs == ERecAndSim) { + // Fill reconstructed-level event histograms + int multiplicityRec = static_cast(tracks.size()); + if constexpr (cuts == ENoCuts) { + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]->Fill(multiplicityRec); + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]->Fill(thisCent); + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][ENoCuts]->Fill(thisRefMult); + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]->Fill(collision.posX()); + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]->Fill(collision.posY()); + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]->Fill(collision.posZ()); + } + if constexpr (cuts == EWithCuts) { + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]->Fill(multiplicityRec); + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]->Fill(thisCent); + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][EWithCuts]->Fill(thisRefMult); + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]->Fill(collision.posX()); + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]->Fill(collision.posY()); + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]->Fill(collision.posZ()); + } + + // Fill MC simulated-level event histograms if both reconstructed and simulated data are processed + if constexpr (rs == ERecAndSim) { + if (!collision.has_mcCollision()) { + return; + } + auto mcCollision = collision.mcCollision(); // corresponding MC truth simulated particle + int multiplicitySim = static_cast(tracks.size()); + float impactParameter = mcCollision.impactParameter(); + float centralitySim = math::PI * impactParameter * impactParameter / sigmaInel; // centrality for sim derived from impact parameter + if constexpr (cuts == ENoCuts) { + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]->Fill(multiplicitySim); + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]->Fill(centralitySim); + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]->Fill(mcCollision.impactParameter()); + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]->Fill(mcCollision.posX()); + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]->Fill(mcCollision.posY()); + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]->Fill(mcCollision.posZ()); + } + + if constexpr (cuts == EWithCuts) { + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]->Fill(multiplicitySim); + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]->Fill(centralitySim); + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]->Fill(mcCollision.impactParameter()); + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]->Fill(mcCollision.posX()); + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]->Fill(mcCollision.posY()); + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]->Fill(mcCollision.posZ()); + } + } + } + } + + template + bool particlECuts(T const& track) + { + if constexpr (rs == ERec || rs == ERecAndSim) { + if (cfPtSwitch) // Vertex Z cuts for Rec + { + if (track.pt() < cfPt.value[0] || track.pt() > cfPt.value[1]) { + return false; + } + if constexpr (rs == ERecAndSim) // Vertex Z cuts for Sim + { + if (!track.has_mcParticle()) { + return false; + } + auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle + if (mcParticle.pt() < cfPt.value[0] || mcParticle.pt() > cfPt.value[1]) { + return false; + } + } + } + } + + return true; + } + + template + void particleHistFill(T1 const& track) + { + if constexpr (rs == ERec || rs == ERecAndSim) { + if constexpr (cuts == ENoCuts) { + pc.fParticlEHistograms[EHistPt][ERec][ENoCuts]->Fill(track.pt()); + pc.fParticlEHistograms[EHistPhi][ERec][ENoCuts]->Fill(track.phi()); + pc.fParticlEHistograms[EHistEta][ERec][ENoCuts]->Fill(track.eta()); + } + + if constexpr (cuts == EWithCuts) { + pc.fParticlEHistograms[EHistPt][ERec][EWithCuts]->Fill(track.pt()); + pc.fParticlEHistograms[EHistPhi][ERec][EWithCuts]->Fill(track.phi()); + pc.fParticlEHistograms[EHistEta][ERec][EWithCuts]->Fill(track.eta()); + } + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == ERecAndSim) { + if (!track.has_mcParticle()) { + LOGF(warning, " No MC particle for this track, skip..."); + return; + } + auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle + if constexpr (cuts == ENoCuts) { + pc.fParticlEHistograms[EHistPt][ESim][ENoCuts]->Fill(mcParticle.pt()); + pc.fParticlEHistograms[EHistPhi][ESim][ENoCuts]->Fill(mcParticle.phi()); + pc.fParticlEHistograms[EHistEta][ESim][ENoCuts]->Fill(mcParticle.eta()); + } + + if constexpr (cuts == EWithCuts) { + pc.fParticlEHistograms[EHistPt][ESim][EWithCuts]->Fill(mcParticle.pt()); + pc.fParticlEHistograms[EHistPhi][ESim][EWithCuts]->Fill(mcParticle.phi()); + pc.fParticlEHistograms[EHistEta][ESim][EWithCuts]->Fill(mcParticle.eta()); + } + } + } + } + + template + void qaFill(T1 const& collision) + { + auto thisCent = collision.centFT0C(); // use auto to determine the type + switch (centralityEstimator) { + case EFT0C: + thisCent = collision.centFT0C(); + break; + case EFT0M: + thisCent = collision.centFT0M(); + break; + case EFV0A: + thisCent = collision.centFV0A(); + break; + case ENTPV: + thisCent = collision.centNTPV(); + break; + } + if constexpr (rs == ERecAndSim || rs == ESim) { + if (!collision.has_mcCollision()) { + return; + } + auto mcCollision = collision.mcCollision(); + float impactParameter = mcCollision.impactParameter(); + float centralitySim = math::PI * impactParameter * impactParameter / sigmaInel; // centrality for sim derived from impact parameter + qa.fHistCentralityRecSim->Fill(thisCent, centralitySim); + } + } + + // *) Define all member functions to be called in the main process* functions: + template + void steer(T1 const& collision, T2 const& tracks) + { + // Dry run: + if (tc.fDryRun) { + return; + } + + // Fill Quality Assurance + if (qualityAssurance) { + qaFill(collision); + } + + // Fill Event Hist + eventHistFill(collision, tracks); + if (eventCuts(collision)) { + eventHistFill(collision, tracks); + } + + // Print current run number: + LOGF(info, "Run number: %d", collision.bc().runNumber()); + + // Print centrality estimated with the selected estimator: + // LOGF(info, "Centrality: %f", thisCent); + + // Print vertex X position: + LOGF(info, "Vertex X position: %f", collision.posX()); + + // Main loop over particles: + auto track = tracks.iteratorAt(0); // set the type and scope from one instance + for (int64_t i = 0; i < tracks.size(); i++) { + // Print track azimuthal angle: + // LOGF(info, "Track azimuthal angle: %f", track.phi()); + + track = tracks.iteratorAt(i); + // Fill reconstructed ...: + particleHistFill(track); + if (eventCuts(collision) && particlECuts(track)) { + particleHistFill(track); + } + } // end of for (int64_t i = 0; i < tracks.size(); i++) { + } // end of template void steer(T1 const& collision, T2 const& tracks) { + + // *) Initialize and book all objects: + void init(InitContext&) + { + // ... code to book and initialize all analysis objects ... + + // *) Set automatically what to process, from an implicit variable "doprocessSomEProcessName" within a PROCESS_SWITCH clause: + tc.fProcess[EProcessRec] = doprocessRec; + tc.fProcess[EProcessRecSim] = doprocessRecSim; + tc.fProcess[EProcessSim] = doprocessSim; + + // *) Configure your task using configurables in the json file: + tc.fDryRun = cfDryRun; + + // *) Book base list: + TList* temp = new TList(); + temp->SetOwner(true); + fBaseList.setObject(temp); + + // *) Book External Hist List + ex.fExternalHistogramsList = new TList(); + ex.fExternalHistogramsList->SetName("ExternalHistograms"); + ex.fExternalHistogramsList->SetOwner(true); + fBaseList->Add(ex.fExternalHistogramsList); + + // *) Book and Fill external hist + ex.fhistWeights = getHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); + ex.fhistWeights->SetTitle(cfFileWithWeights.value.c_str()); + ex.fExternalHistogramsList->Add(ex.fhistWeights); + + // *) Book and nest all other TLists: + pc.fParticlEHistogramsList = new TList(); + pc.fParticlEHistogramsList->SetName("ParticlEHistograms"); + pc.fParticlEHistogramsList->SetOwner(true); + fBaseList->Add(pc.fParticlEHistogramsList); // any nested TList in the base TList appears as a subdir in the output ROOT file + + // *) Book pt and phi distribution with binning defined through configurables in the json file: + vector lPtBins = cfPtBins.value; // define local array and initialize it from an array set in the configurables + int nBinsPt = static_cast(lPtBins[0]); + float minPt = lPtBins[1]; + float maxPt = lPtBins[2]; + + vector lPhiBins = cfPhiBins.value; // define local array and initialize it from an array set in the configurables + int nBinsPhi = static_cast(lPhiBins[0]); + float minPhi = lPhiBins[1]; + float maxPhi = lPhiBins[2]; + + vector lEtaBins = cfEtaBins.value; // define local array and initialize it from an array set in the configurables + int nBinsEta = static_cast(lEtaBins[0]); + float minEta = lEtaBins[1]; + float maxEta = lEtaBins[2]; + + if (doprocessRec || doprocessRecSim) { + pc.fParticlEHistograms[EHistPt][ERec][ENoCuts] = new TH1F("[EHistPt][ERec][ENoCuts]", "pt distribution for reconstructed particles before cuts", nBinsPt, minPt, maxPt); + pc.fParticlEHistograms[EHistPt][ERec][ENoCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticlEHistograms[EHistPt][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPt][ERec][ENoCuts]); + + pc.fParticlEHistograms[EHistPhi][ERec][ENoCuts] = new TH1F("[EHistPhi][ERec][ENoCuts]", "phi distribution for reconstructed particles before cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticlEHistograms[EHistPhi][ERec][ENoCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticlEHistograms[EHistPhi][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPhi][ERec][ENoCuts]); + + pc.fParticlEHistograms[EHistEta][ERec][ENoCuts] = new TH1F("[EHistEta][ERec][ENoCuts]", "eta distribution for reconstructed particles before cuts", nBinsEta, minEta, maxEta); + pc.fParticlEHistograms[EHistEta][ERec][ENoCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticlEHistograms[EHistEta][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistEta][ERec][ENoCuts]); + + if (cfPtSwitch) { + pc.fParticlEHistograms[EHistPt][ERec][EWithCuts] = new TH1F("[EHistPt][ERec][EWithCuts]", "pt distribution for reconstructed particles after cuts", nBinsPt, minPt, maxPt); + pc.fParticlEHistograms[EHistPt][ERec][EWithCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticlEHistograms[EHistPt][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPt][ERec][EWithCuts]); + + pc.fParticlEHistograms[EHistPhi][ERec][EWithCuts] = new TH1F("[EHistPhi][ERec][EWithCuts]", "phi distribution for reconstructed particles after cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticlEHistograms[EHistPhi][ERec][EWithCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticlEHistograms[EHistPhi][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPhi][ERec][EWithCuts]); + + pc.fParticlEHistograms[EHistEta][ERec][EWithCuts] = new TH1F("[EHistEta][ERec][EWithCuts]", "eta distribution for reconstructed particles after cuts", nBinsEta, minEta, maxEta); + pc.fParticlEHistograms[EHistEta][ERec][EWithCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticlEHistograms[EHistEta][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistEta][ERec][EWithCuts]); + } + } + + if (doprocessSim || doprocessRecSim) { + pc.fParticlEHistograms[EHistPt][ESim][ENoCuts] = new TH1F("[EHistPt][ESim][ENoCuts]", "pt distribution for simulated particles before cuts", nBinsPt, minPt, maxPt); + pc.fParticlEHistograms[EHistPt][ESim][ENoCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticlEHistograms[EHistPt][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPt][ESim][ENoCuts]); + + pc.fParticlEHistograms[EHistPhi][ESim][ENoCuts] = new TH1F("[EHistPhi][ESim][ENoCuts]", "phi distribution for simulated particles before cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticlEHistograms[EHistPhi][ESim][ENoCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticlEHistograms[EHistPhi][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPhi][ESim][ENoCuts]); + + pc.fParticlEHistograms[EHistEta][ESim][ENoCuts] = new TH1F("[EHistEta][ESim][ENoCuts]", "eta distribution for simulated particles before cuts", nBinsEta, minEta, maxEta); + pc.fParticlEHistograms[EHistEta][ESim][ENoCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticlEHistograms[EHistEta][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistEta][ESim][ENoCuts]); + + if (cfPtSwitch) { + pc.fParticlEHistograms[EHistPt][ESim][EWithCuts] = new TH1F("[EHistPt][ESim][EWithCuts]", "pt distribution for simulated particles after cuts", nBinsPt, minPt, maxPt); + pc.fParticlEHistograms[EHistPt][ESim][EWithCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticlEHistograms[EHistPt][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPt][ESim][EWithCuts]); + + pc.fParticlEHistograms[EHistPhi][ESim][EWithCuts] = new TH1F("[EHistPhi][ESim][EWithCuts]", "phi distribution for simulated particles after cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticlEHistograms[EHistPhi][ESim][EWithCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticlEHistograms[EHistPhi][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistPhi][ESim][EWithCuts]); + + pc.fParticlEHistograms[EHistEta][ESim][EWithCuts] = new TH1F("[EHistEta][ESim][EWithCuts]", "eta distribution for simulated particles after cuts", nBinsEta, minEta, maxEta); + pc.fParticlEHistograms[EHistEta][ESim][EWithCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticlEHistograms[EHistEta][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticlEHistogramsList->Add(pc.fParticlEHistograms[EHistEta][ESim][EWithCuts]); + } + } + + // Book event-level histograms + ec.fEventHistogramsList = new TList(); + ec.fEventHistogramsList->SetName("EventHistograms"); + ec.fEventHistogramsList->SetOwner(true); + fBaseList->Add(ec.fEventHistogramsList); + + vector lCent = cfCentBins.value; + int nBinsCent = static_cast(lCent[0]); + float minCent = lCent[1]; + float maxCent = lCent[2]; + + vector lMultRec = cfMultBinsRec.value; + int nBinsMultRec = static_cast(lMultRec[0]); + float minMultRec = lMultRec[1]; + float maxMultRec = lMultRec[2]; + + vector lMultRef = cfMultBinsRef.value; + int nBinsMultRef = static_cast(lMultRef[0]); + float minMultRef = lMultRef[1]; + float maxMultRef = lMultRef[2]; + + vector lMultSim = cfMultBinsSim.value; + int nBinsMultSim = static_cast(lMultSim[0]); + float minMultSim = lMultSim[1]; + float maxMultSim = lMultSim[2]; + + vector lVx = cfVxBins.value; + int nBinsVx = static_cast(lVx[0]); + float minVx = lVx[1]; + float maxVx = lVx[2]; + + vector lVy = cfVyBins.value; + int nBinsVy = static_cast(lVy[0]); + float minVy = lVy[1]; + float maxVy = lVy[2]; + + vector lVz = cfVzBins.value; + int nBinsVz = static_cast(lVz[0]); + float minVz = lVz[1]; + float maxVz = lVz[2]; + + vector lIp = cfIpBins.value; + int nBinsIp = static_cast(lIp[0]); + float minIp = lIp[1]; + float maxIp = lIp[2]; + + if (doprocessRec || doprocessRecSim) { + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts] = new TH1F("[EHistCentrality][ERec][ENoCuts]", "Centrality (reconstructed) before cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]); + + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts] = new TH1F("[EHistMultiplicity][ERec][ENoCuts]", "Multiplicity (reconstructed) before cuts", nBinsMultRec, minMultRec, maxMultRec); + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]); + + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][ENoCuts] = new TH1F("[EHistReferencEMultiplicity][ERec][ENoCuts]", "Reference Multiplicity before cuts", nBinsMultRef, minMultRef, maxMultRef); + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][ENoCuts]->GetXaxis()->SetTitle("Reference Multiplicity"); + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistReferencEMultiplicity][ERec][ENoCuts]); + + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts] = new TH1F("[EHistVertexX][ERec][ENoCuts]", "Vertex X (reconstructed) before cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]); + + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts] = new TH1F("[EHistVertexY][ERec][ENoCuts]", "Vertex Y (reconstructed) before cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]); + + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts] = new TH1F("[EHistVertexZ][ERec][ENoCuts]", "Vertex Z (reconstructed) before cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]); + + if (cfVertexZSwitch) { + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts] = new TH1F("[EHistCentrality][ERec][EWithCuts]", "Centrality (reconstructed) after cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]); + + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts] = new TH1F("[EHistMultiplicity][ERec][EWithCuts]", "Multiplicity (reconstructed) after cuts", nBinsMultRec, minMultRec, maxMultRec); + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]); + + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][EWithCuts] = new TH1F("[EHistReferencEMultiplicity][ERec][EWithCuts]", "Reference Multiplicity after cuts", nBinsMultRef, minMultRef, maxMultRef); + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][EWithCuts]->GetXaxis()->SetTitle("Reference Multiplicity"); + ec.fEventHistograms[EHistReferencEMultiplicity][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistReferencEMultiplicity][ERec][EWithCuts]); + + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts] = new TH1F("[EHistVertexX][ERec][EWithCuts]", "Vertex X (reconstructed) after cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]); + + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts] = new TH1F("[EHistVertexY][ERec][EWithCuts]", "Vertex Y (reconstructed) after cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]); + + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts] = new TH1F("[EHistVertexZ][ERec][EWithCuts]", "Vertex Z (reconstructed) after cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]); + } + } + + if (doprocessSim || doprocessRecSim) { + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts] = new TH1F("[EHistCentrality][ESim][ENoCuts]", "Centrality (simulated) before cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]); + + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts] = new TH1F("[EHistMultiplicity][ESim][ENoCuts]", "Multiplicity (simulated) before cuts", nBinsMultSim, minMultSim, maxMultSim); + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]); + + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts] = new TH1F("[EHistVertexX][ESim][ENoCuts]", "Vertex X (simulated) before cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]); + + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts] = new TH1F("[EHistVertexY][ESim][ENoCuts]", "Vertex Y (simulated) before cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]); + + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts] = new TH1F("[EHistVertexZ][ESim][ENoCuts]", "Vertex Z (simulated) before cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]); + + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts] = new TH1F("[EHistImpactParameter][ESim][ENoCuts]", "Impact Parameter (simulated) before cuts", nBinsIp, minIp, maxIp); + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]->GetXaxis()->SetTitle("Impact Parameter"); + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]); + + if (cfVertexZSwitch) { + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts] = new TH1F("[EHistCentrality][ESim][EWithCuts]", "Centrality (simulated) after cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]); + + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts] = new TH1F("[EHistMultiplicity][ESim][EWithCuts]", "Multiplicity (simulated) after cuts", nBinsMultSim, minMultSim, maxMultSim); + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]); + + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts] = new TH1F("[EHistVertexX][ESim][EWithCuts]", "Vertex X (simulated) after cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]); + + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts] = new TH1F("[EHistVertexY][ESim][EWithCuts]", "Vertex Y (simulated) after cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]); + + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts] = new TH1F("[EHistVertexZ][ESim][EWithCuts]", "Vertex Z (simulated) after cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]); + + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts] = new TH1F("[EHistImpactParameter][ESim][EWithCuts]", "Impact Parameter (simulated) after cuts", nBinsIp, minIp, maxIp); + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]->GetXaxis()->SetTitle("Impact Parameter"); + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]); + } + } + + if (qualityAssurance && doprocessRecSim) { + qa.fQualityAssuranceList = new TList(); + qa.fQualityAssuranceList->SetName("QualityAssurance"); + qa.fQualityAssuranceList->SetOwner(true); + fBaseList->Add(qa.fQualityAssuranceList); + + qa.fHistCentralityRecSim = new TH2F("fHistCentralityRecSim", "Centrality Rec vs Sim", nBinsCent, minCent, maxCent, nBinsCent, minCent, maxCent); + qa.fHistCentralityRecSim->GetXaxis()->SetTitle("Centrality (reconstructed)"); + qa.fHistCentralityRecSim->GetYaxis()->SetTitle("Centrality (simulated)"); + qa.fQualityAssuranceList->Add(qa.fHistCentralityRecSim); + } + } // end of void init(InitContext&) { + + // A) Process only reconstructed data: + void processRec(CollisionRec const& collision, aod::BCs const&, TracksRec const& tracks) + { + // *) steer all analysis steps: + steer(collision, tracks); + } + PROCESS_SWITCH(MultiparticleCorrelationsMei, processRec, "process only reconstructed data", true); // yes, keep always one process switch "true", so that there is default running version + + // ------------------------------------------- + + // B) Process both reconstructed and corresponding MC truth simulated data: + void processRecSim(CollisionRecSim const& collision, aod::BCs const&, TracksRecSim const& tracks, aod::McParticles const&, aod::McCollisions const&) + { + steer(collision, tracks); + } + PROCESS_SWITCH(MultiparticleCorrelationsMei, processRecSim, "process both reconstructed and corresponding MC truth simulated data", false); + + // ------------------------------------------- + + // C) Process only simulated data: + void processSim(CollisionSim const& /*collision*/, aod::BCs const&, TracksSim const& /*tracks*/) + { + // steer(collision, tracks); // TBI 20241105 not ready yet, but I do not really need this one urgently, since RecSim is working, and I need that one for efficiencies... + } + PROCESS_SWITCH(MultiparticleCorrelationsMei, processSim, "process only simulated data", false); + +}; // struct MultiparticleCorrelationsMei { + +// *) The final touch: +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} // WorkflowSpec... diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx index bded4d120ae..85e7b44cf06 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx @@ -135,6 +135,17 @@ static constexpr std::array CorrHistNames = { "Multiplicity", "NContributionMultiplicity"}; +enum EnCorrBound { + eCentABBound, + eCentACBound, + eCentBCBound, + eMultABBound, + eMultACBound, + eMultBCBound, + eNumContribMultBound, + eCorrBound_N +}; + enum EnCentEstm { eCentFT0C, eCentFT0M, @@ -232,15 +243,18 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam Configurable> cfVertexZCut{"cfVertexZCut", {-10., 10.}, "vertex z position range: {min, max}[cm]"}; Configurable> cfCentCut{"cfCentCut", {10., 20.}, "centrality range: {min, max}[%]"}; Configurable> cfNumContribCut{"cfNumContribCut", {0, 3000.}, "NContribution range: {min, max}"}; - Configurable> cfCentCorrCut{"cfCentCorrCut", {1., 10.}, "parameters of limits in centralities 2D histograms, (x-t)/m < y < mx+t: {m, t}"}; + // Configurable> cfCentCorrCut{"cfCentCorrCut", {1., 10.}, "parameters of limits in centralities 2D histograms, (x-t)/m < y < mx+t: {m, t}"}; + Configurable> cfCentABCorrCut{"cfCentABCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M centrality 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfCentACCorrCut{"cfCentACCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M centrality 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfCentBCCorrCut{"cfCentBCCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M centrality 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; Configurable> cfMultABCorrCut{"cfMultABCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M multiplicities 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; Configurable> cfMultACCorrCut{"cfMultACCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FV0A multiplicities 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; Configurable> cfMultBCCorrCut{"cfMultBCCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0M vs. FV0A multiplicities 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; Configurable> cfNumContribMultCorrCut{"cfNumContribMultCorrCut", {0.035, 100., 0.024, -600.}, "parameters of limits in NContribution vs. multiplicity 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; // *) Particle cut - Configurable> cfPtCut{"cfPtCut", {0.2, 5.0}, "Pt range: {min, max}[GeV], with convention: min <= Pt < max"}; - Configurable> cfEtaCut{"cfEtaCut", {-0.8, 0.8}, "Eta range: {min, max}, with convention: min <= Eta < max"}; + Configurable> cfPtCut{"cfPtCut", {0.2, 5.0}, "Pt range: {min, max}[GeV], with convention: min < Pt < max"}; + Configurable> cfEtaCut{"cfEtaCut", {-0.8, 0.8}, "Eta range: {min, max}, with convention: min < Eta < max"}; Configurable> cfSignCut{"cfSignCut", {1, 0, 1}, "sign of charge, 1 to keep and 0 to discard, {negative, neutral, positive}"}; Configurable> cfTpcNClsFoundCut{"cfTpcNClsFoundCut", {70., 160.}, "range of found TPC clusters for this track geometry: {min, max}"}; Configurable> cfDCAXYCut{"cfDCAXYCut", {-3.2, 3.2}, "range of distance-of-closest-approach (DCA) of the extrapolated track to the primary position in XY-direction: {min, max}[cm]"}; @@ -296,7 +310,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::vector fVertexZCut = {-10., 10.}; std::vector fCentCut = {10., 20.}; std::vector fNumContribCut = {0, 3000.}; - std::vector fCentCorrCut = {1., 10.}; + std::vector>> fCentAllCorrCut = {{{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}}; std::vector>> fMultAllCorrCut = {{{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}}; std::vector fNumContribMultCorrCut = {0.024, -600., 0.035, 100.}; std::vector fPtCut = {0.2, 5.0}; @@ -347,7 +361,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam struct CorrHistograms { TList* fCorrHistogramsList = nullptr; std::array, eMultEstm_N>, eMultEstm_N>, eCorrHistograms_N - 1> fCorrHistograms{}; // [mult/cent][type][type][before/after cut] - std::array, eCorrHistograms_N + 2> fCorrBounds{}; // [cent/multAB/multAC/multBC/NumContrib vs. mult][upper/lower] + std::array, eCorrBound_N> fCorrBounds{}; // [centAB/centAC/centBC/multAB/multAC/multBC/NumContrib vs. mult][upper/lower] } cr; struct WeightHistograms { @@ -382,8 +396,10 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::array, MaxHarmonic> fQvectorBefore; std::array, MaxHarmonic> fQvectorAfter; - std::array, MaxHarmonic> fQvectorAfterA; // Q-vector with eta gap - std::array, MaxHarmonic> fQvectorAfterB; // Q-vector with eta gap + std::array, MaxHarmonic> fQvectorBeforeA; // Q-vector with eta gap + std::array, MaxHarmonic> fQvectorBeforeB; // Q-vector with eta gap + std::array, MaxHarmonic> fQvectorAfterA; // Q-vector with eta gap + std::array, MaxHarmonic> fQvectorAfterB; // Q-vector with eta gap } mcc; struct MultiparticleCorrelationProfile { @@ -393,6 +409,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::array fTwoParticleCorrelationProfiles{}; // [cut] std::array fFourParticleCorrelationProfiles{}; std::array fSixParticleCorrelationProfiles{}; + std::array fTwoParticleCorrelationGapProfiles{}; std::array, eBeforeAfter_N>, eBeforeAfter_N> fTwoParticleCorrelationHistograms{}; // [cut][event weight][n] std::array, eBeforeAfter_N>, eBeforeAfter_N> fFourParticleCorrelationHistograms{}; std::array, eBeforeAfter_N>, eBeforeAfter_N> fSixParticleCorrelationHistograms{}; @@ -457,32 +474,34 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam // *) CentCorrCut float iCent = 0.; float jCent = 0.; + int nCentComb = 0; for (int i = 0; i < eCentEstm_N; i++) { iCent = rlCollisionCentAll[i]; for (int j = i + 1; j < eCentEstm_N; j++) { jCent = rlCollisionCentAll[j]; - float upper = cr.fCorrBounds[eCorrCent][0]->Eval(iCent); - float lower = cr.fCorrBounds[eCorrCent][1]->Eval(iCent); + float upper = cr.fCorrBounds[eCentABBound + nCentComb][0]->Eval(iCent); + float lower = cr.fCorrBounds[eCentABBound + nCentComb][1]->Eval(iCent); bCentCorrCut &= jCent >= lower && jCent <= upper; + nCentComb += 1; } } // *) MultCorrCut float iMult = 0.; float jMult = 0.; - int nComb = 0; + int nMultComb = 0; for (int i = 0; i < eMultEstm_N; i++) { iMult = rlCollisionMultAll[i]; for (int j = i + 1; j < eMultEstm_N; j++) { jMult = rlCollisionMultAll[j]; - float upper = cr.fCorrBounds[eCorrMult + nComb][0]->Eval(iMult); - float lower = cr.fCorrBounds[eCorrMult + nComb][1]->Eval(iMult); + float upper = cr.fCorrBounds[eMultABBound + nMultComb][0]->Eval(iMult); + float lower = cr.fCorrBounds[eMultABBound + nMultComb][1]->Eval(iMult); bMultCorrCut &= jMult >= lower && jMult <= upper; - nComb += 1; + nMultComb += 1; } } // *) NumContribMultCorrCut - float upper = cr.fCorrBounds[eCorrNumContribMult + nComb - 1][0]->Eval(ebye.fReferenceMultiplicity); - float lower = cr.fCorrBounds[eCorrNumContribMult + nComb - 1][1]->Eval(ebye.fReferenceMultiplicity); + float upper = cr.fCorrBounds[eNumContribMultBound][0]->Eval(ebye.fReferenceMultiplicity); + float lower = cr.fCorrBounds[eNumContribMultBound][1]->Eval(ebye.fReferenceMultiplicity); bNumContribMultCorrCut = rlCollisionNumContrib >= lower && rlCollisionNumContrib <= upper; } @@ -588,7 +607,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam return pass; } - TComplex mccQ(int n, int p, EnBeforeAfter eba, int egap) + TComplex mccQ(int n, int p, EnBeforeAfter eba) { // Using the fact that Q{-n,p} = Q{n,p}^*. if (eba == eBefore) { @@ -598,43 +617,28 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } return TComplex::Conjugate(mcc.fQvectorBefore[-n][p]); } - if (egap == 0) { - // Q-vector after cut: - if (n >= 0) { - return mcc.fQvectorAfter[n][p]; - } - return TComplex::Conjugate(mcc.fQvectorAfter[-n][p]); - } - if (egap == 1) { - // Q-vector after cut, eta < gap: - if (n >= 0) { - return mcc.fQvectorAfterA[n][p]; - } - return TComplex::Conjugate(mcc.fQvectorAfterA[-n][p]); - } - // Q-vector after cut, eta > gap: if (n >= 0) { return mcc.fQvectorAfterB[n][p]; } return TComplex::Conjugate(mcc.fQvectorAfterB[-n][p]); } - TComplex mccTwo(int n1, int n2, EnBeforeAfter eba, int egap) + TComplex mccTwo(int n1, int n2, EnBeforeAfter eba) { - return mccQ(n1, 1, eba, egap) * mccQ(n2, 1, eba, egap) - mccQ(n1 + n2, 2, eba, egap); + return mccQ(n1, 1, eba) * mccQ(n2, 1, eba) - mccQ(n1 + n2, 2, eba); } template - TComplex mccRecursion(int n, std::array harmonic, EnBeforeAfter eba, int egap, int mult = 1, int skip = 0) + TComplex mccRecursion(int n, std::array harmonic, EnBeforeAfter eba, int mult = 1, int skip = 0) { // Calculate multi-particle correlators by using recursion (an improved faster version) originally developed by Kristjan Gulbrandsen (gulbrand@nbi.dk). int nm1 = n - 1; - TComplex c(mccQ(harmonic[nm1], mult, eba, egap)); + TComplex c(mccQ(harmonic[nm1], mult, eba)); if (nm1 == 0) { return c; } - c *= mccRecursion(nm1, harmonic, eba, egap); + c *= mccRecursion(nm1, harmonic, eba); if (nm1 == skip) { return c; } @@ -645,7 +649,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam int hhold = harmonic[counter1]; harmonic[counter1] = harmonic[nm2]; harmonic[nm2] = hhold + harmonic[nm1]; - TComplex c2(mccRecursion(nm1, harmonic, eba, egap, multp1, nm2)); + TComplex c2(mccRecursion(nm1, harmonic, eba, multp1, nm2)); int counter2 = n - 3; while (counter2 >= skip) { harmonic[nm2] = harmonic[counter1]; @@ -654,7 +658,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam hhold = harmonic[counter1]; harmonic[counter1] = harmonic[nm2]; harmonic[nm2] = hhold + harmonic[nm1]; - c2 += mccRecursion(nm1, harmonic, eba, egap, multp1, counter2); + c2 += mccRecursion(nm1, harmonic, eba, multp1, counter2); --counter2; } harmonic[nm2] = harmonic[counter1]; @@ -861,6 +865,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam for (int p = 0; p < mcc.MaxPower; p++) { mcc.fQvectorBefore[h][p] = TComplex(0., 0.); mcc.fQvectorAfter[h][p] = TComplex(0., 0.); + mcc.fQvectorBeforeA[h][p] = TComplex(0., 0.); + mcc.fQvectorBeforeB[h][p] = TComplex(0., 0.); mcc.fQvectorAfterA[h][p] = TComplex(0., 0.); mcc.fQvectorAfterB[h][p] = TComplex(0., 0.); } @@ -953,6 +959,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam mc.fTwoParticleCorrelationProfiles[i] = nullptr; mc.fFourParticleCorrelationProfiles[i] = nullptr; mc.fSixParticleCorrelationProfiles[i] = nullptr; + mc.fTwoParticleCorrelationGapProfiles[i] = nullptr; for (int j = 0; j < eBeforeAfter_N; j++) { // before/after weight mc.fTwoParticleCorrelationHistograms[i][j].fill(nullptr); @@ -965,9 +972,13 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam for (int i = 0; i < eBeforeAfter_N; i++) { // before/after cut mc.fTwoParticleCorrelationProfiles[i] = new TProfile(Form("prof2%sCut", BeforeAfterNames[i + 2]), Form("2-p correlation %s cut", BeforeAfterNames[i]), NumTwoPCorrBins, 0., 1.); mc.fTwoParticleCorrelationProfiles[i]->Sumw2(); + mc.fTwoParticleCorrelationGapProfiles[i] = new TProfile(Form("prof2%sCutGapped", BeforeAfterNames[i + 2]), Form("2-p correlation %s cut, gapped", BeforeAfterNames[i]), NumTwoPCorrBins, 0., 1.); + mc.fTwoParticleCorrelationProfiles[i]->Sumw2(); + mc.fTwoParticleCorrelationGapProfiles[i]->Sumw2(); for (int k = 0; k < NumTwoPCorrBins; k++) { // v2, v3, v4 mc.fTwoParticleCorrelationProfiles[i]->GetXaxis()->SetBinLabel(k + 1, Form("", k + 2)); + mc.fTwoParticleCorrelationGapProfiles[i]->GetXaxis()->SetBinLabel(k + 1, Form("", k + 2)); if (static_cast(i)) { mc.fTwoParticleCorrelationGapHistograms[k] = new TH1D(Form("hist2v%dAfterCutWithGap", k + 2), Form("2-p correlation v%d^2 after cut with gap", k + 2), static_cast(tc.fTwoParticleCorrBins[0]), tc.fTwoParticleCorrBins[1], tc.fTwoParticleCorrBins[2]); mc.fTwoParticleCorrelationGapHistograms[k]->Sumw2(); @@ -986,6 +997,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } } mc.fMultiparticleCorrelationByRunMap[ebye.fRunNumber]->Add(mc.fTwoParticleCorrelationProfiles[i]); + mc.fMultiparticleCorrelationByRunMap[ebye.fRunNumber]->Add(mc.fTwoParticleCorrelationGapProfiles[i]); } // Define 4p profiles and histograms: @@ -1240,6 +1252,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam int nTracksBefore = tracks.size(); int nTracksAfter = 0; + int nTracksBeforeA = 0; + int nTracksBeforeB = 0; int nTracksAfterA = 0; int nTracksAfterB = 0; @@ -1292,6 +1306,21 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam wPhiToPowerP = std::pow(wPhi, p); } mcc.fQvectorBefore[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + if (tc.fEtaGapSwitch) { + if (dEta < -tc.fEtaGap / 2.) { + mcc.fQvectorBeforeA[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + } else if (dEta > tc.fEtaGap / 2.) { + mcc.fQvectorBeforeB[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + } + } + } + } + + if (tc.fEtaGapSwitch) { + if (dEta < -tc.fEtaGap / 2.) { + nTracksBeforeA += 1; + } else if (dEta > tc.fEtaGap / 2.) { + nTracksBeforeB += 1; } } @@ -1319,10 +1348,12 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } nTracksAfter += 1; - if (dEta < -tc.fEtaGap / 2) { - nTracksAfterA += 1; - } else if (dEta > tc.fEtaGap / 2) { - nTracksAfterB += 1; + if (tc.fEtaGapSwitch) { + if (dEta < -tc.fEtaGap / 2.) { + nTracksAfterA += 1; + } else if (dEta > tc.fEtaGap / 2.) { + nTracksAfterB += 1; + } } } // ... @@ -1367,8 +1398,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::array harmonicsTwoDen = {0, 0}; // Before cut: - TComplex twoRecursionBefore = mccRecursion(2, harmonicsTwoNum, eBefore, 0) / mccRecursion(2, harmonicsTwoDen, eBefore, 0).Re(); - double wTwoRecursionBefore = mccRecursion(2, harmonicsTwoDen, eBefore, 0).Re(); + TComplex twoRecursionBefore = mccRecursion(2, harmonicsTwoNum, eBefore) / mccRecursion(2, harmonicsTwoDen, eBefore).Re(); + double wTwoRecursionBefore = mccRecursion(2, harmonicsTwoDen, eBefore).Re(); ebye.fTwoParticleCorrelationEbye[eBefore][i] = twoRecursionBefore.Re(); if (nTracksBefore > k - 1 && wTwoRecursionBefore > 0.) { @@ -1391,8 +1422,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } // After cut: - TComplex twoRecursionAfter = mccRecursion(2, harmonicsTwoNum, eAfter, 0) / mccRecursion(2, harmonicsTwoDen, eAfter, 0).Re(); - double wTwoRecursionAfter = mccRecursion(2, harmonicsTwoDen, eAfter, 0).Re(); + TComplex twoRecursionAfter = mccRecursion(2, harmonicsTwoNum, eAfter) / mccRecursion(2, harmonicsTwoDen, eAfter).Re(); + double wTwoRecursionAfter = mccRecursion(2, harmonicsTwoDen, eAfter).Re(); ebye.fTwoParticleCorrelationEbye[eAfter][i] = twoRecursionAfter.Re(); if (nTracksAfter > k - 1 && wTwoRecursionAfter > 0.) { @@ -1414,13 +1445,26 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam LOGF(warning, "cent=%f, nTracksAfter = %d, wTwoRecursionAfter = %e", rlCollisionCent, nTracksAfter, wTwoRecursionAfter); } + // Before cut, with gap: + TComplex qvba = mcc.fQvectorBeforeA[mcc.h2][0]; + TComplex qvbb = mcc.fQvectorBeforeB[mcc.h2][0]; + double gapb = 0.; + if (nTracksBeforeA * nTracksBeforeB > 0) { + gapb = (qvba * TComplex::Conjugate(qvbb)).Re() / (nTracksBeforeA * nTracksBeforeB); + mc.fTwoParticleCorrelationGapProfiles[eBefore]->Fill(mc.fTwoParticleCorrelationGapProfiles[eBefore]->GetXaxis()->GetBinCenter(i + 1), gapb, nTracksBeforeA * nTracksBeforeB); + // mc.fTwoParticleCorrelationGapHistograms[i]->Fill(gapb, nTracksBeforeA * nTracksBeforeB); + } else { + LOGF(warning, "cent=%f, nTracksBeforeA = %d, nTracksBeforeB = %d", rlCollisionCent, nTracksBeforeA, nTracksBeforeB); + } + // After cut, with gap: - TComplex qva = mcc.fQvectorAfterA[mcc.h2][0]; - TComplex qvb = mcc.fQvectorAfterB[mcc.h2][0]; - double gap = 0.; + TComplex qvaa = mcc.fQvectorAfterA[mcc.h2][0]; + TComplex qvab = mcc.fQvectorAfterB[mcc.h2][0]; + double gapa = 0.; if (nTracksAfterA * nTracksAfterB > 0) { - gap = (qva * TComplex::Conjugate(qvb)).Re() / (nTracksAfterA * nTracksAfterB); - mc.fTwoParticleCorrelationGapHistograms[i]->Fill(gap, nTracksAfterA * nTracksAfterB); + gapa = (qvaa * TComplex::Conjugate(qvab)).Re() / (nTracksAfterA * nTracksAfterB); + mc.fTwoParticleCorrelationGapProfiles[eAfter]->Fill(mc.fTwoParticleCorrelationGapProfiles[eAfter]->GetXaxis()->GetBinCenter(i + 1), gapa, nTracksAfterA * nTracksAfterB); + mc.fTwoParticleCorrelationGapHistograms[i]->Fill(gapa, nTracksAfterA * nTracksAfterB); } else { LOGF(warning, "cent=%f, nTracksAfterA = %d, nTracksAfterB = %d", rlCollisionCent, nTracksAfterA, nTracksAfterB); } @@ -1437,8 +1481,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::array harmonicsFourDen = {0, 0, 0, 0}; // Before cut: - TComplex fourRecursionBefore = mccRecursion(4, harmonicsFourNum, eBefore, 0) / mccRecursion(4, harmonicsFourDen, eBefore, 0).Re(); - double wFourRecursionBefore = mccRecursion(4, harmonicsFourDen, eBefore, 0).Re(); + TComplex fourRecursionBefore = mccRecursion(4, harmonicsFourNum, eBefore) / mccRecursion(4, harmonicsFourDen, eBefore).Re(); + double wFourRecursionBefore = mccRecursion(4, harmonicsFourDen, eBefore).Re(); ebye.fFourParticleCorrelationEbye[eBefore][i] = fourRecursionBefore.Re(); if (nTracksBefore > k - 1 && wFourRecursionBefore > 0.) { @@ -1461,8 +1505,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } // After cut: - TComplex fourRecursionAfter = mccRecursion(4, harmonicsFourNum, eAfter, 0) / mccRecursion(4, harmonicsFourDen, eAfter, 0).Re(); - double wFourRecursionAfter = mccRecursion(4, harmonicsFourDen, eAfter, 0).Re(); + TComplex fourRecursionAfter = mccRecursion(4, harmonicsFourNum, eAfter) / mccRecursion(4, harmonicsFourDen, eAfter).Re(); + double wFourRecursionAfter = mccRecursion(4, harmonicsFourDen, eAfter).Re(); ebye.fFourParticleCorrelationEbye[eAfter][i] = fourRecursionAfter.Re(); if (nTracksAfter > k - 1 && wFourRecursionAfter > 0.) { @@ -1498,8 +1542,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::array harmonicsSixDen = {0, 0, 0, 0, 0, 0}; // Before cut: - TComplex sixRecursionBefore = mccRecursion(6, harmonicsSixNum, eBefore, 0) / mccRecursion(6, harmonicsSixDen, eBefore, 0).Re(); - double wSixRecursionBefore = mccRecursion(6, harmonicsSixDen, eBefore, 0).Re(); + TComplex sixRecursionBefore = mccRecursion(6, harmonicsSixNum, eBefore) / mccRecursion(6, harmonicsSixDen, eBefore).Re(); + double wSixRecursionBefore = mccRecursion(6, harmonicsSixDen, eBefore).Re(); ebye.fSixParticleCorrelationEbye[eBefore][i] = sixRecursionBefore.Re(); if (nTracksBefore > k - 1 && wSixRecursionBefore > 0.) { @@ -1522,8 +1566,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } // After cut: - TComplex sixRecursionAfter = mccRecursion(6, harmonicsSixNum, eAfter, 0) / mccRecursion(6, harmonicsSixDen, eAfter, 0).Re(); - double wSixRecursionAfter = mccRecursion(6, harmonicsSixDen, eAfter, 0).Re(); + TComplex sixRecursionAfter = mccRecursion(6, harmonicsSixNum, eAfter) / mccRecursion(6, harmonicsSixDen, eAfter).Re(); + double wSixRecursionAfter = mccRecursion(6, harmonicsSixDen, eAfter).Re(); ebye.fSixParticleCorrelationEbye[eAfter][i] = sixRecursionAfter.Re(); if (nTracksAfter > k - 1 && wSixRecursionAfter > 0.) { @@ -1675,32 +1719,33 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam template void bookCorrHistograms(T1 const& lCrBins) { + // (mult)(cent)(NContribMult) offset + constexpr int BoundOffset = histType == eCorrCent ? eCentABBound : histType == eCorrMult ? eMultABBound + : eNumContribMultBound; - // book limit functions: - if constexpr (histType == eCorrCent) { - cr.fCorrBounds[histType][0] = new TF1(Form("fCorrUpperBound%s", CorrHistNames[histType]), "[0] * x + [1]"); - cr.fCorrBounds[histType][1] = new TF1(Form("fCorrLowerBound%s", CorrHistNames[histType]), "(x - [1]) / [0]"); - cr.fCorrBounds[histType][0]->SetTitle(Form("%s upper bound", CorrHistNames[histType])); - cr.fCorrBounds[histType][1]->SetTitle(Form("%s lower bound", CorrHistNames[histType])); - } else if constexpr (histType == eCorrMult) { + // (mult)(cent)(NContribMult) book functions: + if constexpr (histType == eCorrCent || histType == eCorrMult) { for (int i = 0; i < eEstmCorr_N; i++) { - int indexBound = static_cast(histType) + i; + int indexBound = BoundOffset + i; cr.fCorrBounds[indexBound][0] = new TF1(Form("fCorrUpperBound%s%s", EstmCorrName[i], CorrHistNames[histType]), "[0] * x + [1]"); cr.fCorrBounds[indexBound][1] = new TF1(Form("fCorrLowerBound%s%s", EstmCorrName[i], CorrHistNames[histType]), "[0] * x + [1]"); cr.fCorrBounds[indexBound][0]->SetTitle(Form("%s %s upper bound", EstmCorrName[i], CorrHistNames[histType])); cr.fCorrBounds[indexBound][1]->SetTitle(Form("%s %s lower bound", EstmCorrName[i], CorrHistNames[histType])); } } else if constexpr (histType == eCorrNumContribMult) { - int indexBound = static_cast(histType) + static_cast(eEstmCorr_N) - 1; + int indexBound = BoundOffset; cr.fCorrBounds[indexBound][0] = new TF1(Form("fCorrUpperBound%s", CorrHistNames[histType]), "[0] * x + [1]"); cr.fCorrBounds[indexBound][1] = new TF1(Form("fCorrLowerBound%s", CorrHistNames[histType]), "[0] * x + [1]"); cr.fCorrBounds[indexBound][0]->SetTitle(Form("%s upper bound", CorrHistNames[histType])); cr.fCorrBounds[indexBound][1]->SetTitle(Form("%s lower bound", CorrHistNames[histType])); } - int nBinsCent = 0; - float minCent = 0.; - float maxCent = 0.; + int nBinsXCent = 0; + float minXCent = 0.; + float maxXCent = 0.; + int nBinsYCent = 0; + float minYCent = 0.; + float maxYCent = 0.; int nBinsXMult = 0; float minXMult = 0.; float maxXMult = 0.; @@ -1711,44 +1756,23 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam // float minNumContrib = 0.; float maxNumContrib = 0.; - if constexpr (histType == eCorrCent) { - - // (cent) get bins: - const auto& lCentBins = lCrBins[histType]; - nBinsCent = static_cast(lCentBins[0]); - minCent = lCentBins[1]; - maxCent = lCentBins[2]; - - // (cent) set functions and add to list: - cr.fCorrBounds[histType][0]->SetRange(minCent, maxCent); - cr.fCorrBounds[histType][1]->SetRange(minCent, maxCent); - cr.fCorrBounds[histType][0]->SetMinimum(0); - cr.fCorrBounds[histType][1]->SetMinimum(0); - cr.fCorrBounds[histType][0]->SetMaximum(100); - cr.fCorrBounds[histType][1]->SetMaximum(100); - cr.fCorrBounds[histType][0]->SetParameters(tc.fCentCorrCut[0], tc.fCentCorrCut[1]); - cr.fCorrBounds[histType][1]->SetParameters(tc.fCentCorrCut[0], tc.fCentCorrCut[1]); - cr.fCorrHistogramsList->Add(cr.fCorrBounds[histType][0]); - cr.fCorrHistogramsList->Add(cr.fCorrBounds[histType][1]); - - } else if constexpr (histType == eCorrNumContribMult) { + // (NContribMult) set functions and add to list: + if constexpr (histType == eCorrNumContribMult) { int indexBins = static_cast(histType) + static_cast(eMultEstm_N); - // (mult) get bins: + // (NContribMult) get bins: const auto& lMultXBins = lCrBins[indexBins]; nBinsXMult = static_cast(lMultXBins[0]); minXMult = lMultXBins[1]; maxXMult = lMultXBins[2]; - - // (NContribMult) get bins: const auto& lNumContribBins = lCrBins[indexBins - 1]; // nBinsNumContrib = static_cast(lNumContribBins[0]); // minNumContrib = lNumContribBins[1]; maxNumContrib = lNumContribBins[2]; // (NContribMult) set functions and add to list: - int indexBound = static_cast(histType) + static_cast(eEstmCorr_N) - 1; + int indexBound = BoundOffset; cr.fCorrBounds[indexBound][0]->SetRange(minXMult, maxXMult); cr.fCorrBounds[indexBound][1]->SetRange(minXMult, maxXMult); cr.fCorrBounds[indexBound][0]->SetMinimum(0); @@ -1761,7 +1785,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][1]); } - // Book multiplicities and centralities hisrograms, and set multiplicities functions: + // (mult)(cent) Book histograms, set functions and add to list: if constexpr (histType != eCorrNumContribMult) { for (int ba = 0; ba < eBeforeAfter_N; ba++) { std::string name; @@ -1793,8 +1817,33 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam name = Form("fHist%s[%s vs. %s][%s cut]", CorrHistNames[histType], CentEstmNames[i], CentEstmNames[j], BeforeAfterNames[ba]); titleY = Form("%s %s", CentEstmNames[j], CorrHistNames[histType]); + // (cent) get bins: + const auto& lCentXBins = lCrBins[0]; + nBinsXCent = static_cast(lCentXBins[0]); + minXCent = lCentXBins[1]; + maxXCent = lCentXBins[2]; + const auto& lCentYBins = lCrBins[0]; + nBinsYCent = static_cast(lCentYBins[0]); + minYCent = lCentYBins[1]; + maxYCent = lCentYBins[2]; + + // (cent) set functions and add to list: + if (static_cast(ba)) { + int indexBound = BoundOffset + nComb; + cr.fCorrBounds[indexBound][0]->SetRange(minXCent, maxXCent); + cr.fCorrBounds[indexBound][1]->SetRange(minXCent, maxXCent); + cr.fCorrBounds[indexBound][0]->SetParameters(tc.fCentAllCorrCut[i][j][0], tc.fCentAllCorrCut[i][j][1]); + cr.fCorrBounds[indexBound][1]->SetParameters(tc.fCentAllCorrCut[i][j][2], tc.fCentAllCorrCut[i][j][3]); + cr.fCorrBounds[indexBound][0]->SetMinimum(0); + cr.fCorrBounds[indexBound][1]->SetMinimum(0); + cr.fCorrBounds[indexBound][0]->SetMaximum(maxYCent); + cr.fCorrBounds[indexBound][1]->SetMaximum(maxYCent); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][0]); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][1]); + } + // (cent) book corr 2D histogram: - cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsCent, minCent, maxCent, nBinsCent, minCent, maxCent); + cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsXCent, minXCent, maxXCent, nBinsYCent, minYCent, maxYCent); } else if constexpr (histType == eCorrMult) { name = Form("fHist%s[%s vs. %s][%s cut]", CorrHistNames[histType], MultEstmNames[i], MultEstmNames[j], BeforeAfterNames[ba]); @@ -1812,7 +1861,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam // (mult) set functions and add to list: if (static_cast(ba)) { - int indexBound = static_cast(histType) + nComb; + int indexBound = BoundOffset + nComb; cr.fCorrBounds[indexBound][0]->SetRange(minXMult, maxXMult); cr.fCorrBounds[indexBound][1]->SetRange(minXMult, maxXMult); cr.fCorrBounds[indexBound][0]->SetParameters(tc.fMultAllCorrCut[i][j][0], tc.fMultAllCorrCut[i][j][1]); @@ -1829,7 +1878,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsXMult, minXMult, maxXMult, nBinsYMult, minYMult, maxYMult); } - // (cent/mult) set corr histogram + // (cent)(mult) set corr histogram cr.fCorrHistograms[histType][i][j][ba]->GetYaxis()->SetTitle(titleY.c_str()); cr.fCorrHistograms[histType][i][j][ba]->GetXaxis()->SetTitle(titleX.c_str()); cr.fCorrHistogramsList->Add(cr.fCorrHistograms[histType][i][j][ba]); @@ -1878,7 +1927,9 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam tc.fVertexZCut = cfVertexZCut; tc.fCentCut = cfCentCut; tc.fNumContribCut = cfNumContribCut; - tc.fCentCorrCut = cfCentCorrCut; + tc.fCentAllCorrCut[0][1] = cfCentABCorrCut; + tc.fCentAllCorrCut[0][2] = cfCentACCorrCut; + tc.fCentAllCorrCut[1][2] = cfCentBCCorrCut; tc.fMultAllCorrCut[0][1] = cfMultABCorrCut; tc.fMultAllCorrCut[0][2] = cfMultACCorrCut; tc.fMultAllCorrCut[1][2] = cfMultBCCorrCut; diff --git a/PWGCF/Tasks/correlations.cxx b/PWGCF/Tasks/correlations.cxx index f8dce2e6257..76698f1d6c7 100644 --- a/PWGCF/Tasks/correlations.cxx +++ b/PWGCF/Tasks/correlations.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +115,7 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgEfficiencyTrigger, std::string, "", "CCDB path to efficiency object for trigger particles") O2_DEFINE_CONFIGURABLE(cfgEfficiencyAssociated, std::string, "", "CCDB path to efficiency object for associated particles") + O2_DEFINE_CONFIGURABLE(cfgUseRun3MagField, bool, false, "false: Run 2 GRPObject; true: Run 3 GRPMagField") O2_DEFINE_CONFIGURABLE(cfgNoMixedEvents, int, 5, "Number of mixed events per event") O2_DEFINE_CONFIGURABLE(cfgRejectMixedPhiProngEvents, bool, true, "Reject associated hadrons from either mixed-phi prong event") @@ -186,6 +188,8 @@ struct CorrelationTask { PairCuts mPairCuts; Service ccdb; + int mCachedRunNumber{-1}; // cached run number for magnetic field -- to avoid re-fetching the magnetic field for the same run, assuming that the magnetic field remains the same for the same run + int mCachedMagField{0}; // cached magnetic field --reduces number of calls to the CCDB using AodCollisions = soa::Filtered>; using AodTracks = soa::Filtered>; @@ -331,21 +335,32 @@ struct CorrelationTask { ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time } - int getMagneticField(uint64_t timestamp) + int getMagneticField(int runNumber, uint64_t timestamp) { - // TODO done only once (and not per run). Will be replaced by CCDBConfigurable - static o2::parameters::GRPObject* grpo = nullptr; - // static o2::parameters::GRPMagField* grpo = nullptr; - if (grpo == nullptr) { - grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); - // grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + static constexpr const char* kGRPPathRun2 = "GLO/GRP/GRP"; // fixed path for now, can be made into a config + static constexpr const char* kGRPPathRun3 = "GLO/Config/GRPMagField"; // fixed path for now, can be made into a config + + if (runNumber == mCachedRunNumber) { + return mCachedMagField; + } + + if (cfgUseRun3MagField) { + auto* grpmag = ccdb->getForTimeStamp(kGRPPathRun3, timestamp); + if (grpmag == nullptr) { + LOGF(fatal, "Run 3 GRPMagField not found at %s for run %d timestamp %llu", kGRPPathRun3, runNumber, timestamp); + } + mCachedMagField = grpmag->getNominalL3Field(); + } else { + auto* grpo = ccdb->getForTimeStamp(kGRPPathRun2, timestamp); if (grpo == nullptr) { - LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); - return 0; + LOGF(fatal, "Run 2 GRPObject not found at %s for run %d timestamp %llu", kGRPPathRun2, runNumber, timestamp); } - LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + mCachedMagField = grpo->getNominalL3Field(); } - return grpo->getNominalL3Field(); + + mCachedRunNumber = runNumber; + LOGF(info, "Run %d: magnetic field %d kG", runNumber, mCachedMagField); + return mCachedMagField; } template @@ -894,7 +909,7 @@ struct CorrelationTask { } registry.fill(HIST("eventcount_same"), -2); fillQA(collision, multiplicity, tracks); - fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.timestamp()), 1.0f); + fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.runNumber(), bc.timestamp()), 1.0f); } PROCESS_SWITCH(CorrelationTask, processSameAOD, "Process same event on AOD", true); @@ -911,7 +926,7 @@ struct CorrelationTask { const auto multiplicity = collision.multiplicity(); int field = 0; if (cfgTwoTrackCut > 0) { - field = getMagneticField(collision.timestamp()); + field = getMagneticField(collision.runNumber(), collision.timestamp()); } int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); @@ -1011,7 +1026,7 @@ struct CorrelationTask { // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); - fillCorrelations(mixed, tracks1, tracks2, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.timestamp()), 1.0f / it.currentWindowNeighbours()); + fillCorrelations(mixed, tracks1, tracks2, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.runNumber(), bc.timestamp()), 1.0f / it.currentWindowNeighbours()); } } PROCESS_SWITCH(CorrelationTask, processMixedAOD, "Process mixed events on AOD", false); @@ -1045,7 +1060,7 @@ struct CorrelationTask { float eventWeight = 1.0f / it.currentWindowNeighbours(); int field = 0; if (cfgTwoTrackCut > 0) { - field = getMagneticField(collision1.timestamp()); + field = getMagneticField(collision1.runNumber(), collision1.timestamp()); } if (cfgVerbosity > 0) { diff --git a/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx b/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx index bfd3ccbd7fa..98cd608aa39 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx @@ -120,6 +120,7 @@ struct ChargeBalanceFunction { // Efficiency Correction Configurable cGetCorrectionFlag{"cGetCorrectionFlag", false, "Apply correction flag"}; Configurable cGetNuaCorrectionFlag{"cGetNuaCorrectionFlag", false, "Apply NUA correction flag"}; + Configurable cDoEffNuaCorrection{"cDoEffNuaCorrection", false, "Do NUE x NUA correction"}; // CCDB Configurable cUrlCCDB{"cUrlCCDB", "http://alice-ccdb.cern.ch", "ALICE CCDB URL"}; @@ -248,6 +249,10 @@ struct ChargeBalanceFunction { histos.add("Reco/h3f_n1_rapphi_P", "#rho_{1}^{#plus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); histos.add("Reco/h3f_n1_rapphi_M", "#rho_{1}^{#minus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); + // Rho1 for P2 pT + histos.add("Reco/h2f_n1_pt_P", "#rho_{1}^{#plus}", kTH2F, {axisCent, axisTrackPt}); + histos.add("Reco/h2f_n1_pt_M", "#rho_{1}^{#minus}", kTH2F, {axisCent, axisTrackPt}); + // Rho1 for P2 RapPhi histos.add("Reco/h3f_pt_rapphi_P", "#rho_{1}^{#plus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); histos.add("Reco/h3f_pt_rapphi_M", "#rho_{1}^{#minus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); @@ -394,7 +399,7 @@ struct ChargeBalanceFunction { } template - float getCorrectionFactor(T const& track, S const& sign) + float getEffCorrectionFactor(T const& track, S const& sign) { if (!cGetCorrectionFlag) { return 1.; @@ -530,7 +535,13 @@ struct ChargeBalanceFunction { const auto phibin1 = static_cast(trk_1.phi() / phibinwidth); const auto phibin2 = static_cast(trk_2.phi() / phibinwidth); - float corfac = getCorrectionFactor(trk_1, sign_1) * getCorrectionFactor(trk_2, sign_2); + float effcorr = getEffCorrectionFactor(trk_1, sign_1) * getEffCorrectionFactor(trk_2, sign_2); + float nuacorr = getNuaCorrectionFactor(trk_1, sign_1) * getNuaCorrectionFactor(trk_2, sign_2); + float corrfact = effcorr; + + if (cDoEffNuaCorrection) { + corrfact *= nuacorr; + } if (rapbin1 >= 0 && rapbin2 >= 0 && phibin1 >= 0 && phibin2 >= 0 && rapbin1 < nrapbins && rapbin2 < nrapbins && phibin1 < nphibins && phibin2 < nphibins) { @@ -538,21 +549,21 @@ struct ChargeBalanceFunction { int rapphiy = rapbin2 * nphibins + phibin2; if ((sign_1 > 0 && sign_2 < 0) || (sign_1 < 0 && sign_2 > 0)) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corrfact); } else { if (sign_1 > 0 && sign_2 > 0) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corrfact); } else if (sign_1 < 0 && sign_2 < 0) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corrfact); } } } @@ -573,8 +584,13 @@ struct ChargeBalanceFunction { static constexpr auto SubDirRecGen = std::array{"Reco/", "McGen/"}; // Correction factor - float corrFact = getCorrectionFactor(track, sign); + float effCorr = getEffCorrectionFactor(track, sign); float nuaCorr = getNuaCorrectionFactor(track, sign); + float corrFact = effCorr; + + if (cDoEffNuaCorrection) { + corrFact *= nuaCorr; + } // Histograms if (sign > 0) { @@ -584,14 +600,15 @@ struct ChargeBalanceFunction { histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("NUA/h3f_n1_vzrapphi_P"), posz, track.eta(), track.phi()); // Checks - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_pt_P"), track.pt(), corrFact); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_rap_P"), track.eta(), corrFact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_pt_P"), track.pt(), effCorr); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_rap_P"), track.eta(), effCorr); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_phi_P"), track.phi(), nuaCorr); // R2 Rho1 (Eta,Phi) histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_rapphi_P"), cent, track.eta(), track.phi(), corrFact); // P2 Rho1 (Eta,Phi) + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2f_n1_pt_P"), cent, track.pt(), corrFact); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_pt_rapphi_P"), cent, track.eta(), track.phi(), track.pt() * corrFact); } else if (sign < 0) { // Corrections @@ -608,6 +625,7 @@ struct ChargeBalanceFunction { histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_rapphi_M"), cent, track.eta(), track.phi(), corrFact); // P2 Rho1 (Eta,Phi) + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2f_n1_pt_M"), cent, track.pt(), corrFact); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_pt_rapphi_M"), cent, track.eta(), track.phi(), track.pt() * corrFact); } } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx index 7d4222a57cf..bcf8852121d 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx @@ -123,36 +123,6 @@ DECLARE_SOA_TABLE(LambdaTracks, "AOD", "LAMBDATRACKS", o2::soa::Index<>, lambdatrack::CorrFact); using LambdaTrack = LambdaTracks::iterator; -namespace kaontrack -{ -DECLARE_SOA_INDEX_COLUMN(LambdaCollision, lambdaCollision); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Rap, rap, float); -DECLARE_SOA_COLUMN(Px, px, float); -DECLARE_SOA_COLUMN(Py, py, float); -DECLARE_SOA_COLUMN(Pz, pz, float); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(KaonTrackId, kaonTrackId, int64_t); -DECLARE_SOA_COLUMN(PartType, partType, int8_t); -DECLARE_SOA_COLUMN(CorrFact, corrFact, float); -} // namespace kaontrack -DECLARE_SOA_TABLE(KaonTracks, "AOD", "KAONTRACKS", o2::soa::Index<>, - kaontrack::LambdaCollisionId, - kaontrack::Pt, - kaontrack::Eta, - kaontrack::Phi, - kaontrack::Rap, - kaontrack::Px, - kaontrack::Py, - kaontrack::Pz, - kaontrack::Mass, - kaontrack::KaonTrackId, - kaontrack::PartType, - kaontrack::CorrFact); -using KaonTrack = KaonTracks::iterator; - namespace lambdatrackext { DECLARE_SOA_COLUMN(LambdaSharingDaughter, lambdaSharingDaughter, bool); @@ -166,18 +136,6 @@ DECLARE_SOA_TABLE(LambdaTracksExt, "AOD", "LAMBDATRACKSEXT", using LambdaTrackExt = LambdaTracksExt::iterator; -namespace kaontrackext -{ -DECLARE_SOA_COLUMN(KaonSharingLambdaDau, kaonSharingLambdaDau, bool); -DECLARE_SOA_COLUMN(KaonSharingLambdaDauIds, kaonSharingLambdaDauIds, std::vector); -DECLARE_SOA_COLUMN(TrueKaonFlag, trueKaonFlag, bool); -} // namespace kaontrackext -DECLARE_SOA_TABLE(KaonTracksExt, "AOD", "KAONTRACKSEXT", - kaontrackext::KaonSharingLambdaDau, - kaontrackext::KaonSharingLambdaDauIds, - kaontrackext::TrueKaonFlag); -using KaonTrackExt = KaonTracksExt::iterator; - namespace lambdamcgentrack { DECLARE_SOA_INDEX_COLUMN(LambdaMcGenCollision, lambdaMcGenCollision); @@ -197,25 +155,6 @@ DECLARE_SOA_TABLE(LambdaMcGenTracks, "AOD", "LMCGENTRACKS", o2::soa::Index<>, lambdatrack::PartType, lambdatrack::CorrFact); using LambdaMcGenTrack = LambdaMcGenTracks::iterator; - -namespace kaonmcgentrack -{ -DECLARE_SOA_INDEX_COLUMN(LambdaMcGenCollision, lambdaMcGenCollision); -} -DECLARE_SOA_TABLE(KaonMcGenTracks, "AOD", "KMCGENTRACKS", o2::soa::Index<>, - kaonmcgentrack::LambdaMcGenCollisionId, - kaontrack::Pt, - kaontrack::Eta, - kaontrack::Phi, - kaontrack::Rap, - kaontrack::Px, - kaontrack::Py, - kaontrack::Pz, - kaontrack::Mass, - kaontrack::KaonTrackId, - kaontrack::PartType, - kaontrack::CorrFact); -using KaonMcGenTrack = KaonMcGenTracks::iterator; } // namespace o2::aod enum CollisionLabels { @@ -236,15 +175,6 @@ enum LambdaLabels { kGenLambdaNoDau, }; -enum KaonLabels { - kKaonAllChargedTracks = 1, - kKaonPassKinSel, - kKaonPassGlobalSel, - kKaonPassDcaSel, - kKaonPassElRejSel, - kKaonPassAllSel -}; - enum EffCorrType { kEffCorrPtCent = 0, kEffCorrPtRapCent @@ -257,19 +187,13 @@ enum CentEstType { enum ParticleType { kLambda = 0, - kAntiLambda, - kKaonPlus, - kKaonMinus + kAntiLambda }; enum ParticlePairType { kLambdaAntiLambda = 0, kLambdaLambda, kAntiLambdaAntiLambda, - kLambdaKaonPlus, - kLambdaKaonMinus, - kAntiLambdaKaonPlus, - kAntiLambdaKaonMinus }; enum ShareDauLambda { @@ -291,10 +215,8 @@ struct LambdaTableProducer { // Table Producers Produces lambdaCollisionTable; Produces lambdaTrackTable; - Produces kaonTrackTable; Produces lambdaMCGenCollisionTable; Produces lambdaMCGenTrackTable; - Produces kaonMCGenTrackTable; // Centrality Axis ConfigurableAxis cCentBins{"cCentBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f}, "Variable Centrality Bins"}; @@ -314,21 +236,6 @@ struct LambdaTableProducer { Configurable cTpcNsigmaCut{"cTpcNsigmaCut", 3.0, "TPC NSigma Selection Cut"}; Configurable cRemoveAmbiguousTracks{"cRemoveAmbiguousTracks", false, "Remove Ambiguous Tracks"}; - // Kaon Tracks - Configurable cKaonMinPt{"cKaonMinPt", 0.3, "Kaon Min pT"}; - Configurable cKaonMaxPt{"cKaonMaxPt", 2.4, "Kaon Max pT"}; - Configurable cKaonRapCut{"cKaonRapCut", 0.5, "Kaon |y| cut"}; - Configurable cKaonGlobalSel{"cKaonGlobalSel", true, "Global Track"}; - Configurable cKaonDcaXYCut{"cKaonDcaXYCut", 0.1, "DcaXY Cut"}; - Configurable cKaonDcaZCut{"cKaonDcaZCut", 1., "DcaZ Cut"}; - Configurable cTpcElRejCutMin{"cTpcElRejCutMin", -3., "Electron Rejection Cut Minimum"}; - Configurable cTpcElRejCutMax{"cTpcElRejCutMax", 5., "Electron Rejection Cut Maximum"}; - Configurable cKaonTpcNSigmaCut{"cKaonTpcNSigmaCut", 2, "TPC Kaon NSigma Cut"}; - Configurable cTpcRejCut{"cTpcRejCut", 3, "TPC Rej Cut"}; - Configurable cKaonTofNSigmaCut{"cKaonTofNSigmaCut", 2, "TOF Kaon NSigma Cut"}; - Configurable cTofRejCut{"cTofRejCut", 3, "TOF Rej Cut"}; - Configurable cKaonTpcPtSel{"cKaonTpcPtSel", 0.7, "Kaon TPC pT cutoff"}; - // V0s Configurable cMinDcaProtonToPV{"cMinDcaProtonToPV", 0.02, "Minimum Proton DCAr to PV"}; Configurable cMinDcaPionToPV{"cMinDcaPionToPV", 0.06, "Minimum Pion DCAr to PV"}; @@ -372,19 +279,19 @@ struct LambdaTableProducer { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // Initialize corr_factor objects - std::vector> vCorrFactStrings = {{"hEffVsPtCentLambda", "hEffVsPtCentAntiLambda", "hEffVsPtCentKaonPlus", "hEffVsPtCentKaonMinus"}, {"hEffVsPtYCentLambda", "hEffVsPtYCentAntiLambda", "hEffVsPtYCentKaonPlus", "hEffVsPtYCentKaonMinus"}}; + std::vector> vCorrFactStrings = {{"hEffVsPtCentLambda", "hEffVsPtCentAntiLambda"}, {"hEffVsPtYCentLambda", "hEffVsPtYCentAntiLambda"}}; // Store correction histograms struct CorrHist { - std::array vPtCentCorrHists{}; - std::array vPtRapCentCorrHists{}; + std::array vPtCentCorrHists{}; + std::array vPtRapCentCorrHists{}; } corrHist; // Initialize Global Variables float cent = 0.; TList* ccdbObjRecoEff = nullptr; TList* ccdbObjMatchEff = nullptr; - static constexpr auto SubDir = std::array{"QA/Lambda/", "QA/AntiLambda/", "QA/KaonPlus/", "QA/KaonMinus/"}; + static constexpr auto SubDir = std::array{"QA/Lambda/", "QA/AntiLambda/"}; void init(InitContext const&) { @@ -404,7 +311,7 @@ struct LambdaTableProducer { const AxisSpec axisV0Eta(48, -1.2, 1.2, "#eta"); const AxisSpec axisV0Phi(36, 0., TwoPI, "#phi (rad)"); - const AxisSpec axisRadius(200, 0, 200, "r(cm)"); + const AxisSpec axisRadius(5000, 0, 5, "r(cm)"); const AxisSpec axisCosPA(100, 0.99, 1.0, "cos(#theta_{PA})"); const AxisSpec axisDcaV0PV(100, 0., 0.1, "dca (cm)"); const AxisSpec axisDcaProngPV(5000, -50., 50., "dca (cm)"); @@ -414,15 +321,12 @@ struct LambdaTableProducer { const AxisSpec axisQtarm(40, 0, 0.4, "q_{T}"); const AxisSpec axisDcaLambda(100, 0., cMaxDcaV0ToPV, "Dca_{V^{0}}"); - const AxisSpec axisDcaKaon(100, -cKaonDcaXYCut, cKaonDcaXYCut, "Dca_{K}"); - const AxisSpec axisITSTPCTrackPt(100, 0, 10, "p_{T} (GeV/#it{c})"); const AxisSpec axisTrackPt(40, 0, 4, "p_{T} (GeV/#it{c})"); const AxisSpec axisTrackDCA(200, -1, 1, "dca_{XY} (cm)"); const AxisSpec axisMomPID(80, 0, 4, "p_{T} (GeV/#it{c})"); const AxisSpec axisTrackNsigma(401, -10.025, 10.025, {"n#sigma"}); const AxisSpec axisTrackdEdx(360, 20, 200, "#frac{dE}{dx}"); - const AxisSpec axisTrackTofSignal(240, 0, 1.2, "#beta"); // Create Histograms. // Event histograms @@ -432,7 +336,6 @@ struct LambdaTableProducer { // QA histos.add("Tracks/h1f_lambda_info", "Lambda selection info", kTH1F, {axisTrks}); - histos.add("Tracks/h1f_kaon_info", "Kaon selection info", kTH1F, {axisTrks}); histos.add("Tracks/h1f_effcorr_info", "Efficiency correction info", kTH1F, {axisEffChecks}); histos.add("Tracks/h2f_armpod_before_sel", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); histos.add("Tracks/h2f_armpod_after_sel", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); @@ -458,13 +361,6 @@ struct LambdaTableProducer { // Dca analysis histogram histos.add("QA/Lambda/DCA/h3f_Dca_vs_pT_cent", "DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); - histos.add("QA/KaonPlus/DCA/h3f_Dca_vs_pT_cent", "DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); - - // QA Kaons - histos.add("QA/KaonPlus/hdEdX", "dE/dx vs pT", kTH2F, {axisMomPID, axisTrackdEdx}); - histos.add("QA/KaonPlus/hTOFSignal", "#beta_{TOF} vs p_{T}", kTH2F, {axisMomPID, axisTrackTofSignal}); - histos.add("QA/KaonPlus/hTPCNSigma", "n#sigma_{TPC} vs p_{T}", kTH2F, {axisMomPID, axisTrackNsigma}); - histos.add("QA/KaonPlus/hTOFNSigma", "n#sigma_{TOF} vs p_{T}", kTH2F, {axisMomPID, axisTrackNsigma}); // MC Generated Histograms if (doprocessMCRecoGen || doprocessMCReco) { @@ -472,9 +368,6 @@ struct LambdaTableProducer { histos.add("QA/Lambda/DCA/h3f_Prm_Dca_vs_pT_cent", "Primary DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); histos.add("QA/Lambda/DCA/h3f_Scd_Dca_vs_pT_cent", "Weak Decay DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); histos.add("QA/Lambda/DCA/h3f_Mat_Dca_vs_pT_cent", "Material DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); - histos.add("QA/KaonPlus/DCA/h3f_Prm_Dca_vs_pT_cent", "Primary DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); - histos.add("QA/KaonPlus/DCA/h3f_Scd_Dca_vs_pT_cent", "Weak Decay DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); - histos.add("QA/KaonPlus/DCA/h3f_Mat_Dca_vs_pT_cent", "Material DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); // McGen Histos histos.add("McGen/h1f_collision_recgen", "# of Reco Collision Associated to One Mc Generator Collision", kTH1F, {axisMult}); @@ -497,9 +390,6 @@ struct LambdaTableProducer { // QA Anti-Lambda histos.addClone("QA/Lambda/", "QA/AntiLambda/"); - // QA KaonMinus - histos.addClone("QA/KaonPlus/", "QA/KaonMinus/"); - // Set bin labels histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotCol, "kTotCol"); histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kPassSelCol, "kPassSelCol"); @@ -509,12 +399,6 @@ struct LambdaTableProducer { histos.get(HIST("Tracks/h1f_lambda_info"))->GetXaxis()->SetBinLabel(LambdaLabels::kPassV0KinCuts, "kPassV0KinCuts"); histos.get(HIST("Tracks/h1f_lambda_info"))->GetXaxis()->SetBinLabel(LambdaLabels::kPassV0TopoSel, "kPassV0TopoSel"); histos.get(HIST("Tracks/h1f_lambda_info"))->GetXaxis()->SetBinLabel(LambdaLabels::kAllSelPassed, "kAllSelPassed"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonAllChargedTracks, "kKaonAllChargedTracks"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassKinSel, "kKaonPassKinSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassGlobalSel, "kKaonPassGlobalSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassDcaSel, "kKaonPassDcaSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassElRejSel, "kKaonPassElRejSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassAllSel, "kKaonPassAllSel"); // Load correction factor if (cGetCorrectionFlag) { @@ -751,53 +635,6 @@ struct LambdaTableProducer { return true; } - template - bool selKaonTrack(T const& track, float const& rap) - { - // Kinematic selection - if (track.pt() <= cKaonMinPt || track.pt() >= cKaonMaxPt || std::abs(rap) >= cKaonRapCut) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassKinSel); - - // Global track selection - if (cKaonGlobalSel && !track.isGlobalTrackWoDCA()) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassGlobalSel); - - // Dca selection - if (std::abs(track.dcaXY()) >= cKaonDcaXYCut || std::abs(track.dcaZ()) >= cKaonDcaZCut) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassDcaSel); - - // Electron rejection - if (std::abs(track.tpcNSigmaPi()) > cTpcRejCut && std::abs(track.tpcNSigmaKa()) > cTpcRejCut && std::abs(track.tpcNSigmaPr()) > cTpcRejCut && track.tpcNSigmaEl() > cTpcElRejCutMin && track.tpcNSigmaEl() < cTpcElRejCutMax) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassElRejSel); - - // Kaon PID TPC + TOF - if (track.hasTOF()) { - if (std::abs(track.tofNSigmaKa()) >= cKaonTofNSigmaCut || std::abs(track.tofNSigmaPi()) < cTofRejCut || std::abs(track.tofNSigmaPr()) < cTofRejCut || std::abs(track.tpcNSigmaKa()) >= cKaonTpcNSigmaCut) { - return false; - } - } else { - if (track.pt() >= cKaonTpcPtSel || std::abs(track.tpcNSigmaKa()) >= cKaonTpcNSigmaCut || std::abs(track.tpcNSigmaPi()) < cTpcRejCut || std::abs(track.tpcNSigmaPr()) < cTpcRejCut) { - return false; - } - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassAllSel); - - return true; - } - // Correction factors template float getCorrectionFactors(V const& v, float const& rap) @@ -851,18 +688,6 @@ struct LambdaTableProducer { histos.fill(HIST(SubDir[part]) + HIST("h2f_neg_prong_tpc_nsigma_pi_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPi()); } - // Kaon QA - template - void fillKaonQA(T const& track) - { - histos.fill(HIST(SubDir[part]) + HIST("hdEdX"), track.pt(), track.tpcSignal()); - histos.fill(HIST(SubDir[part]) + HIST("hTPCNSigma"), track.pt(), track.tpcNSigmaKa()); - if (track.hasTOF()) { - histos.fill(HIST(SubDir[part]) + HIST("hTOFSignal"), track.pt(), track.beta()); - histos.fill(HIST(SubDir[part]) + HIST("hTOFNSigma"), track.pt(), track.tofNSigmaKa()); - } - } - // Dca analysis template void getDcaHist(T const& track, float const& dca) @@ -973,61 +798,6 @@ struct LambdaTableProducer { v0.template posTrack_as().index(), v0.template negTrack_as().index(), posTrackKin, negTrackKin, (int8_t)partType, lambdaCorrFact); } - - // Loop over tracks to select Kaon - float kaonCorrFact = 1.; - for (auto const& track : tracks) { - // Check corresponding MC particle - if constexpr (dmc == kMC) { - if (!track.has_mcParticle()) { - continue; - } - } - - // All charged tracks - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonAllChargedTracks); - - // Kaon rapidity - std::array mom = {track.px(), track.py(), track.pz()}; - float rap = RecoDecay::y(mom, MassKPlus); - if (!selKaonTrack(track, rap)) { // Kaon selection - continue; - } - - // MC matching - if constexpr (dmc == kMC) { - auto mcpart = track.mcParticle(); - if (cSelPrimaryParticle && !mcpart.isPhysicalPrimary()) { // Primary kaon selection - continue; - } - - if (cSelTrueParticle && std::abs(mcpart.pdgCode()) != kKPlus) { // True kaon selection - continue; - } - } - - // K+ / K- - if (track.sign() >= 0) { - getDcaHist(track, track.dcaXY()); - fillKaonQA(track); - partType = kKaonPlus; - } else if (track.sign() <= 0) { - getDcaHist(track, track.dcaXY()); - fillKaonQA(track); - partType = kKaonMinus; - } else { - continue; - } - - // Get Kaon correction factor - if (cGetCorrectionFlag) { - kaonCorrFact = (partType == kKaonPlus) ? getCorrectionFactors(track, rap) : getCorrectionFactors(track, rap); - } - - // Fill table - kaonTrackTable(lambdaCollisionTable.lastIndex(), track.pt(), track.eta(), track.phi(), rap, track.px(), track.py(), track.pz(), MassKaonCharged, - track.globalIndex(), (int8_t)partType, kaonCorrFact); - } } // MC Generater Level Tables @@ -1042,65 +812,46 @@ struct LambdaTableProducer { // Loop over MC particles for (auto const& mcpart : mcParticles) { - // Check for Primary Lambda/Anti-Lambda/K+/K- + // Check for Primary Lambda/Anti-Lambda if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kLambda0) { partType = kLambda; } else if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kLambda0Bar) { partType = kAntiLambda; - } else if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kKPlus) { - partType = kKaonPlus; - } else if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kKMinus) { - partType = kKaonMinus; } else { continue; } - // Fill Lambda Table - if (partType == kLambda || partType == kAntiLambda) { - // Kinematic selection - if (mcpart.pt() <= cLambdaMinPt || mcpart.pt() >= cLambdaMaxPt || std::abs(mcpart.y()) >= cLambdaRapCut) { - continue; - } + // Kinematic selection + if (mcpart.pt() <= cLambdaMinPt || mcpart.pt() >= cLambdaMaxPt || std::abs(mcpart.y()) >= cLambdaRapCut) { + continue; + } - histos.fill(HIST("Tracks/h1f_lambda_info"), kGenTotAccLambda); + histos.fill(HIST("Tracks/h1f_lambda_info"), kGenTotAccLambda); - // get daughter track info and check for decay channel flag - if (!mcpart.has_daughters()) { - histos.fill(HIST("Tracks/h1f_lambda_info"), kGenLambdaNoDau); - continue; - } - auto dautracks = mcpart.template daughters_as(); - std::vector daughterPDGs, daughterIDs; - for (auto const& dautrack : dautracks) { - daughterPDGs.push_back(dautrack.pdgCode()); - daughterIDs.push_back(dautrack.globalIndex()); - } - - if (partType == kLambda) { - histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[0]); - histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[1]); - histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), mcpart.pdgCode()); - } else { - histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[0]); - histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[1]); - histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), mcpart.pdgCode()); - } - // Fill table - lambdaMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), mcpart.px(), mcpart.py(), mcpart.pz(), RecoDecay::m(mcpart.p(), mcpart.e()), - daughterIDs[0], daughterIDs[1], (int8_t)partType, 1.); + // get daughter track info and check for decay channel flag + if (!mcpart.has_daughters()) { + histos.fill(HIST("Tracks/h1f_lambda_info"), kGenLambdaNoDau); + continue; + } + auto dautracks = mcpart.template daughters_as(); + std::vector daughterPDGs, daughterIDs; + for (auto const& dautrack : dautracks) { + daughterPDGs.push_back(dautrack.pdgCode()); + daughterIDs.push_back(dautrack.globalIndex()); } - // Fill Kaon Table - if (partType == kKaonPlus || partType == kKaonMinus) { - // Kinematic selection - if (mcpart.pt() <= cKaonMinPt || mcpart.pt() >= cKaonMaxPt || std::abs(mcpart.y()) >= cKaonRapCut) { - continue; - } - - // Fill table - kaonMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), mcpart.px(), mcpart.py(), mcpart.pz(), RecoDecay::m(mcpart.p(), mcpart.e()), - mcpart.globalIndex(), (int8_t)partType, 1.); + if (partType == kLambda) { + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[0]); + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[1]); + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), mcpart.pdgCode()); + } else { + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[0]); + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[1]); + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), mcpart.pdgCode()); } + // Fill table + lambdaMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), mcpart.px(), mcpart.py(), mcpart.pz(), RecoDecay::m(mcpart.p(), mcpart.e()), + daughterIDs[0], daughterIDs[1], (int8_t)partType, 1.); } } @@ -1177,13 +928,10 @@ struct LambdaTableProducer { struct LambdaTracksExtProducer { // Tables Produces lambdaTrackExtTable; - Produces kaonTrackExtTable; // Configurables Configurable cAcceptAllLambda{"cAcceptAllLambda", false, "Accept all Lambda"}; Configurable cRejAllLambdaShaDau{"cRejAllLambdaShaDau", true, "Reject all Lambda sharing daughters"}; - Configurable cAcceptAllKaon{"cAcceptAllKaon", false, "Accept all Kaons"}; - Configurable cRejAllKaonShaLaDau{"cRejAllKaonShaLaDau", true, "Reject all Kaons sharing Lambda daughters"}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -1200,20 +948,9 @@ struct LambdaTracksExtProducer { histos.add("h1i_totantilambda_mult", "Multiplicity", kTH1I, {axisMult}); histos.add("h1i_lambda_mult", "Multiplicity", kTH1I, {axisMult}); histos.add("h1i_antilambda_mult", "Multiplicity", kTH1I, {axisMult}); - - histos.add("h1i_totkaplus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h1i_totkaminus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h1i_kaplus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h1i_kaminus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h2d_n2_etaphi_LaP_LaM", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); histos.add("h2d_n2_etaphi_LaP_LaP", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); histos.add("h2d_n2_etaphi_LaM_LaM", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); - - histos.add("h2d_n2_etaphi_KaPLaP", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); - histos.add("h2d_n2_etaphi_KaPLaM", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); - histos.add("h2d_n2_etaphi_KaMLaP", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); - histos.add("h2d_n2_etaphi_KaMLaM", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); } void processDummy(aod::LambdaCollisions::iterator const&) {} @@ -1291,75 +1028,6 @@ struct LambdaTracksExtProducer { } PROCESS_SWITCH(LambdaTracksExtProducer, processLambdaTrackExt, "Process for lambda track extension", false); - - void processKaonTrackExt(aod::LambdaCollisions::iterator const&, aod::LambdaTracks const& lambdaTracks, aod::KaonTracks const& kaonTracks) - { - int nTotKaonPlus = 0, nTotKaonMinus = 0, nSelKaonPlus = 0, nSelKaonMinus = 0; - - for (auto const& kaonTrack : kaonTracks) { - bool kaonSharingLambdaDauFlag = false, trueKaonFlag = false; - std::vector vKaonShareDauLambdaIndex; - - if (kaonTrack.partType() == kKaonPlus) { - ++nTotKaonPlus; - } else if (kaonTrack.partType() == kKaonMinus) { - ++nTotKaonMinus; - } - - for (auto const& lambdaTrack : lambdaTracks) { - // Removal based on shared track index - if (kaonTrack.kaonTrackId() == lambdaTrack.posTrackId() || kaonTrack.kaonTrackId() == lambdaTrack.negTrackId()) { - vKaonShareDauLambdaIndex.push_back(kaonTrack.kaonTrackId()); - kaonSharingLambdaDauFlag = true; - - // Fill Deta-Dphi Histogram - if (kaonTrack.partType() == kKaonPlus && lambdaTrack.partType() == kLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaPLaP"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } else if (kaonTrack.partType() == kKaonPlus && lambdaTrack.partType() == kAntiLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaPLaM"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } else if (kaonTrack.partType() == kKaonMinus && lambdaTrack.partType() == kLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaMLaP"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } else if (kaonTrack.partType() == kKaonMinus && lambdaTrack.partType() == kAntiLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaMLaM"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } - } - } - - // Accept / Reject - trueKaonFlag = cAcceptAllKaon || (cRejAllKaonShaLaDau && !kaonSharingLambdaDauFlag); - - // Multiplicity of selected kaons - if (trueKaonFlag) { - if (kaonTrack.partType() == kKaonPlus) { - ++nSelKaonPlus; - } else if (kaonTrack.partType() == kKaonMinus) { - ++nSelKaonMinus; - } - } - - // Fill LambdaTrackExt table - kaonTrackExtTable(kaonSharingLambdaDauFlag, vKaonShareDauLambdaIndex, trueKaonFlag); - } - - // Fill multiplicity histograms - if (nTotKaonPlus != 0) { - histos.fill(HIST("h1i_totkaplus_mult"), nTotKaonPlus); - } - - if (nTotKaonMinus != 0) { - histos.fill(HIST("h1i_totkaminus_mult"), nTotKaonMinus); - } - - if (nSelKaonPlus != 0) { - histos.fill(HIST("h1i_kaplus_mult"), nSelKaonPlus); - } - - if (nSelKaonMinus != 0) { - histos.fill(HIST("h1i_kaminus_mult"), nSelKaonMinus); - } - } - - PROCESS_SWITCH(LambdaTracksExtProducer, processKaonTrackExt, "Process for kaon track extension", false); }; struct LambdaR2Correlation { @@ -1367,9 +1035,6 @@ struct LambdaR2Correlation { Configurable cLambdaNPtBins{"cLambdaNPtBins", 34, "N pT Bins"}; Configurable cLambdaPtMin{"cLambdaPtMin", 0.7, "Lambda pT Min"}; Configurable cLambdaPtMax{"cLambdaPtMax", 3.4, "Lambda pT Max"}; - Configurable cKaonNPtBins{"cKaonNPtBins", 20, "N pT Bins"}; - Configurable cKaonPtMin{"cKaonPtMin", 0.3, "Kaon pT Min"}; - Configurable cKaonPtMax{"cKaonPtMax", 2.2, "Kaon pT Max"}; Configurable cNRapBins{"cNRapBins", 10, "N Rapidity Bins"}; Configurable cMinRap{"cMinRap", -0.5, "Minimum Rapidity"}; @@ -1382,7 +1047,7 @@ struct LambdaR2Correlation { // Lambda Kaon femtoscopic correction Configurable cApplyFemtoSel{"cApplyFemtoSel", false, "Femto qinv selection"}; - Configurable cFemtoCut{"cFemtoCut", 0.1, "Kaon--Lambda Femto qinv cut"}; + Configurable cFemtoCut{"cFemtoCut", 0.1, "Femto qinv cut"}; // Lambda Kaon two-track cuts Configurable cApplyTwoTrackCut{"cApplyTwoTrackCut", false, "Flag for two track cut"}; @@ -1434,8 +1099,6 @@ struct LambdaR2Correlation { const AxisSpec axisDPhi(640, -PIHalf, 3. * PIHalf, "#Delta#varphi"); const AxisSpec axisMass(100, 1.06, 1.16, "M_{#Lambda} (GeV/#it{c}^{2})"); const AxisSpec axisPtLambda(cLambdaNPtBins, cLambdaPtMin, cLambdaPtMax, "p_{T} (GeV/#it{c})"); - const AxisSpec axisPtKaon(cKaonNPtBins, cKaonPtMin, cKaonPtMax, "p_{T} (GeV/#it{c})"); - const AxisSpec axisEta(cNRapBins, cMinRap, cMaxRap, "#eta"); const AxisSpec axisRap(cNRapBins, cMinRap, cMaxRap, "y"); const AxisSpec axisPhi(cNPhiBins, 0., TwoPI, "#varphi (rad)"); const AxisSpec axisRapPhi(knrapphibins, kminrapphi, kmaxrapphi, "y #varphi"); @@ -1444,7 +1107,6 @@ struct LambdaR2Correlation { // Event histos.add("Event/Reco/h1f_collision_posz", "V_{Z} Distribution", kTH1F, {axisPosZ}); histos.add("Event/Reco/h1f_ft0m_mult_percentile", "FT0M (%)", kTH1F, {axisCent}); - histos.add("Event/Reco/h2f_Mult_vs_Centrality", "N_{ch} vs FT0M(%)", kTProfile, {axisCent}); // Two track cut histos.add("QA/TwoTrackCut/Before/h2d_n2_detadphi", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); @@ -1457,16 +1119,10 @@ struct LambdaR2Correlation { if (cAnaEff) { histos.add("Reco/Efficiency/h2f_n1_centpt_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisPtLambda}); histos.add("Reco/Efficiency/h2f_n1_centpt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisPtLambda}); - histos.add("Reco/Efficiency/h2f_n1_centpt_KaP", "#rho_{1}^{K^{#plus}}", kTH2F, {axisCent, axisPtKaon}); - histos.add("Reco/Efficiency/h2f_n1_centpt_KaM", "#rho_{1}^{K^{#minus}}", kTH2F, {axisCent, axisPtKaon}); histos.add("Reco/Efficiency/h3f_n1_centptrap_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPtLambda, axisRap}); histos.add("Reco/Efficiency/h3f_n1_centptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPtLambda, axisRap}); - histos.add("Reco/Efficiency/h3f_n1_centptrap_KaP", "#rho_{1}^{K^{#plus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); - histos.add("Reco/Efficiency/h3f_n1_centptrap_KaM", "#rho_{1}^{K^{#minus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); histos.add("Reco/Efficiency/h4f_n1_centvzptrap_LaP", "#rho_{1}^{#Lambda}", kTHnSparseF, {axisCent, axisVz, axisPtLambda, axisRap}); histos.add("Reco/Efficiency/h4f_n1_centvzptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTHnSparseF, {axisCent, axisVz, axisPtLambda, axisRap}); - histos.add("Reco/Efficiency/h4f_n1_centvzptrap_KaP", "#rho_{1}^{K^{#plus}}", kTHnSparseF, {axisCent, axisVz, axisPtKaon, axisRap}); - histos.add("Reco/Efficiency/h4f_n1_centvzptrap_KaM", "#rho_{1}^{K^{#minus}}", kTHnSparseF, {axisCent, axisVz, axisPtKaon, axisRap}); } // Single and Two Particle Densities @@ -1475,24 +1131,16 @@ struct LambdaR2Correlation { histos.add("Reco/h3f_n1_centptmass_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPtLambda, axisMass}); histos.add("Reco/h3f_n1_centptrap_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPtLambda, axisRap}); histos.add("Reco/h3f_n1_centptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPtLambda, axisRap}); - histos.add("Reco/h3f_n1_centptrap_KaP", "#rho_{1}^{K^{#plus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); - histos.add("Reco/h3f_n1_centptrap_KaM", "#rho_{1}^{K^{#minus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); // rho1 for R2 RapPhi histos.add("Reco/h3f_n1_rapphi_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisRap, axisPhi}); histos.add("Reco/h3f_n1_rapphi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisRap, axisPhi}); - histos.add("Reco/h3f_n1_rapphi_KaP", "#rho_{1}^{K^{#plus}}", kTH3F, {axisCent, axisRap, axisPhi}); - histos.add("Reco/h3f_n1_rapphi_KaM", "#rho_{1}^{K^{#minus}}", kTH3F, {axisCent, axisRap, axisPhi}); if (cAnaPairs) { // rho2 for R2 Rap1Phi1Rap2Phi2 histos.add("Reco/h3f_n2_rapphi_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); histos.add("Reco/h3f_n2_rapphi_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); histos.add("Reco/h3f_n2_rapphi_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaP_KaM", "#rho_{2}^{#LambdaK^{#minus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaP_KaP", "#rho_{2}^{#LambdaK^{#plus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaM_KaM", "#rho_{2}^{#bar{#Lambda}K^{#plus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaM_KaP", "#rho_{2}^{#bar{#Lambda}K^{#minus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); } // MCGen @@ -1531,29 +1179,24 @@ struct LambdaR2Correlation { return (std::abs(deta) < cDEtaCut && std::abs(dphistar) < cDPhiStarCut); } - template - bool isClosePair(V const& lambda, T const& track) + template + bool isClosePair(V const& l1, V const& l2) { // Before - histos.fill(HIST("QA/TwoTrackCut/Before/h2d_n2_detadphi"), track.eta() - lambda.eta(), RecoDecay::constrainAngle(track.phi() - lambda.phi(), -PIHalf)); - - // Close pair flag - bool retFlag = false; + histos.fill(HIST("QA/TwoTrackCut/Before/h2d_n2_detadphi"), l1.eta() - l2.eta(), RecoDecay::constrainAngle(l1.phi() - l2.phi(), -PIHalf)); // Assign kinematics - std::array trackKin = {track.pt(), track.eta(), track.phi()}; - std::array lambdaPosTrackKin = {lambda.posTrackKin()[0], lambda.posTrackKin()[1], lambda.posTrackKin()[2]}; - std::array lambdaNegTrackKin = {lambda.negTrackKin()[0], lambda.negTrackKin()[1], lambda.negTrackKin()[2]}; - - if (track.partType() == kKaonPlus) { - retFlag = checkClosePair(trackKin, lambdaPosTrackKin, 1, 1) || checkClosePair(trackKin, lambdaNegTrackKin, 1, -1); - } else if (track.partType() == kKaonMinus) { - retFlag = checkClosePair(trackKin, lambdaPosTrackKin, -1, 1) || checkClosePair(trackKin, lambdaNegTrackKin, -1, -1); - } + std::array posTrackKinLambda1 = {l1.posTrackKin()[0], l1.posTrackKin()[1], l1.posTrackKin()[2]}; + std::array negTrackKinLambda1 = {l1.negTrackKin()[0], l1.negTrackKin()[1], l1.negTrackKin()[2]}; + std::array posTrackKinLambda2 = {l2.posTrackKin()[0], l2.posTrackKin()[1], l2.posTrackKin()[2]}; + std::array negTrackKinLambda2 = {l2.negTrackKin()[0], l2.negTrackKin()[1], l2.negTrackKin()[2]}; + + // Check close pair + bool retFlag = checkClosePair(posTrackKinLambda1, posTrackKinLambda2, 1, 1) && checkClosePair(negTrackKinLambda1, negTrackKinLambda2, -1, -1); // Fill QA if (!retFlag) { // Pair accept - histos.fill(HIST("QA/TwoTrackCut/After/h2d_n2_detadphi"), track.eta() - lambda.eta(), RecoDecay::constrainAngle(track.phi() - lambda.phi(), -PIHalf)); + histos.fill(HIST("QA/TwoTrackCut/After/h2d_n2_detadphi"), l1.eta() - l2.eta(), RecoDecay::constrainAngle(l1.phi() - l2.phi(), -PIHalf)); } // Pair reject @@ -1585,7 +1228,7 @@ struct LambdaR2Correlation { void fillPairHistos(T1& p1, T2& p2) { static constexpr auto SubDirRecGen = std::array{"Reco/", "McGen/"}; - static constexpr auto SubDirHist = std::array{"LaP_LaM", "LaP_LaP", "LaM_LaM", "LaP_KaP", "LaP_KaM", "LaM_KaP", "LaM_KaM", "KaP_KaM", "KaP_KaP", "KaM_KaM"}; + static constexpr auto SubDirHist = std::array{"LaP_LaM", "LaP_LaP", "LaM_LaM"}; const auto rapbin1 = static_cast((p1.rap() - kminrap) / rapbinwidth); const auto rapbin2 = static_cast((p2.rap() - kminrap) / rapbinwidth); @@ -1608,7 +1251,7 @@ struct LambdaR2Correlation { void analyzeSingles(T const& tracks) { static constexpr auto SubDirRecGen = std::array{"Reco/", "McGen/"}; - static constexpr auto SubDirHist = std::array{"LaP", "LaM", "KaP", "KaM"}; + static constexpr auto SubDirHist = std::array{"LaP", "LaM"}; for (auto const& track : tracks) { // Efficiency Plots @@ -1619,9 +1262,7 @@ struct LambdaR2Correlation { } // QA Plots - if (part == kLambda || part == kAntiLambda) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_centptmass_") + HIST(SubDirHist[part]), cent, track.pt(), track.mass()); - } + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_centptmass_") + HIST(SubDirHist[part]), cent, track.pt(), track.mass()); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_centptrap_") + HIST(SubDirHist[part]), cent, track.pt(), track.rap(), track.corrFact()); // Rho1 for N1RapPhi @@ -1639,17 +1280,15 @@ struct LambdaR2Correlation { continue; } - // Lambda-Kaon close pair rejection + // Lambda close pair rejection if constexpr (rec_gen == kRec) { - if constexpr (partpair == kLambdaKaonPlus || partpair == kLambdaKaonMinus || partpair == kAntiLambdaKaonPlus || partpair == kAntiLambdaKaonMinus) { - // Close pair - if (cApplyTwoTrackCut && isClosePair(trk_1, trk_2)) { - continue; - } - // Femto selection - if (cApplyFemtoSel && isCloseQinv(trk_1, trk_2)) { - continue; - } + // Close pair + if (cApplyTwoTrackCut && isClosePair(trk_1, trk_2)) { + continue; + } + // Femto selection + if (cApplyFemtoSel && isCloseQinv(trk_1, trk_2)) { + continue; } } @@ -1661,19 +1300,16 @@ struct LambdaR2Correlation { using LambdaCollisions = aod::LambdaCollisions; using LambdaTracks = soa::Join; - using KaonTracks = soa::Join; SliceCache cache; Partition partLambdaTracks = (aod::lambdatrack::partType == (int8_t)kLambda) && (aod::lambdatrackext::trueLambdaFlag == true); Partition partAntiLambdaTracks = (aod::lambdatrack::partType == (int8_t)kAntiLambda) && (aod::lambdatrackext::trueLambdaFlag == true); - Partition partKaonPlusTracks = (aod::kaontrack::partType == (int8_t)kKaonPlus) && (aod::kaontrackext::trueKaonFlag == true); - Partition partKaonMinusTracks = (aod::kaontrack::partType == (int8_t)kKaonMinus) && (aod::kaontrackext::trueKaonFlag == true); void processDummy(aod::LambdaCollisions::iterator const&) {} PROCESS_SWITCH(LambdaR2Correlation, processDummy, "Dummy Process", true); - void processDataReco(LambdaCollisions::iterator const& collision, LambdaTracks const&, KaonTracks const&) + void processDataReco(LambdaCollisions::iterator const& collision, LambdaTracks const&) { histos.fill(HIST("Event/Reco/h1f_collision_posz"), collision.posZ()); histos.fill(HIST("Event/Reco/h1f_ft0m_mult_percentile"), collision.cent()); @@ -1684,23 +1320,15 @@ struct LambdaR2Correlation { auto lambdaTracks = partLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); auto antiLambdaTracks = partAntiLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - auto kaonPlusTracks = partKaonPlusTracks->sliceByCached(aod::kaontrack::lambdaCollisionId, collision.globalIndex(), cache); - auto kaonMinusTracks = partKaonMinusTracks->sliceByCached(aod::kaontrack::lambdaCollisionId, collision.globalIndex(), cache); analyzeSingles(lambdaTracks); analyzeSingles(antiLambdaTracks); - analyzeSingles(kaonPlusTracks); - analyzeSingles(kaonMinusTracks); if (cAnaPairs) { // Pairs Only analyzePairs(lambdaTracks, antiLambdaTracks); analyzePairs(lambdaTracks, lambdaTracks); analyzePairs(antiLambdaTracks, antiLambdaTracks); - analyzePairs(lambdaTracks, kaonPlusTracks); - analyzePairs(lambdaTracks, kaonMinusTracks); - analyzePairs(antiLambdaTracks, kaonPlusTracks); - analyzePairs(antiLambdaTracks, kaonMinusTracks); } } @@ -1708,15 +1336,12 @@ struct LambdaR2Correlation { using LambdaMcGenCollisions = aod::LambdaMcGenCollisions; using LambdaMcGenTracks = aod::LambdaMcGenTracks; - using KaonMcGenTracks = aod::KaonMcGenTracks; SliceCache cachemc; Partition partMcLambdaTracks = (aod::lambdatrack::partType == (int8_t)kLambda); Partition partMcAntiLambdaTracks = (aod::lambdatrack::partType == (int8_t)kAntiLambda); - Partition partMcKaonPlusTracks = (aod::kaontrack::partType == (int8_t)kKaonPlus); - Partition partMcKaonMinusTracks = (aod::kaontrack::partType == (int8_t)kKaonMinus); - void processMCGen(LambdaMcGenCollisions::iterator const& mcgencol, LambdaMcGenTracks const&, KaonMcGenTracks const&) + void processMCGen(LambdaMcGenCollisions::iterator const& mcgencol, LambdaMcGenTracks const&) { histos.fill(HIST("Event/McGen/h1f_collision_posz"), mcgencol.posZ()); histos.fill(HIST("Event/McGen/h1f_ft0m_mult_percentile"), mcgencol.cent()); @@ -1726,22 +1351,14 @@ struct LambdaR2Correlation { auto lambdaTracks = partMcLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); auto antiLambdaTracks = partMcAntiLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); - auto kaonPlusTracks = partMcKaonPlusTracks->sliceByCached(aod::kaonmcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); - auto kaonMinusTracks = partMcKaonMinusTracks->sliceByCached(aod::kaonmcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); analyzeSingles(lambdaTracks); analyzeSingles(antiLambdaTracks); - analyzeSingles(kaonPlusTracks); - analyzeSingles(kaonMinusTracks); if (cAnaPairs) { analyzePairs(lambdaTracks, antiLambdaTracks); analyzePairs(lambdaTracks, lambdaTracks); analyzePairs(antiLambdaTracks, antiLambdaTracks); - analyzePairs(lambdaTracks, kaonPlusTracks); - analyzePairs(lambdaTracks, kaonMinusTracks); - analyzePairs(antiLambdaTracks, kaonPlusTracks); - analyzePairs(antiLambdaTracks, kaonMinusTracks); } } diff --git a/PWGDQ/Core/MCProng.cxx b/PWGDQ/Core/MCProng.cxx index ee95463839d..611db4bcd5c 100644 --- a/PWGDQ/Core/MCProng.cxx +++ b/PWGDQ/Core/MCProng.cxx @@ -92,19 +92,19 @@ MCProng::MCProng(int n, int m) : fNGenerations(n), } //________________________________________________________________________________________________________________ -MCProng::MCProng(int n, const std::vector pdgs, const std::vector checkBothCharges, const std::vector excludePDG, - const std::vector sourceBits, const std::vector excludeSource, - const std::vector useANDonSourceBitMap, bool checkGenerationsInTime, - const std::vector checkIfPDGInHistory, const std::vector excludePDGInHistory) : fNGenerations(n), - fPDGcodes(pdgs), - fCheckBothCharges(checkBothCharges), - fExcludePDG(excludePDG), - fSourceBits(sourceBits), - fExcludeSource(excludeSource), - fUseANDonSourceBitMap(useANDonSourceBitMap), - fCheckGenerationsInTime(checkGenerationsInTime), - fPDGInHistory(checkIfPDGInHistory), - fExcludePDGInHistory(excludePDGInHistory) {} +MCProng::MCProng(int n, const std::vector& pdgs, const std::vector& checkBothCharges, const std::vector& excludePDG, + const std::vector& sourceBits, const std::vector& excludeSource, + const std::vector& useANDonSourceBitMap, bool checkGenerationsInTime, + const std::vector& checkIfPDGInHistory, const std::vector& excludePDGInHistory) : fNGenerations(n), + fPDGcodes(pdgs), + fCheckBothCharges(checkBothCharges), + fExcludePDG(excludePDG), + fSourceBits(sourceBits), + fExcludeSource(excludeSource), + fUseANDonSourceBitMap(useANDonSourceBitMap), + fCheckGenerationsInTime(checkGenerationsInTime), + fPDGInHistory(checkIfPDGInHistory), + fExcludePDGInHistory(excludePDGInHistory) {} //________________________________________________________________________________________________________________ void MCProng::SetPDGcode(int generation, int code, bool checkBothCharges /*= false*/, bool exclude /*= false*/) diff --git a/PWGDQ/Core/MCProng.h b/PWGDQ/Core/MCProng.h index 7d795834855..5db3b8feb1a 100644 --- a/PWGDQ/Core/MCProng.h +++ b/PWGDQ/Core/MCProng.h @@ -89,9 +89,9 @@ class MCProng MCProng(); explicit MCProng(int n); MCProng(int n, int m); - MCProng(int n, std::vector pdgs, std::vector checkBothCharges, std::vector excludePDG, - std::vector sourceBits, std::vector excludeSource, std::vector useANDonSourceBitMap, - bool checkGenerationsInTime = false, std::vector checkIfPDGInHistory = {}, std::vector excludePDGInHistory = {}); + MCProng(int n, const std::vector& pdgs, const std::vector& checkBothCharges, const std::vector& excludePDG, + const std::vector& sourceBits, const std::vector& excludeSource, const std::vector& useANDonSourceBitMap, + bool checkGenerationsInTime = false, const std::vector& checkIfPDGInHistory = {}, const std::vector& excludePDGInHistory = {}); MCProng(const MCProng& c) = default; virtual ~MCProng() = default; diff --git a/PWGDQ/Core/MCSignal.cxx b/PWGDQ/Core/MCSignal.cxx index 20e510b0662..2068d426a70 100644 --- a/PWGDQ/Core/MCSignal.cxx +++ b/PWGDQ/Core/MCSignal.cxx @@ -19,6 +19,7 @@ #include #include +#include #include using std::cout; @@ -52,28 +53,28 @@ MCSignal::MCSignal(int nProngs, const char* name /*= ""*/, const char* title /*= } //________________________________________________________________________________________________ -MCSignal::MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors, bool excludeCommonAncestor) : TNamed(name, title), - fProngs(prongs), - fNProngs(prongs.size()), - fCommonAncestorIdxs(commonAncestors), - fExcludeCommonAncestor(excludeCommonAncestor), - fDecayChannelIsExclusive(false), - fDecayChannelIsNotExclusive(false), - fNAncestorDirectProngs(0), - fTempAncestorLabel(-1) +MCSignal::MCSignal(const char* name, const char* title, const std::vector& prongs, std::vector commonAncestors, bool excludeCommonAncestor) : TNamed(name, title), + fProngs(prongs), + fNProngs(prongs.size()), + fCommonAncestorIdxs(std::move(commonAncestors)), + fExcludeCommonAncestor(excludeCommonAncestor), + fDecayChannelIsExclusive(false), + fDecayChannelIsNotExclusive(false), + fNAncestorDirectProngs(0), + fTempAncestorLabel(-1) { } //________________________________________________________________________________________________ void MCSignal::SetProngs(std::vector prongs, std::vector commonAncestors) { - fProngs = prongs; + fProngs = std::move(prongs); fNProngs = fProngs.size(); - fCommonAncestorIdxs = commonAncestors; + fCommonAncestorIdxs = std::move(commonAncestors); } //________________________________________________________________________________________________ -void MCSignal::AddProng(MCProng prong, int8_t commonAncestor) +void MCSignal::AddProng(const MCProng& prong, int8_t commonAncestor) { if (fProngs.size() < fNProngs) { fProngs.push_back(prong); diff --git a/PWGDQ/Core/MCSignal.h b/PWGDQ/Core/MCSignal.h index f13f9657fbd..476fb4b8751 100644 --- a/PWGDQ/Core/MCSignal.h +++ b/PWGDQ/Core/MCSignal.h @@ -68,12 +68,12 @@ class MCSignal : public TNamed public: MCSignal(); MCSignal(int nProngs, const char* name = "", const char* title = ""); // NOLINT - MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors, bool excludeCommonAncestor = false); + MCSignal(const char* name, const char* title, const std::vector& prongs, std::vector commonAncestors, bool excludeCommonAncestor = false); MCSignal(const MCSignal& c) = default; ~MCSignal() override = default; void SetProngs(std::vector prongs, std::vector commonAncestors); - void AddProng(MCProng prong, int8_t commonAncestor = -1); + void AddProng(const MCProng& prong, int8_t commonAncestor = -1); void SetDecayChannelIsExclusive(int nProngs, bool option = true) { fDecayChannelIsExclusive = option; diff --git a/PWGDQ/Core/MixingHandler.cxx b/PWGDQ/Core/MixingHandler.cxx index 962032ca864..7d3a8e49f62 100644 --- a/PWGDQ/Core/MixingHandler.cxx +++ b/PWGDQ/Core/MixingHandler.cxx @@ -58,7 +58,7 @@ MixingHandler::~MixingHandler() } //_________________________________________________________________________ -void MixingHandler::AddMixingVariable(int var, std::vector binLims) +void MixingHandler::AddMixingVariable(int var, const std::vector& binLims) { fVariables[var] = fVariableLimits.size(); fVariableLimits.push_back(binLims); diff --git a/PWGDQ/Core/MixingHandler.h b/PWGDQ/Core/MixingHandler.h index 8a6f8597db8..931db50f8a2 100644 --- a/PWGDQ/Core/MixingHandler.h +++ b/PWGDQ/Core/MixingHandler.h @@ -174,7 +174,7 @@ class MixingHandler : public TNamed virtual ~MixingHandler(); // setters - void AddMixingVariable(int var, std::vector binLims); + void AddMixingVariable(int var, const std::vector& binLims); void SetPoolDepth(int16_t depth) { fPoolDepth = depth; } // getters diff --git a/PWGDQ/Macros/dqFlowAccWeights.C b/PWGDQ/Macros/dqFlowAccWeights.C index d4786089810..3d9018b7f3d 100644 --- a/PWGDQ/Macros/dqFlowAccWeights.C +++ b/PWGDQ/Macros/dqFlowAccWeights.C @@ -32,7 +32,7 @@ using namespace o2; using namespace std; -void dqFlowAccWeights(int64_t tmin = 1546300800000, int64_t tmax = 1577833200000, std::string Period = "LHC23zzh_pass2", std::string SubDir = "d-q-event-qvector", std::string FileName = "AnalysisResults.root") +void dqFlowAccWeights(int64_t tmin = 1546300800000, int64_t tmax = 1577833200000, const std::string& Period = "LHC23zzh_pass2", const std::string& SubDir = "d-q-event-qvector", const std::string& FileName = "AnalysisResults.root") { if (tmax < tmin) { LOG(fatal) << "Wrong validity syntax!"; diff --git a/PWGDQ/TableProducer/tableMaker.cxx b/PWGDQ/TableProducer/tableMaker.cxx index f2938705e87..15edcac01ec 100644 --- a/PWGDQ/TableProducer/tableMaker.cxx +++ b/PWGDQ/TableProducer/tableMaker.cxx @@ -1246,7 +1246,7 @@ struct TableMaker { } // end if constexpr (TMuonFillMap) } // end fullSkimming() - void DefineHistograms(TString histClasses) + void DefineHistograms(const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/TableProducer/tableMakerMC.cxx b/PWGDQ/TableProducer/tableMakerMC.cxx index 8a2d93f9f89..41e26e1a374 100644 --- a/PWGDQ/TableProducer/tableMakerMC.cxx +++ b/PWGDQ/TableProducer/tableMakerMC.cxx @@ -1534,7 +1534,7 @@ struct TableMakerMC { fEventLabels.clear(); } - void DefineHistograms(TString histClasses) + void DefineHistograms(const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx index 84d9a42bbbc..a499141f60d 100644 --- a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx +++ b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx @@ -246,7 +246,7 @@ struct tableMakerMuonMchTrkEfficiency { /// extrapolate tracks to a given r value (spherical coordinates) /// to mimic the (x,y) position in a given chamber - void extrapolate(TLorentzVector vec, int ich, double& x, double& y) + void extrapolate(const TLorentzVector& vec, int ich, double& x, double& y) { // i = 0..9 double zposCh[10] = {5, 5, 7, 7, 10, 10, 12.5, 12.5, 14.5, 14.5}; double theta = vec.Theta(); @@ -396,7 +396,7 @@ struct tableMakerMuonMchTrkEfficiency { /// Event selection template - void runEventSelection(TEvent event) + void runEventSelection(const TEvent& event) { VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillEvent(event); // extract event information and place it in the fValues array diff --git a/PWGDQ/Tasks/TagAndProbe.cxx b/PWGDQ/Tasks/TagAndProbe.cxx index b637ec64aad..8ee82257af1 100644 --- a/PWGDQ/Tasks/TagAndProbe.cxx +++ b/PWGDQ/Tasks/TagAndProbe.cxx @@ -79,7 +79,7 @@ constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedE constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks template void PrintBitMap(TMap map, int nbits) @@ -348,7 +348,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/dqCorrelation.cxx b/PWGDQ/Tasks/dqCorrelation.cxx index 890bdefe46b..30c0bc1a38b 100644 --- a/PWGDQ/Tasks/dqCorrelation.cxx +++ b/PWGDQ/Tasks/dqCorrelation.cxx @@ -286,7 +286,7 @@ struct DqCumulantFlow { float weff = 1.0, wacc = 1.0; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); } @@ -316,7 +316,7 @@ struct DqCumulantFlow { } } - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { registry.fill(HIST("dimuon_mass"), dilepton.mass()); VarManager::FillTrack(dilepton, fValuesDilepton); diff --git a/PWGDQ/Tasks/dqEfficiency.cxx b/PWGDQ/Tasks/dqEfficiency.cxx index 45e84b4c3e4..32548b335d5 100644 --- a/PWGDQ/Tasks/dqEfficiency.cxx +++ b/PWGDQ/Tasks/dqEfficiency.cxx @@ -95,7 +95,7 @@ constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | Va constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; constexpr static uint32_t gkParticleMCFillMap = VarManager::ObjTypes::ParticleMC; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct AnalysisEventSelection { Produces eventSel; @@ -1197,12 +1197,12 @@ struct AnalysisDileptonTrack { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { int indexLepton1 = dilepton.index0Id(); int indexLepton2 = dilepton.index1Id(); @@ -1504,14 +1504,14 @@ struct AnalysisDileptonTrackTrack { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } // loop over dileptons - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesQuadruplet); // apply the dilepton cut @@ -1665,7 +1665,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx index d61bf37ea71..6fea83a556d 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx @@ -301,7 +301,7 @@ constexpr static uint32_t gkTrackFillMapWithCovNoTOF = VarManager::ObjTypes::Tra constexpr static uint32_t gkDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks template void PrintBitMap(TMap map, int nbits) @@ -2737,7 +2737,7 @@ struct AnalysisDileptonTrack { auto bc = event.template bc_as(); - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { // get full track info of tracks based on the index auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); @@ -3180,7 +3180,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx b/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx index 06c997df1fd..4038c855ec0 100644 --- a/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx +++ b/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx @@ -84,7 +84,7 @@ constexpr static uint32_t gkEventFillMapWithMults = VarManager::ObjTypes::BC | V constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; // Forward declarations -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks struct AnalysisEnergyCorrelator { OutputObj fOutputList{"output"}; @@ -1182,7 +1182,7 @@ struct AnalysisEnergyCorrelator { }; // Histogram definitions -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/Tasks/dqFlow.cxx b/PWGDQ/Tasks/dqFlow.cxx index fe16c52daee..323ec4ade4a 100644 --- a/PWGDQ/Tasks/dqFlow.cxx +++ b/PWGDQ/Tasks/dqFlow.cxx @@ -100,7 +100,7 @@ constexpr static uint32_t gkEventFillMapRun3 = VarManager::ObjTypes::BC | VarMan constexpr static uint32_t gkEventFillMapRun3Qvect = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::ObjTypes::CollisionQvectCentr; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct DQEventQvector { @@ -142,7 +142,7 @@ struct DQEventQvector { ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100.1}, "multiplicity / centrality axis for histograms"}; // Define the filter for barrel tracks and forward tracks - Filter trackFilter = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); + Filter trackFilter = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); Filter fwdFilter = (aod::fwdtrack::eta < -2.45f) && (aod::fwdtrack::eta > -3.6f); // Histograms used for optionnal efficiency and non-uniform acceptance corrections @@ -656,7 +656,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/filterPP.cxx b/PWGDQ/Tasks/filterPP.cxx index 1bfa487594e..71e59bd6f32 100644 --- a/PWGDQ/Tasks/filterPP.cxx +++ b/PWGDQ/Tasks/filterPP.cxx @@ -106,7 +106,7 @@ constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct DQEventSelectionTask { Produces eventSel; @@ -521,7 +521,7 @@ struct DQFilterPPTask { std::vector objCountersBarrel(fNBarrelCuts, 0); // init all counters to zero // count the number of barrel tracks fulfilling each cut - for (auto track : tracksBarrel) { + for (const auto& track : tracksBarrel) { for (int i = 0; i < fNBarrelCuts; ++i) { if (track.isDQBarrelSelected() & (static_cast(1) << i)) { objCountersBarrel[i] += 1; @@ -585,7 +585,7 @@ struct DQFilterPPTask { std::vector objCountersMuon(fNMuonCuts, 0); // init all counters to zero // count the number of muon tracks fulfilling each selection - for (auto muon : muons) { + for (const auto& muon : muons) { for (int i = 0; i < fNMuonCuts; ++i) { if (muon.isDQMuonSelected() & (static_cast(1) << i)) { objCountersMuon[i] += 1; @@ -701,7 +701,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/filterPPwithAssociation.cxx b/PWGDQ/Tasks/filterPPwithAssociation.cxx index cf7c18ce8f6..a338691417b 100644 --- a/PWGDQ/Tasks/filterPPwithAssociation.cxx +++ b/PWGDQ/Tasks/filterPPwithAssociation.cxx @@ -123,7 +123,7 @@ constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarMana constexpr static uint32_t gkTrackFillMapTPCPID = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackTPCPID; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; -void DefineHistograms(HistogramManager* histMan, TString histClasses, TString subgroups = ""); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const TString& subgroups = ""); template void PrintBitMap(TMap map, int nbits) @@ -720,7 +720,7 @@ struct DQFilterPPTask { uint32_t pairFilter = 0; // count the number of barrel tracks fulfilling each cut if constexpr (static_cast(TTrackFillMap)) { - for (auto trackAssoc : barrelAssocs) { + for (const auto& trackAssoc : barrelAssocs) { for (int i = 0; i < fNBarrelCuts; ++i) { if (trackAssoc.isDQBarrelSelected() & (static_cast(1) << i)) { objCountersBarrel[i] += 1; @@ -1227,7 +1227,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, TString subgroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const TString& subgroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/quarkoniaToHyperons.cxx b/PWGDQ/Tasks/quarkoniaToHyperons.cxx index 102936f70af..9c1fcb459f8 100644 --- a/PWGDQ/Tasks/quarkoniaToHyperons.cxx +++ b/PWGDQ/Tasks/quarkoniaToHyperons.cxx @@ -1203,7 +1203,7 @@ struct QuarkoniaToHyperons { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) @@ -1295,7 +1295,7 @@ struct QuarkoniaToHyperons { } template - void fillEventHistograms(TCollision collision, float& centrality, int& selGapSide) + void fillEventHistograms(const TCollision& collision, float& centrality, int& selGapSide) { if (isPP) { // centrality = collision.centFT0M(); @@ -1337,7 +1337,7 @@ struct QuarkoniaToHyperons { } template - uint64_t computeReconstructionBitmap(TV0 v0, TCollision collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) + uint64_t computeReconstructionBitmap(const TV0& v0, const TCollision& collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1492,7 +1492,7 @@ struct QuarkoniaToHyperons { } template - bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity, bool isXi) + bool isCascadeSelected(const TCascade& casc, const TCollision& collision, float rapidity, bool isXi) // precalculate this information so that a check is one mask operation, not many { // @@ -1728,7 +1728,7 @@ struct QuarkoniaToHyperons { } template - uint64_t computeMCAssociation(TV0 v0) + uint64_t computeMCAssociation(const TV0& v0) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1758,7 +1758,7 @@ struct QuarkoniaToHyperons { } template - void analyseV0Candidate(TV0 v0, float pt, uint64_t selMap, std::vector& selK0ShortIndices, std::vector& selLambdaIndices, std::vector& selAntiLambdaIndices /*, int v0TableOffset*/) + void analyseV0Candidate(const TV0& v0, float pt, uint64_t selMap, std::vector& selK0ShortIndices, std::vector& selLambdaIndices, std::vector& selAntiLambdaIndices /*, int v0TableOffset*/) // precalculate this information so that a check is one mask operation, not many { bool passK0ShortSelections = false; @@ -1825,7 +1825,7 @@ struct QuarkoniaToHyperons { } template - void fillQAplot(TCollision collision, PairTopoInfo pair, THyperon hyperon, THyperon antiHyperon, float pt, float invmass, int type) + void fillQAplot(const TCollision& collision, PairTopoInfo pair, const THyperon& hyperon, const THyperon& antiHyperon, float pt, float invmass, int type) { // fill QA information about hyperon - antihyperon pair if (type == 0) { if constexpr (requires { hyperon.mK0Short(); antiHyperon.mK0Short(); }) { // check if v0 information is available @@ -2152,7 +2152,7 @@ struct QuarkoniaToHyperons { } template - void analyseHyperonPairCandidate(TCollision collision, THyperon hyperon, THyperon antiHyperon, float centrality, uint8_t gapSide, int type) + void analyseHyperonPairCandidate(const TCollision& collision, const THyperon& hyperon, const THyperon& antiHyperon, float centrality, uint8_t gapSide, int type) // fill information related to the quarkonium mother // type = 0 (Lambda), 1 (Xi), 2 (Omega) { @@ -2408,7 +2408,7 @@ struct QuarkoniaToHyperons { // function to check that the hyperon and antihyperon have different daughter tracks template - bool checkTrackIndices(THyperon hyperon, THyperon antiHyperon) + bool checkTrackIndices(const THyperon& hyperon, const THyperon& antiHyperon) { if constexpr (requires { hyperon.template bachTrackExtra_as(); }) { // cascade case: check if bachelor information is available // check that bachelor track from hyperon is different from daughter tracks of antiHyperon diff --git a/PWGDQ/Tasks/tableReader.cxx b/PWGDQ/Tasks/tableReader.cxx index f8e00266743..8501e0792e5 100644 --- a/PWGDQ/Tasks/tableReader.cxx +++ b/PWGDQ/Tasks/tableReader.cxx @@ -158,7 +158,7 @@ constexpr static int pairTypeMuMu = VarManager::kDecayToMuMu; constexpr static int pairTypeEMu = VarManager::kElectronMuon; // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const Configurable& configVar); // defines histograms for all tasks struct AnalysisEventSelection { Produces eventSel; @@ -1984,13 +1984,13 @@ struct AnalysisDileptonHadron { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } // loop once over dileptons for QA purposes - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesDilepton); fHistMan->FillHistClass("DileptonsSelected", fValuesDilepton); @@ -2062,7 +2062,7 @@ struct AnalysisDileptonHadron { auto evTracks = tracks.sliceBy(perEventTracks, event2.globalIndex()); evTracks.bindExternalIndices(&events); - for (auto dilepton : evDileptons) { + for (const auto& dilepton : evDileptons) { for (auto& track : evTracks) { if (!(static_cast(track.isBarrelSelected()) & (static_cast(1) << fNHadronCutBit))) { @@ -2189,14 +2189,14 @@ struct AnalysisDileptonTrackTrack { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } // loop over dileptons - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesQuadruplet); // apply the dilepton cut @@ -2315,7 +2315,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const Configurable& configVar) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx b/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx index 883513615ed..781930985c7 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx @@ -258,7 +258,7 @@ constexpr static uint32_t gkTrackFillMapWithCovNoTOF = VarManager::ObjTypes::Tra constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks // Enum containing the ordering of statistics histograms to be written in the QA file enum ZorroStatHist { @@ -2013,7 +2013,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/taskFwdTrackPid.cxx b/PWGDQ/Tasks/taskFwdTrackPid.cxx index 8f7febbbf28..4947a37a942 100644 --- a/PWGDQ/Tasks/taskFwdTrackPid.cxx +++ b/PWGDQ/Tasks/taskFwdTrackPid.cxx @@ -56,7 +56,7 @@ constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | constexpr static uint32_t gkMCEventFillMap = VarManager::ObjTypes::ReducedEventMC; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct taskFwdTrackPid { Produces fwdPidAllList; @@ -243,7 +243,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/Tasks/v0selector.cxx b/PWGDQ/Tasks/v0selector.cxx index f464459adf0..bc27b0eb06e 100644 --- a/PWGDQ/Tasks/v0selector.cxx +++ b/PWGDQ/Tasks/v0selector.cxx @@ -762,7 +762,7 @@ struct trackPIDQA { } // end of track loop } // end of process - void DefineHistograms(TString histClasses) + void DefineHistograms(const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGEM/Dilepton/Core/SingleTrackQC.h b/PWGEM/Dilepton/Core/SingleTrackQC.h index 15289d398f2..0530a64e6e2 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQC.h @@ -70,7 +70,7 @@ using MyCollisions = o2::soa::Join; using MyCollision = MyCollisions::iterator; -using MyCollisionsSWT = o2::soa::Join; +using MyCollisionsSWT = o2::soa::Join; using MyCollisionSWT = MyCollisionsSWT::iterator; using MyElectrons = o2::soa::Join; @@ -331,8 +331,10 @@ struct SingleTrackQC { fRegistry.add("Track/positive/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#Delta#eta;#Delta#varphi (rad.);", o2::framework::HistType::kTHnSparseF, {axis_pt, {100, -0.5, +0.5}, {100, -0.5, +0.5}, {90, -M_PI / 4, M_PI / 4}}, false); fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", o2::framework::HistType::kTH1F, {{1000, -5, 5}}, false); fRegistry.add("Track/positive/hTrackType", "track type", o2::framework::HistType::kTH1F, {{6, -0.5f, 5.5}}, false); - fRegistry.add("Track/positive/hDCAxy", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); - fRegistry.add("Track/positive/hDCAxySigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); + fRegistry.add("Track/positive/hDCAxy2DinSigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxy", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH1F, {{1000, 0.f, 1.0f}}, false); // dummy comment + fRegistry.add("Track/positive/hDCAxyinSigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH1F, {{100, 0.0f, 10.0f}}, false); fRegistry.add("Track/positive/hDCAxRes_Pt", "DCA_{x} resolution vs. pT;p_{T} (GeV/c);DCA_{x} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); fRegistry.add("Track/positive/hDCAyRes_Pt", "DCA_{y} resolution vs. pT;p_{T} (GeV/c);DCA_{y} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); fRegistry.add("Track/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); @@ -664,8 +666,10 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/positive/hsDelta"), track.pt(), reldpt, deta, dphi, weight); fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/positive/hTrackType"), track.trackType()); - fRegistry.fill(HIST("Track/positive/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/positive/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/positive/hDCAxy"), std::hypot(track.fwdDcaX(), track.fwdDcaY())); + fRegistry.fill(HIST("Track/positive/hDCAxyinSigma"), dca_xy); + fRegistry.fill(HIST("Track/positive/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/positive/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); fRegistry.fill(HIST("Track/positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); fRegistry.fill(HIST("Track/positive/hDCAxyRes_Pt"), track.pt(), o2::aod::pwgem::dilepton::utils::emtrackutil::sigmaFwdDcaXY(track) * 1e+4); @@ -689,8 +693,10 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/negative/hsDelta"), track.pt(), reldpt, deta, dphi, weight); fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/negative/hTrackType"), track.trackType()); - fRegistry.fill(HIST("Track/negative/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/negative/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/negative/hDCAxy"), std::hypot(track.fwdDcaX(), track.fwdDcaY())); + fRegistry.fill(HIST("Track/negative/hDCAxyinSigma"), dca_xy); + fRegistry.fill(HIST("Track/negative/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/negative/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); fRegistry.fill(HIST("Track/negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); fRegistry.fill(HIST("Track/negative/hDCAxyRes_Pt"), track.pt(), o2::aod::pwgem::dilepton::utils::emtrackutil::sigmaFwdDcaXY(track) * 1e+4); diff --git a/PWGEM/Dilepton/Core/SingleTrackQCMC.h b/PWGEM/Dilepton/Core/SingleTrackQCMC.h index 222f863e71f..947530afce5 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQCMC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQCMC.h @@ -375,7 +375,8 @@ struct SingleTrackQCMC { fRegistry.add("Track/PromptLF/positive/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#Delta#eta;#Delta#varphi (rad.);", o2::framework::HistType::kTHnSparseF, {axis_pt, {100, -0.5, +0.5}, {100, -0.5, +0.5}, {90, -M_PI / 4, M_PI / 4}}, false); fRegistry.add("Track/PromptLF/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", o2::framework::HistType::kTH1F, {{1000, -5, 5}}, false); fRegistry.add("Track/PromptLF/positive/hTrackType", "track type", o2::framework::HistType::kTH1F, {{6, -0.5f, 5.5}}, false); - fRegistry.add("Track/PromptLF/positive/hDCAxy", "DCAxy;DCA_{xy} (cm)", o2::framework::HistType::kTH1F, {{100, 0.f, 1.0f}}, false); + fRegistry.add("Track/PromptLF/positive/hDCAxy", "DCAxy;DCA_{xy} (cm)", o2::framework::HistType::kTH1F, {{1000, 0.f, 1.0f}}, false); + fRegistry.add("Track/PromptLF/positive/hDCAxyinSigma", "DCAxy;DCA_{xy} (#sigma)", o2::framework::HistType::kTH1F, {{100, 0.f, 10.0f}}, false); fRegistry.add("Track/PromptLF/positive/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); fRegistry.add("Track/PromptLF/positive/hDCAxy2DinSigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); fRegistry.add("Track/PromptLF/positive/hDCAxRes_Pt", "DCA_{x} resolution vs. pT;p_{T} (GeV/c);DCA_{x} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); @@ -776,6 +777,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy"), std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2))); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyinSigma"), dca_xy); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); @@ -810,6 +812,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy"), std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2))); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyinSigma"), dca_xy); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); diff --git a/PWGEM/Dilepton/TableProducer/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/CMakeLists.txt index 5d2889041ae..8a00046766a 100644 --- a/PWGEM/Dilepton/TableProducer/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/CMakeLists.txt @@ -46,11 +46,6 @@ o2physics_add_dpl_workflow(skimmer-primary-muon PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(skimmer-primary-muon-qc - SOURCES skimmerPrimaryMuonQC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(skimmer-primary-track SOURCES skimmerPrimaryTrack.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx index 8706432f69d..27ad0708be0 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -112,16 +112,26 @@ struct skimmerPrimaryMuon { // for z shift for propagation Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; + Configurable cfgManualXShiftMFTtop{"cfgManualXShiftMFTtop", 0, "manual x shift on MFT top when propagating global muon to PV"}; + Configurable cfgManualYShiftMFTtop{"cfgManualYShiftMFTtop", 0, "manual y shift on MFT top when propagating global muon to PV"}; + Configurable cfgManualZShiftMFTtop{"cfgManualZShiftMFTtop", 0, "manual z shift on MFT top when propagating global muon to PV"}; + Configurable cfgManualXShiftMFTbottom{"cfgManualXShiftMFTbottom", 0, "manual x shift on MFT bottom when propagating global muon to PV"}; + Configurable cfgManualYShiftMFTbottom{"cfgManualYShiftMFTbottom", 0, "manual y shift on MFT bottom when propagating global muon to PV"}; + Configurable cfgManualZShiftMFTbottom{"cfgManualZShiftMFTbottom", 0, "manual z shift on MFT bottom when propagating global muon to PV"}; o2::ccdb::CcdbApi ccdbApi; Service ccdb; int mRunNumber = 0; float mBz = 0; - float mZShift = 0; + float mXShiftMFTtop = 0; + float mYShiftMFTtop = 0; + float mZShiftMFTtop = 0; + float mXShiftMFTbottom = 0; + float mYShiftMFTbottom = 0; + float mZShiftMFTbottom = 0; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; + // static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; void init(InitContext&) { @@ -140,7 +150,12 @@ struct skimmerPrimaryMuon { } mRunNumber = 0; mBz = 0; - mZShift = 0; + mXShiftMFTtop = 0; + mYShiftMFTtop = 0; + mZShiftMFTtop = 0; + mXShiftMFTbottom = 0; + mYShiftMFTbottom = 0; + mZShiftMFTbottom = 0; } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -168,14 +183,22 @@ struct skimmerPrimaryMuon { auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); if (zShift != nullptr && !zShift->empty()) { LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); - mZShift = (*zShift)[0]; + mZShiftMFTtop = (*zShift)[0]; + mZShiftMFTbottom = (*zShift)[0]; } else { LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); - mZShift = 0; + mZShiftMFTtop = 0; + mZShiftMFTbottom = 0; } } else { - LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); - mZShift = cfgManualZShift; + LOGF(info, "z shift on MFT top is manually set to %f cm", cfgManualZShiftMFTtop.value); + LOGF(info, "z shift on MFT bottom is manually set to %f cm", cfgManualZShiftMFTbottom.value); + mXShiftMFTtop = cfgManualXShiftMFTtop; + mYShiftMFTtop = cfgManualYShiftMFTtop; + mZShiftMFTtop = cfgManualZShiftMFTtop; + mXShiftMFTbottom = cfgManualXShiftMFTbottom; + mYShiftMFTbottom = cfgManualYShiftMFTbottom; + mZShiftMFTbottom = cfgManualZShiftMFTbottom; } } @@ -209,8 +232,10 @@ struct skimmerPrimaryMuon { fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); fRegistry.add("MFTMCHMID/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", kTH1F, {{100, -5, 5}}, false); fRegistry.add("MFTMCHMID/hSqrtChi2IP", "chi2IP;#sqrt{#chi^{2}_{IP}}", kTH1F, {{100, 0, 10}}, false); - fRegistry.add("MFTMCHMID/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - fRegistry.add("MFTMCHMID/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAx_PosZ_MFTtop", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAy_PosZ_MFTtop", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAx_PosZ_MFTbottom", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAy_PosZ_MFTbottom", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); fRegistry.add("MFTMCHMID/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{180, -M_PI, M_PI}, {400, -0.2, +0.2}}, false); fRegistry.add("MFTMCHMID/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{180, -M_PI, M_PI}, {400, -0.2, +0.2}}, false); fRegistry.add("MFTMCHMID/hMeanDCAx", ";X_{IU} (cm);Y_{IU} (cm); (cm)", kTProfile2D, {{240, -12, +12}, {240, -12, +12}}, false); @@ -279,51 +304,24 @@ struct skimmerPrimaryMuon { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); + o2::dataformats::GlobalFwdTrack propmuonAtPV; + float pt = 0.f, eta = 0.f, phi = 0.f; - o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - - float dcaX = propmuonAtDCA.getX() - collision.posX(); - float dcaY = propmuonAtDCA.getY() - collision.posY(); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack - float cXXatDCA = propmuonAtDCA.getSigma2X(); - float cYYatDCA = propmuonAtDCA.getSigma2Y(); - float cXYatDCA = propmuonAtDCA.getSigmaXY(); - - float det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat + o2::dataformats::GlobalFwdTrack propmuonAtDCA; + float dcaX = 999.f, dcaY = 999.f, dcaXY = 999.f; + float rAtAbsorberEnd = 1e+10; + float cXXatDCA = 1e+10, cYYatDCA = 1e+10, cXYatDCA = 1e+10; float dcaXYinSigma = 999.f; - if (det < 0) { - dcaXYinSigma = 999.f; - } else { - dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma - } - float sigma_dcaXY = dcaXY / dcaXYinSigma; + float sigma_dcaXY = 1e+10; - float pDCA = propmuonAtPV.getP() * dcaXY; + float pDCA = 1e+10; int nClustersMFT = 0; - float ptMatchedMCHMID = propmuonAtPV.getPt(); - float etaMatchedMCHMID = propmuonAtPV.getEta(); - float phiMatchedMCHMID = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - // float x = fwdtrack.x(); - // float y = fwdtrack.y(); - // float z = fwdtrack.z(); - // float tgl = fwdtrack.tgl(); + float ptMatchedMCHMID = 1e+10, etaMatchedMCHMID = 1e+10, phiMatchedMCHMID = 1e+10; float chi2mft = 0.f; uint64_t mftClusterSizesAndTrackFlags = 0; int ndf_mchmft = 1; int ndf_mft = 1; - // float etaMatchedMCHMIDatMP = 999.f; - float phiMatchedMCHMIDatMP = 999.f; - // float etaMatchedMFTatMP = 999.f; - float phiMatchedMFTatMP = 999.f; - float deta = 999.f; float dphi = 999.f; @@ -341,17 +339,40 @@ struct skimmerPrimaryMuon { return false; } - // apply dca cut here to minimize the number of calling propagateMuon. - if (maxDCAxy < dcaXY) { - return false; - } - auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa if (mfttrack.chi2() < 0.f) { return false; } + propmuonAtPV = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); + pt = propmuonAtPV.getPt(); + eta = propmuonAtPV.getEta(); + phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + propmuonAtDCA = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); + dcaX = propmuonAtDCA.getX() - collision.posX(); + dcaY = propmuonAtDCA.getY() - collision.posY(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + cXXatDCA = propmuonAtDCA.getSigma2X(); + cYYatDCA = propmuonAtDCA.getSigma2Y(); + cXYatDCA = propmuonAtDCA.getSigmaXY(); + rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + + float det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant + if (det < 0) { + dcaXYinSigma = 999.f; + } else { + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma + } + sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2); + + // apply dca cut here to minimize the number of calling propagateMuon. + if (maxDCAxy < dcaXY) { + return false; + } + xMFT = mfttrack.x(); yMFT = mfttrack.y(); @@ -369,39 +390,30 @@ struct skimmerPrimaryMuon { ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; ndf_mft = 2.f * nClustersMFT - 5.f; chi2mft = mfttrack.chi2(); - // chi2mft = mfttrack.chi2() / (2.f * nClustersMFT - 5.f); // apply chi2/ndf cut here to minimize the number of calling propagateMuon. if (maxChi2GL < fwdtrack.chi2() / ndf_mchmft) { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, 0.f, 0.f, 0.f); ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - pDCA = mchtrack.p() * dcaXY_Matched; + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, 0.f, 0.f, 0.f); + // float dcaXY_Matched = std::hypot(propmuonAtDCA_Matched.getX() - collision.posX(), propmuonAtDCA_Matched.getY() - collision.posY()); + pDCA = mchtrack.p() * std::hypot(propmuonAtDCA_Matched.getX() - collision.posX(), propmuonAtDCA_Matched.getY() - collision.posY()); if constexpr (withMFTCov) { auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); - auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz, mZShift); // propagated to matching plane - o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwdShift(mfttrack, mZShift, mfttrackcov); // values at innermost update - mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane - // etaMatchedMFTatMP = mftsaAtMP.getEta(); - phiMatchedMFTatMP = mftsaAtMP.getPhi(); - // etaMatchedMCHMIDatMP = muonAtMP.getEta(); - phiMatchedMCHMIDatMP = muonAtMP.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMIDatMP); - o2::math_utils::bringTo02Pi(phiMatchedMFTatMP); - - o2::track::TrackParCovFwd mftsa = getTrackParCovFwdShift(mfttrack, mZShift, mfttrackcov); // values at innermost update - o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. + // auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz, 0.f, 0.f, 0.f); // propagated to matching plane + // o2::track::TrackParCovFwd mftsaAtMP = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? getTrackParCovFwd3DShift(mfttrack, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop, mfttrackcov) : getTrackParCovFwd3DShift(mfttrack, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom, mfttrackcov); // values at innermost update + // mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane + + o2::track::TrackParCovFwd mftsa = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? getTrackParCovFwd3DShift(mfttrack, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop, mfttrackcov) : getTrackParCovFwd3DShift(mfttrack, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom, mfttrackcov); // values at innermost update + o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. auto globalMuon = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonRefit, fwdtrack.trackType(), collision, propagationPoint::kToVertex, matchingZ, mBz); pt = globalMuon.getPt(); eta = globalMuon.getEta(); @@ -414,8 +426,7 @@ struct skimmerPrimaryMuon { dcaX = globalMuon.getX() - collision.posX(); dcaY = globalMuon.getY() - collision.posY(); dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat - dcaXYinSigma = 999.f; + det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant if (det < 0) { dcaXYinSigma = 999.f; } else { @@ -428,7 +439,7 @@ struct skimmerPrimaryMuon { dphi = phiMatchedMCHMID - phi; o2::math_utils::bringToPMPi(dphi); - chi2IP = getFwdChi2IP(fwdtrack, collision, mBz, mZShift); + chi2IP = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); if (std::sqrt(std::pow(deta / maxDEta, 2) + std::pow(dphi / maxDPhi, 2)) > 1.f) { return false; @@ -440,14 +451,14 @@ struct skimmerPrimaryMuon { const auto& fwdcov = propmuonAtPV.getCovariances(); // covatiance matrix at PV - auto globalMuonManual = getTrackParCovFwdShiftManual( + auto globalMuonManual = getTrackParCovFwd3DShiftManual( propmuonAtPV.getX(), propmuonAtPV.getY(), propmuonAtPV.getPhi(), propmuonAtPV.getTgl(), propmuonAtPV.getInvQPt() / sfPt, fwdcov(0, 0), fwdcov(1, 0), fwdcov(1, 1), fwdcov(2, 0), fwdcov(2, 1), fwdcov(2, 2), fwdcov(3, 0), fwdcov(3, 1), fwdcov(3, 2), fwdcov(3, 3), fwdcov(4, 0) / sfPt, fwdcov(4, 1) / sfPt, fwdcov(4, 2) / sfPt, fwdcov(4, 3) / sfPt, fwdcov(4, 4) / sfPt / sfPt, - propmuonAtPV.getZ(), 0.0, fwdtrack.chi2()); + propmuonAtPV.getZ(), 0.0, 0.0, 0.0, fwdtrack.chi2()); auto globalMuonManualAtZPV = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonManual, fwdtrack.trackType(), collision, propagationPoint::kToDCA, matchingZ, mBz); @@ -471,24 +482,29 @@ struct skimmerPrimaryMuon { cXYatDCA = cXYatDCA + resPVXY; cYYatDCA = cYYatDCA + resPVYY; - det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat - dcaXYinSigma = 999.f; + det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant if (det < 0) { dcaXYinSigma = 999.f; } else { dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma } - sigma_dcaXY = dcaXY / dcaXYinSigma; + sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2); chi2IP = getFwdChi2IP(globalMuonManual, collision, mBz); } } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, mZShift); // this is necessary only for MuonStandaloneTrack + propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, 0.f, 0.f, 0.f); + pt = propmuonAtPV.getPt(); + eta = propmuonAtPV.getEta(); + phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, 0.f, 0.f, 0.f); // this is necessary only for MuonStandaloneTrack float xAbs = propmuonAtRabs.getX(); float yAbs = propmuonAtRabs.getY(); rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction - o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); + propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, 0.f, 0.f, 0.f); cXXatDCA = propmuonAtDCA.getSigma2X(); cYYatDCA = propmuonAtDCA.getSigma2Y(); cXYatDCA = propmuonAtDCA.getSigmaXY(); @@ -497,14 +513,13 @@ struct skimmerPrimaryMuon { dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); pDCA = fwdtrack.p() * dcaXY; - det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat - dcaXYinSigma = 999.f; + float det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant if (det < 0) { dcaXYinSigma = 999.f; } else { dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma } - sigma_dcaXY = dcaXY / dcaXYinSigma; + sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2); } else { return false; } @@ -516,10 +531,6 @@ struct skimmerPrimaryMuon { if constexpr (fillTable) { float dpt = (ptMatchedMCHMID - pt) / pt; - // float detaMP = etaMatchedMCHMIDatMP - etaMatchedMFTatMP; - // float dphiMP = phiMatchedMCHMIDatMP - phiMatchedMFTatMP; - // o2::math_utils::bringToPMPi(dphiMP); - bool isAssociatedToMPC = fwdtrack.collisionId() == collision.globalIndex(); // LOGF(info, "isAmbiguous = %d, isAssociatedToMPC = %d, fwdtrack.globalIndex() = %d, fwdtrack.collisionId() = %d, collision.globalIndex() = %d", isAmbiguous, isAssociatedToMPC, fwdtrack.globalIndex(), fwdtrack.collisionId(), collision.globalIndex()); @@ -572,8 +583,13 @@ struct skimmerPrimaryMuon { fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/hLog10Chi2IP"), std::log10(chi2IP)); fRegistry.fill(HIST("MFTMCHMID/hSqrtChi2IP"), std::sqrt(chi2IP)); - fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ"), collision.posZ(), dcaX); - fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ"), collision.posZ(), dcaY); + if (std::atan2(yMFT, xMFT) > 0.f) { + fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ_MFTtop"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ_MFTtop"), collision.posZ(), dcaY); + } else { + fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ_MFTbottom"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ_MFTbottom"), collision.posZ(), dcaY); + } fRegistry.fill(HIST("MFTMCHMID/hDCAx_Phi"), std::atan2(yMFT, xMFT), dcaX); fRegistry.fill(HIST("MFTMCHMID/hDCAy_Phi"), std::atan2(yMFT, xMFT), dcaY); fRegistry.fill(HIST("MFTMCHMID/hMeanDCAx"), fwdtrack.x(), fwdtrack.y(), dcaX); @@ -627,17 +643,6 @@ struct skimmerPrimaryMuon { // LOGF(info, "stanadalone: muon.globalIndex() = %d, muon.chi2MatchMCHMFT() = %f", muon.globalIndex(), muon.chi2MatchMCHMFT()); // LOGF(info, "muons_per_MCHMID.size() = %d", muons_per_MCHMID.size()); - // o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - // float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); - // float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - // o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - - // o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - // float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - // float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - // float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - // float pDCA = fwdtrack.p() * dcaXY_Matched; - float min_chi2MatchMCHMFT = 1e+10; std::tuple tupleId_at_min_chi2mftmch; std::vector vec_chi2tmp; @@ -653,41 +658,6 @@ struct skimmerPrimaryMuon { continue; } - // if (muon_tmp.chi2() < 0.f || muon_tmp.chi2MatchMCHMFT() < 0.f || muon_tmp.chi2MatchMCHMID() < 0.f || mfttrack.chi2() < 0.f) { // reject negative chi2, i.e. wrong. - // continue; - // } - - // o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(muon_tmp, muon_tmp, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - // float pt = propmuonAtPV.getPt(); - // float eta = propmuonAtPV.getEta(); - // float phi = propmuonAtPV.getPhi(); - // o2::math_utils::bringTo02Pi(phi); - - // if (refitGlobalMuon) { - // pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); - // } - - // float deta = etaMatchedMCHMID - eta; - // float dphi = phiMatchedMCHMID - phi; - // o2::math_utils::bringToPMPi(dphi); - // int ndf = 2 * (mchtrack.nClusters() + mfttrack.nClusters()) - 5; - - // float dcaX = propmuonAtPV.getX() - collision.posX(); - // float dcaY = propmuonAtPV.getY() - collision.posY(); - // float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - - // if (cfgApplyPreselectionInBestMatch) { - // if (!isSelected(pt, eta, muon_tmp.rAtAbsorberEnd(), pDCA, muon_tmp.chi2() / ndf, muon_tmp.trackType(), dcaXY)) { - // continue; - // } - // if (std::sqrt(std::pow(deta / maxDEta, 2) + std::pow(dphi / maxDPhi, 2)) > 1.f) { - // continue; - // } - // if (muon_tmp.chi2MatchMCHMFT() > maxMatchingChi2MCHMFT) { - // continue; - // } - // } - vec_chi2tmp.emplace_back(muon_tmp.chi2MatchMCHMFT()); if (0.f < muon_tmp.chi2MatchMCHMFT() && muon_tmp.chi2MatchMCHMFT() < min_chi2MatchMCHMFT) { min_chi2MatchMCHMFT = muon_tmp.chi2MatchMCHMFT(); diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx deleted file mode 100644 index 246634a975d..00000000000 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx +++ /dev/null @@ -1,797 +0,0 @@ -// Copyright 2019-2020 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. - -/// \brief write relevant information for muons. -/// \author daiki.sekihata@cern.ch - -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" - -#include "Common/Core/fwdtrackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/DataModel/EventSelection.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using namespace o2::aod::fwdtrackutils; - -struct skimmerPrimaryMuonQC { - using MyCollisions = soa::Join; - using MyCollisionsWithSWT = soa::Join; - - using MyFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. - using MyFwdTrack = MyFwdTracks::iterator; - - using MyFwdTracksMC = soa::Join; - using MyFwdTrackMC = MyFwdTracksMC::iterator; - - using MFTTracksMC = soa::Join; - using MFTTrackMC = MFTTracksMC::iterator; - - Produces emprimarymuons; - Produces emprimarymuonscov; - - // Configurables - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable fillQAHistograms{"fillQAHistograms", false, "flag to fill QA histograms"}; - - // for z shift for propagation - Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; - Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; - Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; - Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; - - struct : ConfigurableGroup { // tight cut - std::string prefix = "tagMuonCut"; - Configurable minPt{"minPt", 0.8, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 27.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 0.06, "max. DCAxy for global muons"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 40.f, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 4.f, "max. chi2/ndf for global muon"}; - // Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - // Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable maxDEta{"maxDEta", 0.08, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 0.08, "max. dphi between MFT-MCH-MID and MCH-MID"}; - } tagMuonCut; - - struct : ConfigurableGroup { // loose cut - std::string prefix = "probeMuonCut"; - Configurable minPt{"minPt", 0.01, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEtaSA{"minEtaSA", -4.0, "min. eta acceptance for MFT-MCH"}; - Configurable maxEtaSA{"maxEtaSA", -2.5, "max. eta acceptance for MFT-MCH"}; - Configurable minEtaGL{"minEtaGL", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEtaGL{"maxEtaGL", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable midRabs{"midRabs", 26.5, "middle R at absorber end for pDCA cut"}; - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 1.f, "max. DCAxy for global muons"}; - Configurable maxPDCAforLargeR{"maxPDCAforLargeR", 324.f, "max. pDCA for large R at absorber end"}; - Configurable maxPDCAforSmallR{"maxPDCAforSmallR", 594.f, "max. pDCA for small R at absorber end"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 100, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 1e+10, "max. chi2/ndf for global muon"}; - // Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - // Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable maxDEta{"maxDEta", 1e+10, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 1e+10, "max. dphi between MFT-MCH-MID and MCH-MID"}; - } probeMuonCut; - - struct : ConfigurableGroup { - std::string prefix = "pairCuts"; - Configurable minMass{"minMass", 0.21, "min mass"}; - Configurable maxMass{"maxMass", 0.30, "max mass"}; - } pairCuts; - - o2::ccdb::CcdbApi ccdbApi; - Service ccdb; - int mRunNumber = 0; - float mBz = 0; - float mZShift = 0; - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - // static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; - - void init(InitContext&) - { - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - ccdbApi.init(ccdburl); - - if (fillQAHistograms) { - addHistograms(); - } - mRunNumber = 0; - mBz = 0; - mZShift = 0; - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - - std::map metadata; - auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); - auto ts = soreor.first; - auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); - o2::base::Propagator::initFieldFromGRP(grpmag); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); - } - o2::mch::TrackExtrap::setField(); - const double centerMFT[3] = {0, 0, -61.4}; - o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); - mBz = field->getBz(centerMFT); // Get field at centre of MFT - LOGF(info, "Bz at center of MFT = %f kZG", mBz); - - if (cfgApplyZShiftFromCCDB) { - auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); - if (zShift != nullptr && !zShift->empty()) { - LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); - mZShift = (*zShift)[0]; - } else { - LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); - mZShift = 0; - } - } else { - LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); - mZShift = cfgManualZShift; - } - } - - void addHistograms() - { - // auto hMuonType = fRegistry.add("hMuonType", "muon type", kTH1F, {{5, -0.5f, 4.5f}}, false); - // hMuonType->GetXaxis()->SetBinLabel(1, "MFT-MCH-MID (global muon)"); - // hMuonType->GetXaxis()->SetBinLabel(2, "MFT-MCH-MID (global muon other match)"); - // hMuonType->GetXaxis()->SetBinLabel(3, "MFT-MCH"); - // hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); - // hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); - - // fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{200, 0.0f, 10}}, false); - // fRegistry.add("MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); - // fRegistry.add("MFTMCHMID/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); - // fRegistry.add("MFTMCHMID/hDeltaPt_Pt", "#Deltap_{T}/p_{T} vs. p_{T};p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl}", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - // fRegistry.add("MFTMCHMID/hDeltaEta_Pt", "#Delta#eta vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - // fRegistry.add("MFTMCHMID/hDeltaPhi_Pt", "#Delta#varphi vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - // fRegistry.add("MFTMCHMID/hSign", "sign;sign", kTH1F, {{3, -1.5, +1.5}}, false); - // fRegistry.add("MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); - // fRegistry.add("MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); - // fRegistry.add("MFTMCHMID/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); - // fRegistry.add("MFTMCHMID/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); - // fRegistry.add("MFTMCHMID/hChi2", "chi2;chi2/ndf", kTH1F, {{200, 0.0f, 20}}, false); - // fRegistry.add("MFTMCHMID/hChi2MFT", "chi2 MFT;chi2 MFT/ndf", kTH1F, {{200, 0.0f, 20}}, false); - // fRegistry.add("MFTMCHMID/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{200, 0.0f, 20}}, false); - // fRegistry.add("MFTMCHMID/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{200, 0.0f, 100}}, false); - // fRegistry.add("MFTMCHMID/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -1, 1}, {200, -1, +1}}, false); - // fRegistry.add("MFTMCHMID/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); - // fRegistry.add("MFTMCHMID/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1F, {{100, 0, 1}}, false); - // fRegistry.add("MFTMCHMID/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{100, 0, 1}, {200, -0.1, 0.1}}, false); - // fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); - // fRegistry.add("MFTMCHMID/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hNmu", "#mu multiplicity;N_{#mu} per collision", kTH1F, {{21, -0.5, 20.5}}, false); - - // fRegistry.addClone("MFTMCHMID/", "MCHMID/"); - // fRegistry.add("MFTMCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); - // fRegistry.add("MFTMCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); - // fRegistry.add("MFTMCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); - // fRegistry.add("MCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); - // fRegistry.add("MCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); - // fRegistry.add("MCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); - - fRegistry.add("Pair/uls/gl_gl/hMvsPt", "dimuon;m_{#mu#mu} (GeV/c^{2});p_{T,#mu} (GeV/c);", kTH2F, {{380, 0.2, 4.f}, {100, 0, 10}}, false); - fRegistry.add("Pair/uls/gl_sa/hMvsPt", "dimuon;m_{#mu#mu} (GeV/c^{2});p_{T,#mu} (GeV/c);", kTH2F, {{380, 0.2, 4.f}, {100, 0, 10}}, false); - } - - struct Muon { - int globalIndex = -1; - int collisionId = -1; - int matchMCHTrackId = -1; - int matchMFTTrackId = -1; - uint8_t trackType = 99; - int8_t sign = 0; - float pt = 0; - float eta = 0; - float phi = 0; - float dcaX = 0; // in cm - float dcaY = 0; // in cm - float dcaXY = 0; // in cm - float cXX = 0; - float cYY = 0; - float cXY = 0; - float rAtAbsorberEnd = 0; - float pDCA = 0; - float chi2ndf = 0; - float chi2MatchMCHMID = 0; - - // only for global muons - float ptMatchedMCHMID = 0; - float etaMatchedMCHMID = 0; - float phiMatchedMCHMID = 0; - float chi2MatchMCHMFT = 0; - float chi2mft = -999.f; - uint64_t mftClusterSizesAndTrackFlags = 0; - }; - - bool isSelected(Muon const& muon) - { - if (muon.pt < probeMuonCut.minPt || probeMuonCut.maxPt < muon.pt) { - return false; - } - - if (muon.rAtAbsorberEnd < probeMuonCut.minRabs || probeMuonCut.maxRabs < muon.rAtAbsorberEnd) { - return false; - } - - if (muon.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (muon.eta < probeMuonCut.minEtaGL || probeMuonCut.maxEtaGL < muon.eta) { - return false; - } - if (probeMuonCut.maxDCAxy < muon.dcaXY) { - return false; - } - if (probeMuonCut.maxMatchingChi2MCHMFT < muon.chi2MatchMCHMFT) { - return false; - } - } else if (muon.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (muon.eta < probeMuonCut.minEtaSA || probeMuonCut.maxEtaSA < muon.eta) { - return false; - } - if (muon.rAtAbsorberEnd < probeMuonCut.midRabs ? muon.pDCA > probeMuonCut.maxPDCAforSmallR : muon.pDCA > probeMuonCut.maxPDCAforLargeR) { - return false; - } - } else { - return false; - } - - return true; - } - - bool isSelectedTight(Muon const& muon) - { - if (muon.trackType != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { // tag muon should be tight. - return false; - } - - if (muon.pt < tagMuonCut.minPt || tagMuonCut.maxPt < muon.pt) { - return false; - } - - if (muon.rAtAbsorberEnd < tagMuonCut.minRabs || tagMuonCut.maxRabs < muon.rAtAbsorberEnd) { - return false; - } - - if (muon.chi2ndf < 0.f || tagMuonCut.maxChi2 < muon.chi2ndf) { - return false; - } - - if (muon.eta < tagMuonCut.minEta || tagMuonCut.maxEta < muon.eta) { - return false; - } - - if (tagMuonCut.maxDCAxy < muon.dcaXY) { - return false; - } - - if (tagMuonCut.maxMatchingChi2MCHMFT < muon.chi2MatchMCHMFT) { - return false; - } - - float deta = muon.etaMatchedMCHMID - muon.eta; - float dphi = muon.phiMatchedMCHMID - muon.phi; - // LOGF(info, "muon.trackType = %d, deta = %f, dphi = %f", muon.trackType, deta, dphi); - if (std::sqrt(std::pow(deta / tagMuonCut.maxDEta, 2) + std::pow(dphi / tagMuonCut.maxDPhi, 2)) > 1.f) { - return false; - } - - return true; - } - - template - bool fillMuonInfo(TCollision const& collision, TFwdTrack fwdtrack) - { - if (fwdtrack.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && fwdtrack.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - return false; - } - - if (fwdtrack.chi2MatchMCHMID() < 0.f) { // this should never happen. only for protection. - return false; - } - - if (fwdtrack.chi2() < 0.f) { // this should never happen. only for protection. - return false; - } - - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); - - float dcaX = propmuonAtPV.getX() - collision.posX(); - float dcaY = propmuonAtPV.getY() - collision.posY(); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack - float cXX = propmuonAtPV.getSigma2X(); - float cYY = propmuonAtPV.getSigma2Y(); - float cXY = propmuonAtPV.getSigmaXY(); - - float pDCA = propmuonAtPV.getP() * dcaXY; - int nClustersMFT = 0; - float ptMatchedMCHMID = propmuonAtPV.getPt(); - float etaMatchedMCHMID = propmuonAtPV.getEta(); - float phiMatchedMCHMID = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - float chi2mft = -999.f; - uint64_t mftClusterSizesAndTrackFlags = 0; - int ndf_mchmft = 1; - - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - if (fwdtrack.chi2MatchMCHMFT() < 0.f) { - return false; - } // Users have to decide the best match between MFT and MCH-MID at analysis level. The same global muon is repeatedly stored. - - auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID - auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa - if (mfttrack.chi2() < 0.f) { - return false; - } - - if constexpr (isMC) { - if (!mfttrack.has_mcParticle() || !mchtrack.has_mcParticle() || !fwdtrack.has_mcParticle()) { - return false; - } - // auto mcParticle_MFTMCHMID = fwdtrack.template mcParticle_as(); // this is identical to mcParticle_MCHMID - auto mcParticle_MCHMID = mchtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID - auto mcParticle_MFT = mfttrack.template mcParticle_as(); - } - - nClustersMFT = mfttrack.nClusters(); - mftClusterSizesAndTrackFlags = mfttrack.mftClusterSizesAndTrackFlags(); - ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; - chi2mft = mfttrack.chi2(); - - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); - etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); - phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - pDCA = mchtrack.p() * dcaXY_Matched; - - if (refitGlobalMuon) { - pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); - } - } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, mZShift); // this is necessary only for MuonStandaloneTrack - float xAbs = propmuonAtRabs.getX(); - float yAbs = propmuonAtRabs.getY(); - rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction - ndf_mchmft = 1; // chi2 is already normalized by ndf for MCH-MID tracks. - - o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - cXX = propmuonAtDCA.getSigma2X(); - cYY = propmuonAtDCA.getSigma2Y(); - cXY = propmuonAtDCA.getSigmaXY(); - dcaX = propmuonAtDCA.getX() - collision.posX(); - dcaY = propmuonAtDCA.getY() - collision.posY(); - dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - pDCA = fwdtrack.p() * dcaXY; - } else { - return false; - } - - Muon muon; - muon.globalIndex = fwdtrack.globalIndex(); - muon.collisionId = collision.globalIndex(); - muon.trackType = fwdtrack.trackType(); - muon.sign = fwdtrack.sign(); - muon.pt = pt; - muon.eta = eta; - muon.phi = phi; - muon.dcaX = dcaX; - muon.dcaY = dcaY; - muon.dcaXY = dcaXY; - muon.cXX = cXX; - muon.cYY = cYY; - muon.cXY = cXY; - muon.rAtAbsorberEnd = rAtAbsorberEnd; - muon.pDCA = pDCA; - muon.chi2ndf = fwdtrack.chi2() / ndf_mchmft; - muon.ptMatchedMCHMID = ptMatchedMCHMID; - muon.etaMatchedMCHMID = etaMatchedMCHMID; - muon.phiMatchedMCHMID = phiMatchedMCHMID; - muon.chi2mft = chi2mft; - muon.matchMCHTrackId = fwdtrack.matchMCHTrackId(); - muon.matchMFTTrackId = fwdtrack.matchMFTTrackId(); - muon.mftClusterSizesAndTrackFlags = mftClusterSizesAndTrackFlags; - - vecMuons.emplace_back(muon); - return true; - } - - template - bool fillFwdTrackTable(TCollision const& collision, TMuon const& muon, TFwdTrack const& fwdtrack) - { - emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), fwdtrack.matchMFTTrackId(), fwdtrack.matchMCHTrackId(), fwdtrack.trackType(), - muon.pt, muon.eta, muon.phi, fwdtrack.sign(), muon.dcaX, muon.dcaY, muon.cXX, muon.cYY, muon.cXY, muon.ptMatchedMCHMID, muon.etaMatchedMCHMID, muon.phiMatchedMCHMID, - fwdtrack.nClusters(), muon.pDCA, muon.rAtAbsorberEnd, fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), 9999.f, - fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), muon.mftClusterSizesAndTrackFlags, muon.chi2mft, true, false); - - // if (fillQAHistograms) { - // fRegistry.fill(HIST("hMuonType"), fwdtrack.trackType()); - // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - // fRegistry.fill(HIST("MFTMCHMID/hPt"), pt); - // fRegistry.fill(HIST("MFTMCHMID/hEtaPhi"), phi, eta); - // fRegistry.fill(HIST("MFTMCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); - // fRegistry.fill(HIST("MFTMCHMID/hDeltaPt_Pt"), pt, dpt); - // fRegistry.fill(HIST("MFTMCHMID/hDeltaEta_Pt"), pt, deta); - // fRegistry.fill(HIST("MFTMCHMID/hDeltaPhi_Pt"), pt, dphi); - // fRegistry.fill(HIST("MFTMCHMID/hSign"), fwdtrack.sign()); - // fRegistry.fill(HIST("MFTMCHMID/hNclusters"), fwdtrack.nClusters()); - // fRegistry.fill(HIST("MFTMCHMID/hNclustersMFT"), nClustersMFT); - // fRegistry.fill(HIST("MFTMCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); - // fRegistry.fill(HIST("MFTMCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); - // fRegistry.fill(HIST("MFTMCHMID/hChi2"), fwdtrack.chi2() / ndf_mchmft); - // fRegistry.fill(HIST("MFTMCHMID/hChi2MFT"), chi2mft / ndf_mft); - // fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - // fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxy2D"), dcaX, dcaY); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxy"), dcaXY); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxyz"), dcaXY, dcaZ); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxyinSigma"), dcaXYinSigma); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MFTMCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ"), collision.posZ(), dcaX); - // fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ"), collision.posZ(), dcaY); - // fRegistry.fill(HIST("MFTMCHMID/hDCAx_Phi"), phi, dcaX); - // fRegistry.fill(HIST("MFTMCHMID/hDCAy_Phi"), phi, dcaY); - // } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - // fRegistry.fill(HIST("MCHMID/hPt"), pt); - // fRegistry.fill(HIST("MCHMID/hEtaPhi"), phi, eta); - // fRegistry.fill(HIST("MCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); - // fRegistry.fill(HIST("MCHMID/hDeltaPt_Pt"), pt, dpt); - // fRegistry.fill(HIST("MCHMID/hDeltaEta_Pt"), pt, deta); - // fRegistry.fill(HIST("MCHMID/hDeltaPhi_Pt"), pt, dphi); - // fRegistry.fill(HIST("MCHMID/hSign"), fwdtrack.sign()); - // fRegistry.fill(HIST("MCHMID/hNclusters"), fwdtrack.nClusters()); - // fRegistry.fill(HIST("MCHMID/hNclustersMFT"), nClustersMFT); - // fRegistry.fill(HIST("MCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); - // fRegistry.fill(HIST("MCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); - // fRegistry.fill(HIST("MCHMID/hChi2"), fwdtrack.chi2()); - // fRegistry.fill(HIST("MCHMID/hChi2MFT"), chi2mft / ndf_mft); - // fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - // fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); - // fRegistry.fill(HIST("MCHMID/hDCAxy2D"), dcaX, dcaY); - // fRegistry.fill(HIST("MCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); - // fRegistry.fill(HIST("MCHMID/hDCAxy"), dcaXY); - // fRegistry.fill(HIST("MCHMID/hDCAxyz"), dcaXY, dcaZ); - // fRegistry.fill(HIST("MCHMID/hDCAxyinSigma"), dcaXYinSigma); - // fRegistry.fill(HIST("MCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um - // } - // } - return true; - } - - SliceCache cache; - Preslice perCollision = o2::aod::fwdtrack::collisionId; - Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; - PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; - PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; - - // Filter trackFilter = o2::aod::fwdtrack::trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) || o2::aod::fwdtrack::trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack); - // using filteredMyFwdTracks = soa::Filtered; - // Partition posTracks = o2::aod::fwdtrack::signed1Pt > 0.f; - // Partition negTracks = o2::aod::fwdtrack::signed1Pt < 0.f; - - std::vector vecMuons; - - void processRec(MyCollisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) - { - vecMuons.reserve(fwdtracks.size()); - - for (const auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - - if (!collision.isSelected()) { - continue; - } - - auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); - for (const auto& fwdtrack : fwdtracks_per_coll) { - fillMuonInfo(collision, fwdtrack); - } - - auto pos_muons_per_col = std::views::filter(vecMuons, [](Muon muon) { return muon.sign > 0; }); - auto neg_muons_per_col = std::views::filter(vecMuons, [](Muon muon) { return muon.sign < 0; }); - - // ULS - for (const auto& pos : pos_muons_per_col) { - if (!isSelectedTight(pos)) { // pos is tag, neg is probe - continue; - } - for (const auto& neg : neg_muons_per_col) { - if (!isSelected(neg)) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(pos.pt, pos.eta, pos.phi, o2::constants::physics::MassMuon); // tag - ROOT::Math::PtEtaPhiMVector v2(neg.pt, neg.eta, neg.phi, o2::constants::physics::MassMuon); // probe - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (neg.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (pos.matchMCHTrackId == neg.matchMCHTrackId || pos.matchMFTTrackId == neg.matchMFTTrackId) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_gl/hMvsPt"), v12.M(), v2.Pt()); - } else if (neg.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (pos.matchMCHTrackId == neg.globalIndex) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_sa/hMvsPt"), v12.M(), v2.Pt()); - } - if (pairCuts.minMass < v12.M() && v12.M() < pairCuts.maxMass) { - fillFwdTrackTable(collision, neg, fwdtracks.rawIteratorAt(neg.globalIndex)); - } - } // end of neg - } // end of pos - - // ULS - for (const auto& neg : neg_muons_per_col) { - if (!isSelectedTight(neg)) { // neg is tag, pos is probe - continue; - } - for (const auto& pos : pos_muons_per_col) { - if (!isSelected(pos)) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(neg.pt, neg.eta, neg.phi, o2::constants::physics::MassMuon); // tag - ROOT::Math::PtEtaPhiMVector v2(pos.pt, pos.eta, pos.phi, o2::constants::physics::MassMuon); // probe - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (pos.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (pos.matchMCHTrackId == neg.matchMCHTrackId || pos.matchMFTTrackId == neg.matchMFTTrackId) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_gl/hMvsPt"), v12.M(), v2.Pt()); - } else if (pos.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (neg.matchMCHTrackId == pos.globalIndex) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_sa/hMvsPt"), v12.M(), v2.Pt()); - } - if (pairCuts.minMass < v12.M() && v12.M() < pairCuts.maxMass) { - fillFwdTrackTable(collision, pos, fwdtracks.rawIteratorAt(pos.globalIndex)); - } - } // end of pos - } // end of neg - - } // end of collision loop - - vecMuons.clear(); - vecMuons.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuonQC, processRec, "process reconstructed info", false); - - void processRec_SWT(MyCollisionsWithSWT const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) - { - vecMuons.reserve(fwdtracks.size()); - - for (const auto& collision : collisions) { - const auto& bc = collision.template bc_as(); - initCCDB(bc); - - if (!collision.isSelected()) { - continue; - } - - if (collision.triggerMask_raw() == 0) { - continue; - } - - // const auto& fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); - // for (const auto& fwdtrack : fwdtracks_per_coll) { - // if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - // continue; - // } - - // if (!fillFwdTrackTable(collision, fwdtrack, false)) { - // continue; - // } - - // } // end of fwdtrack loop - } // end of collision loop - - vecMuons.clear(); - vecMuons.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuonQC, processRec_SWT, "process reconstructed info only with standalone", false); - - using filteredMyFwdTracksMC = soa::Filtered; - void processMC(soa::Join const& collisions, MyFwdTracksMC const& fwdtracks, MFTTracksMC const&, aod::BCsWithTimestamps const&, aod::McParticles const&) - { - vecMuons.reserve(fwdtracks.size()); - - for (const auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - if (!collision.isSelected()) { - continue; - } - if (!collision.has_mcCollision()) { - continue; - } - - // auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); - // for (const auto& fwdtrack : fwdtracks_per_coll) { - // if (!fwdtrack.has_mcParticle()) { - // continue; - // } - // if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - // continue; - // } - - // if (!fillFwdTrackTable(collision, fwdtrack, false)) { - // continue; - // } - - // } // end of fwdtrack loop - } // end of collision loop - - vecMuons.clear(); - vecMuons.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuonQC, processMC, "process reconstructed and MC info", false); - - void processDummy(aod::Collisions const&) {} - PROCESS_SWITCH(skimmerPrimaryMuonQC, processDummy, "process dummy", true); -}; -struct associateAmbiguousMuon { - Produces em_amb_muon_ids; - - SliceCache cache; - PresliceUnsorted perTrack = o2::aod::emprimarymuon::fwdtrackId; - std::vector ambmuon_self_Ids; - - void process(aod::EMPrimaryMuons const& muons) - { - for (const auto& muon : muons) { - auto muons_with_same_trackId = muons.sliceBy(perTrack, muon.fwdtrackId()); - ambmuon_self_Ids.reserve(muons_with_same_trackId.size()); - for (const auto& amb_muon : muons_with_same_trackId) { - if (amb_muon.globalIndex() == muon.globalIndex()) { // don't store myself. - continue; - } - ambmuon_self_Ids.emplace_back(amb_muon.globalIndex()); - } - em_amb_muon_ids(ambmuon_self_Ids); - ambmuon_self_Ids.clear(); - ambmuon_self_Ids.shrink_to_fit(); - } - } -}; - -struct associateSameMuonElement { - Produces glmuon_same_ids; - - SliceCache cache; - PresliceUnsorted perMFTTrack = o2::aod::emprimarymuon::mfttrackId; - PresliceUnsorted perMCHTrack = o2::aod::emprimarymuon::mchtrackId; - std::vector selfIds_per_MFT; - std::vector selfIds_per_MCHMID; - - // Multiple MCH-MID tracks can match with the same MFTsa. This function is to reject such global muons. - void process(aod::EMPrimaryMuons const& muons) - { - for (const auto& muon : muons) { - if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - auto muons_with_same_mfttrackId = muons.sliceBy(perMFTTrack, muon.mfttrackId()); - auto muons_with_same_mchtrackId = muons.sliceBy(perMCHTrack, muon.mchtrackId()); - selfIds_per_MFT.reserve(muons_with_same_mfttrackId.size()); - selfIds_per_MCHMID.reserve(muons_with_same_mchtrackId.size()); - // LOGF(info, "muons_with_same_mchtrackId.size() = %d, muons_with_same_mfttrackId.size() = %d", muons_with_same_mchtrackId.size(), muons_with_same_mfttrackId.size()); - - for (const auto& global_muon : muons_with_same_mfttrackId) { - // LOGF(info, "same MFT: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); - if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. - continue; - } - if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. - selfIds_per_MFT.emplace_back(global_muon.globalIndex()); - } - } - - for (const auto& global_muon : muons_with_same_mchtrackId) { - // LOGF(info, "same MCH: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); - if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. - continue; - } - if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. - selfIds_per_MCHMID.emplace_back(global_muon.globalIndex()); - } - } - - glmuon_same_ids(selfIds_per_MCHMID, selfIds_per_MFT); - selfIds_per_MFT.clear(); - selfIds_per_MFT.shrink_to_fit(); - selfIds_per_MCHMID.clear(); - selfIds_per_MCHMID.shrink_to_fit(); - } else { - glmuon_same_ids(std::vector{}, std::vector{}); // empty for standalone muons - selfIds_per_MFT.clear(); - selfIds_per_MFT.shrink_to_fit(); - selfIds_per_MCHMID.clear(); - selfIds_per_MCHMID.shrink_to_fit(); - } - } // end of muon loop - } -}; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon-qc"}), - adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-muon"}), - adaptAnalysisTask(cfgc, TaskName{"associate-same-muon-element"})}; -} diff --git a/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h index 1056de45a76..26b1f2c9490 100644 --- a/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h +++ b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h @@ -50,8 +50,8 @@ class EMPhotonEventCut kNCuts }; - const std::string getName() const { return name; } - const std::string getTitle() const { return title; } + [[nodiscard]] const std::string& getName() const { return name; } + [[nodiscard]] const std::string& getTitle() const { return title; } template bool IsSelected(T const& collision) const diff --git a/PWGEM/PhotonMeson/DataModel/EventTables.h b/PWGEM/PhotonMeson/DataModel/EventTables.h index 7bbd2a761dc..93630002fc5 100644 --- a/PWGEM/PhotonMeson/DataModel/EventTables.h +++ b/PWGEM/PhotonMeson/DataModel/EventTables.h @@ -29,36 +29,37 @@ #include // for BIT #include +#include namespace o2::aod { namespace pmevsel { -// Event selection criteria. See O2Physics/Common/CCDB/EventSelectionParams.h -enum EventSelectionFlags { - kIsTriggerTVX = 0, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level - kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border - kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders - kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC - kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 - kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) - kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF - kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD - kNoCollInTimeRangeNarrow, // no other collisions in specified time range (narrower than Strict) - kNoCollInTimeRangeStrict, // no other collisions in specified time range - kNoCollInTimeRangeStandard, // no other collisions in specified time range with per-collision multiplicity above threshold - kNoCollInRofStrict, // no other collisions in this Readout Frame - kNoCollInRofStandard, // no other collisions in this Readout Frame with per-collision multiplicity above threshold - kNoHighMultCollInPrevRof, // veto an event if FT0C amplitude in previous ITS ROF is above threshold - kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value - kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values - kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values - kNsel // counter -}; -DECLARE_SOA_BITMAP_COLUMN(Selection, selection, 32); //! Bitmask of selection flags -DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint32_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::pmevsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::pmevsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::pmevsel::kNoITSROFrameBorder)); }); +DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint64_t selection_bit, int runNumber) -> bool { + return (selection_bit & BIT(o2::aod::evsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::evsel::kNoTimeFrameBorder)) && (runNumber < 568873 ? (selection_bit & BIT(o2::aod::evsel::kNoITSROFrameBorder)) : true); // o2-linter: disable=magic-number (hard-coded run range to indicate 2026 datataking) +}); + +// Enum used for filling table for event-norm purposes +enum EventAcceptanceBits { + kAll = 0, // o2-linter: disable=magic-number (enum) + kHasMCColl, + kGoodZVtx, + kIsFT0AND, + kNoTFB, + kITSROFB, + kNoSameBunchPileUp, + kGoodZVtxFTOPV, + kNoCollInTimeRange, + kGoodTrackOccupancy, + kGoodFT0Occupancy, + kTVXInEMC, + kGoodCent, + kGoodRCT, + kGoodSel8, + kSize +}; } // namespace pmevsel @@ -66,16 +67,27 @@ namespace pmevent { DECLARE_SOA_COLUMN(CollisionId, collisionId, int); -DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint64_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::evsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::evsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::evsel::kNoITSROFrameBorder)); }); } // namespace pmevent DECLARE_SOA_TABLE(PMEvents, "AOD", "PMEVENT", //! Main event information table o2::soa::Index<>, pmevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Selection, evsel::Rct, timestamp::Timestamp, collision::PosZ, - collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, pmevent::Sel8); + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, pmevsel::Sel8); using PMEvent = PMEvents::iterator; +// Tables for event selection and event bookkeeping + +DECLARE_SOA_COLUMN(IsSelected, isSelected, bool); //! MB event selection info +DECLARE_SOA_TABLE(PMEvSels, "AOD", "PMEVSEL", //! joinable to o2::aod::Collisions + IsSelected); +using PMEvSel = PMEvSels::iterator; + +DECLARE_SOA_COLUMN(EventSelectionBit, eventSelectionBit, std::vector); //! Event selection info stored in binned data for each DF +DECLARE_SOA_TABLE(PMEvSelBits, "AOD", "PMEVSELBITS", //! produces binned data that can be loaded in analysis task for event counting + EventSelectionBit); +using PMEvSelBit = PMEvSelBits::iterator; + namespace ccdbPcm { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) diff --git a/PWGEM/PhotonMeson/Legacy/CMakeLists.txt b/PWGEM/PhotonMeson/Legacy/CMakeLists.txt index eb838a12cd8..0fae049d13a 100644 --- a/PWGEM/PhotonMeson/Legacy/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Legacy/CMakeLists.txt @@ -38,3 +38,18 @@ o2physics_add_dpl_workflow(gammaconversionstruthonlymc SOURCES gammaConversionsTruthOnlyMc.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(material-budget + SOURCES MaterialBudget.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(material-budget-mc + SOURCES MaterialBudgetMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pcm-qc-mc + SOURCES pcmQCMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx b/PWGEM/PhotonMeson/Legacy/MaterialBudget.cxx similarity index 100% rename from PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx rename to PWGEM/PhotonMeson/Legacy/MaterialBudget.cxx diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx b/PWGEM/PhotonMeson/Legacy/MaterialBudgetMC.cxx similarity index 100% rename from PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx rename to PWGEM/PhotonMeson/Legacy/MaterialBudgetMC.cxx diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Legacy/pcmQCMC.cxx similarity index 100% rename from PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx rename to PWGEM/PhotonMeson/Legacy/pcmQCMC.cxx diff --git a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt index 4cc5fb529b5..4088e60c489 100644 --- a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt +++ b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt @@ -60,3 +60,8 @@ o2physics_add_dpl_workflow(material-budget-weights SOURCES materialBudgetWeights.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::CCDB ROOT::Hist ROOT::Core COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-selection-photon + SOURCES eventSelection.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx index 786e373470c..e89f5c765e6 100644 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -13,6 +13,7 @@ /// \brief This code produces EmMc tables were the McParticleIds get reshuffled due to not storing all McParticles /// \author Daiki Sekihata (daiki.sekihata@cern.ch), Marvin Hemmer (marvin.hemmer@cern.ch), Nicolas Strangmann (nicolas.strangmann@cern.ch) +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -56,7 +57,7 @@ using namespace o2::soa; using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::constants::physics; -using MyCollisionsMC = soa::Join; +using MyCollisionsMC = soa::Join; using TracksMC = soa::Join; using FwdTracksMC = soa::Join; using MyEMCClusters = soa::Join; diff --git a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx index 4a3ab9a1a91..03aba7421de 100644 --- a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx @@ -50,7 +50,7 @@ using namespace o2::soa; using MyBCs = soa::Join; using MyQvectors = soa::Join; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollisionsCent = soa::Join; // centrality table has dependency on multiplicity table. using MyCollisionsCentQvec = soa::Join; @@ -95,6 +95,7 @@ struct CreateEMEventPhoton { template void skimEvent(TCollisions const& collisions, TBCs const&) { + for (const auto& collision : collisions) { if constexpr (isMC) { if (!collision.has_mcCollision()) { diff --git a/PWGEM/PhotonMeson/TableProducer/eventSelection.cxx b/PWGEM/PhotonMeson/TableProducer/eventSelection.cxx new file mode 100644 index 00000000000..64c46cda5b3 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/eventSelection.cxx @@ -0,0 +1,196 @@ +// Copyright 2019-2020 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. +// +// ======================== +// +// This code produces event selection table for PWG-EM Photon/Meson. + +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +// +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using EventAccBits = o2::aod::pmevsel::EventAcceptanceBits; + +using MyCollisions = soa::Join; +using MyCollisions_Cent = soa::Join; + +using MyCollisionsMC = soa::Join; +using MyCollisionsMC_Cent = soa::Join; + +struct PMEventSelection { + Produces pmevsel; + Produces pmevselbits; + + // Configurables + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1.f, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + + Configurable cfgZvtxMin{"cfgZvtxMin", -1e+10, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 1e+10, "max. Zvtx"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", false, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + + Configurable cfgRequireTVXinEMC{"cfgRequireTVXinEMC", false, "require kTVXinEMC (only for EMC analyses)"}; + + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 condition"}; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + std::vector vecEvSelBits; + + void init(InitContext&) + { + rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + vecEvSelBits.assign(EventAccBits::kSize, 0); + } + + template + bool isSelectedEvent(TCollision const& collision) + { + vecEvSelBits[EventAccBits::kAll]++; + if constexpr (std::is_same_v, MyCollisionsMC::iterator> || std::is_same_v, MyCollisionsMC_Cent::iterator>) { + if (!collision.has_mcCollision()) { + return false; + } + } + vecEvSelBits[EventAccBits::kHasMCColl]++; + + if (collision.posZ() < cfgZvtxMin || cfgZvtxMax < collision.posZ()) { + return false; + } + vecEvSelBits[EventAccBits::kGoodZVtx]++; + + if (cfgRequireFT0AND && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + vecEvSelBits[EventAccBits::kIsFT0AND]++; + + if (cfgRequireNoTFB && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + vecEvSelBits[EventAccBits::kNoTFB]++; + + if (cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + vecEvSelBits[EventAccBits::kITSROFB]++; + + if (cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + vecEvSelBits[EventAccBits::kNoSameBunchPileUp]++; + + if (cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + vecEvSelBits[EventAccBits::kGoodZVtxFTOPV]++; + + if (cfgRequireNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + vecEvSelBits[EventAccBits::kNoCollInTimeRange]++; + + if (!(cfgTrackOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < cfgTrackOccupancyMax)) { + return false; + } + vecEvSelBits[EventAccBits::kGoodTrackOccupancy]++; + + if (!(cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < cfgFT0COccupancyMax)) { + return false; + } + vecEvSelBits[EventAccBits::kGoodFT0Occupancy]++; + + if (cfgRequireTVXinEMC && !collision.alias_bit(triggerAliases::kTVXinEMC)) { + return false; + } + vecEvSelBits[EventAccBits::kTVXInEMC]++; + + if constexpr (std::is_same_v, MyCollisions_Cent::iterator>) { + std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + return false; + } + } + vecEvSelBits[EventAccBits::kGoodCent]++; + + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + // LOGF(info, "rejected by RCT flag"); + return false; + } + vecEvSelBits[EventAccBits::kGoodRCT]++; + + if (cfgRequireSel8 && !collision.sel8()) { + return false; + } + vecEvSelBits[EventAccBits::kGoodSel8]++; + + return true; + } + + template + void processEventSelection(TCollisions const& collisions) + { + // reset the event counter to zero for all elements + vecEvSelBits.assign(EventAccBits::kSize, 0); + + for (const auto& collision : collisions) { + pmevsel(isSelectedEvent(collision)); + } // end of collision loop + // Write event selection info at the end of DF + pmevselbits(vecEvSelBits); + } // end of process + + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelection, "event selection", true); + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelection_Cent, "event selection with cent", false); + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelectionMC, "event selection MC", false); + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelectionMC_Cent, "event selection MC with cent", false); +}; +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + return WorkflowSpec{adaptAnalysisTask(context, TaskName{"em-event-selection"})}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index 01429a688b1..738d18a4415 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -88,7 +88,7 @@ using namespace o2::constants::physics; using namespace o2::pwgem::photonmeson; using std::array; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; // using MyCollisionsWithSWT = soa::Join; using MyCollisionsMC = soa::Join; using MyBCs = soa::Join; diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx index e82c3284c4c..3bb208f0452 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx @@ -14,6 +14,7 @@ /// \author marvin.hemmer@cern.ch /// dependencies: emcal-correction-task +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" @@ -311,19 +312,19 @@ struct SkimmerGammaCalo { } } - void processRec(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) + void processRec(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) { runAnalysis(collision, emcclusters, emcclustercells, emcmatchedtracks, tracks); } PROCESS_SWITCH(SkimmerGammaCalo, processRec, "process only reconstructed info", true); - void processRecWithSecondaries(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) + void processRecWithSecondaries(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) { runAnalysis(collision, emcclusters, emcclustercells, emcmatchedtracks, tracks, emcmatchedsecondaries); } PROCESS_SWITCH(SkimmerGammaCalo, processRecWithSecondaries, "process reconstructed info with secondary track matching.", false); - void processRecMC(soa::Join::iterator const& collision, + void processRecMC(soa::Join::iterator const& collision, soa::Join const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) @@ -332,7 +333,7 @@ struct SkimmerGammaCalo { } PROCESS_SWITCH(SkimmerGammaCalo, processRecMC, "process reconstructed info + MC labels at once", false); - void processRecMCWithSecondaries(soa::Join::iterator const& collision, + void processRecMCWithSecondaries(soa::Join::iterator const& collision, soa::Join const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx index 1f29b03cf07..fd55f41b1a0 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx @@ -64,7 +64,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::constants::physics; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollisionsWithSWT = soa::Join; using MyBCs = soa::Join; diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index 328f039590f..8afdf504200 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt @@ -31,11 +31,6 @@ o2physics_add_dpl_workflow(pcm-qc PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(pcm-qc-mc - SOURCES pcmQCMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(dalitz-ee-qc SOURCES dalitzEEQC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore O2Physics::PWGEMDileptonCore @@ -126,16 +121,6 @@ o2physics_add_dpl_workflow(tag-and-probe PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(material-budget - SOURCES MaterialBudget.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(material-budget-mc - SOURCES MaterialBudgetMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(check-mc-v0 SOURCES CheckMCV0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 1b161a8976a..63b1425bff0 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -9,15 +9,38 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file MaterialBudget.cxx -/// \brief This code runs loop over v0 photons for PCM QC. -/// \author Daiki Sekihata, daiki.sekihata@cern.ch +/// \file pcmQC.cxx +/// \brief Quality, purity, material and reconstruction monitoring of the selected V0 photon candidates +/// +/// - processQC: kinematics, conversion-point and leg-track QA of the +/// reconstructed photons. Material-budget configurables +/// add conversion-point maps, restricted to selectable +/// detector regions for material studies. +/// - processQCML: the same QC with the ML-based photon selection (BDT +/// models from CCDB) instead of the classical V0 cuts +/// - processPCMQCMC: MC-truth of the QC observables for the purity +/// assessment, plus resolution assessment. +/// Configurables activate collision-association studies +/// and the same regional material-budget mode as in +/// processQC, there with per-region resolution on top. +/// - processPCMQCMCML: the same MC QC with the ML-based photon selection +/// - processGen: generator-level distributions as the denominator +/// reference (requires the binned generated-pT derived +/// data as input). +/// - processRecoQA: runs on AO2Ds, before any skimming: track-level QA +/// plus a truth-based check of the SVertexer candidate +/// building and deduplication, separating genuine +/// reconstruction quality from reconstruction artifacts. +/// +/// \author Daiki Sekihata and author Stefanie Mrozinski +#include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCandidate.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" #include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" #include "Common/CCDB/EventSelectionParams.h" #include "Common/DataModel/Centrality.h" @@ -41,12 +64,16 @@ #include #include +#include +#include #include #include #include #include #include +#include +#include #include using namespace o2; @@ -55,6 +82,8 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; @@ -65,6 +94,19 @@ using MyV0Photon = MyV0Photons::iterator; using MyV0PhotonsML = soa::Join; using MyV0PhotonML = MyV0PhotonsML::iterator; +// MC Joins +using MyCollisionsMC = soa::Join; +using MyCollisionMC = MyCollisionsMC::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +// AO2D level (processRecoQA): tracks before any skimming, with their MC labels +using MyTracksMC = soa::Join; + struct PCMQC { Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; @@ -98,61 +140,112 @@ struct PCMQC { } eventcuts; V0PhotonCut fV0PhotonCut; + // v0 photon cuts + struct : ConfigurableGroup { + std::string prefix = "v0cut_group"; + Configurable cfgRequireV0WithITSTPC{"cfgRequireV0WithITSTPC", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfgRequireV0WithITSonly{"cfgRequireV0WithITSonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfgRequireV0WithTPConly{"cfgRequireV0WithTPConly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfgMinPtV0{"cfgMinPtV0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfgMaxPtV0{"cfgMaxPtV0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfgMinEtaV0{"cfgMinEtaV0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfgMaxEtaV0{"cfgMaxEtaV0", +0.8, "max eta for v0 photons at PV"}; + Configurable cfgMinV0Radius{"cfgMinV0Radius", 4.0, "min v0 radius"}; + Configurable cfgMaxV0Radius{"cfgMaxV0Radius", 90.0, "max v0 radius"}; + Configurable cfgMidLV0Radius{"cfgMidLV0Radius", -1.0, "middle low v0 radius for rejection if >0"}; + Configurable cfgMidHV0Radius{"cfgMidHV0Radius", -1.0, "middle high v0 radius for rejection if >0"}; + Configurable cfgMaxAlphaAP{"cfgMaxAlphaAP", 0.95, "max alpha for AP cut"}; + Configurable cfgMaxQtAP{"cfgMaxQtAP", 0.01, "max qT for AP cut"}; + Configurable cfgMinV0CosPA{"cfgMinV0CosPA", 0.999, "min V0 CosPA"}; + Configurable cfgMaxPCA{"cfgMaxPCA", 1.5, "max distance btween 2 legs"}; + Configurable cfgMaxChi2KF{"cfgMaxChi2KF", 1e+10, "max chi2/ndf with KF"}; + Configurable cfgRejectV0OnITSib{"cfgRejectV0OnITSib", true, "flag to reject V0s on ITSib"}; + } v0cuts; + + // single track cuts + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable cfgMinNClustersTPC{"cfgMinNClustersTPC", 0, "min ncluster tpc"}; + Configurable cfgMinNCrossedRows{"cfgMinNCrossedRows", 40, "min crossed rows"}; + Configurable cfgMaxFracSharedClustersTPC{"cfgMaxFracSharedClustersTPC", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfgMaxChi2TPC{"cfgMaxChi2TPC", 4.0, "max chi2/NclsTPC"}; + Configurable cfgMaxChi2ITS{"cfgMaxChi2ITS", 36.0, "max chi2/NclsITS"}; + Configurable cfgMinTPCNsigmaEl{"cfgMinTPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfgMaxTPCNsigmaEl{"cfgMaxTPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfgDisableITSonlyTracks{"cfgDisableITSonlyTracks", false, "disable ITSonly tracks in V0 legs"}; + Configurable cfgDisableTPConlyTracks{"cfgDisableTPConlyTracks", false, "disable TPConly tracks in V0 legs"}; + Configurable cfgDoDEdxPostCalibration{"cfgDoDEdxPostCalibration", false, "flag to enable dEdx post calibration"}; + } trackcuts; + + // pT-dependent loss QA + struct : ConfigurableGroup { + std::string prefix = "qaSettings_group"; + Configurable cfgDoPtDependentLossQA{"cfgDoPtDependentLossQA", false, "fill the cut variables vs. pT before AND after the V0 selection - the after/before ratio shows which candidates the cuts remove"}; + } qaSettingsGroup; + + // PCM ML inference + struct : ConfigurableGroup { + std::string prefix = "mlcut_group"; + Configurable cfgApplyPCMMl{"cfgApplyPCMMl", false, "Flag to apply ML selections"}; + Configurable cfgUse2DBinning{"cfgUse2DBinning", false, "Flag to enable/disable 2D binning for ML application"}; + Configurable cfgLoadModelsFromCCDB{"cfgLoadModelsFromCCDB", true, "Flag to enable or disable the loading of models from CCDB"}; + Configurable cfgTimestampCCDB{"cfgTimestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable cfgNClassesPCMMl{"cfgNClassesPCMMl", static_cast(o2::analysis::em_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> cfgCutDirPCMMl{"cfgCutDirPCMMl", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cfgNamesInputFeatures{"cfgNamesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + Configurable> cfgModelPathsCCDB{"cfgModelPathsCCDB", std::vector{"path_ccdb/BDT_PCM/"}, "Paths of models on CCDB"}; + Configurable> cfgOnnxFileNames{"cfgOnnxFileNames", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable> cfgLabelsBinsPCMMl{"cfgLabelsBinsPCMMl", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; + Configurable> cfgLabelsCutScoresPCMMl{"cfgLabelsCutScoresPCMMl", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; + Configurable> cfgBinsPtPCMMl{"cfgBinsPtPCMMl", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; + Configurable> cfgBinsCentPCMMl{"cfgBinsCentPCMMl", std::vector{o2::analysis::em_cuts_ml::vecBinsCent}, "Centrality bin limits for ML application"}; + Configurable> cfgCutsPCMMlFlat{"cfgCutsPCMMlFlat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; + } mlcuts; + + struct : ConfigurableGroup { + std::string prefix = "mcAnalysisModeSettings_group"; + Configurable cfgDoDetailedResolution{"cfgDoDetailedResolution", false, "purpose of the configurable is to choose if we have more THnSparses included in order to see if some regions have better or worse resolution"}; + Configurable cfgDoCollisionAssociationQA{"cfgDoCollisionAssociationQA", false, "include the QA Plots which give an idea how photon distribution changes with different subclasses or what the effect of wrong collision association is"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association for the truth-classified QC observables"}; + } mcAnalysisModeSettings; + struct : ConfigurableGroup { - std::string prefix = "pcmcut_group"; - Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; - Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; - Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; - Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; - Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; - Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; - Configurable cfg_max_eta_v0{"cfg_max_eta_v0", +0.8, "max eta for v0 photons at PV"}; - Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; - Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; - Configurable cfg_midL_v0radius{"cfg_midL_v0radius", -1.0, "middle low v0 radius for rejection if >0"}; - Configurable cfg_midH_v0radius{"cfg_midH_v0radius", -1.0, "middle high v0 radius for rejection if >0"}; - Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; - Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; - Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min V0 CosPA"}; - Configurable cfg_max_pca{"cfg_max_pca", 1.5, "max distance btween 2 legs"}; - Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; - Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; - Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; - Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; - Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; - Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; - Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; - Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; - Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; - Configurable cfg_dEdx_postcalibration{"cfg_dEdx_postcalibration", false, "flag to enable dEdx post calibration"}; - // for ML cuts - Configurable cfg_apply_ml_cuts{"cfg_apply_ml", false, "flag to apply ML cut"}; - Configurable cfg_use_2d_binning{"cfg_use_2d_binning", false, "flag to use 2D binning (pT, cent)"}; - Configurable cfg_load_ml_models_from_ccdb{"cfg_load_ml_models_from_ccdb", true, "flag to load ML models from CCDB"}; - Configurable cfg_timestamp_ccdb{"cfg_timestamp_ccdb", -1, "timestamp for CCDB"}; - Configurable cfg_nclasses_ml{"cfg_nclasses_ml", static_cast(o2::analysis::em_cuts_ml::NCutScores), "number of classes for ML"}; - Configurable> cfg_cut_dir_ml{"cfg_cut_dir_ml", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "cut direction for ML"}; - Configurable> cfg_input_feature_names{"cfg_input_feature_names", std::vector{"feature1", "feature2"}, "input feature names for ML models"}; - Configurable> cfg_model_paths_ccdb{"cfg_model_paths_ccdb", std::vector{"path_ccdb/BDT_PCM/"}, "CCDB paths for ML models"}; - Configurable> cfg_onnx_file_names{"cfg_onnx_file_names", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for ML models"}; - Configurable> cfg_labels_bins_ml{"cfg_labels_bins_ml", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; - Configurable> cfg_labels_cut_scores_ml{"cfg_labels_cut_scores_ml", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; - Configurable> cfg_bins_pt_ml{"cfg_bins_pt_ml", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; - Configurable> cfg_bins_cent_ml{"cfg_bins_cent_ml", std::vector{o2::analysis::em_cuts_ml::vecBinsCent}, "centrality bins for ML"}; - Configurable> cfg_cuts_ml_flat{"cfg_cuts_ml_flat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; - } pcmcuts; + std::string prefix = "materialBudgetSettings_group"; + Configurable cfgDoMaterialDistribution{"cfgDoMaterialDistribution", false, "add THnSparses of the conversion-point distribution for the material budget study"}; + Configurable cfgDoWiresDetail{"cfgDoWiresDetail", false, "add detailed conversion-point histograms around the wire region"}; + Configurable cfgDoMFTDetail{"cfgDoMFTDetail", false, "add detailed conversion-point histograms around the MFT region"}; + Configurable cfgDoITSDetail{"cfgDoITSDetail", false, "add detailed conversion-point histograms around the ITS layers"}; + Configurable cfgDoTPCInnerBarrelDetail{"cfgDoTPCInnerBarrelDetail", false, "add detailed conversion-point histograms around the TPC inner barrel"}; + } materialBudgetSettingsGroup; + + struct : ConfigurableGroup { + std::string prefix = "genSettings_group"; + Configurable cfgMaxRGen{"cfgMaxRGen", 90.f, "maximum conversion radius for generated photons (fiducial cut, matches the reco acceptance)"}; + Configurable cfgMarginZMC{"cfgMarginZMC", 7.0, "margin for z cut in cm for MC"}; + } genSettingsGroup; + + struct : ConfigurableGroup { + std::string prefix = "recoQASettings_group"; + Configurable cfgDoDetailedTrackQA{"cfgDoDetailedTrackQA", false, "add track-quality histograms of surviving vs. lost conversion legs"}; + Configurable cfgRMinGen{"cfgRMinGen", 1.f, "min true conversion radius (cm)"}; + Configurable cfgRMaxGen{"cfgRMaxGen", 90.f, "max true conversion radius (cm)"}; + Configurable cfgLegEtaMax{"cfgLegEtaMax", 0.9f, "max |eta| of true MC legs"}; + Configurable cfgPhotonEtaMax{"cfgPhotonEtaMax", 0.9f, "max |eta| of true MC photon"}; + Configurable cfgPhotonPtMin{"cfgPhotonPtMin", 0.1f, "min pT of true MC photon"}; + } recoQASettingsGroup; o2::ccdb::CcdbApi ccdbApi; o2::framework::Service ccdb{}; int mRunNumber = 0; float d_bz = 0; static constexpr std::array event_types = {"before/", "after/"}; + static constexpr std::array mcphoton_types = {"primary/", "fromWD/", "fromHS/", "fromPi0Dalitz/", "fromEtaDalitz/"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - void init(InitContext&) + void init(InitContext& context) { + + (void)context; addhistograms(); DefineEMEventCut(); DefinePCMCut(); @@ -174,11 +267,11 @@ struct PCMQC { } // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { + if (d_bz_input > -990) { // o2-linter: disable=magic-number (dummy value to indicate override) d_bz = d_bz_input; o2::parameters::GRPMagField grpmag; - if (std::fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + if (std::fabs(d_bz) > 1e-5) { // o2-linter: disable=magic-number (dummy value to indicate override) + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); // o2-linter: disable=magic-number (dummy value to indicate override) } mRunNumber = collision.runNumber(); return; @@ -245,6 +338,11 @@ struct PCMQC { fRegistry.add("V0/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}, false); fRegistry.add("V0/hDCAz_Pt", "DCA_{z} to PV vs. p_{T};DCA_{z} (cm);p_{T} (GeV/c)", kTH2F, {{200, -5.f, +5.f}, {2000, 0.0f, 20}}, false); fRegistry.add("V0/hAPplot", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}, false); + fRegistry.add("V0/hRxyVsPt", "conversion radius vs. pT;p_{T,#gamma} (GeV/c);R_{xy} (cm)", kTH2F, {{100, 0, 10}, {200, 0, 100}}, false); + fRegistry.add("V0/hEtaVsPt", "#eta vs. pT;p_{T,#gamma} (GeV/c);#eta", kTH2F, {{100, 0, 10}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/hPhiVsPt", "#varphi vs. pT;p_{T,#gamma} (GeV/c);#varphi (rad.)", kTH2F, {{100, 0, 10}, {90, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/hsAlphaQtPt", "Armenteros vs. pT;#alpha;q_{T} (GeV/c);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{100, -1.0f, +1.0f}, {125, 0.0f, 0.25f}, {100, 0, 10}}, false); + fRegistry.add("V0/hPsiPairVsPt", "#psi_{pair} vs. pT;p_{T,#gamma} (GeV/c);#psi_{pair} (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5f, +0.5f}}, false); fRegistry.add("V0/hMassGamma", "hMassGamma;R_{xy} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.0f, 0.1f}}, false); fRegistry.add("V0/hKFChi2vsM", "KF chi2 vs. m_{ee};m_{ee} (GeV/c^{2});KF chi2/NDF", kTH2F, {{100, 0.0f, 0.1f}, {100, 0.f, 100.0f}}, false); fRegistry.add("V0/hKFChi2vsR", "KF chi2 vs. conversion point in XY;R_{xy} (cm);KF chi2/NDF", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.f, 100.0f}}, false); @@ -254,12 +352,12 @@ struct PCMQC { fRegistry.add("V0/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); fRegistry.add("V0/hNgamma", "Number of #gamma candidates per collision", kTH1F, {{101, -0.5f, 100.5f}}); - if (pcmcuts.cfg_apply_ml_cuts) { - if (pcmcuts.cfg_nclasses_ml == 2) { + if (mlcuts.cfgApplyPCMMl) { + if (mlcuts.cfgNClassesPCMMl == 2) { // o2-linter: disable=magic-number (BDT class) fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hBDTSignalScoreVsPt", "BDT signal score vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); - } else if (pcmcuts.cfg_nclasses_ml == 3) { + } else if (mlcuts.cfgNClassesPCMMl == 3) { // o2-linter: disable=magic-number (BDT class) fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hBDTPrimaryPhotonScoreVsPt", "BDT primary photon score vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hBDTSecondaryPhotonScoreVsPt", "BDT secondary photon score vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); @@ -281,6 +379,7 @@ struct PCMQC { fRegistry.add("V0Leg/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); fRegistry.add("V0Leg/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); fRegistry.add("V0Leg/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/hTPCNsigmaElVsEta", "TPC n sigma el vs. eta;#eta;n #sigma_{e}^{TPC}", kTH2F, {{40, -1.0f, 1.0f}, {100, -5, +5}}, false); // eta-dependence = dE/dx calibration check (TOF/ITS n#sigma not stored in the V0Leg skim) fRegistry.add("V0Leg/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); fRegistry.add("V0Leg/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); fRegistry.add("V0Leg/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); @@ -288,13 +387,193 @@ struct PCMQC { fRegistry.add("V0Leg/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); fRegistry.add("V0Leg/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); fRegistry.add("V0Leg/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); - if (pcmcuts.cfg_dEdx_postcalibration) { + if (trackcuts.cfgDoDEdxPostCalibration) { fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos", "momentum of pos leg vs. conversion point of V0 vs. TPC n sigma pos vs. eta of pos leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele", "momentum of neg leg vs. conversion point of V0 vs. TPC n sigma el vs. eta of neg leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); } - // fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); - // fRegistry.add("V0Leg/hZX", "Z vs. X;Z (cm);X (cm)", kTH2F, {{200, -100, 100}, {100, 0, 100}}, false); - // fRegistry.add("V0Leg/hZY", "Z vs. Y;Z (cm);Y (cm)", kTH2F, {{200, -100, 100}, {80, -20, 20}}, false); + + if (materialBudgetSettingsGroup.cfgDoMaterialDistribution) { + fRegistry.add("MaterialBudget/hs", "conversion point;z (cm);r_{xy} (cm);#eta;#varphi (rad.);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{200, -100, 100}, {100, 0, 100}, {80, -2, +2}, {90, 0, o2::constants::math::TwoPI}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoWiresDetail) { + fRegistry.add("MaterialBudget/Wires/hsLeft", "conversion point near left wire;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{200, -20, 20}, {200, -20, 20}, {80, -20, 20}, {40, 3.15, 3.4}, {80, 0, 20}, {100, 0, 10}}, false); + fRegistry.add("MaterialBudget/Wires/hsRight", "conversion point near right wire;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{200, -20, 20}, {200, -20, 20}, {80, -20, 20}, {40, 6.00, 6.15}, {80, 0, 20}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoITSDetail) { + fRegistry.add("MaterialBudget/ITS/hs", "conversion point around the ITS layers;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{160, -40, 40}, {160, -40, 40}, {80, -40, 40}, {90, 0, o2::constants::math::TwoPI}, {150, 0, 60}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoMFTDetail) { + fRegistry.add("MaterialBudget/MFT/hs", "conversion point around the MFT region;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{160, -80, 80}, {160, -80, 80}, {40, -40, 40}, {90, 0, o2::constants::math::TwoPI}, {40, 40, 60}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoTPCInnerBarrelDetail) { + fRegistry.add("MaterialBudget/TPC/hs", "conversion point around the TPC inner barrel;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{160, -90, 90}, {160, -90, 90}, {80, -40, 40}, {90, 0, o2::constants::math::TwoPI}, {80, 60, 80}, {100, 0, 10}}, false); + } + + if (doprocessGen) { + std::vector ptbins; + ptbins.reserve(72); + for (int i = 0; i < 2; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c + } + for (int i = 2; i < 51; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(0.1 * (i - 2) + 0.1); // from 0.1 to 4.9 GeV/c, every 0.1 GeV/c + } + for (int i = 51; i < 61; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(0.5 * (i - 51) + 5.0); // from 5 to 9.5 GeV/c, every 0.5 GeV/c + } + for (int i = 61; i < 72; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(1.0 * (i - 61) + 10.0); // from 10 to 20 GeV/c, every 1 GeV/c + } + const AxisSpec axisPtGen{ptbins, "p_{T,#gamma} (GeV/c)"}; + const AxisSpec axisRapidityGen{{0.0, +0.8, +0.9}, "rapidity |y_{#gamma}|"}; + + fRegistry.add("Generated/hPt", "pT;p_{T} (GeV/c)", kTH1D, {axisPtGen}, true); + fRegistry.add("Generated/hPtY", "Generated info", kTH2D, {axisPtGen, axisRapidityGen}, true); + fRegistry.add("Generated/hPt_ConversionPhoton", "converted photon pT;p_{T} (GeV/c)", kTH1D, {axisPtGen}, true); + fRegistry.add("Generated/hY_ConversionPhoton", "converted photon y;rapidity y", kTH1F, {{40, -2.0f, 2.0f}}, true); + fRegistry.add("Generated/hPhi_ConversionPhoton", "converted photon #varphi;#varphi (rad.)", kTH1F, {{180, 0, o2::constants::math::TwoPI}}, true); + fRegistry.add("Generated/hXY", "conversion point in XY MC;V_{x} (cm);V_{y} (cm)", kTH2F, {{800, -100.0f, 100.0f}, {800, -100.0f, 100.0f}}, true); + fRegistry.add("Generated/hRZ", "conversion point in RZ MC;V_{z} (cm);R_{xy} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, 0.f, 100.0f}}, true); + fRegistry.add("Generated/hRPhi", "conversion point of #varphi vs. R_{xy} MC;#varphi (rad.);R_{xy} (cm);N_{e}", kTH2F, {{360, 0.0f, o2::constants::math::TwoPI}, {400, 0, 100}}, true); + fRegistry.add("Generated/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, true); + fRegistry.add("Generated/hR_ConversionPhoton_wideR", "converted photon R_{xy} up to the EMCal, before fiducial cuts;R_{xy} (cm);N_{#gamma}", kTH1F, {{250, 0.0f, 500.0f}}, true); + fRegistry.add("Generated/hRZ_wideR", "conversion point in RZ up to the EMCal, before fiducial cuts;V_{z} (cm);R_{xy} (cm)", kTH2F, {{200, -400.0f, 400.0f}, {250, 0.0f, 500.0f}}, true); + fRegistry.add("Generated/hsRZPhi_wideR", "conversion point up to the EMCal, before fiducial cuts;V_{z} (cm);#varphi (rad.);R_{xy} (cm)", kTHnSparseF, {{200, -400.0f, 400.0f}, {360, 0.0f, o2::constants::math::TwoPI}, {250, 0.0f, 500.0f}}, true); + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + fRegistry.add("Generated/hPtEtaPhi", "Photon pt vs eta, and phi;p_{T, gen} (GeV/c);#eta;#phi", kTHnSparseF, {{200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + } + } + + if (doprocessPCMQCMC || doprocessPCMQCMCML) { + fRegistry.add("V0/primary/hPt", "pT;p_{T,#gamma} (GeV/c)", kTH1F, {{2000, 0.0f, 20}}, false); + fRegistry.add("V0/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, o2::constants::math::TwoPI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/primary/hXY", "conversion point in XY;V_{x} (cm);V_{y} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, -100.0f, 100.0f}}, false); + fRegistry.add("V0/primary/hRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}, false); + fRegistry.add("V0/primary/hCosPA", "V0CosPA;cosine pointing angle in 3D", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hCosPAXY", "V0CosPA;cosine pointing angle in XY", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hCosPARZ", "V0CosPA;cosine pointing angle in RZ", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hPCA", "distance between 2 legs;PCA (cm)", kTH1F, {{500, 0.0f, 5.0f}}, false); + fRegistry.add("V0/primary/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}, false); + fRegistry.add("V0/primary/hDCAz_Pt", "DCA_{z} to PV vs. p_{T};DCA_{z} (cm);p_{T} (GeV/c)", kTH2F, {{200, -5.f, +5.f}, {2000, 0.0f, 20}}, false); + fRegistry.add("V0/primary/hAPplot", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}, false); + fRegistry.add("V0/primary/hRxyVsPt", "conversion radius vs. pT;p_{T,#gamma} (GeV/c);R_{xy} (cm)", kTH2F, {{100, 0, 10}, {200, 0, 100}}, false); + fRegistry.add("V0/primary/hEtaVsPt", "#eta vs. pT;p_{T,#gamma} (GeV/c);#eta", kTH2F, {{100, 0, 10}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/primary/hPhiVsPt", "#varphi vs. pT;p_{T,#gamma} (GeV/c);#varphi (rad.)", kTH2F, {{100, 0, 10}, {90, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/primary/hsAlphaQtPt", "Armenteros vs. pT;#alpha;q_{T} (GeV/c);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{100, -1.0f, +1.0f}, {125, 0.0f, 0.25f}, {100, 0, 10}}, false); + fRegistry.add("V0/primary/hPsiPairVsPt", "#psi_{pair} vs. pT;p_{T,#gamma} (GeV/c);#psi_{pair} (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5f, +0.5f}}, false); + fRegistry.add("V0/primary/hMassGamma", "hMassGamma;R_{xy} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("V0/primary/hKFChi2vsM", "KF chi2 vs. m_{ee};m_{ee} (GeV/c^{2});KF chi2/NDF", kTH2F, {{100, 0.0f, 0.1f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsR", "KF chi2 vs. conversion point in XY;R_{xy} (cm);KF chi2/NDF", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsX", "KF chi2 vs. conversion point in X;X (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsY", "KF chi2 vs. conversion point in Y;Y (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsZ", "KF chi2 vs. conversion point in Z;Z (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hNgamma", "Number of true #gamma per collision;N_{#gamma} per event;Number of events", kTH1F, {{101, -0.5f, 100.5f}}); + fRegistry.add("V0/primary/hConvPoint_diffX", "conversion point diff X MC;X_{MC} (cm);X_{rec} - X_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hConvPoint_diffY", "conversion point diff Y MC;Y_{MC} (cm);Y_{rec} - Y_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hConvPoint_diffZ", "conversion point diff Z MC;Z_{MC} (cm);Z_{rec} - Z_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaPtOverPtGen", "photon p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaEta", "photon #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{200, 0, 20}, {199, -0.099, 0.099}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaPhi", "photon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{200, 0, 20}, {199, -0.099, 0.099}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaPtOverPtGen", "photon p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaEta", "photon #eta resolution;R_{xy}^{gen} (cm);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaPhi", "photon #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaR", "photon R_{xy} resolution;R_{xy}^{gen} (cm);R_{xy}^{rec} - R_{xy}^{gen} (cm)", kTH2F, {{100, 0, 100}, {100, 0, 100}}, true); + fRegistry.add("V0/primary/hXY_MC", "X vs. Y of true photon conversion point.;X (cm);Y (cm)", kTH2F, {{400, -100.0f, +100}, {400, -100, +100}}, true); + fRegistry.add("V0/primary/hRZ_MC", "R vs. Z of true photon conversion point;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100.0f, +100}, {200, 0, 100}}, true); + fRegistry.add("V0/primary/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + fRegistry.add("V0/primary/hEtaPhiResol", "Photon eta-phi resolution;p_{T} (GeV/c);#eta-diff;#phi-diff", kTH3F, {{200, 0., 20.}, {99, -0.049, 0.049}, {99, -0.049, 0.049}}, false); + fRegistry.add("V0/primary/hPtResolPtEtaPhi", "Photon resolution vs. pt, eta, and phi;p_{T_rec} - p_{T true} / p_{T true};p_{T} (GeV/c);#eta;#phi", kTHnSparseF, {{199, -0.995, 0.995}, {200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/primary/hMomResolPtEtaPhi", "Photon momentum resolution vs. p, eta, and phi;p_{rec} - p_{true} / p_{true};p_{T} (GeV/c);#eta;#phi", kTHnSparseF, {{199, -0.995, 0.995}, {200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/primary/hPtEtaPhi", "pt, eta, and phi;p_{T} (GeV/c);#eta;#phi", kTHnSparseF, {{200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + } + if (mlcuts.cfgApplyPCMMl) { + if (mlcuts.cfgNClassesPCMMl == 2) { // o2-linter: disable=magic-number (BDT group) + fRegistry.add("V0/primary/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTSignalScoreVsPt", "BDT signal score vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + } else if (mlcuts.cfgNClassesPCMMl == 3) { // o2-linter: disable=magic-number (BDT group) + fRegistry.add("V0/primary/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTPrimaryPhotonScoreVsPt", "BDT primary photon score vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTSecondaryPhotonScoreVsPt", "BDT secondary photon score vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + } else { + fRegistry.add("V0/primary/hBDTScoreVsPt", "BDT score vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + } + fRegistry.add("V0/primary/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } + fRegistry.addClone("V0/primary/", "V0/fromWD/"); // from weak decay + fRegistry.addClone("V0/primary/", "V0/fromHS/"); // from hadronic shower in detector materials + fRegistry.addClone("V0/primary/", "V0/fromPi0Dalitz/"); // misidentified dielectron from pi0 dalitz decay + fRegistry.addClone("V0/primary/", "V0/fromEtaDalitz/"); // misidentified dielectron from eta dalitz decay + fRegistry.addClone("V0/primary/hPt", "V0/candidate/hPt"); // only for purity + fRegistry.addClone("V0/primary/hEtaPhi", "V0/candidate/hEtaPhi"); // only for purity + + fRegistry.add("V0Leg/primary/hPt", "pT;p_{T,e} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("V0Leg/primary/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -50, 50}}, false); + fRegistry.add("V0Leg/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, o2::constants::math::TwoPI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0Leg/primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -50.0f, 50.0f}, {200, -50.0f, 50.0f}}, false); + fRegistry.add("V0Leg/primary/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/primary/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/primary/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/primary/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaElVsEta", "TPC n sigma el vs. eta;#eta;n #sigma_{e}^{TPC}", kTH2F, {{40, -1.0f, 1.0f}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/primary/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/primary/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("V0Leg/primary/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("V0Leg/primary/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/primary/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("V0Leg/primary/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); + fRegistry.add("V0Leg/primary/hPtGen_DeltaPtOverPtGen", "electron p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0Leg/primary/hPtGen_DeltaEta", "electron #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaPtOverPtGen", "electron p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaEta", "electron #eta resolution;R_{xy}^{gen} (cm);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaPhi", "electron #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromWD/"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromHS/"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromPi0Dalitz/"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromEtaDalitz/"); + fRegistry.addClone("V0Leg/primary/hPt", "V0Leg/candidate/hPt"); // only for purity + fRegistry.addClone("V0Leg/primary/hEtaPhi", "V0Leg/candidate/hEtaPhi"); // only for purity + + // collision-association QA: + if (mcAnalysisModeSettings.cfgDoCollisionAssociationQA) { + fRegistry.add("CollisionAssociation/hDeltaCollId", "MC-event index difference;#Delta coll ID (rec - true);N_{#gamma}", kTH1F, {{21, -10.5, 10.5}}, true); + fRegistry.add("CollisionAssociation/RightCollisions/hs", "correctly associated;R_{rec} (cm);p_{T} (GeV/c);#Delta p_{T}/p_{T,gen};#Delta z (cm);#Delta R (cm);#Delta coll ID", kTHnSparseF, {{100, 0, 100}, {200, 0, 10}, {200, -1, 1}, {200, -20, 20}, {200, -8, 8}, {21, -10.5, 10.5}}, true); + fRegistry.add("CollisionAssociation/WrongCollisions/hs", "wrongly associated;R_{rec} (cm);p_{T} (GeV/c);#Delta p_{T}/p_{T,gen};#Delta z (cm);#Delta R (cm);#Delta coll ID", kTHnSparseF, {{100, 0, 100}, {200, 0, 10}, {200, -1, 1}, {200, -20, 20}, {200, -8, 8}, {21, -10.5, 10.5}}, true); + } + } + + // pT-dependent loss QA: + if (qaSettingsGroup.cfgDoPtDependentLossQA) { + fRegistry.add("V0/LossQA/before/hCosPAvsPt", "cosPA vs. pT;p_{T,#gamma} (GeV/c);cosine pointing angle", kTH2F, {{100, 0, 10}, {100, 0.99, 1.0}}, false); + fRegistry.add("V0/LossQA/before/hPCAvsPt", "PCA vs. pT;p_{T,#gamma} (GeV/c);PCA (cm)", kTH2F, {{100, 0, 10}, {500, 0, 5}}, false); + fRegistry.add("V0/LossQA/before/hQtAPvsPt", "AP q_{T} vs. pT;p_{T,#gamma} (GeV/c);q_{T} (GeV/c)", kTH2F, {{100, 0, 10}, {250, 0, 0.25}}, false); + fRegistry.add("V0/LossQA/before/hRxyVsPt", "conversion radius vs. pT;p_{T,#gamma} (GeV/c);R_{xy} (cm)", kTH2F, {{100, 0, 10}, {200, 0, 100}}, false); + fRegistry.add("V0/LossQA/before/hMeeVsPt", "m_{ee} vs. pT;p_{T,#gamma} (GeV/c);m_{ee} (GeV/c^{2})", kTH2F, {{100, 0, 10}, {100, 0, 0.1}}, false); + fRegistry.addClone("V0/LossQA/before/", "V0/LossQA/after/"); + } + + if (doprocessRecoQA) { + fRegistry.add("RecoQA/0_converted/hs", "true converted photons;p_{T,#gamma} (GeV/c);#eta;#varphi (rad.);R_{conv}^{true} (cm)", kTHnSparseF, {{100, 0, 10}, {36, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}, {100, 0, 100}}, true); + fRegistry.addClone("RecoQA/0_converted/hs", "RecoQA/1_bothLegsTracked/hs"); + fRegistry.addClone("RecoQA/0_converted/hs", "RecoQA/2_bothLegsInV0Legs/hs"); + fRegistry.addClone("RecoQA/0_converted/hs", "RecoQA/3_photonInV0PhotonsKF/hs"); + fRegistry.add("RecoQA/hStageVsPt", "reconstruction stage vs. pT;p_{T,#gamma} (GeV/c);stage (0=converted,1=tracked,2=V0Legs,3=V0PhotonsKF)", kTH2F, {{100, 0, 10}, {4, -0.5, 3.5}}, true); + fRegistry.add("RecoQA/hMissingLeg_PtRconv", "legs tracked but lost before V0Legs;p_{T,leg}^{true} (GeV/c);R_{conv}^{true} (cm)", kTH2F, {{100, 0, 1}, {100, 0, 100}}, true); + fRegistry.add("RecoQA/Duplicates/hNTracksPerTrueLeg", "reconstructed tracks per true conversion leg;N_{tracks} per true leg;N_{legs}", kTH1F, {{6, -0.5, 5.5}}, true); + fRegistry.add("RecoQA/Duplicates/hNV0LegsPerTrueLeg", "V0Leg entries per true conversion leg;N_{V0Legs} per true leg;N_{legs}", kTH1F, {{6, -0.5, 5.5}}, true); + fRegistry.add("RecoQA/Duplicates/hNV0CandsPerPhoton_Rconv", "correctly built V0 candidates per true photon;N_{cand} per true #gamma;R_{conv}^{true} (cm)", kTH2F, {{6, -0.5, 5.5}, {100, 0, 100}}, true); + if (recoQASettingsGroup.cfgDoDetailedTrackQA) { + fRegistry.add("RecoQA/LegQuality/survived/hNcrTPC", "TPC crossed rows;TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, true); + fRegistry.add("RecoQA/LegQuality/survived/hChi2TPC", "chi2 per TPC cluster;#chi^{2}/N_{cls}^{TPC}", kTH1F, {{100, 0, 10}}, true); + fRegistry.add("RecoQA/LegQuality/survived/hSharedFracTPC", "TPC shared-cluster fraction;N_{cls}^{shared}/N_{cls}", kTH1F, {{110, 0, 1.1}}, true); + fRegistry.add("RecoQA/LegQuality/survived/hNclsTPC", "number of TPC clusters;N_{cls}^{TPC}", kTH1F, {{161, -0.5, 160.5}}, true); + fRegistry.addClone("RecoQA/LegQuality/survived/", "RecoQA/LegQuality/lost/"); + } + } } void DefineEMEventCut() @@ -320,52 +599,52 @@ struct PCMQC { fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); // for v0 - fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); - fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); - fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); - fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); - fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); - fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius, pcmcuts.cfg_midL_v0radius, pcmcuts.cfg_midH_v0radius); - fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); - fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + fV0PhotonCut.SetV0PtRange(v0cuts.cfgMinPtV0, v0cuts.cfgMaxPtV0); + fV0PhotonCut.SetV0EtaRange(v0cuts.cfgMinEtaV0, v0cuts.cfgMaxEtaV0); + fV0PhotonCut.SetMinCosPA(v0cuts.cfgMinV0CosPA); + fV0PhotonCut.SetMaxPCA(v0cuts.cfgMaxPCA); + fV0PhotonCut.SetMaxChi2KF(v0cuts.cfgMaxChi2KF); + fV0PhotonCut.SetRxyRange(v0cuts.cfgMinV0Radius, v0cuts.cfgMaxV0Radius, v0cuts.cfgMidLV0Radius, v0cuts.cfgMidHV0Radius); + fV0PhotonCut.SetAPRange(v0cuts.cfgMaxAlphaAP, v0cuts.cfgMaxQtAP); + fV0PhotonCut.RejectITSib(v0cuts.cfgRejectV0OnITSib); // for track - fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); - fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNClustersTPC(trackcuts.cfgMinNClustersTPC); + fV0PhotonCut.SetMinNCrossedRowsTPC(trackcuts.cfgMinNCrossedRows); fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); - fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); - fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); - fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); - fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetMaxFracSharedClustersTPC(trackcuts.cfgMaxFracSharedClustersTPC); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, trackcuts.cfgMaxChi2TPC); + fV0PhotonCut.SetTPCNsigmaElRange(trackcuts.cfgMinTPCNsigmaEl, trackcuts.cfgMaxTPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, trackcuts.cfgMaxChi2ITS); fV0PhotonCut.SetNClustersITS(0, 7); fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); - fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); - fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); - fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); - fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + fV0PhotonCut.SetDisableITSonly(trackcuts.cfgDisableITSonlyTracks); + fV0PhotonCut.SetDisableTPConly(trackcuts.cfgDisableTPConlyTracks); + fV0PhotonCut.SetRequireITSTPC(v0cuts.cfgRequireV0WithITSTPC); + fV0PhotonCut.SetRequireITSonly(v0cuts.cfgRequireV0WithITSonly); + fV0PhotonCut.SetRequireTPConly(v0cuts.cfgRequireV0WithTPConly); // for ML - fV0PhotonCut.SetApplyMlCuts(pcmcuts.cfg_apply_ml_cuts); - fV0PhotonCut.SetUse2DBinning(pcmcuts.cfg_use_2d_binning); - fV0PhotonCut.SetLoadMlModelsFromCCDB(pcmcuts.cfg_load_ml_models_from_ccdb); - fV0PhotonCut.SetNClassesMl(pcmcuts.cfg_nclasses_ml); - fV0PhotonCut.SetMlTimestampCCDB(pcmcuts.cfg_timestamp_ccdb); + fV0PhotonCut.SetApplyMlCuts(mlcuts.cfgApplyPCMMl); + fV0PhotonCut.SetUse2DBinning(mlcuts.cfgUse2DBinning); + fV0PhotonCut.SetLoadMlModelsFromCCDB(mlcuts.cfgLoadModelsFromCCDB); + fV0PhotonCut.SetNClassesMl(mlcuts.cfgNClassesPCMMl); + fV0PhotonCut.SetMlTimestampCCDB(mlcuts.cfgTimestampCCDB); fV0PhotonCut.SetCcdbUrl(ccdburl); auto mCentralityTypeMlEnum = static_cast(cfgCentEstimator.value); fV0PhotonCut.SetCentralityTypeMl(mCentralityTypeMlEnum); - fV0PhotonCut.SetCutDirMl(pcmcuts.cfg_cut_dir_ml); - fV0PhotonCut.SetMlModelPathsCCDB(pcmcuts.cfg_model_paths_ccdb); - fV0PhotonCut.SetMlOnnxFileNames(pcmcuts.cfg_onnx_file_names); - fV0PhotonCut.SetBinsPtMl(pcmcuts.cfg_bins_pt_ml); - fV0PhotonCut.SetBinsCentMl(pcmcuts.cfg_bins_cent_ml); - fV0PhotonCut.SetCutsMl(pcmcuts.cfg_cuts_ml_flat); - fV0PhotonCut.SetNamesInputFeatures(pcmcuts.cfg_input_feature_names); - fV0PhotonCut.SetLabelsBinsMl(pcmcuts.cfg_labels_bins_ml); - fV0PhotonCut.SetLabelsCutScoresMl(pcmcuts.cfg_labels_cut_scores_ml); - fV0PhotonCut.SetD_Bz(0.0f); // dummy value -> only for psi_pair calculation - - if (pcmcuts.cfg_apply_ml_cuts) { + fV0PhotonCut.SetCutDirMl(mlcuts.cfgCutDirPCMMl); + fV0PhotonCut.SetMlModelPathsCCDB(mlcuts.cfgModelPathsCCDB); + fV0PhotonCut.SetMlOnnxFileNames(mlcuts.cfgOnnxFileNames); + fV0PhotonCut.SetBinsPtMl(mlcuts.cfgBinsPtPCMMl); + fV0PhotonCut.SetBinsCentMl(mlcuts.cfgBinsCentPCMMl); + fV0PhotonCut.SetCutsMl(mlcuts.cfgCutsPCMMlFlat); + fV0PhotonCut.SetNamesInputFeatures(mlcuts.cfgNamesInputFeatures); + fV0PhotonCut.SetLabelsBinsMl(mlcuts.cfgLabelsBinsPCMMl); + fV0PhotonCut.SetLabelsCutScoresMl(mlcuts.cfgLabelsCutScoresPCMMl); + fV0PhotonCut.SetD_Bz(0.0f); + + if (mlcuts.cfgApplyPCMMl) { fV0PhotonCut.initV0MlModels(ccdbApi); } } @@ -395,7 +674,7 @@ struct PCMQC { if (collision.sel8()) { fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); } - if (std::fabs(collision.posZ()) < 10.0) { + if (std::fabs(collision.posZ()) < 10.0) { // o2-linter: disable=magic-number (vertex cut) fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); } fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); @@ -424,6 +703,13 @@ struct PCMQC { fRegistry.fill(HIST("V0/hDCAxyz"), v0.dcaXYtopv(), v0.dcaZtopv()); fRegistry.fill(HIST("V0/hDCAz_Pt"), v0.dcaZtopv(), v0.pt()); fRegistry.fill(HIST("V0/hAPplot"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("V0/hRxyVsPt"), v0.pt(), v0.v0radius()); + fRegistry.fill(HIST("V0/hEtaVsPt"), v0.pt(), v0.eta()); + fRegistry.fill(HIST("V0/hPhiVsPt"), v0.pt(), v0.phi()); + fRegistry.fill(HIST("V0/hsAlphaQtPt"), v0.alpha(), v0.qtarm(), v0.pt()); + if constexpr (requires { v0.psipair(); }) { + fRegistry.fill(HIST("V0/hPsiPairVsPt"), v0.pt(), v0.psipair()); + } fRegistry.fill(HIST("V0/hMassGamma"), v0.v0radius(), v0.mGamma()); fRegistry.fill(HIST("V0/hKFChi2vsM"), v0.mGamma(), v0.chiSquareNDF()); fRegistry.fill(HIST("V0/hKFChi2vsR"), v0.v0radius(), v0.chiSquareNDF()); @@ -437,7 +723,7 @@ struct PCMQC { fRegistry.fill(HIST("V0/hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); // BDT response histogram can be filled here when apply BDT is true - if (pcmcuts.cfg_apply_ml_cuts) { + if (mlcuts.cfgApplyPCMMl) { const std::span& bdtValue = fV0PhotonCut.getBDTValue(); float psipair = 999.f; float phiv = 999.f; @@ -446,15 +732,15 @@ struct PCMQC { phiv = v0.phiv(); } fRegistry.fill(HIST("V0/hPhiVPsi"), psipair, phiv); - if (pcmcuts.cfg_nclasses_ml == 2 && bdtValue.size() == 2) { + if (mlcuts.cfgNClassesPCMMl == 2 && bdtValue.size() == 2) { // o2-linter: disable=magic-number (BDT) fRegistry.fill(HIST("V0/hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); fRegistry.fill(HIST("V0/hBDTSignalScoreVsPt"), v0.pt(), bdtValue[1]); - } else if (pcmcuts.cfg_nclasses_ml == 3 && bdtValue.size() == 3) { + } else if (mlcuts.cfgNClassesPCMMl == 3 && bdtValue.size() == 3) { // o2-linter: disable=magic-number (BDT) fRegistry.fill(HIST("V0/hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); fRegistry.fill(HIST("V0/hBDTPrimaryPhotonScoreVsPt"), v0.pt(), bdtValue[1]); fRegistry.fill(HIST("V0/hBDTSecondaryPhotonScoreVsPt"), v0.pt(), bdtValue[2]); } else if (bdtValue.size() == 1) { - fRegistry.fill(HIST("V0/hBDTCutVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/hBDTScoreVsPt"), v0.pt(), bdtValue[0]); } } } @@ -481,9 +767,44 @@ struct PCMQC { fRegistry.fill(HIST("V0Leg/hTPCdEdx"), leg.tpcInnerParam(), leg.tpcSignal()); fRegistry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); fRegistry.fill(HIST("V0Leg/hTPCNsigmaPi"), leg.tpcInnerParam(), leg.tpcNSigmaPi()); - // fRegistry.fill(HIST("V0Leg/hXY"), leg.x(), leg.y()); - // fRegistry.fill(HIST("V0Leg/hZX"), leg.z(), leg.x()); - // fRegistry.fill(HIST("V0Leg/hZY"), leg.z(), leg.y()); + fRegistry.fill(HIST("V0Leg/hTPCNsigmaElVsEta"), leg.eta(), leg.tpcNSigmaEl()); + } + + template + void fillLossQAInfo(TV0 const& v0) + { + if (!qaSettingsGroup.cfgDoPtDependentLossQA) { + return; + } + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hCosPAvsPt"), v0.pt(), v0.cospa()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hPCAvsPt"), v0.pt(), v0.pca()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hQtAPvsPt"), v0.pt(), v0.qtarm()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hRxyVsPt"), v0.pt(), v0.v0radius()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hMeeVsPt"), v0.pt(), v0.mGamma()); + } + + template + void fillMaterialBudgetInfo(TV0 const& v0) + { + if (materialBudgetSettingsGroup.cfgDoMaterialDistribution) { + fRegistry.fill(HIST("MaterialBudget/hs"), v0.vz(), v0.v0radius(), v0.eta(), v0.phi(), v0.pt()); + } + if (materialBudgetSettingsGroup.cfgDoWiresDetail && v0.v0radius() < 20.f && std::fabs(v0.vz()) < 20.f) { // o2-linter: disable=magic-number (region window = booking range) + if (3.15f < v0.phi() && v0.phi() < 3.4f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/Wires/hsLeft"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } else if (6.00f < v0.phi() && v0.phi() < 6.15f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/Wires/hsRight"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + } + if (materialBudgetSettingsGroup.cfgDoITSDetail && v0.v0radius() < 60.f && std::fabs(v0.vz()) < 40.f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/ITS/hs"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + if (materialBudgetSettingsGroup.cfgDoMFTDetail && 40.f < v0.v0radius() && v0.v0radius() < 60.f && std::fabs(v0.vz()) < 40.f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/MFT/hs"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + if (materialBudgetSettingsGroup.cfgDoTPCInnerBarrelDetail && 60.f < v0.v0radius() && v0.v0radius() < 80.f && std::fabs(v0.vz()) < 40.f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/TPC/hs"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } } Preslice perCollisionV0 = aod::v0photonkf::pmeventId; @@ -492,6 +813,7 @@ struct PCMQC { Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; using FilteredMyCollisions = soa::Filtered; + using FilteredMyCollisionsMC = soa::Filtered; // same filters, they act column-wise template void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const&, TPerCollision const& perCollision) @@ -517,14 +839,17 @@ struct PCMQC { for (const auto& v0 : v0photons_coll) { auto pos = v0.template posTrack_as(); auto ele = v0.template negTrack_as(); + fillLossQAInfo<0>(v0); // all candidates offered to the selection if (!fV0PhotonCut.IsSelected(v0)) { continue; } + fillLossQAInfo<1>(v0); fillV0Info(v0); + fillMaterialBudgetInfo(v0); for (const auto& leg : {pos, ele}) { fillV0LegInfo(leg); } - if (pcmcuts.cfg_dEdx_postcalibration) { + if (trackcuts.cfgDoDEdxPostCalibration) { fRegistry.fill(HIST("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos"), pos.p(), v0.v0radius(), pos.tpcNSigmaEl(), pos.eta()); fRegistry.fill(HIST("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele"), ele.p(), v0.v0radius(), ele.tpcNSigmaEl(), ele.eta()); } @@ -543,11 +868,511 @@ struct PCMQC { process(collisions, v0photonsML, v0legs, perCollisionV0ML); } // end of ML process - void processDummy(MyCollisions const&) {} + template + void fillV0InfoMC(TV0 const& v0, TMCV0 const& mcphoton, TMCLeg const& mcleg) + { + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPt"), v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhi"), v0.phi(), v0.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hXY"), v0.vx(), v0.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ"), v0.vz(), v0.v0radius()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPA"), v0.cospa()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPAXY"), v0.cospaXY()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPARZ"), v0.cospaRZ()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPCA"), v0.pca()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hDCAxyz"), v0.dcaXYtopv(), v0.dcaZtopv()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hDCAz_Pt"), v0.dcaZtopv(), v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hAPplot"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyVsPt"), v0.pt(), v0.v0radius()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaVsPt"), v0.pt(), v0.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPhiVsPt"), v0.pt(), v0.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsAlphaQtPt"), v0.alpha(), v0.qtarm(), v0.pt()); + if constexpr (requires { v0.psipair(); }) { // only the ML join carries psi_pair + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPsiPairVsPt"), v0.pt(), v0.psipair()); + } + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hMassGamma"), v0.v0radius(), v0.mGamma()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsM"), v0.mGamma(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsR"), v0.v0radius(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsX"), v0.vx(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsY"), v0.vy(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsZ"), v0.vz(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPtOverPtGen"), mcphoton.pt(), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaEta"), mcphoton.pt(), v0.eta() - mcphoton.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPhi"), mcphoton.pt(), v0.phi() - mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPtOverPtGen"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.eta() - mcphoton.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.phi() - mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaR"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.v0radius() - std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffX"), mcleg.vx(), v0.vx() - mcleg.vx()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffY"), mcleg.vy(), v0.vy() - mcleg.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffZ"), mcleg.vz(), v0.vz() - mcleg.vz()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hXY_MC"), mcleg.vx(), mcleg.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ_MC"), mcleg.vz(), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + float resolPt = (v0.pt() - mcphoton.pt()) / mcphoton.pt(); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtResolPtEtaPhi"), resolPt, mcphoton.pt(), mcphoton.eta(), mcphoton.phi()); + float resolMom = (v0.p() - mcphoton.p()) / mcphoton.p(); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hMomResolPtEtaPhi"), resolMom, mcphoton.pt(), mcphoton.eta(), mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtEtaPhi"), mcphoton.pt(), mcphoton.eta(), mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhiResol"), mcphoton.pt(), v0.eta() - mcphoton.eta(), v0.phi() - mcphoton.phi()); + } + + float phi_cp = std::atan2(v0.vy(), v0.vx()); + o2::math_utils::bringTo02Pi(phi_cp); + float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); + + if (mlcuts.cfgApplyPCMMl) { + const std::span& bdtValue = fV0PhotonCut.getBDTValue(); + float psipair = 999.f; + float phiv = 999.f; + if constexpr (requires { v0.psipair(); v0.phiv(); }) { + psipair = v0.psipair(); + phiv = v0.phiv(); + } + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPhiVPsi"), psipair, phiv); + if (mlcuts.cfgNClassesPCMMl == 2 && bdtValue.size() == 2) { // o2-linter: disable=magic-number (BDT) + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTSignalScoreVsPt"), v0.pt(), bdtValue[1]); + } else if (mlcuts.cfgNClassesPCMMl == 3 && bdtValue.size() == 3) { // o2-linter: disable=magic-number (BDT) + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTPrimaryPhotonScoreVsPt"), v0.pt(), bdtValue[1]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTSecondaryPhotonScoreVsPt"), v0.pt(), bdtValue[2]); + } else if (bdtValue.size() == 1) { // o2-linter: disable=magic-number (BDT) + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTScoreVsPt"), v0.pt(), bdtValue[0]); + } + } + } + + template + void fillV0LegInfoMC(TLeg const& leg) + { + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hQoverPt"), leg.sign() / leg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhi"), leg.phi(), leg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hDCAxyz"), leg.dcaXY(), leg.dcaZ()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNclsITS"), leg.itsNCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNclsTPC"), leg.tpcNClsFound()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNcrTPC"), leg.tpcNClsCrossedRows()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNcr2Nf"), leg.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNcls2Nf"), leg.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNclsShared"), leg.pt(), leg.tpcFractionSharedCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hChi2TPC"), leg.tpcChi2NCl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hChi2ITS"), leg.itsChi2NCl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hITSClusterMap"), leg.itsClusterMap()); + if (leg.hasITS()) { + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hMeanClusterSizeITS"), leg.p(), leg.meanClusterSizeITS() * std::cos(std::atan(leg.tgl()))); + } + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCdEdx"), leg.tpcInnerParam(), leg.tpcSignal()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaPi"), leg.tpcInnerParam(), leg.tpcNSigmaPi()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaElVsEta"), leg.eta(), leg.tpcNSigmaEl()); + auto mcleg = leg.template emmcparticle_as(); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPtOverPtGen"), mcleg.pt(), (leg.pt() - mcleg.pt()) / mcleg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaEta"), mcleg.pt(), leg.eta() - mcleg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPhi"), mcleg.pt(), leg.phi() - mcleg.phi()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPtOverPtGen"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), (leg.pt() - mcleg.pt()) / mcleg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.eta() - mcleg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.phi() - mcleg.phi()); + } + + template + void processMC(FilteredMyCollisionsMC const& collisions, TV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const&, aod::EMMCEvents const&, TPerCollision const& percollision) + { + for (const auto& collision : collisions) { + initCCDB(collision); + const std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + fillEventInfo<0>(collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + fillEventInfo<1>(collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted + + fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); // set centrality for BDT response + auto v0photons_coll = v0photons.sliceBy(percollision, collision.globalIndex()); + int ng_primary = 0, ng_wd = 0, ng_hs = 0, nee_pi0 = 0, nee_eta = 0; + for (const auto& v0 : v0photons_coll) { + auto pos = v0.template posTrack_as(); + auto ele = v0.template negTrack_as(); + auto posmc = pos.template emmcparticle_as(); + auto elemc = ele.template emmcparticle_as(); + + fillLossQAInfo<0>(v0); // all candidates offered to the selection + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + fillLossQAInfo<1>(v0); + + fillMaterialBudgetInfo(v0); + + fRegistry.fill(HIST("V0/candidate/hPt"), v0.pt()); + fRegistry.fill(HIST("V0/candidate/hEtaPhi"), v0.phi(), v0.eta()); + for (const auto& leg : {pos, ele}) { + fRegistry.fill(HIST("V0Leg/candidate/hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/candidate/hEtaPhi"), leg.phi(), leg.eta()); + } + + int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles); + int pi0id = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles); // pi0 dalitz decay + int etaid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles); // eta dalitz decay + if (photonid < 0 && pi0id < 0 && etaid < 0) { + continue; + } + + if (photonid > 0) { + auto mcphoton = mcparticles.iteratorAt(photonid); + + if (mcAnalysisModeSettings.cfgDoCollisionAssociationQA) { + const int deltaCol = static_cast(collision.emmceventId()) - static_cast(mcphoton.emmceventId()); + const float rGen = std::sqrt(std::pow(elemc.vx(), 2) + std::pow(elemc.vy(), 2)); + const float deltaR = v0.v0radius() - rGen; + const float deltaZ = v0.vz() - elemc.vz(); + const float relPtRes = mcphoton.pt() > 0.f ? (v0.pt() - mcphoton.pt()) / mcphoton.pt() : 0.f; + fRegistry.fill(HIST("CollisionAssociation/hDeltaCollId"), deltaCol); + if (deltaCol == 0) { + fRegistry.fill(HIST("CollisionAssociation/RightCollisions/hs"), v0.v0radius(), v0.pt(), relPtRes, deltaZ, deltaR, deltaCol); + } else { + fRegistry.fill(HIST("CollisionAssociation/WrongCollisions/hs"), v0.v0radius(), v0.pt(), relPtRes, deltaZ, deltaR, deltaCol); + } + } + + if (mcAnalysisModeSettings.cfgRequireTrueAssociation && (mcphoton.emmceventId() != collision.emmceventId())) { + continue; + } + + if (mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) { + fillV0InfoMC<0>(v0, mcphoton, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<0>(leg); + } + ng_primary++; + } else if (IsFromWD(mcphoton.template emmcevent_as(), mcphoton, mcparticles) > 0) { + fillV0InfoMC<1>(v0, mcphoton, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<1>(leg); + } + ng_wd++; + } else { + fillV0InfoMC<2>(v0, mcphoton, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<2>(leg); + } + ng_hs++; + } + } else if (pi0id > 0) { + auto mcpi0 = mcparticles.iteratorAt(pi0id); + if (mcAnalysisModeSettings.cfgRequireTrueAssociation && (mcpi0.emmceventId() != collision.emmceventId())) { + continue; + } + if (mcpi0.isPhysicalPrimary() || mcpi0.producedByGenerator()) { + fillV0InfoMC<3>(v0, mcpi0, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<3>(leg); + } + nee_pi0++; + } + } else if (etaid > 0) { + auto mceta = mcparticles.iteratorAt(etaid); + if (mcAnalysisModeSettings.cfgRequireTrueAssociation && (mceta.emmceventId() != collision.emmceventId())) { + continue; + } + if (mceta.isPhysicalPrimary() || mceta.producedByGenerator()) { + fillV0InfoMC<4>(v0, mceta, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<4>(leg); + } + nee_eta++; + } + } + } // end of v0 loop + fRegistry.fill(HIST("V0/primary/hNgamma"), ng_primary); + fRegistry.fill(HIST("V0/fromWD/hNgamma"), ng_wd); + fRegistry.fill(HIST("V0/fromHS/hNgamma"), ng_hs); + fRegistry.fill(HIST("V0/fromPi0Dalitz/hNgamma"), nee_pi0); + fRegistry.fill(HIST("V0/fromEtaDalitz/hNgamma"), nee_eta); + } // end of collision loop + } // end of MC process + + void processPCMQCMC(FilteredMyCollisionsMC const& collisions, MyV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + { + processMC(collisions, v0photons, mcparticles, mcv0legs, mcevents, perCollisionV0); + } // end of MC QC process + + void processPCMQCMCML(FilteredMyCollisionsMC const& collisions, MyV0PhotonsML const& v0photonsML, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + { + processMC(collisions, v0photonsML, mcparticles, mcv0legs, mcevents, perCollisionV0ML); + } // end of MC QC process with ML cuts + + template + void fillBinnedData(TBinnedData const& binned_data, const float weight = 1.f) + { + int xbin = 0, ybin = 0, zbin = 0; + auto hPtY = fRegistry.get(HIST("Generated/hPtY")); // 2D + auto hPt = fRegistry.get(HIST("Generated/hPt")); // 1D + + for (int ibin = 0; ibin < hPtY->GetNcells(); ibin++) { + int nentry = binned_data[ibin]; + hPtY->GetBinXYZ(ibin, xbin, ybin, zbin); + float pt = hPtY->GetXaxis()->GetBinCenter(xbin); + float y = hPtY->GetYaxis()->GetBinCenter(ybin); + if (y > v0cuts.cfgMaxEtaV0) { + continue; + } + + for (int j = 0; j < nentry; j++) { + hPtY->Fill(pt, y, weight); + hPt->Fill(pt, weight); + } + } + } + + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + void processGen(FilteredMyCollisionsMC const& collisions, MyMCCollisions const&, aod::EMMCParticles const& mcparticles) + { + + for (const auto& collision : collisions) { + const std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto mccollision = collision.template emmcevent_as(); + auto binned_data_gamma_gen = mccollision.generatedGamma(); + fillBinnedData(binned_data_gamma_gen, 1.f); + + auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); + for (const auto& mctrack : mctracks_coll) { + if (std::fabs(mctrack.y()) > v0cuts.cfgMaxEtaV0) { + continue; + } + if (std::abs(mctrack.pdgCode()) != PDG_t::kGamma || !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + continue; + } + + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + fRegistry.fill(HIST("Generated/hPtEtaPhi"), mctrack.pt(), mctrack.eta(), mctrack.phi()); // for all generated photons before any kinematic cut + } + if (mctrack.daughtersIds().empty()) { + continue; + } + auto daughter = mcparticles.iteratorAt(mctrack.daughtersIds()[0]); // choose ele or pos. + float rxy_gen_e = std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2)); + float phi_cp = std::atan2(daughter.vy(), daughter.vx()); + o2::math_utils::bringTo02Pi(phi_cp); + float eta_cp = std::atanh(daughter.vz() / std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2) + std::pow(daughter.vz(), 2))); + + fRegistry.fill(HIST("Generated/hR_ConversionPhoton_wideR"), rxy_gen_e); + fRegistry.fill(HIST("Generated/hRZ_wideR"), daughter.vz(), rxy_gen_e); + fRegistry.fill(HIST("Generated/hsRZPhi_wideR"), daughter.vz(), phi_cp, rxy_gen_e); + if (rxy_gen_e < std::fabs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-v0cuts.cfgMaxEtaV0))) - genSettingsGroup.cfgMarginZMC) { + continue; + } + if (rxy_gen_e > genSettingsGroup.cfgMaxRGen) { + continue; + } + + fRegistry.fill(HIST("Generated/hPt_ConversionPhoton"), mctrack.pt()); + fRegistry.fill(HIST("Generated/hY_ConversionPhoton"), mctrack.y()); + fRegistry.fill(HIST("Generated/hPhi_ConversionPhoton"), mctrack.phi()); + fRegistry.fill(HIST("Generated/hsConvPoint"), rxy_gen_e, phi_cp, eta_cp); + fRegistry.fill(HIST("Generated/hXY"), daughter.vx(), daughter.vy()); + fRegistry.fill(HIST("Generated/hRZ"), daughter.vz(), rxy_gen_e); + fRegistry.fill(HIST("Generated/hRPhi"), phi_cp, rxy_gen_e); + } // end of mctrack loop per collision + } // end of collision loop + } + + template + void fillLegQualityRecoQA(TTrack const& track) + { + if constexpr (survived) { + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hSharedFracTPC"), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hNclsTPC"), track.tpcNClsFound()); + } else { + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hSharedFracTPC"), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hNclsTPC"), track.tpcNClsFound()); + } + } + + Preslice perMcCollisionTruth = aod::mcparticle::mcCollisionId; + void processRecoQA(aod::McCollisions const& mcCollisions, aod::McParticles const& mcparticles, MyTracksMC const& tracks, aod::V0Legs const& v0legs, aod::V0PhotonsKF const& v0photonsKF) + { + std::unordered_map nTracksOfMcId; + std::unordered_map mcIdToBestTrack; + std::unordered_map mcIdBestCrossedRows; + nTracksOfMcId.reserve(tracks.size()); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + const int mcId = track.mcParticleId(); + nTracksOfMcId[mcId]++; + const float ncr = track.tpcNClsCrossedRows(); + auto it = mcIdBestCrossedRows.find(mcId); + if (it == mcIdBestCrossedRows.end() || ncr > it->second) { + mcIdBestCrossedRows[mcId] = ncr; + mcIdToBestTrack[mcId] = track.globalIndex(); + } + } + + std::unordered_map nV0LegsOfMcId; + nV0LegsOfMcId.reserve(v0legs.size()); + for (const auto& leg : v0legs) { + const int trackId = leg.trackId(); + if (trackId < 0 || trackId >= static_cast(tracks.size())) { + continue; + } + const auto track = tracks.iteratorAt(trackId); + if (track.has_mcParticle()) { + nV0LegsOfMcId[track.mcParticleId()]++; + } + } + auto legMcMotherId = [&](auto const& leg) -> int { + const int trackId = leg.trackId(); + if (trackId < 0 || trackId >= static_cast(tracks.size())) { + return -1; + } + const auto track = tracks.iteratorAt(trackId); + if (!track.has_mcParticle()) { + return -1; + } + const auto mc = track.mcParticle(); + if (!mc.has_mothers()) { + return -1; + } + return mc.mothersIds()[0]; + }; + std::unordered_map nV0CandsOfMcPhoton; + for (const auto& v0 : v0photonsKF) { + const int legPosIdx = v0.posTrackId(); + const int legNegIdx = v0.negTrackId(); + if (legPosIdx < 0 || legPosIdx >= static_cast(v0legs.size()) || legNegIdx < 0 || legNegIdx >= static_cast(v0legs.size())) { + continue; + } + const int motherPos = legMcMotherId(v0legs.iteratorAt(legPosIdx)); + const int motherNeg = legMcMotherId(v0legs.iteratorAt(legNegIdx)); + if (motherPos >= 0 && motherPos == motherNeg) { + nV0CandsOfMcPhoton[motherPos]++; + } + } + for (const auto& mcCollision : mcCollisions) { + const auto mcparticles_coll = mcparticles.sliceBy(perMcCollisionTruth, mcCollision.globalIndex()); + for (const auto& mctrack : mcparticles_coll) { + if (mctrack.pdgCode() != PDG_t::kGamma || !mctrack.isPhysicalPrimary()) { + continue; + } + if (std::fabs(mctrack.eta()) > recoQASettingsGroup.cfgPhotonEtaMax || mctrack.pt() < recoQASettingsGroup.cfgPhotonPtMin) { + continue; + } + if (!mctrack.has_daughters()) { + continue; + } + int idPos = -1, idNeg = -1; + for (const auto& daughterId : mctrack.daughtersIds()) { + if (daughterId < 0 || daughterId >= static_cast(mcparticles.size())) { + continue; + } + const auto daughter = mcparticles.iteratorAt(daughterId); + if (daughter.pdgCode() == -PDG_t::kElectron) { + idPos = daughterId; + } else if (daughter.pdgCode() == PDG_t::kElectron) { + idNeg = daughterId; + } + } + if (idPos < 0 || idNeg < 0) { + continue; // not an e+e- conversion + } + const auto daughterPos = mcparticles.iteratorAt(idPos); + const auto daughterNeg = mcparticles.iteratorAt(idNeg); + const float rConv = std::sqrt(std::pow(daughterPos.vx(), 2) + std::pow(daughterPos.vy(), 2)); + if (rConv < recoQASettingsGroup.cfgRMinGen || rConv > recoQASettingsGroup.cfgRMaxGen) { + continue; + } + if (std::fabs(daughterPos.eta()) > recoQASettingsGroup.cfgLegEtaMax || std::fabs(daughterNeg.eta()) > recoQASettingsGroup.cfgLegEtaMax) { + continue; + } + + fRegistry.fill(HIST("RecoQA/0_converted/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 0.f); + + auto countIn = [](std::unordered_map const& m, int key) -> int { + const auto it = m.find(key); + return (it == m.end()) ? 0 : it->second; + }; + const int nTrkPos = countIn(nTracksOfMcId, idPos); + const int nTrkNeg = countIn(nTracksOfMcId, idNeg); + const int nLegPos = countIn(nV0LegsOfMcId, idPos); + const int nLegNeg = countIn(nV0LegsOfMcId, idNeg); + const bool posTracked = nTrkPos > 0; + const bool negTracked = nTrkNeg > 0; + const bool posInV0Legs = nLegPos > 0; + const bool negInV0Legs = nLegNeg > 0; + + fRegistry.fill(HIST("RecoQA/Duplicates/hNTracksPerTrueLeg"), nTrkPos); + fRegistry.fill(HIST("RecoQA/Duplicates/hNTracksPerTrueLeg"), nTrkNeg); + fRegistry.fill(HIST("RecoQA/Duplicates/hNV0LegsPerTrueLeg"), nLegPos); + fRegistry.fill(HIST("RecoQA/Duplicates/hNV0LegsPerTrueLeg"), nLegNeg); + fRegistry.fill(HIST("RecoQA/Duplicates/hNV0CandsPerPhoton_Rconv"), countIn(nV0CandsOfMcPhoton, static_cast(mctrack.globalIndex())), rConv); + + if (posTracked && negTracked) { + fRegistry.fill(HIST("RecoQA/1_bothLegsTracked/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 1.f); + } + if (posInV0Legs && negInV0Legs) { + fRegistry.fill(HIST("RecoQA/2_bothLegsInV0Legs/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 2.f); + } + if (countIn(nV0CandsOfMcPhoton, static_cast(mctrack.globalIndex())) > 0) { + fRegistry.fill(HIST("RecoQA/3_photonInV0PhotonsKF/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 3.f); + } + if (posTracked && !posInV0Legs) { + fRegistry.fill(HIST("RecoQA/hMissingLeg_PtRconv"), daughterPos.pt(), rConv); + } + if (negTracked && !negInV0Legs) { + fRegistry.fill(HIST("RecoQA/hMissingLeg_PtRconv"), daughterNeg.pt(), rConv); + } + + if (recoQASettingsGroup.cfgDoDetailedTrackQA) { + for (const auto& legMcId : {idPos, idNeg}) { + if (countIn(nTracksOfMcId, legMcId) == 0) { + continue; + } + const auto itTrack = mcIdToBestTrack.find(legMcId); + if (itTrack == mcIdToBestTrack.end() || itTrack->second < 0 || itTrack->second >= static_cast(tracks.size())) { + continue; + } + const auto track = tracks.iteratorAt(itTrack->second); + if (countIn(nV0LegsOfMcId, legMcId) > 0) { + fillLegQualityRecoQA(track); + } else { + fillLegQualityRecoQA(track); + } + } + } + } // end of mc particle loop per true event + } // end of true event loop + } // end of reco QA process PROCESS_SWITCH(PCMQC, processQC, "run PCM QC", true); PROCESS_SWITCH(PCMQC, processQCML, "run PCM QC with ML", false); - PROCESS_SWITCH(PCMQC, processDummy, "Dummy function", false); + PROCESS_SWITCH(PCMQC, processPCMQCMC, "run PCM QC in MC", false); + PROCESS_SWITCH(PCMQC, processPCMQCMCML, "run PCM QC in MC with ML cuts", false); + PROCESS_SWITCH(PCMQC, processGen, "run generated information", false); + PROCESS_SWITCH(PCMQC, processRecoQA, "run single-photon reconstruction QA on AO2Ds", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& context) diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index 05d09e91216..1bbaab29506 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -301,6 +302,8 @@ struct Photonhbt { [[nodiscard]] float legEta(int i) const { return fLegEta[i]; } [[nodiscard]] float legPhi(int i) const { return fLegPhi[i]; } [[nodiscard]] float legPt(int i) const { return fLegPt[i]; } + std::array fLegNsigEl{}; // TPC electron nsigma per leg, for the mixed-event leg similarity + [[nodiscard]] float legNsigEl(int i) const { return fLegNsigEl[i]; } int fNITSTPC{0}; pairutil::V0PhotonLegCounts fLegCounts{}; [[nodiscard]] pairutil::V0PhotonLegCounts const& legCounts() const { return fLegCounts; } @@ -356,6 +359,7 @@ struct Photonhbt { Configurable cfgMaxQinvForProcessing{"cfgMaxQinvForProcessing", 0.5, "skip mixed pairs with q_inv above this before building observables"}; Configurable cfgFillLegPairSparses{"cfgFillLegPairSparses", false, "book/fill the 4D leg-pair QA sparses (very large)"}; Configurable cfgFillLegSimilaritySparse{"cfgFillLegSimilaritySparse", true, "book/fill the like-sign leg similarity sparse (duplicate diagnostic: DeltaEta, DeltaPhi, pT ratio, dNsigma_e vs qinv)"}; + Configurable cfgFillLegSimilarityMixSparse{"cfgFillLegSimilarityMixSparse", false, "book/fill the MIXED-EVENT leg similarity sparse (kinematic baseline for the SE-ME duplicate excess; needs cfgFillLegSimilaritySparse)"}; Configurable cfgFillR1R2Sparse{"cfgFillR1R2Sparse", true, "book/fill the FullRange (R1, R2, q_inv) sparse: fix one conversion radius, see where the partner sits, per q_inv"}; } qaflags; @@ -364,6 +368,7 @@ struct Photonhbt { std::string prefix = "hbtanalysis_group"; Configurable cfgDo3D{"cfgDo3D", false, "enable 3D (qout,qside,qlong) analysis"}; Configurable cfgDo2D{"cfgDo2D", false, "enable 2D (qout,qinv) projection (requires cfgDo3D)"}; + Configurable cfgDo2DSideLong{"cfgDo2DSideLong", false, "additionally book/fill CF_2D_Side and CF_2D_Long (qside/qlong vs qinv; two extra 5D sparses -> costs fill time and merge size; requires cfgDo2D)"}; Configurable cfgUseLCMS{"cfgUseLCMS", false, "measure 1D relative momentum in LCMS"}; Configurable cfgDoQinvGate3D{"cfgDoQinvGate3D", false, "book/fill CF_3D_Qinv: 3D LCMS CF with a COARSE qinv axis (edges = candidate gate values)"}; ConfigurableAxis confMultNTracksBins{"confMultNTracksBins", {VARIABLE_WIDTH, 0., 100., 200., 300., 400., 500., 600, 700, 800, 900, 1000., 1100., 1200., 1300., 1400., 1500., 1600., 1700., 1800., 1900., 2000., 2100., 2200., 2300., 2400., 2500., 2600., 2700., 2800., 2900., 3000., 4000., 5000.}, "N_{tracks}^{PV} |#eta|<1 bins for CF sparses"}; @@ -925,6 +930,7 @@ struct Photonhbt { void addMCAODHistograms() { fRegistryTruthMC.add("MCAOD/hPhotonStage", "conversion photons;0=converted, 1=both legs tracked, 2=both legs in same collision, 3=V0 matched;counts", kTH1F, {{4, -0.5f, 3.5f}}, true); + fRegistryTruthMC.add("MCAOD/hPhotonStageVsPt", "conversion photon stage vs p_{T};0=converted, 1=both legs tracked, 2=both legs in same collision, 3=V0 matched;p_{T,#gamma} (GeV/c)", kTH2F, {{4, -0.5f, 3.5f}, {100, 0.f, 10.f}}, true); fRegistryTruthMC.add("MCAOD/hV0Type", "matched V0, raw v0Type bitmap;v0Type;counts", kTH1F, {{8, -0.5f, 7.5f}}, true); fRegistryTruthMC.add("MCAOD/hV0MatchMultiplicity", "SVertexer V0 candidates per matched truth photon;N V0;counts", kTH1F, {{10, 0.5f, 10.5f}}, true); fRegistryTruthMC.add("MCAOD/hNTrackedColls", "collisions in which BOTH legs of a photon are tracked;N collisions;counts", kTH1F, {{5, 0.5f, 5.5f}}, true); @@ -935,6 +941,7 @@ struct Photonhbt { const AxisSpec axType{8, -0.5f, 7.5f, "v0Type (raw)"}; fRegistryTruthMC.add("MCAOD/hPairStage", "pair step histogram;pair stage;counts", kTH1F, {{4, -0.5f, 3.5f}}, true); + fRegistryTruthMC.add("MCAOD/hPairStageVsKt", "pair stage vs k_{T};pair stage;k_{T} (GeV/c)", kTH2F, {{4, -0.5f, 3.5f}, {75, 0.f, 0.75f}}, true); fRegistryTruthMC.add("MCAOD/hSparsePairStage", "pair step histogram", kTHnSparseF, {axStage, axisDeltaEta, axisDeltaPhi, axisQinv}, true); fRegistryTruthMC.add("MCAOD/hSparseDRStage", "pair step histogram", kTHnSparseF, {axStage, axisDeltaR, axisQinv}, true); @@ -984,10 +991,15 @@ struct Photonhbt { fRegistryCF.add("Pair/same/CF_3D", "diphoton correlation 3D LCMS", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); if (hbtanalysis.cfgDo2D) { fRegistryCF.add("Pair/same/CF_2D", "diphoton correlation 2D (qout,qinv)", kTHnSparseD, {axisQout, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + if (hbtanalysis.cfgDo2DSideLong) { + fRegistryCF.add("Pair/same/CF_2D_Side", "diphoton correlation 2D (qside,qinv)", kTHnSparseD, {axisQside, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + fRegistryCF.add("Pair/same/CF_2D_Long", "diphoton correlation 2D (qlong,qinv)", kTHnSparseD, {axisQlong, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + } } if (hbtanalysis.cfgDoQinvGate3D) { const AxisSpec axisQinvGate{{0.0, 0.01, 0.02, 0.03, 0.05, 0.30}, "q_{inv} (GeV/c)"}; - fRegistryCF.add("Pair/same/CF_3D_Qinv", "diphoton correlation 3D LCMS + qinv gate axis", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt, axisQinvGate}, true); + fRegistryCF.add("Pair/same/CF_3D_Qinv", "diphoton correlation 3D LCMS + qinv gate axis", + kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt, axisQinvGate}, true); } } else { fRegistryCF.add("Pair/same/CF_1D", hbtanalysis.cfgUseLCMS ? "diphoton correlation 1D LCMS" : "diphoton correlation 1D (qinv)", kTH2D, {hbtanalysis.cfgUseLCMS ? axisQabsLcms : axisQinv, axisKt}, true); @@ -1131,11 +1143,14 @@ struct Photonhbt { } if (qaflags.cfgFillLegSimilaritySparse.value) { - const AxisSpec axisLSDEta{50, -0.5f, 0.5f, "#Delta#eta(LS legs)"}; - const AxisSpec axisLSDPhi{50, -0.5f, 0.5f, "#Delta#varphi(LS legs) (rad)"}; + const AxisSpec axisLSDEta{100, -0.1f, 0.1f, "#Delta#eta(LS legs)"}; + const AxisSpec axisLSDPhi{100, -0.1f, 0.1f, "#Delta#varphi(LS legs) (rad)"}; const AxisSpec axisLSPtRatio{50, 0.f, 1.f, "|p_{T,1}-p_{T,2}|/(p_{T,1}+p_{T,2})"}; const AxisSpec axisLSDNsig{40, 0.f, 8.f, "|#Delta n#sigma_{e}^{TPC}|"}; fRegistryPairQA.add("Pair/same/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv", "like-sign leg similarity;#Delta#eta(LS legs);#Delta#varphi(LS legs) (rad);|p_{T,1}-p_{T,2}|/(p_{T,1}+p_{T,2});|#Delta n#sigma_{e}^{TPC}|;q_{inv} (GeV/c)", kTHnSparseF, {axisLSDEta, axisLSDPhi, axisLSPtRatio, axisLSDNsig, axisQinv}, true); + if (qaflags.cfgFillLegSimilarityMixSparse.value) { + fRegistryPairQA.addClone("Pair/same/LegSimilarity/", "Pair/mix/LegSimilarity/"); + } } fRegistryPairQA.addClone("Pair/same/QA/", "Pair/mix/QA/"); if (mQa.legPairQa) { @@ -1656,6 +1671,7 @@ struct Photonhbt { p.fLegPt = {static_cast(pos.pt()), static_cast(ele.pt())}; p.fLegEta = {static_cast(pos.eta()), static_cast(ele.eta())}; p.fLegPhi = {static_cast(pos.phi()), static_cast(ele.phi())}; + p.fLegNsigEl = {static_cast(pos.tpcNSigmaEl()), static_cast(ele.tpcNSigmaEl())}; p.fLegCounts = pairutil::getV0PhotonLegCounts(pos, ele); p.fNITSTPC = p.fLegCounts.nITSTPC; // legHelixAt itself rejects radii below the conversion point @@ -1907,23 +1923,48 @@ struct Photonhbt { /*************************************************/ // FILL HELPERS /*************************************************/ - - template - void fillLegSimilarity(TLegA const& legA, TLegB const& legB, float qinv) + template + void fillLegSimilarityValues(float etaA, float phiA, float ptA, float nsigA, + float etaB, float phiB, float ptB, float nsigB, float qinv) { if (!qaflags.cfgFillLegSimilaritySparse.value || qinv > 0.3f) { // o2-linter: disable=magic-number (sparse axis range) return; } - const float deta = legA.eta() - legB.eta(); - const float dphi = RecoDecay::constrainAngle(legA.phi() - legB.phi(), -o2::constants::math::PI); - if (std::fabs(deta) > 0.5f || std::fabs(dphi) > 0.5f) { // o2-linter: disable=magic-number (sparse axis range) + if constexpr (ev_id == 1) { + if (!qaflags.cfgFillLegSimilarityMixSparse.value) { + return; // mixed-event sparse not booked + } + } + const float deta = etaA - etaB; + const float dphi = RecoDecay::constrainAngle(phiA - phiB, -o2::constants::math::PI); + if (std::fabs(deta) > 0.1f || std::fabs(dphi) > 0.1f) { // o2-linter: disable=magic-number (sparse axis range) return; } - const float ptSum = legA.pt() + legB.pt(); - const float ptRatio = (ptSum > 0.f) ? std::fabs(legA.pt() - legB.pt()) / ptSum : 0.f; - const float dNsigma = std::fabs(legA.tpcNSigmaEl() - legB.tpcNSigmaEl()); - fRegistryPairQA.fill(HIST("Pair/same/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv"), - deta, dphi, ptRatio, std::min(dNsigma, 7.99f), qinv); // o2-linter: disable=magic-number (clamp to axis) + const float ptSum = ptA + ptB; + const float ptRatio = (ptSum > 0.f) ? std::fabs(ptA - ptB) / ptSum : 0.f; + const float dNsigma = std::fabs(nsigA - nsigB); + if constexpr (ev_id == 0) { + fRegistryPairQA.fill(HIST("Pair/same/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv"), + deta, dphi, ptRatio, std::min(dNsigma, 7.99f), qinv); // o2-linter: disable=magic-number (clamp to axis) + } else { + fRegistryPairQA.fill(HIST("Pair/mix/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv"), + deta, dphi, ptRatio, std::min(dNsigma, 7.99f), qinv); // o2-linter: disable=magic-number (clamp to axis) + } + } + + template + void fillLegSimilarity(TLegA const& legA, TLegB const& legB, float qinv) + { + fillLegSimilarityValues<0>(legA.eta(), legA.phi(), legA.pt(), legA.tpcNSigmaEl(), + legB.eta(), legB.phi(), legB.pt(), legB.tpcNSigmaEl(), qinv); + } + + void fillLegSimilarityMix(PhotonWithLegs const& a, PhotonWithLegs const& b, float qinv) + { + fillLegSimilarityValues<1>(a.legEta(0), a.legPhi(0), a.legPt(0), a.legNsigEl(0), + b.legEta(0), b.legPhi(0), b.legPt(0), b.legNsigEl(0), qinv); + fillLegSimilarityValues<1>(a.legEta(1), a.legPhi(1), a.legPt(1), a.legNsigEl(1), + b.legEta(1), b.legPhi(1), b.legPt(1), b.legNsigEl(1), qinv); } template @@ -2068,6 +2109,10 @@ struct Photonhbt { fRegistryCF.fill(HIST("Pair/same/CF_3D"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); if (hbtanalysis.cfgDo2D) { fRegistryCF.fill(HIST("Pair/same/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + if (hbtanalysis.cfgDo2DSideLong) { + fRegistryCF.fill(HIST("Pair/same/CF_2D_Side"), std::fabs(qside_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + fRegistryCF.fill(HIST("Pair/same/CF_2D_Long"), std::fabs(qlong_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + } } if (hbtanalysis.cfgDoQinvGate3D) { fRegistryCF.fill(HIST("Pair/same/CF_3D_Qinv"), std::fabs(qout_lcms), std::fabs(qside_lcms), @@ -2077,6 +2122,10 @@ struct Photonhbt { fRegistryCF.fill(HIST("Pair/mix/CF_3D"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); if (hbtanalysis.cfgDo2D) { fRegistryCF.fill(HIST("Pair/mix/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + if (hbtanalysis.cfgDo2DSideLong) { + fRegistryCF.fill(HIST("Pair/mix/CF_2D_Side"), std::fabs(qside_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + fRegistryCF.fill(HIST("Pair/mix/CF_2D_Long"), std::fabs(qlong_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + } } if (hbtanalysis.cfgDoQinvGate3D) { fRegistryCF.fill(HIST("Pair/mix/CF_3D_Qinv"), std::fabs(qout_lcms), std::fabs(qside_lcms), @@ -2506,12 +2555,11 @@ struct Photonhbt { return PairTruthType::TrueTrueDistinct; } - // 0 = electron from a photon conversion, 1 = pi0 Dalitz electron, 2 = eta Dalitz electron, 3 = primary electron, 4 = other electron, 5 = not an electron at all (PID contamination) + // 0 = electron from a photon conversion, 1 = pi0 Dalitz electron, 2 = eta Dalitz electron, 3 = primary electron, 4 = other electron, 5 = not an electron at all (-> PID contamination) template static int classifyLegOrigin(TMCParticles const& mcParticles, int legMcId) { constexpr int kNotElectron = 5; - constexpr int kEtaMesonPdg = 221; // o2-linter: disable=magic-number (PDG code) if (legMcId < 0) { return kNotElectron; } @@ -2529,7 +2577,7 @@ struct Photonhbt { if (motherPdg == kPi0) { return 1; } - if (motherPdg == kEtaMesonPdg) { + if (motherPdg == o2::constants::physics::Pdg::kEta) { return 2; } return 4; @@ -2771,6 +2819,8 @@ struct Photonhbt { fillFullRangeDeltaRCosOA<1>(obs.qinv, obs.drOverCosOA); } + fillLegSimilarityMix(g1, g2, obs.qinv); + // ─── Pair cuts ──────────────────────────────────────────────── if (!passPhotonClassPairCut(g1.legCounts(), g2.legCounts())) { continue; @@ -3003,7 +3053,7 @@ struct Photonhbt { } const auto crossMC = computeCrossObs(pwl1, pwl2, obs.qinv); - if (crossMC.meeOverQ < 900.f) { // 999 = qinv was zero, skip + if (crossMC.meeOverQ < 900.f) { // o2-linter: disable=magic-number (qinv was zero, skip) fRegistryPairMC.fill(HIST("Pair/same/MC/hSparse_MeeRatio_Qinv_Type"), crossMC.meeOverQ, obs.qinv, static_cast(static_cast(truthType))); } @@ -3089,6 +3139,8 @@ struct Photonhbt { fillFullRangeDeltaRCosOA<1>(obs.qinv, obs.drOverCosOA); } + fillLegSimilarityMix(g1, g2, obs.qinv); + // ─── Pair cuts ──────────────────────────────────────────────── if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; @@ -3122,7 +3174,7 @@ struct Photonhbt { fillPairHistogram<1>(collision, obs.v1, obs.v2, 1.f); if (g1.fIsTruePhoton >= 0 && g2.fIsTruePhoton >= 0) { const int nTrue = g1.fIsTruePhoton + g2.fIsTruePhoton; - if (nTrue == 2) { + if (nTrue == 2) { // o2-linter: disable=magic-number (both pairs are true) fRegistryPairMC.fill(HIST("Pair/mix/MC/hQinv_TrueTrue"), obs.qinv); fillPairHistogramMC<1, PairTruthType::TrueTrueDistinct>(collision, obs.v1, obs.v2); } else if (nTrue == 1) { @@ -3772,6 +3824,7 @@ struct Photonhbt { } fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 0.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 0.f, mc.pt()); GammaLite g; g.mcId = mc.globalIndex(); g.eta = mc.eta(); @@ -3786,6 +3839,7 @@ struct Photonhbt { if (itPos != tracksOfMc.end() && itNeg != tracksOfMc.end()) { g.tracked = true; fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 1.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 1.f, mc.pt()); std::set commonColls; for (const auto& [posGi, posCol] : itPos->second) { @@ -3797,6 +3851,7 @@ struct Photonhbt { } if (!commonColls.empty()) { fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 2.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 2.f, mc.pt()); fRegistryTruthMC.fill(HIST("MCAOD/hNTrackedColls"), static_cast(commonColls.size())); g.trackedColls.assign(commonColls.begin(), commonColls.end()); @@ -3844,6 +3899,7 @@ struct Photonhbt { } if (!g.matches.empty()) { fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 3.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 3.f, mc.pt()); } } } @@ -4063,8 +4119,10 @@ struct Photonhbt { const float dEta = a.eta - b.eta; const float dPhi = RecoDecay::constrainAngle(a.phi - b.phi, -o2::constants::math::PI); const float dR = std::fabs(a.rConv - b.rConv); + const float kt = 0.5f * std::hypot(a.px + b.px, a.py + b.py); auto fillStage = [&](float s) { fRegistryTruthMC.fill(HIST("MCAOD/hPairStage"), s); + fRegistryTruthMC.fill(HIST("MCAOD/hPairStageVsKt"), s, kt); fRegistryTruthMC.fill(HIST("MCAOD/hSparsePairStage"), s, dEta, dPhi, qinv); fRegistryTruthMC.fill(HIST("MCAOD/hSparseDRStage"), s, dR, qinv); }; diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index 146f38007f2..ae67846b2de 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -247,6 +247,8 @@ struct TaskPi0FlowEMC { Configurable cfgApplySPresolution{"cfgApplySPresolution", false, "Apply resolution correction"}; Configurable doEMCalCalib{"doEMCalCalib", false, "Produce output for EMCal calibration"}; Configurable cfgEnableNonLin{"cfgEnableNonLin", false, "flag to turn extra non linear energy calibration on/off"}; + Configurable cfgEmcalEffRadius{"cfgEmcalEffRadius", 430.f, "effective EMCal radius (cm) used for mixed-event vertex-swap correction"}; + Configurable cfgCorrectMixedVtxEta{"cfgCorrectMixedVtxEta", true, "re-project cluster2 eta onto collision1's vertex in mixed event"}; } correctionConfig; SliceCache cache; @@ -528,6 +530,18 @@ struct TaskPi0FlowEMC { registry.fill(HIST(HistTypes[histType]), mass, pt, cent); } + /// \brief eta a cluster would have if its own vertex vzOld is swapped for vzNew, + /// assuming a nominal cylindrical EMCal surface at transverse radius emcalR (cm). + /// phi is untouched: transverse vertex spread is negligible next to emcalR. + /// \param etaOld old eta value + /// \param vzOld old primary vertex z position + /// \param vzNew new primary vertex z position + /// \param emcalR radius of the EMCal + static float correctEtaForVertexShift(float etaOld, float vzOld, float vzNew, float emcalR) + { + return std::asinh(std::sinh(etaOld) + (vzOld - vzNew) / emcalR); + } + /// Get the centrality /// \param collision is the collision with the centrality information template @@ -1202,7 +1216,13 @@ struct TaskPi0FlowEMC { } } ROOT::Math::PtEtaPhiMVector v1(g1.corrPt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.corrPt(), g2.eta(), g2.phi(), 0.); + + // changing the eta position of cluster 2 from collision 2 to match the z-vertex position of collision 1 + float eta2 = g2.eta(); + if (correctionConfig.cfgCorrectMixedVtxEta.value) { + eta2 = correctEtaForVertexShift(g2.eta(), c2.posZ(), c1.posZ(), correctionConfig.cfgEmcalEffRadius.value); + } + ROOT::Math::PtEtaPhiMVector v2(g2.corrPt(), eta2, g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; float dTheta = v1.Theta() - v2.Theta(); diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h index e63216a4821..f9f9fcdec0b 100644 --- a/PWGEM/PhotonMeson/Utils/EventHistograms.h +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -47,34 +47,13 @@ inline void addEventHistograms(o2::framework::HistogramRegistry* fRegistry, bool hCollisionCounter->GetXaxis()->SetBinLabel(11, "EMC L0 Triggered"); hCollisionCounter->GetXaxis()->SetBinLabel(12, "accepted"); - const o2::framework::AxisSpec axis_cent_ft0m{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, - "centrality FT0M (%)"}; - - const o2::framework::AxisSpec axis_cent_ft0a{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, - "centrality FT0A (%)"}; - - const o2::framework::AxisSpec axis_cent_ft0c{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, - "centrality FT0C (%)"}; - fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::HistType::kTH1D, {{220, -11, +11}}, useWeight); fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", o2::framework::HistType::kTH1F, {{6001, -0.5, 6000.5}}, useWeight); fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", o2::framework::HistType::kTH1F, {{6001, -0.5, 6000.5}}, useWeight); fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", o2::framework::HistType::kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, useWeight); - fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", o2::framework::HistType::kTH1F, {{axis_cent_ft0a}}, useWeight); - fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", o2::framework::HistType::kTH1F, {{axis_cent_ft0c}}, useWeight); - fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", o2::framework::HistType::kTH1F, {{axis_cent_ft0m}}, useWeight); + fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", o2::framework::HistType::kTH1F, {{100, 0., 100.}}, useWeight); + fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", o2::framework::HistType::kTH1F, {{100, 0., 100.}}, useWeight); + fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", o2::framework::HistType::kTH1F, {{100, 0., 100.}}, useWeight); fRegistry->add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", o2::framework::HistType::kTH2F, {{110, 0, 110}, {500, 0, 5000}}, useWeight); fRegistry->add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", o2::framework::HistType::kTH2F, {{60, 0, 60000}, {500, 0, 5000}}, useWeight); fRegistry->add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", o2::framework::HistType::kTH2F, {{60, 0, 60000}, {500, 0, 10000}}, useWeight); diff --git a/PWGHF/D2H/Tasks/taskCd.cxx b/PWGHF/D2H/Tasks/taskCd.cxx index 501b244811b..8282a7eecf5 100644 --- a/PWGHF/D2H/Tasks/taskCd.cxx +++ b/PWGHF/D2H/Tasks/taskCd.cxx @@ -117,6 +117,8 @@ DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); //! Candidat DECLARE_SOA_COLUMN(CandidateSign, candidateSign, int8_t); //! Candidates sign DECLARE_SOA_COLUMN(FlagMc, flagMc, int8_t); //! Main MC decay-channel flag; 0 for unmatched candidates DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! MC-matched prong permutation; -1 for data +DECLARE_SOA_COLUMN(HypothesisMask, hypothesisMask, uint8_t); //! Bit 0: DeKPi selected; bit 1: PiKDe selected +DECLARE_SOA_COLUMN(CandidateGlobalIndex, candidateGlobalIndex, int64_t); //! Input candidate index, shared by rows from the same candidate DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! MC origin for reconstructed candidates DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! Resonant MC decay channel for reconstructed candidates DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! MC origin for generated particles @@ -158,6 +160,9 @@ DECLARE_SOA_TABLE(HfCandCdLite, "AOD", "HFCANDCDLITE", full::CandidateSelFlag, full::CandidateSign, full::FlagMc, + full::IsCandidateSwapped, + full::HypothesisMask, + full::CandidateGlobalIndex, full::OriginMcRec, full::FlagMcDecayChanRec, full::CtGen, @@ -196,6 +201,8 @@ DECLARE_SOA_TABLE(HfCandCdFull, "AOD", "HFCANDCDFULL", full::CandidateSign, full::FlagMc, full::IsCandidateSwapped, + full::HypothesisMask, + full::CandidateGlobalIndex, full::OriginMcRec, full::FlagMcDecayChanRec, full::CtGen, @@ -535,18 +542,25 @@ struct HfTaskCd { float ctGen{-1.f}, ptGen{-1.f}; int pdgCodeProng0{0}; + int8_t isCandidateSwapped{-1}; if (isTrueCd) { const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as(); pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); + isCandidateSwapped = static_cast(pdgCodeProng0 == kPiPlus); const auto indexMother = RecoDecay::getMother(mcParticles, mcParticleProng0, o2::constants::physics::Pdg::kCDeuteron, true); const auto particleMother = mcParticles.rawIteratorAt(indexMother); ctGen = RecoDecay::ct(std::array{particleMother.px(), particleMother.py(), particleMother.pz()}, RecoDecay::distance(std::array{particleMother.vx(), particleMother.vy(), particleMother.vz()}, std::array{mcParticleProng0.vx(), mcParticleProng0.vy(), mcParticleProng0.vz()}), o2::constants::physics::MassCDeuteron) * CmToMum; ptGen = particleMother.pt(); + } else if (absFlagMc != 0) { + isCandidateSwapped = candidate.isCandidateSwapped(); } if (fillCandLiteTree || fillCandFullTree) { const bool selDeKPi = (candidate.isSelCdToDeKPi() >= selectionFlagCd); const bool selPiKDe = (candidate.isSelCdToPiKDe() >= selectionFlagCd); + const uint8_t hypothesisMask = static_cast((selDeKPi ? 0x1 : 0x0) | + (selPiKDe ? 0x2 : 0x0)); + const int64_t candidateGlobalIndex = candidate.globalIndex(); auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); @@ -593,7 +607,7 @@ struct HfTaskCd { nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe, tofBetaDe, tpcInnerParamDe, tofExpMomDe, candidate.ct(o2::constants::physics::MassCDeuteron) * CmToMum, - candFlag, candSign, candidate.flagMcMatchRec(), candidate.originMcRec(), + candFlag, candSign, candidate.flagMcMatchRec(), isCandidateSwapped, hypothesisMask, candidateGlobalIndex, candidate.originMcRec(), candidate.flagMcDecayChanRec(), ctGen, o2::hf_centrality::getCentralityColl(collision)); } @@ -608,7 +622,7 @@ struct HfTaskCd { tofBetaDe, tpcInnerParamDe, tofExpMomDe, nSigmaTpcPi, nSigmaTofPi, nSigmaTpcKa, nSigmaTofKa, candidate.ct(o2::constants::physics::MassCDeuteron) * CmToMum, - candFlag, candSign, candidate.flagMcMatchRec(), candidate.isCandidateSwapped(), candidate.originMcRec(), + candFlag, candSign, candidate.flagMcMatchRec(), isCandidateSwapped, hypothesisMask, candidateGlobalIndex, candidate.originMcRec(), candidate.flagMcDecayChanRec(), ctGen, collision.numContrib(), o2::hf_centrality::getCentralityColl(collision), collision.posZ(), collision.globalIndex(), timeStamp); } @@ -813,6 +827,9 @@ struct HfTaskCd { if (fillCandLiteTree || fillCandFullTree) { const bool selDeKPi = (candidate.isSelCdToDeKPi() >= selectionFlagCd); const bool selPiKDe = (candidate.isSelCdToPiKDe() >= selectionFlagCd); + const uint8_t hypothesisMask = static_cast((selDeKPi ? 0x1 : 0x0) | + (selPiKDe ? 0x2 : 0x0)); + const int64_t candidateGlobalIndex = candidate.globalIndex(); auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); @@ -874,7 +891,7 @@ struct HfTaskCd { decayLength, cpa, chi2PCA, nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe, tofBetaDe, tpcInnerParamDe, tofExpMomDe, candidate.ct(o2::constants::physics::MassCDeuteron), - candFlag, candSign, 0, 0, -1, -1.f, cent); + candFlag, candSign, 0, -1, hypothesisMask, candidateGlobalIndex, 0, -1, -1.f, cent); } if (fillCandFullTree) { @@ -887,7 +904,7 @@ struct HfTaskCd { tofBetaDe, tpcInnerParamDe, tofExpMomDe, nSigmaTpcPi, nSigmaTofPi, nSigmaTpcKa, nSigmaTofKa, candidate.ct(o2::constants::physics::MassCDeuteron), - candFlag, candSign, 0, -1, 0, 0, -1.f, collision.numContrib(), cent, + candFlag, candSign, 0, -1, hypothesisMask, candidateGlobalIndex, 0, 0, -1.f, collision.numContrib(), cent, collision.posZ(), collision.globalIndex(), timeStamp); } }; diff --git a/PWGHF/D2H/Tasks/taskSigmac.cxx b/PWGHF/D2H/Tasks/taskSigmac.cxx index 69e370f3fd1..3f73c812615 100644 --- a/PWGHF/D2H/Tasks/taskSigmac.cxx +++ b/PWGHF/D2H/Tasks/taskSigmac.cxx @@ -69,6 +69,7 @@ struct HfTaskSigmac { Configurable addMassDiffAbsLambdaCToSigmacSparse{"addMassDiffAbsLambdaCToSigmacSparse", false, "enable the filling of |M(pkpi, piKp) - M(LambdaC)| in the Σc0,++ THnSparse"}; Configurable deltaMassSigmacRecoMax{"deltaMassSigmacRecoMax", 1000, "Maximum allowed value for Sigmac deltaMass. Conceived to reduce the output size (i.e. reject background above a certain threshold)"}; Configurable ptMinSc{"ptMinSc", -1.f, "Minimum accepted value for SigmaC-hadron pt (GeV/c)"}; + Configurable trackingInfo4SoftPiOnly{"trackingInfo4SoftPiOnly", false, "Flag to enable the storage of tracking info about the soft pion only"}; bool isMc{}; bool storeTrackProp{}; @@ -578,7 +579,13 @@ struct HfTaskSigmac { const auto& trackLcProng0 = candidateLc.template prong0_as(); const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -745,7 +752,13 @@ struct HfTaskSigmac { const auto& trackLcProng0 = candidateLc.template prong0_as(); const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1301,7 +1314,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1470,7 +1489,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1676,7 +1701,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1843,7 +1874,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored diff --git a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx index dc18a8a7f5c..496df5d5b51 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx @@ -293,6 +293,8 @@ struct HfCorrelatorD0Hadrons { AxisSpec axisBdtScoreNonPrompt = {binsBdtScoreNonPrompt, "Bdt score Nonprompt"}; AxisSpec axisOrigin = {10, 0., 10., "Candidate origin"}; AxisSpec axisCent = {binsCentFt0m, "Centrality"}; + AxisSpec const axisCandidateStatusMcRec = {64, -0.5, 63.5, "MC candidate status"}; + AxisSpec const axisRecoHypothesis = {4, -0.5, 3.5, "Reconstructed hypothesis"}; // Histograms for Data registry.add("hPtCand", "D0, D0bar candidates", {HistType::kTH1F, {axisPtD}}); @@ -339,6 +341,11 @@ struct HfCorrelatorD0Hadrons { registry.add("hPtVsMultiplicityRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); registry.add("hPtParticleAssocVsCandRec", "Associated Particle - MC reco", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); registry.add("hPtPrimaryParticleAssocVsCandRec", "Associated Particle - MC reco", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + if (useCentrality) { + registry.add("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesisVsCent", "MCRec template information with centrality", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisMassD}, {axisPtD}, {axisEta}, {axisOrigin}, {axisCandidateStatusMcRec}, {axisRecoHypothesis}, {axisCent}}}); + } else { + registry.add("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesis", "MCRec template information", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisMassD}, {axisPtD}, {axisEta}, {axisOrigin}, {axisCandidateStatusMcRec}, {axisRecoHypothesis}}}); + } // Histograms for MC Gen registry.add("hEvtCountGen", "Event counter - MC gen", {HistType::kTH1F, {axisEvtCount}}); registry.add("hPtCandGen", "D0, D0bar candidates - MC gen", {HistType::kTH1F, {axisPtD}}); @@ -681,7 +688,13 @@ struct HfCorrelatorD0Hadrons { const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); - if (candidate.isSelD0() >= selectionFlagD0 || candidate.isSelD0bar() >= selectionFlagD0bar) { + const bool selectedD0 = candidate.isSelD0() >= selectionFlagD0; + const bool selectedD0bar = candidate.isSelD0bar() >= selectionFlagD0bar; + const int recoHypothesis = selectedD0 && selectedD0bar ? aod::hf_correlation_d0_hadron::ParticleTypeData::D0D0barBoth : selectedD0 ? aod::hf_correlation_d0_hadron::ParticleTypeData::D0Only + : selectedD0bar ? aod::hf_correlation_d0_hadron::ParticleTypeData::D0barOnly + : 0; + + if (selectedD0 || selectedD0bar) { hasAcceptedD0ForOfflineMixing = true; } @@ -696,9 +709,13 @@ struct HfCorrelatorD0Hadrons { registry.fill(HIST("hSelectionStatusRec"), candidate.isSelD0bar() + (candidate.isSelD0() * 2)); } // fill invariant mass plots from D0/D0bar signal and background candidates - if (candidate.isSelD0() >= selectionFlagD0) { // only reco as D0 - if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0 + if (selectedD0) { // reconstructed under the D0 hypothesis + int candidateStatus = 0; + + if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Sig); registry.fill(HIST("hMassD0RecSig"), invMassD0, candidate.pt(), efficiencyWeight); + if (isD0Prompt) { registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); @@ -709,22 +726,41 @@ struct HfCorrelatorD0Hadrons { registry.fill(HIST("hPtVsMLScoresVsEtaRecSigNonPrompt"), outputMlD0[0], outputMlD0[1], outputMlD0[2], candidate.pt(), candidate.eta()); } } else if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Ref); registry.fill(HIST("hMassD0RecRef"), invMassD0, candidate.pt(), efficiencyWeight); - if (candidate.isSelD0bar() < selectionFlagD0bar) { + + if (!selectedD0bar) { registry.fill(HIST("hMassD0RecRefAfterRejectBoth"), invMassD0, candidate.pt(), efficiencyWeight); } } else { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Bg); registry.fill(HIST("hMassD0RecBg"), invMassD0, candidate.pt(), efficiencyWeight); } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCent"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt, cent, efficiencyWeight); - entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0, poolBin, gCollisionId, timeStamp, (candidate.isSelD0bar() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only); + + if (useCentrality) { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesisVsCent"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt, + candidateStatus, recoHypothesis, cent, efficiencyWeight); + } else { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesis"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt, + candidateStatus, recoHypothesis, efficiencyWeight); + } + + entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0, poolBin, gCollisionId, timeStamp, selectedD0bar ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only); } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar - if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0bar + + if (selectedD0bar) { // reconstructed under the D0bar hypothesis + int candidateStatus = 0; + + if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barSig); registry.fill(HIST("hMassD0barRecSig"), invMassD0bar, candidate.pt(), efficiencyWeight); + if (isD0Prompt) { registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); @@ -735,18 +771,32 @@ struct HfCorrelatorD0Hadrons { registry.fill(HIST("hPtVsMLScoresVsEtaRecSigNonPrompt"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], candidate.pt(), candidate.eta()); } } else if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barRef); registry.fill(HIST("hMassD0barRecRef"), invMassD0bar, candidate.pt(), efficiencyWeight); - if (candidate.isSelD0() < selectionFlagD0) { + + if (!selectedD0) { registry.fill(HIST("hMassD0barRecRefAfterRejectBoth"), invMassD0bar, candidate.pt(), efficiencyWeight); } } else { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barBg); registry.fill(HIST("hMassD0barRecBg"), invMassD0bar, candidate.pt(), efficiencyWeight); } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCent"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), isD0Prompt, cent, efficiencyWeight); - entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0bar, poolBin, gCollisionId, timeStamp, (candidate.isSelD0() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly); + + if (useCentrality) { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesisVsCent"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), + isD0Prompt, candidateStatus, recoHypothesis, cent, efficiencyWeight); + } else { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesis"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), isD0Prompt, + candidateStatus, recoHypothesis, efficiencyWeight); + } + + entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0bar, poolBin, gCollisionId, timeStamp, selectedD0 ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly); } entryD0CandRecoInfo(invMassD0, invMassD0bar, candidate.pt(), outputMlD0[0], outputMlD0[1], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2]); entryD0CandGenInfo(isD0Prompt); diff --git a/PWGHF/Utils/utilsEvSelHf.h b/PWGHF/Utils/utilsEvSelHf.h index 26a65402ae3..7ce2b179dad 100644 --- a/PWGHF/Utils/utilsEvSelHf.h +++ b/PWGHF/Utils/utilsEvSelHf.h @@ -214,9 +214,9 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { o2::framework::Configurable rctCheckZDC{"rctCheckZDC", false, "RCT flag to check whether the ZDC is present or not"}; o2::framework::Configurable rctTreatLimitedAcceptanceAsBad{"rctTreatLimitedAcceptanceAsBad", false, "RCT flag to reject events with limited acceptance for selected detectors"}; o2::framework::Configurable irSource{"irSource", "", "Estimator of the interaction rate (Empty: automatically set. Otherwise recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - o2::framework::Configurable useUpcZdcTimeCut{"useUpcZdcTimeCut", true, "Apply ZDC time selection for UPC neutron class"}; - o2::framework::Configurable upcZdcTimeMin{"upcZdcTimeMin", -2.f, "Minimum ZDC time for UPC neutron class selection (ns)"}; - o2::framework::Configurable upcZdcTimeMax{"upcZdcTimeMax", 2.f, "Maximum ZDC time for UPC neutron class selection (ns)"}; + o2::framework::Configurable useUpcZdcTimeCut{"useUpcZdcTimeCut", false, "Apply ZDC time selection for UPC neutron class (only relevant for UPC event selection)"}; + o2::framework::Configurable upcZdcTimeMin{"upcZdcTimeMin", -2.f, "Minimum ZDC time for UPC neutron class selection (ns) (only relevant for UPC event selection)"}; + o2::framework::Configurable upcZdcTimeMax{"upcZdcTimeMax", 2.f, "Maximum ZDC time for UPC neutron class selection (ns) (only relevant for UPC event selection)"}; // SG selector SGSelector sgSelector; diff --git a/PWGJE/Tasks/CMakeLists.txt b/PWGJE/Tasks/CMakeLists.txt index d4347cb52e4..a87293c9cca 100644 --- a/PWGJE/Tasks/CMakeLists.txt +++ b/PWGJE/Tasks/CMakeLists.txt @@ -104,6 +104,7 @@ o2physics_add_dpl_workflow(hadron-photon-correlation if(FastJet_FOUND) o2physics_add_dpl_workflow(jet-background-analysis SOURCES jetBackgroundAnalysis.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure @@ -113,6 +114,7 @@ if(FastJet_FOUND) COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure-output SOURCES jetSubstructureOutput.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure-d0 @@ -207,74 +209,92 @@ if(FastJet_FOUND) COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-fragmentation SOURCES jetFragmentation.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-v0-spectra SOURCES v0JetSpectra.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-v0qa SOURCES v0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-charged-qa SOURCES jetFinderQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-outlier-qa SOURCES jetOutlierQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-charged-v2 SOURCES jetChargedV2.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-d0-qa SOURCES jetFinderD0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-dplus-qa SOURCES jetFinderDplusQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-ds-qa SOURCES jetFinderDsQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-dstar-qa SOURCES jetFinderDstarQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-lc-qa SOURCES jetFinderLcQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-b0-qa SOURCES jetFinderB0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-bplus-qa SOURCES jetFinderBplusQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-xictoxipipi-qa SOURCES jetFinderXicToXiPiPiQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-dielectron-qa SOURCES jetFinderDielectronQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-full-qa SOURCES jetFinderFullQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-v0-qa SOURCES jetFinderV0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-spectra-charged SOURCES jetSpectraCharged.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-spectra-charged-gen @@ -283,161 +303,200 @@ if(FastJet_FOUND) COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(charged-jet-hadron SOURCES chargedJetHadron.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(trigger-correlations SOURCES triggerCorrelations.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-trigger-charged-qa SOURCES jetTriggerChargedQa.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-full-trigger-qa SOURCES fullJetTriggerQATask.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-matching-qa SOURCES jetMatchingQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-validation-qa SOURCES jetValidationQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-tutorial SOURCES jetTutorial.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-tutorial-skeleton SOURCES jetTutorialSkeleton.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-jet-qa SOURCES trackJetQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-efficiency SOURCES trackEfficiency.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-hadron-recoil SOURCES jetHadronRecoil.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(recoil-jets SOURCES recoilJets.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-nsubjettiness SOURCES nsubjettiness.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(phi-in-jets SOURCES phiInJets.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(nuclei-in-jets SOURCES nucleiInJets.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-taggerhf-qa SOURCES jetTaggerHFQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-lund-reclustering SOURCES jetLundReclustering.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-lund-plane SOURCES jetLundPlane.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-fragmentation-function SOURCES hfFragmentationFunction.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-planarflow SOURCES jetPlanarFlow.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-ch-corr SOURCES jetChCorr.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-tree-creator SOURCES bjetTreeCreator.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(stat-prompt-photon SOURCES statPromptPhoton.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(full-jet-spectra SOURCES fullJetSpectra.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-tagging-ml SOURCES bjetTaggingML.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-spectra-ese SOURCES jetSpectraEseTask.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-cross-section-efficiency SOURCES jetCrossSectionEfficiency.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(gamma-jet-tree-producer SOURCES gammaJetTreeProducer.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dijet-finder-charged-qa SOURCES dijetFinderQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-tagging-gnn SOURCES bjetTaggingGnn.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-shape SOURCES jetShape.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-formationtimereclustering SOURCES jetFormationTimeReclustering.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-correlation-d0 SOURCES jetCorrelationD0.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-debug SOURCES hfDebug.cxx + REUSE_FROM JetSubstructureHFOutputPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-debug SOURCES jetDebug.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(substructure-debug SOURCES substructureDebug.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-ds-spec-subs SOURCES jetDsSpecSubs.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-d0-ang-substructure SOURCES jetD0AngSubstructure.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-cent-mult SOURCES bjetCentMult.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-hadrons-pid diff --git a/PWGLF/DataModel/LFHypernucleiTables.h b/PWGLF/DataModel/LFHypernucleiTables.h index d494fcbf87a..080dd89646d 100644 --- a/PWGLF/DataModel/LFHypernucleiTables.h +++ b/PWGLF/DataModel/LFHypernucleiTables.h @@ -25,17 +25,19 @@ namespace o2::aod { namespace hyperrec { -DECLARE_SOA_COLUMN(CentralityFT0A, centralityFT0A, float); // centrality with FT0A estimator -DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); // centrality with FT0C estimator -DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); // centrality with FT0M estimator -DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); // Psi with FT0A estimator -DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); // Multiplicity with FT0A estimator -DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); // Psi with FT0C estimator -DECLARE_SOA_COLUMN(QFT0C, qFT0C, float); // Amplitude with FT0C estimator -DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); // Multiplicity with FT0C estimator -DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estimator -DECLARE_SOA_COLUMN(MultTPC, multTPC, float); // Multiplicity with TPC estimator -DECLARE_SOA_COLUMN(CollisionId, collisionId, int64_t); // CollisionID +DECLARE_SOA_COLUMN(CentralityFT0A, centralityFT0A, float); // centrality with FT0A estimator +DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); // centrality with FT0C estimator +DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); // centrality with FT0M estimator +DECLARE_SOA_COLUMN(TrackOccupancyInTimeRange, trackOccupancyInTimeRange, int); // Track occupancy in the time range around the collision +DECLARE_SOA_COLUMN(Ft0cOccupancyInTimeRange, ft0cOccupancyInTimeRange, float); // FT0C occupancy in the time range around the collision +DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); // Psi with FT0A estimator +DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); // Multiplicity with FT0A estimator +DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); // Psi with FT0C estimator +DECLARE_SOA_COLUMN(QFT0C, qFT0C, float); // Amplitude with FT0C estimator +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); // Multiplicity with FT0C estimator +DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estimator +DECLARE_SOA_COLUMN(MultTPC, multTPC, float); // Multiplicity with TPC estimator +DECLARE_SOA_INDEX_COLUMN(Collision, collision); // Collision index DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); // Run number DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); // bool: true for matter @@ -62,19 +64,19 @@ DECLARE_SOA_COLUMN(NTPCpidClusHe, nTPCpidClusHe, uint8_t); // Number DECLARE_SOA_COLUMN(NTPCpidClusPi, nTPCpidClusPi, uint8_t); // Number of TPC clusters with PID information of the Pi daughter DECLARE_SOA_COLUMN(NTPCCrossedRowsHe, nTPCCrossedRowsHe, uint8_t); // Number of TPC crossed rows of the He daughter DECLARE_SOA_COLUMN(NTPCCrossedRowsPi, nTPCCrossedRowsPi, uint8_t); // Number of TPC crossed rows of the Pi daughter -DECLARE_SOA_COLUMN(TPCsignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter -DECLARE_SOA_COLUMN(TPCsignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter -DECLARE_SOA_COLUMN(TPCChi2He, tpcChi2He, float); // TPC chi2 of the He daughter -DECLARE_SOA_COLUMN(ITSChi2He, itsChi2He, float); // ITS chi2 of the He daughter -DECLARE_SOA_COLUMN(ITSChi2Pi, itsChi2Pi, float); // ITS chi2 of the Pi daughter +DECLARE_SOA_COLUMN(TpcSignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter +DECLARE_SOA_COLUMN(TpcSignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter +DECLARE_SOA_COLUMN(TpcChi2He, tpcChi2He, float); // TPC chi2 of the He daughter +DECLARE_SOA_COLUMN(ItsChi2He, itsChi2He, float); // ITS chi2 of the He daughter +DECLARE_SOA_COLUMN(ItsChi2Pi, itsChi2Pi, float); // ITS chi2 of the Pi daughter DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, int); // int: zero for non-tracked candidates DECLARE_SOA_COLUMN(Flags, flags, uint8_t); // Flags for PID in tracking (bits [0, 3] for negative daughter, [4,7] for positive daughter) -DECLARE_SOA_COLUMN(TPCmomHe, tpcMomHe, float); // TPC momentum of the He daughter -DECLARE_SOA_COLUMN(TPCmomPi, tpcMomPi, float); // TPC momentum of the Pi daughter -DECLARE_SOA_COLUMN(TOFMass, tofMass, float); // TOF mass of the candidate -DECLARE_SOA_COLUMN(ITSclusterSizesHe, itsClusterSizesHe, uint32_t); // ITS cluster size of the He daughter -DECLARE_SOA_COLUMN(ITSclusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter -DECLARE_SOA_COLUMN(ITSclusterSizesHyp, itsClusterSizesHyp, uint32_t); // ITS cluster size of the Pi daughter +DECLARE_SOA_COLUMN(TpcMomHe, tpcMomHe, float); // TPC momentum of the He daughter +DECLARE_SOA_COLUMN(TpcMomPi, tpcMomPi, float); // TPC momentum of the Pi daughter +DECLARE_SOA_COLUMN(TofMass, tofMass, float); // TOF mass of the candidate +DECLARE_SOA_COLUMN(ItsClusterSizesHe, itsClusterSizesHe, uint32_t); // ITS cluster size of the He daughter +DECLARE_SOA_COLUMN(ItsClusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter +DECLARE_SOA_COLUMN(ItsClusterSizesHyp, itsClusterSizesHyp, uint32_t); // ITS cluster size of the Pi daughter DECLARE_SOA_COLUMN(DcaHe, dcaHe, float); // DCA between He daughter and V0 DECLARE_SOA_COLUMN(DcaPi, dcaPi, float); // DCA between pi daughter and V0 DECLARE_SOA_COLUMN(GenPt, genPt, float); // Pt of the hypertriton @@ -95,6 +97,7 @@ DECLARE_SOA_COLUMN(IsTwoBodyDecay, isTwoBodyDecay, bool); // bool: t DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, hyperrec::RunNumber, hyperrec::IsMatter, @@ -103,14 +106,15 @@ DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::PsiFT0A, hyperrec::MultFT0A, hyperrec::PsiFT0C, hyperrec::MultFT0C, hyperrec::QFT0C, hyperrec::PsiTPC, hyperrec::MultTPC, @@ -122,14 +126,15 @@ DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, hyperrec::RunNumber, hyperrec::IsMatter, @@ -138,9 +143,9 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize, hyperrec::GenPt, hyperrec::GenPhi, @@ -159,6 +164,7 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", o2::soa::Index<>, hyperrec::CollisionId, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, hyperrec::RunNumber, hyperrec::IsMatter, @@ -167,9 +173,9 @@ DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize); using DataHypCand = DataHypCands::iterator; @@ -187,20 +193,20 @@ DECLARE_SOA_COLUMN(PhiTrit, phiTrit, float); // Phi DECLARE_SOA_COLUMN(EtaTrit, etaTrit, float); // Eta of the triton kink DECLARE_SOA_COLUMN(DcaHyperPv, dcaHyperPv, float); // DCA of the hypertriton to the primary vertex DECLARE_SOA_COLUMN(DcaTritPv, dcaTritPv, float); // DCA of the triton kink to the primary vertex -DECLARE_SOA_COLUMN(DCAKinkTopo, dcaKinkTopo, float); // DCA of the kink topology -DECLARE_SOA_COLUMN(ITSclusterSizesHyper, itsClusterSizesHyper, uint32_t); // ITS cluster size of the hypertriton -DECLARE_SOA_COLUMN(ITSclusterSizesTrit, itsClusterSizesTrit, uint32_t); // ITS cluster size of the triton kink -DECLARE_SOA_COLUMN(PIDinTrackTrit, pidInTrackTrit, uint8_t); // PID in track for the triton kink +DECLARE_SOA_COLUMN(DcaKinkTopo, dcaKinkTopo, float); // DCA of the kink topology +DECLARE_SOA_COLUMN(ItsClusterSizesHyper, itsClusterSizesHyper, uint32_t); // ITS cluster size of the hypertriton +DECLARE_SOA_COLUMN(ItsClusterSizesTrit, itsClusterSizesTrit, uint32_t); // ITS cluster size of the triton kink +DECLARE_SOA_COLUMN(PidInTrackTrit, pidInTrackTrit, uint8_t); // PID in track for the triton kink -DECLARE_SOA_COLUMN(TPCmomTrit, tpcMomTrit, float); // TPC momentum of the triton kink -DECLARE_SOA_COLUMN(TPCsignalTrit, tpcSignalTrit, uint16_t); // TPC signal of the triton kink +DECLARE_SOA_COLUMN(TpcMomTrit, tpcMomTrit, float); // TPC momentum of the triton kink +DECLARE_SOA_COLUMN(TpcSignalTrit, tpcSignalTrit, uint16_t); // TPC signal of the triton kink DECLARE_SOA_COLUMN(NSigmaTPCTrit, nSigmaTPCTrit, float); // Number of tpc sigmas of the triton kink DECLARE_SOA_COLUMN(NSigmaTOFTrit, nSigmaTOFTrit, float); // Number of tof sigmas of the triton kink // MC additional info DECLARE_SOA_COLUMN(GenPtTrit, genPtTrit, float); // Pt of the triton kink DECLARE_SOA_COLUMN(HyperPtITS, hyperPtITS, float); // Pt of the hypertriton from ITS standalone, hypertriton tagged with MC truth -DECLARE_SOA_COLUMN(MCMask, mcMask, bool); // bool: true for fake triton +DECLARE_SOA_COLUMN(McMask, mcMask, bool); // bool: true for fake triton } // namespace hyperkink @@ -210,9 +216,9 @@ DECLARE_SOA_TABLE(DataHypKinkCands, "AOD", "HYPKINKCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::IsMatter, hyperkink::PtHyper, hyperkink::PhiHyper, hyperkink::EtaHyper, hyperkink::PtTrit, hyperkink::PhiTrit, hyperkink::EtaTrit, - hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DCAKinkTopo, - hyperkink::ITSclusterSizesHyper, hyperkink::ITSclusterSizesTrit, hyperkink::PIDinTrackTrit, - hyperkink::TPCmomTrit, hyperkink::TPCsignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit); + hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DcaKinkTopo, + hyperkink::ItsClusterSizesHyper, hyperkink::ItsClusterSizesTrit, hyperkink::PidInTrackTrit, + hyperkink::TpcMomTrit, hyperkink::TpcSignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit); DECLARE_SOA_TABLE(MCHypKinkCands, "AOD", "MCHYPKINKCANDS", o2::soa::Index<>, @@ -220,12 +226,12 @@ DECLARE_SOA_TABLE(MCHypKinkCands, "AOD", "MCHYPKINKCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::IsMatter, hyperkink::PtHyper, hyperkink::PhiHyper, hyperkink::EtaHyper, hyperkink::PtTrit, hyperkink::PhiTrit, hyperkink::EtaTrit, - hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DCAKinkTopo, - hyperkink::ITSclusterSizesHyper, hyperkink::ITSclusterSizesTrit, hyperkink::PIDinTrackTrit, - hyperkink::TPCmomTrit, hyperkink::TPCsignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit, + hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DcaKinkTopo, + hyperkink::ItsClusterSizesHyper, hyperkink::ItsClusterSizesTrit, hyperkink::PidInTrackTrit, + hyperkink::TpcMomTrit, hyperkink::TpcSignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit, hyperrec::GenXDecVtx, hyperrec::GenYDecVtx, hyperrec::GenZDecVtx, hyperrec::GenPt, hyperkink::GenPtTrit, - hyperrec::IsReco, hyperrec::IsSignal, hyperkink::MCMask, hyperkink::HyperPtITS, + hyperrec::IsReco, hyperrec::IsSignal, hyperkink::McMask, hyperkink::HyperPtITS, hyperrec::IsRecoMCCollision, hyperrec::IsSurvEvSel); } // namespace o2::aod diff --git a/PWGLF/DataModel/LFResonanceTables.h b/PWGLF/DataModel/LFResonanceTables.h index 11fd45842ef..673d2ae8393 100644 --- a/PWGLF/DataModel/LFResonanceTables.h +++ b/PWGLF/DataModel/LFResonanceTables.h @@ -38,6 +38,7 @@ #include #include #include +#include namespace o2::aod { @@ -66,6 +67,7 @@ enum { }; DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, Collisions, "_Col"); //! DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); //! Configurable reconstructed multiplicity estimator DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events @@ -84,16 +86,33 @@ DECLARE_SOA_COLUMN(MCMultiplicity, mcMultiplicity, float); //! MC Multiplicit } // namespace resocollision -// Keep the established ResoCollisionColls schema above unchanged. Automatic -// GroupSlicer association to aod::Collisions requires the canonical physical -// column name fIndexCollisions, so the modular initializer writes this small -// companion table for the hybrid daughter process. +// Legacy version-0 companion schema. Its canonical fIndexCollisions column +// enables GroupSlicer association to aod::Collisions, but also makes the table +// dependent on that source parent. The modular initializer therefore writes +// the scalar-only version 001 declared below instead. namespace resocollisiongroup { DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(OriginalCollision, originalCollision, int, Collisions, "Collisions", ""); //! } // namespace resocollisiongroup -DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION", +// Scalar-only original-collision mapping for standalone modular output. Unlike +// resocollisiongroup::OriginalCollisionId above, this column carries no index +// target metadata and therefore does not require the source Collisions table +// to be present while merging the derived AO2D. +namespace resocollisiongroup001 +{ +DECLARE_SOA_COLUMN(OriginalCollisionId, originalCollisionId, int); //! Original aod::Collision row number +} // namespace resocollisiongroup001 + +// Optional soft link from a positional ResoMCCollisions_001 row to its source +// generator collision. It is filled only when the source AO2D is retained as +// a linked-derived-data parent. +namespace resomccollision +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(OriginalMcCollision, originalMcCollision, int, McCollisions, "McCollisions", "_MC"); //! +} // namespace resomccollision + +DECLARE_SOA_TABLE(ResoCollisions_000, "AOD", "RESOCOLLISION", o2::soa::Index<>, o2::aod::mult::MultNTracksPV, o2::aod::mult::MultNTracksPVeta1, @@ -104,6 +123,23 @@ DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION", resocollision::Cent, resocollision::BMagField, resocollision::IsRecINELgt0); + +// Version 001 stores one configurable multiplicity estimator instead of three +// fixed PV-track multiplicities. The producer configuration determines which +// reconstructed estimator is persisted in the common float payload. +DECLARE_SOA_TABLE_VERSIONED(ResoCollisions_001, "AOD", "RESOCOLLISION", 1, + o2::soa::Index<>, + resocollision::Multiplicity, + collision::PosX, + collision::PosY, + collision::PosZ, + resocollision::Cent, + resocollision::BMagField, + resocollision::IsRecINELgt0); + +// Keep the established generic collision-table alias on version 000. The +// modular producer and its consumers request version 001 explicitly. +using ResoCollisions = ResoCollisions_000; using ResoCollision = ResoCollisions::iterator; DECLARE_SOA_TABLE(ResoCollisionColls, "AOD", "RESOCOLLISIONCOL", @@ -114,6 +150,12 @@ DECLARE_SOA_TABLE(ResoCollisionGroups, "AOD", "RESOCOLLGROUP", resocollisiongroup::OriginalCollisionId); using ResoCollisionGroup = ResoCollisionGroups::iterator; +// Version 001 replaces the hard relation to the source Collisions table with +// a scalar row number. The legacy version-0 schema remains unchanged. +DECLARE_SOA_TABLE_VERSIONED(ResoCollisionGroups_001, "AOD", "RESOCOLLGROUP", 1, + resocollisiongroup001::OriginalCollisionId); +using ResoCollisionGroup_001 = ResoCollisionGroups_001::iterator; + DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOLLISION", o2::soa::Index<>, resocollision::IsVtxIn10, @@ -125,6 +167,20 @@ DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOLLISION", resocollision::MCMultiplicity); using ResoMCCollision = ResoMCCollisions::iterator; +// Version 001 deliberately persists generator-collision properties only. +// Reconstructed event-selection decisions remain available only in legacy +// version-0 output and must not be mixed into this generator-level payload. +DECLARE_SOA_TABLE_VERSIONED(ResoMCCollisions_001, "AOD", "RESOMCCOLLISION", 1, + o2::soa::Index<>, + resocollision::IsVtxIn10, + resocollision::IsINELgt0, + resocollision::ImpactParameter, + resocollision::MCMultiplicity); + +DECLARE_SOA_TABLE(ResoMCCollisionIds, "AOD", "RESOMCCOLLID", + resomccollision::OriginalMcCollisionId); +using ResoMCCollisionId = ResoMCCollisionIds::iterator; + DECLARE_SOA_TABLE(ResoSpheroCollisions, "AOD", "RESOSPHEROCOLLISION", o2::soa::Index<>, resocollision::Spherocity); @@ -204,6 +260,12 @@ struct ResoTrackFlags { #define DECLARE_DYN_TRKSEL_COLUMN(_Name_, _Getter_, _Mask_) \ DECLARE_SOA_DYNAMIC_COLUMN(_Name_, _Getter_, [](ResoTrackFlags::flagtype flags) -> bool { return ResoTrackFlags::checkFlag(flags, _Mask_); }); +// Keep the default foreign-key target on the legacy ResoCollisions_000 alias. +// Modular v001 consumers use resoCollisionId() as the scalar row reference and +// explicitly call resoCollision_as() only when the parent row must be +// dereferenced, with T equal to the exact bound v001 table type (plain +// aod::ResoCollisions_001 or its analysis Join). The version-equivalence +// declaration below permits binding the same physical index column to v001. DECLARE_SOA_INDEX_COLUMN(ResoCollision, resoCollision); DECLARE_SOA_INDEX_COLUMN(ResoCollisionDF, resoCollisionDF); DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trk"); //! Soft link to the original track @@ -246,7 +308,7 @@ DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex DECLARE_SOA_COLUMN(Alpha, alpha, float); //! Alpha of the decay vertex DECLARE_SOA_COLUMN(QtArm, qtarm, float); //! Armenteros Qt of the decay vertex, o2-linter: disable=name/o2-column (pre-existing public column name kept for schema and API compatibility) -DECLARE_SOA_COLUMN(TpcSignal10, tpcSignal10, int16_t); //! TPC signal of the track x10 +DECLARE_SOA_COLUMN(TpcSignal10, tpcSignal10, int16_t); //! TPC signal of the track x100 (public column name retained for compatibility) DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPi10, daughterTPCNSigmaPosPi10, int8_t); //! TPC PID x10 of the positive daughter as Pion DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosKa10, daughterTPCNSigmaPosKa10, int8_t); //! TPC PID x10 of the positive daughter as Kaon DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPr10, daughterTPCNSigmaPosPr10, int8_t); //! TPC PID x10 of the positive daughter as Proton @@ -340,7 +402,7 @@ DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachKa, daughterTOFNSigmaBachKa, [](int8_t daughterTOFNSigmaBachKa10) { return (float)daughterTOFNSigmaBachKa10 / 10.f; }); DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachPr, daughterTOFNSigmaBachPr, [](int8_t daughterTOFNSigmaBachPr10) { return (float)daughterTOFNSigmaBachPr10 / 10.f; }); -// TPC signal x10 +// TPC signal x100 DECLARE_SOA_DYNAMIC_COLUMN(TpcSignal, tpcSignal, [](int16_t tpcSignal10) { return (float)tpcSignal10 / 100.f; }); // pT, Eta, Phi @@ -554,6 +616,192 @@ struct ResoMicroTrackSelFlag { DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); } // namespace resomicrodaughter +// Version 001 uses signed, lower-inclusive PID bins and keeps the DCAxy/DCAz +// pT-dependent selection results independently from the quantised DCA values. +namespace resomicrodaughter001 +{ +// Keep the original row number as a scalar for standalone pair comparisons. +// The separate typed relation remains available to legacy version-0 users. +DECLARE_SOA_COLUMN(TrackId, trackId, int); //! Original track row number for pair-level comparisons + +/// @brief Compact signed TPC/TOF n-sigma values into two four-bit fields. +/// The upper bit of each field stores the sign. Magnitudes 1..6 represent +/// lower-inclusive 0.25-sigma-wide bins [2.0, 2.25), ..., [3.25, 3.5), while +/// magnitude 0 is |n-sigma| < 2 and magnitude 7 is |n-sigma| >= 3.5. Overflow +/// decodes to signed infinity, while code 8 is reserved for invalid values and +/// decodes to NaN. Missing TOF information is also carried independently by +/// resodaughter::TrackFlags::kHasTOF. +struct PidNSigma { + static constexpr float MinFineNSigma = 2.f; + static constexpr float Step = 0.25f; + static constexpr float MaxNSigma = 3.5f; + static constexpr uint8_t SignMask = 0x08; + static constexpr uint8_t MagnitudeMask = 0x07; + static constexpr uint8_t MaxRegularCode = 6; + static constexpr uint8_t AboveRangeCode = 7; + static constexpr uint8_t InvalidCode = SignMask; + + uint8_t flag; + + PidNSigma(float tpcNSigma, float tofNSigma, bool hasTOF) + { + const uint8_t tpcEncoded = encodeNSigma(tpcNSigma); + const uint8_t tofEncoded = hasTOF ? encodeNSigma(tofNSigma) : InvalidCode; + flag = (tpcEncoded << 4) | tofEncoded; + } + + static uint8_t encodeNSigma(float nSigma) + { + if (!std::isfinite(nSigma)) { + return InvalidCode; + } + const float value = std::abs(nSigma); + if (value < MinFineNSigma) { + return 0; + } + uint8_t magnitude = AboveRangeCode; + if (value < MaxNSigma) { + const int encoded = 1 + static_cast(std::floor((value - MinFineNSigma) / Step)); + magnitude = static_cast(std::clamp(encoded, 1, static_cast(MaxRegularCode))); + } + const uint8_t sign = std::signbit(nSigma) ? SignMask : 0; + return static_cast(sign | magnitude); + } + + static float decodeNSigma(uint8_t encoded) + { + const uint8_t code = encoded & 0x0F; + if (code == InvalidCode) { + return NAN; + } + const uint8_t magnitude = code & MagnitudeMask; + if (magnitude == 0) { + return 0.f; + } + const float value = magnitude == AboveRangeCode + ? std::numeric_limits::infinity() + : MinFineNSigma + static_cast(magnitude - 1) * Step; + return (code & SignMask) != 0 ? -value : value; + } + + static float getTPCNSigma(uint8_t encoded) + { + return decodeNSigma((encoded >> 4) & 0x0F); + } + + static float getTOFNSigma(uint8_t encoded, bool hasTOF) + { + return hasTOF ? decodeNSigma(encoded & 0x0F) : NAN; + } + + operator uint8_t() const { return flag; } +}; + +/// @brief Store two pT-dependent DCA pass bits and two three-bit DCA values. +/// Bits 7 and 6 store the DCAxy and DCAz pass results, respectively. Bits 5..3 +/// and 2..0 store |DCAxy| and |DCAz| in lower-inclusive 0.025 cm bins from 0 +/// to 0.15 cm. Code 6 represents overflow and code 7 an invalid value. +struct DCAEncoding { + static constexpr float MaxDCA = 0.15f; + static constexpr float Step = 0.025f; + static constexpr float InverseStep = 40.f; + static constexpr uint8_t MaxRegularCode = 5; + static constexpr uint8_t AboveRangeCode = 6; + static constexpr uint8_t InvalidCode = 7; + static constexpr uint8_t PassedPtDependentDCAxyMask = 0x80; + static constexpr uint8_t PassedPtDependentDCAzMask = 0x40; + static constexpr uint8_t DCAxyMask = 0x38; + static constexpr uint8_t DCAzMask = 0x07; + static constexpr uint8_t DCAxyShift = 3; + + uint8_t flag = 0; + + DCAEncoding() = default; + DCAEncoding(float dcaXY, float dcaZ, bool passedPtDependentDCAxy, bool passedPtDependentDCAz) + : flag(static_cast((passedPtDependentDCAxy ? PassedPtDependentDCAxyMask : 0) | + (passedPtDependentDCAz ? PassedPtDependentDCAzMask : 0) | + (encodeDCA(dcaXY) << DCAxyShift) | + encodeDCA(dcaZ))) + { + } + + static uint8_t encodeDCA(float dca) + { + const float value = std::abs(dca); + if (!std::isfinite(value)) { + return InvalidCode; + } + if (value >= MaxDCA) { + return AboveRangeCode; + } + const int encoded = static_cast(std::floor(value * InverseStep)); + return static_cast(std::clamp(encoded, 0, static_cast(MaxRegularCode))); + } + + static float decodeDCA(uint8_t encoded) + { + const uint8_t code = encoded & DCAzMask; + if (code == InvalidCode) { + return NAN; + } + return code == AboveRangeCode ? MaxDCA : static_cast(code) * Step; + } + + static float decodeDCAxy(uint8_t encoded) + { + return decodeDCA((encoded & DCAxyMask) >> DCAxyShift); + } + + static float decodeDCAz(uint8_t encoded) + { + return decodeDCA(encoded & DCAzMask); + } + + static bool testPtDependentDCAxy(uint8_t encoded) + { + return (encoded & PassedPtDependentDCAxyMask) != 0; + } + + static bool testPtDependentDCAz(uint8_t encoded) + { + return (encoded & PassedPtDependentDCAzMask) != 0; + } + + operator uint8_t() const { return flag; } +}; + +DECLARE_SOA_COLUMN(TrackSelectionFlags, trackSelectionFlags, uint8_t); //! Packed DCA selection and absolute DCAxy/DCAz values +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaPi, tpcNSigmaPi, + [](uint8_t pidNSigmaPiFlag) { return PidNSigma::getTPCNSigma(pidNSigmaPiFlag); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaKa, tpcNSigmaKa, + [](uint8_t pidNSigmaKaFlag) { return PidNSigma::getTPCNSigma(pidNSigmaKaFlag); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaPr, tpcNSigmaPr, + [](uint8_t pidNSigmaPrFlag) { return PidNSigma::getTPCNSigma(pidNSigmaPrFlag); }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaPi, tofNSigmaPi, + [](uint8_t pidNSigmaPiFlag, uint8_t trackFlags) -> float { + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); + return PidNSigma::getTOFNSigma(pidNSigmaPiFlag, hasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaKa, tofNSigmaKa, + [](uint8_t pidNSigmaKaFlag, uint8_t trackFlags) -> float { + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); + return PidNSigma::getTOFNSigma(pidNSigmaKaFlag, hasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaPr, tofNSigmaPr, + [](uint8_t pidNSigmaPrFlag, uint8_t trackFlags) -> float { + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); + return PidNSigma::getTOFNSigma(pidNSigmaPrFlag, hasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(DcaXY, dcaXY, + [](uint8_t trackSelectionFlags) { return DCAEncoding::decodeDCAxy(trackSelectionFlags); }); +DECLARE_SOA_DYNAMIC_COLUMN(DcaZ, dcaZ, + [](uint8_t trackSelectionFlags) { return DCAEncoding::decodeDCAz(trackSelectionFlags); }); +DECLARE_SOA_DYNAMIC_COLUMN(PassedPtDependentDCAxy, passedPtDependentDCAxy, + [](uint8_t trackSelectionFlags) { return DCAEncoding::testPtDependentDCAxy(trackSelectionFlags); }); +DECLARE_SOA_DYNAMIC_COLUMN(PassedPtDependentDCAz, passedPtDependentDCAz, + [](uint8_t trackSelectionFlags) { return DCAEncoding::testPtDependentDCAz(trackSelectionFlags); }); +} // namespace resomicrodaughter001 + // Ultra-micro track representation. The momentum components are quantised // to 1 MeV/c and only one (pion/kaon/proton) PID flag is retained. namespace resoultramicrodaughter @@ -786,6 +1034,45 @@ DECLARE_SOA_TABLE(ResoMicroTracks, "AOD", "RESOMICROTRACK", resodaughter::Sign); using ResoMicroTrack = ResoMicroTracks::iterator; +// Keep ResoMicroTracks as the version-0 API for existing producers and +// consumers. Version-1 users must request ResoMicroTracks_001 explicitly. +DECLARE_SOA_TABLE_VERSIONED(ResoMicroTracks_001, "AOD", "RESOMICROTRACK", 1, + o2::soa::Index<>, + resodaughter::ResoCollisionId, + resomicrodaughter001::TrackId, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + resomicrodaughter::PidNSigmaPiFlag, + resomicrodaughter::PidNSigmaKaFlag, + resomicrodaughter::PidNSigmaPrFlag, + resomicrodaughter001::TrackSelectionFlags, + resodaughter::TrackFlags, + // Dynamic columns + resomicrodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resomicrodaughter001::TpcNSigmaPi, + resomicrodaughter001::TpcNSigmaKa, + resomicrodaughter001::TpcNSigmaPr, + resomicrodaughter001::TofNSigmaPi, + resomicrodaughter001::TofNSigmaKa, + resomicrodaughter001::TofNSigmaPr, + resomicrodaughter001::DcaXY, + resomicrodaughter001::DcaZ, + resomicrodaughter001::PassedPtDependentDCAxy, + resomicrodaughter001::PassedPtDependentDCAz, + resodaughter::PassedITSRefit, + resodaughter::PassedTPCRefit, + resodaughter::IsGlobalTrackWoDCA, + resodaughter::IsGlobalTrack, + resodaughter::IsPrimaryTrack, + resodaughter::IsPVContributor, + resodaughter::HasTOF, + resodaughter::Sign); +// Positional soft-link side table retained for ResoMicroTracks version 000. +// Version 001 stores the same row number as a scalar and should be consumed +// without joining this side table, since both columns expose trackId(). DECLARE_SOA_TABLE(ResoMicroTrackTracks, "AOD", "RESOMICROTRACKTRACK", resodaughter::TrackId); using ResoMicroTrackTrack = ResoMicroTrackTracks::iterator; @@ -1074,6 +1361,17 @@ DECLARE_SOA_TABLE(ResoMCTracks, "AOD", "RESOMCTRACK", resodaughter::ProducedByGenerator); using ResoMCTrack = ResoMCTracks::iterator; +// Positional MC extension for ResoMicroTracks_001. One row must be written for +// every ResoMicroTracks_001 row, including tracks without an MC particle label. +DECLARE_SOA_TABLE_VERSIONED(ResoMCMicroTracks_001, "AOD", "RESOMCMICROTRACK", 1, + mcparticle::PdgCode, + resodaughter::MotherId, + resodaughter::MotherPDG, + resodaughter::SiblingIds, + resodaughter::IsPhysicalPrimary, + resodaughter::ProducedByGenerator); +using ResoMCMicroTrack = ResoMCMicroTracks_001::iterator; + DECLARE_SOA_TABLE(ResoMCV0s, "AOD", "RESOMCV0", mcparticle::PdgCode, resodaughter::MotherId, @@ -1123,6 +1421,34 @@ DECLARE_SOA_TABLE(ResoMCParents, "AOD", "RESOMCPARENT", resodaughter::Phi); using ResoMCParent = ResoMCParents::iterator; +// Module-specific parent rows keep the source MC-particle row number as a +// scalar. This avoids a hard relation to McParticles in standalone derived +// AO2D while preserving the legacy ResoMCParents schema and typed API. +namespace resomcparent001 +{ +DECLARE_SOA_COLUMN(OriginalMcParticleId, originalMcParticleId, int); //! Original aod::McParticle row number +} // namespace resomcparent001 + +DECLARE_SOA_TABLE_VERSIONED(ResoMCParents_001, "AOD", "RESOMCPARENT", 1, + o2::soa::Index<>, + resodaughter::ResoCollisionId, + resomcparent001::OriginalMcParticleId, + mcparticle::PdgCode, + resodaughter::DaughterPDG1, + resodaughter::DaughterPDG2, + resodaughter::IsPhysicalPrimary, + resodaughter::ProducedByGenerator, + resodaughter::Pt, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + mcparticle::Y, + mcparticle::E, + mcparticle::StatusCode, + resodaughter::Eta, + resodaughter::Phi); +using ResoMCParent_001 = ResoMCParents_001::iterator; + using Reso2TracksExt = soa::Join; // without Extra using Reso2TracksMC = soa::Join; using Reso2TracksPID = soa::Join; @@ -1141,4 +1467,11 @@ using ResoCascadesCandidatesMC = soa::Join; } // namespace o2::aod + +namespace o2::soa +{ +// Preserve the legacy v000 default target while allowing an explicitly typed +// resoCollision_as() binding to the exact v001 parent in modular analyses. +DECLARE_EQUIVALENT_FOR_INDEX(aod::ResoCollisions_000, aod::ResoCollisions_001); +} // namespace o2::soa #endif // PWGLF_DATAMODEL_LFRESONANCETABLES_H_ diff --git a/PWGLF/DataModel/LFStrangenessPIDTables.h b/PWGLF/DataModel/LFStrangenessPIDTables.h index 067966859ed..848f2a3289f 100644 --- a/PWGLF/DataModel/LFStrangenessPIDTables.h +++ b/PWGLF/DataModel/LFStrangenessPIDTables.h @@ -414,25 +414,33 @@ DECLARE_SOA_COLUMN(TOFNSigmaOmLaPr, tofNSigmaOmLaPr, float); //! baryon track NS DECLARE_SOA_COLUMN(TOFNSigmaOmKa, tofNSigmaOmKa, float); //! bachelor track NSigma from kaon <- om expectation // for wrong hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromLambdaFromXi, tofNSigmaElFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under electron hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromXi, tofNSigmaElFromXi, float); //! nigma of bachelor track from Xi under electron hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromLambdaFromOmega, tofNSigmaElFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under electron hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromOmega, tofNSigmaElFromOmega, float); //! nigma of bachelor track from Omega under electron hypothesis - -DECLARE_SOA_COLUMN(TOFNSigmaPiFromLambdaFromXi, tofNSigmaPiFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under pion hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPiFromXi, tofNSigmaPiFromXi, float); //! nigma of bachelor track from Xi under pion hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPiFromLambdaFromOmega, tofNSigmaPiFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under pion hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPiFromOmega, tofNSigmaPiFromOmega, float); //! nigma of bachelor track from Omega under pion hypothesis - -DECLARE_SOA_COLUMN(TOFNSigmaKaFromLambdaFromXi, tofNSigmaKaFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under kaon hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaKaFromXi, tofNSigmaKaFromXi, float); //! nigma of bachelor track from Xi under kaon hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaKaFromLambdaFromOmega, tofNSigmaKaFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under kaon hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaKaFromOmega, tofNSigmaKaFromOmega, float); //! nigma of bachelor track from Omega under kaon hypothesis - -DECLARE_SOA_COLUMN(TOFNSigmaPrFromLambdaFromXi, tofNSigmaPrFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under proton hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPrFromXi, tofNSigmaPrFromXi, float); //! nigma of bachelor track from Xi under proton hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPrFromLambdaFromOmega, tofNSigmaPrFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under proton hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPrFromOmega, tofNSigmaPrFromOmega, float); //! nigma of bachelor track from Omega under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElPosFromLambdaFromXi, tofNSigmaElPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElNegFromLambdaFromXi, tofNSigmaElNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElFromXi, tofNSigmaElFromXi, float); //! nigma of bachelor track from Xi under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElPosFromLambdaFromOmega, tofNSigmaElPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElNegFromLambdaFromOmega, tofNSigmaElNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElFromOmega, tofNSigmaElFromOmega, float); //! nigma of bachelor track from Omega under electron hypothesis + +DECLARE_SOA_COLUMN(TOFNSigmaPiPosFromLambdaFromXi, tofNSigmaPiPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiNegFromLambdaFromXi, tofNSigmaPiNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiFromXi, tofNSigmaPiFromXi, float); //! nigma of bachelor track from Xi under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiPosFromLambdaFromOmega, tofNSigmaPiPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiNegFromLambdaFromOmega, tofNSigmaPiNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiFromOmega, tofNSigmaPiFromOmega, float); //! nigma of bachelor track from Omega under pion hypothesis + +DECLARE_SOA_COLUMN(TOFNSigmaKaPosFromLambdaFromXi, tofNSigmaKaPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaNegFromLambdaFromXi, tofNSigmaKaNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaFromXi, tofNSigmaKaFromXi, float); //! nigma of bachelor track from Xi under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaPosFromLambdaFromOmega, tofNSigmaKaPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaNegFromLambdaFromOmega, tofNSigmaKaNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaFromOmega, tofNSigmaKaFromOmega, float); //! nigma of bachelor track from Omega under kaon hypothesis + +DECLARE_SOA_COLUMN(TOFNSigmaPrPosFromLambdaFromXi, tofNSigmaPrPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrNegFromLambdaFromXi, tofNSigmaPrNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrFromXi, tofNSigmaPrFromXi, float); //! nigma of bachelor track from Xi under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrPosFromLambdaFromOmega, tofNSigmaPrPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrNegFromLambdaFromOmega, tofNSigmaPrNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrFromOmega, tofNSigmaPrFromOmega, float); //! nigma of bachelor track from Omega under proton hypothesis // dynamics to replace hasTOF (note: that condition does not match track hasTOF!) // note: only single hypothesis check necessary; other hypotheses will always be valid @@ -518,10 +526,14 @@ DECLARE_SOA_TABLE(CascTOFNSigmas, "AOD", "CascTOFNSigmas", // Nsigmas for cascad cascdata::TofXiCompatibility, cascdata::TofOmegaCompatibility); DECLARE_SOA_TABLE(CascTOFNSigmasAll, "AOD", "CascTOFNSigmasAll", // Nsigmas for cascades including wrong hypothesis - cascdata::TOFNSigmaElFromLambdaFromXi, cascdata::TOFNSigmaElFromXi, cascdata::TOFNSigmaElFromLambdaFromOmega, cascdata::TOFNSigmaElFromOmega, - cascdata::TOFNSigmaPiFromLambdaFromXi, cascdata::TOFNSigmaPiFromXi, cascdata::TOFNSigmaPiFromLambdaFromOmega, cascdata::TOFNSigmaPiFromOmega, - cascdata::TOFNSigmaKaFromLambdaFromXi, cascdata::TOFNSigmaKaFromXi, cascdata::TOFNSigmaKaFromLambdaFromOmega, cascdata::TOFNSigmaKaFromOmega, - cascdata::TOFNSigmaPrFromLambdaFromXi, cascdata::TOFNSigmaPrFromXi, cascdata::TOFNSigmaPrFromLambdaFromOmega, cascdata::TOFNSigmaPrFromOmega); + cascdata::TOFNSigmaElPosFromLambdaFromXi, cascdata::TOFNSigmaElNegFromLambdaFromXi, cascdata::TOFNSigmaElFromXi, + cascdata::TOFNSigmaElPosFromLambdaFromOmega, cascdata::TOFNSigmaElNegFromLambdaFromOmega, cascdata::TOFNSigmaElFromOmega, + cascdata::TOFNSigmaPiPosFromLambdaFromXi, cascdata::TOFNSigmaPiNegFromLambdaFromXi, cascdata::TOFNSigmaPiFromXi, + cascdata::TOFNSigmaPiPosFromLambdaFromOmega, cascdata::TOFNSigmaPiNegFromLambdaFromOmega, cascdata::TOFNSigmaPiFromOmega, + cascdata::TOFNSigmaKaPosFromLambdaFromXi, cascdata::TOFNSigmaKaNegFromLambdaFromXi, cascdata::TOFNSigmaKaFromXi, + cascdata::TOFNSigmaKaPosFromLambdaFromOmega, cascdata::TOFNSigmaKaNegFromLambdaFromOmega, cascdata::TOFNSigmaKaFromOmega, + cascdata::TOFNSigmaPrPosFromLambdaFromXi, cascdata::TOFNSigmaPrNegFromLambdaFromXi, cascdata::TOFNSigmaPrFromXi, + cascdata::TOFNSigmaPrPosFromLambdaFromOmega, cascdata::TOFNSigmaPrNegFromLambdaFromOmega, cascdata::TOFNSigmaPrFromOmega); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSTRANGENESSPIDTABLES_H_ diff --git a/PWGLF/DataModel/cascqaanalysis.h b/PWGLF/DataModel/cascqaanalysis.h index 3442c074305..eca673c683d 100644 --- a/PWGLF/DataModel/cascqaanalysis.h +++ b/PWGLF/DataModel/cascqaanalysis.h @@ -118,6 +118,7 @@ DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(Phi, phi, float); DECLARE_SOA_COLUMN(MassLambda, masslambda, float); +DECLARE_SOA_COLUMN(CtauLambda, ctaulambda, float); DECLARE_SOA_COLUMN(MassXi, massxi, float); DECLARE_SOA_COLUMN(MassOmega, massomega, float); DECLARE_SOA_COLUMN(V2CEP, v2CEP, float); @@ -182,7 +183,7 @@ DECLARE_SOA_TABLE(CascAnalysisFull, "AOD", "CascAnalysisFull", o2::soa::Index<>, cascadesflow::CosThetaStarLambdaFromOmega, cascadesflow::CosThetaStarLambdaFromXi, cascadesflow::CosThetaStarProton, mycascades::McPdgCode); DECLARE_SOA_TABLE(LambdaAnalysis, "AOD", "LambdaAnalysis", o2::soa::Index<>, - cascadesflow::CentFT0C, cascadesflow::HasEventPlane, cascadesflow::HasSpectatorPlane, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Phi, cascadesflow::Eta, cascadesflow::MassLambda, cascadesflow::V0Radius, cascadesflow::DcaPosToPV, cascadesflow::DcaNegToPV, cascadesflow::V0CosPA, cascadesflow::DcaV0Daughters, cascadesflow::V2CEP, cascadesflow::PsiT0C, cascadesflow::Pzs2Lambda, cascadesflow::Cos2ThetaLambda, cascadesflow::CosThetaLambda); + cascadesflow::CentFT0C, cascadesflow::HasEventPlane, cascadesflow::HasSpectatorPlane, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Phi, cascadesflow::Eta, cascadesflow::MassLambda, cascadesflow::CtauLambda, cascadesflow::V0Radius, cascadesflow::DcaPosToPV, cascadesflow::DcaNegToPV, cascadesflow::V0CosPA, cascadesflow::DcaV0Daughters, cascadesflow::V2CEP, cascadesflow::PsiT0C, cascadesflow::Pzs2Lambda, cascadesflow::Cos2ThetaLambda, cascadesflow::CosThetaLambda); namespace myMCcascades { diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index b5dc7ca67f2..954f6fc2630 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -79,6 +80,9 @@ using EventCandidatesMC = soa::Join betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; static const std::vector particleName{"He3"}; std::shared_ptr hEvents; @@ -139,8 +143,8 @@ struct hyperCandidate { float genEta() const { return std::asinh(gMom[2] / genPt()); } int v0ID = -1; - int heTrackID; - int piTrackID; + int heTrackID = -1; + int piTrackID = -1; float dcaV0dau = -10; float cosPA = -10; float nSigmaHe3 = -10; @@ -148,12 +152,12 @@ struct hyperCandidate { float piDCAXY = -10; float momHe3TPC = -10.f; float momPiTPC = -10.f; - std::array momHe3; - std::array momPi; - std::array decVtx; - std::array gMom; - std::array gMomHe3; - std::array gDecVtx; + std::array momHe3{}; + std::array momPi{}; + std::array decVtx{}; + std::array gMom{}; + std::array gMomHe3{}; + std::array gDecVtx{}; uint16_t tpcSignalHe3 = 0u; uint16_t tpcSignalPi = 0u; float tpcChi2He3 = 0.f; @@ -183,7 +187,7 @@ struct hyperCandidate { uint8_t flags = 0u; // flags for dughter particles }; -struct hyperRecoTask { +struct HyperRecoTask { Produces outputDataTable; Produces outputDataTableWithFlow; @@ -194,19 +198,19 @@ struct hyperRecoTask { OutputObj zorroSummary{"zorroSummary"}; // PDG codes - Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; - Configurable heDauPdg{"heDauPDG", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; + Configurable hyperPdg{"hyperPdg", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; + Configurable heDauPdg{"heDauPdg", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; Configurable piDauPdg{"piDauPdg", 211, "PDG code of pion"}; // Selection criteria - Configurable v0cospacut{"hypcospa", 0.95, "V0 CosPA"}; - Configurable masswidth{"hypmasswidth", 0.06, "Mass width (GeV/c^2)"}; - Configurable dcaToPvPion{"dcapvPi", 0., "DCA to PV pion"}; - Configurable dcaToPvHe{"dcapvHe", 0., "DCA to PV helium"}; - Configurable dcav0dau{"hypdcaDau", 1.0, "DCA V0 Daughters"}; + Configurable v0CosPaCut{"v0CosPaCut", 0.95, "V0 CosPA"}; + Configurable massWidth{"massWidth", 0.06, "Mass width (GeV/c^2)"}; + Configurable dcaToPvPion{"dcaToPvPion", 0., "DCA to PV pion"}; + Configurable dcaToPvHe{"dcaToPvHe", 0., "DCA to PV helium"}; + Configurable dcaV0Dau{"dcaV0Dau", 1.0, "DCA V0 Daughters"}; Configurable ptMin{"ptMin", 0.5, "Minimum pT of the hypercandidate"}; - Configurable TPCRigidityMinHe{"TPCRigidityMinHe", 0.2, "Minimum rigidity of the helium candidate"}; - Configurable etaMax{"eta", 1., "eta daughter"}; + Configurable tpcRigidityMinHe{"tpcRigidityMinHe", 0.2, "Minimum rigidity of the helium candidate"}; + Configurable etaMax{"etaMax", 1., "eta daughter"}; Configurable nSigmaMaxHe{"nSigmaMaxHe", 5, "helium dEdx cut (n sigma)"}; Configurable nTPCClusMinHe{"nTPCClusMinHe", 70, "helium NTPC clusters cut"}; Configurable nTPCClusMinPi{"nTPCClusMinPi", -1., "pion NTPC clusters cut"}; @@ -237,8 +241,8 @@ struct hyperRecoTask { Configurable cfgEvSelkIsGoodZvtxFT0vsPV{"cfgEvSelkIsGoodZvtxFT0vsPV", false, "Verifies the consistency between the primary vertex z position from tracking and the z position of the PV from FT0 timing"}; // CCDB options - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable dBzInput{"dBzInput", -999, "bz field, -999 is automatic"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; @@ -273,9 +277,9 @@ struct hyperRecoTask { HistogramRegistry qaRegistry{"QA", {}, OutputObjHandlingPolicy::AnalysisObject}; - int mRunNumber; - float d_bz; - std::array mBBparamsHe; + int mRunNumber = -1; + float d_bz = 0.f; + std::array mBBparamsHe{}; void init(InitContext const&) { @@ -284,7 +288,7 @@ struct hyperRecoTask { mRunNumber = 0; d_bz = 0; - ccdb->setURL(ccdburl); + ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); @@ -408,12 +412,12 @@ struct hyperRecoTask { o2::parameters::GRPMagField* grpmag = 0x0; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); - if (d_bz_input < -990) { + if (dBzInput < UseCCDBMagneticFieldThreshold) { // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } else { - d_bz = d_bz_input; + d_bz = dBzInput; } } else { grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); @@ -421,22 +425,22 @@ struct hyperRecoTask { LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); - if (d_bz_input < -990) { + if (dBzInput < UseCCDBMagneticFieldThreshold) { // Fetch magnetic field from ccdb for current collision d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } else { - d_bz = d_bz_input; + d_bz = dBzInput; } } if (!pidPath.value.empty()) { auto he3pid = ccdb->getForTimeStamp>(pidPath.value + "_He3", run3grp_timestamp); std::copy(he3pid->begin(), he3pid->end(), mBBparamsHe.begin()); } else { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < NumBetheBlochParameters; i++) { mBBparamsHe[i] = cfgBetheBlochParams->get("He3", Form("p%i", i)); } - mBBparamsHe[5] = cfgBetheBlochParams->get("He3", "resolution"); + mBBparamsHe[NumBetheBlochParameters] = cfgBetheBlochParams->get("He3", "resolution"); } fitter.setBz(d_bz); mRunNumber = bc.runNumber(); @@ -479,7 +483,7 @@ struct hyperRecoTask { hEvents->Fill(1.); - if (std::abs(collision.posZ()) > 10) { + if (std::abs(collision.posZ()) > MaxAbsVertexZ) { continue; } hEvents->Fill(2.); @@ -524,7 +528,7 @@ struct hyperRecoTask { hEvents->Fill(1.); - if (std::abs(collision.posZ()) > 10) { + if (std::abs(collision.posZ()) > MaxAbsVertexZ) { continue; } hEvents->Fill(2.); @@ -573,7 +577,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSPi = piTrack.itsClusterSizes(); bool heliumPID = heTrack.pidForTracking() == o2::track::PID::Helium3 || heTrack.pidForTracking() == o2::track::PID::Alpha; hypCand.momHe3TPC = (heliumPID && cfgCompensatePIDinTracking) ? heTrack.tpcInnerParam() / 2 : heTrack.tpcInnerParam(); - if (hypCand.momHe3TPC < TPCRigidityMinHe) + if (hypCand.momHe3TPC < tpcRigidityMinHe) return; hypCand.momPiTPC = piTrack.tpcInnerParam(); hDeDxTot->Fill(hypCand.momHe3TPC * heTrack.sign(), heTrack.tpcSignal()); @@ -599,7 +603,7 @@ struct hyperRecoTask { hePropTrack.getPxPyPzGlo(hypCand.momHe3); piPropTrack.getPxPyPzGlo(hypCand.momPi); // the momentum has to be multiplied by 2 (charge) - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.momHe3.size(); i++) { hypCand.momHe3[i] *= 2; } float heP2 = hypCand.momHe3[0] * hypCand.momHe3[0] + hypCand.momHe3[1] * hypCand.momHe3[1] + hypCand.momHe3[2] * hypCand.momHe3[2]; @@ -609,9 +613,9 @@ struct hyperRecoTask { float piE = std::sqrt(piP2 + piMass * piMass); float h3lE = he3E + piE; float h4lE = he4E + piE; - std::array hypMom; + std::array hypMom{}; const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.decVtx.size(); i++) { hypCand.decVtx[i] = vtx[i]; hypMom[i] = hypCand.momHe3[i] + hypCand.momPi[i]; } @@ -621,9 +625,9 @@ struct hyperRecoTask { float massH3L = std::sqrt(h3lE * h3lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); float massH4L = std::sqrt(h4lE * h4lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); bool isHypMass = false; - if (massH3L > o2::constants::physics::MassHyperTriton - masswidth && massH3L < o2::constants::physics::MassHyperTriton + masswidth) + if (massH3L > o2::constants::physics::MassHyperTriton - massWidth && massH3L < o2::constants::physics::MassHyperTriton + massWidth) isHypMass = true; - if (massH4L > o2::constants::physics::MassHyperhydrog4 - masswidth && massH4L < o2::constants::physics::MassHyperhydrog4 + masswidth) + if (massH4L > o2::constants::physics::MassHyperhydrog4 - massWidth && massH4L < o2::constants::physics::MassHyperhydrog4 + massWidth) isHypMass = true; if (!isHypMass) return; @@ -636,7 +640,7 @@ struct hyperRecoTask { } hypCand.dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); - if (hypCand.dcaV0dau > dcav0dau) { + if (hypCand.dcaV0dau > dcaV0Dau) { return; } @@ -658,13 +662,13 @@ struct hyperRecoTask { return; } - if (cosPAmax < v0cospacut) { + if (cosPAmax < v0CosPaCut) { return; } auto collision = collisions.rawIteratorAt(collIDmax); std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.decVtx.size(); i++) { hypCand.decVtx[i] = hypCand.decVtx[i] - primVtx[i]; } @@ -783,7 +787,7 @@ struct hyperRecoTask { } void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) { - for (auto& hypCand : hyperCandidates) { + for (auto& hypCand : hyperCandidates) { // o2-linter: disable=const-ref-in-for-loop (candidate is enriched with MC information in this loop) auto mcLabHe = trackLabels.rawIteratorAt(hypCand.heTrackID); auto mcLabPi = trackLabels.rawIteratorAt(hypCand.piTrackID); @@ -804,13 +808,13 @@ struct hyperRecoTask { auto secVtx = std::array{mcTrackHe.vx(), mcTrackHe.vy(), mcTrackHe.vz()}; hypCand.gMom = std::array{heMother.px(), heMother.py(), heMother.pz()}; hypCand.gMomHe3 = std::array{mcTrackHe.px(), mcTrackHe.py(), mcTrackHe.pz()}; - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.gDecVtx.size(); i++) { hypCand.gDecVtx[i] = secVtx[i] - primVtx[i]; } hypCand.isSignal = true; hypCand.isFakeHeOnITSLayer = mcLabHe.mcMask() & 0x7F; // check if any of the first 7 bits is set hypCand.pdgCode = heMother.pdgCode(); - hypCand.isRecoMCCollision = recoCollisionIds[heMother.mcCollisionId()] > 0; + hypCand.isRecoMCCollision = recoCollisionIds[heMother.mcCollisionId()] >= 0; hypCand.isSurvEvSelection = isSurvEvSelCollision[heMother.mcCollisionId()]; filledMothers.push_back(heMother.globalIndex()); } @@ -829,7 +833,7 @@ struct hyperRecoTask { } processData(collisions, V0s, tracks, ambiTracks, bcs); } - PROCESS_SWITCH(hyperRecoTask, processDataTracked, "Data analysis wit tracked V0s information", false); + PROCESS_SWITCH(HyperRecoTask, processDataTracked, "Data analysis wit tracked V0s information", false); void processData(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { @@ -844,6 +848,7 @@ struct hyperRecoTask { auto collision = collisions.rawIteratorAt(hypCand.collisionID); float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), @@ -858,7 +863,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } - PROCESS_SWITCH(hyperRecoTask, processData, "Data analysis", true); + PROCESS_SWITCH(HyperRecoTask, processData, "Data analysis", true); void processDataWithFlow(CollisionsFullWithFlow const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { @@ -877,6 +882,7 @@ struct hyperRecoTask { } float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTableWithFlow(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.psiFT0A(), collision.multFT0A(), collision.psiFT0C(), collision.multFT0C(), collision.qFT0C(), collision.psiTPC(), collision.multTPC(), @@ -894,7 +900,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } - PROCESS_SWITCH(hyperRecoTask, processDataWithFlow, "Data analysis with flow", false); + PROCESS_SWITCH(HyperRecoTask, processDataWithFlow, "Data analysis with flow", false); void processDataWithCollID(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { @@ -909,6 +915,7 @@ struct hyperRecoTask { auto collision = collisions.rawIteratorAt(hypCand.collisionID); float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTableWithCollID(hypCand.collisionID, collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), @@ -923,7 +930,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } - PROCESS_SWITCH(hyperRecoTask, processDataWithCollID, "Data analysis with collision ID", false); + PROCESS_SWITCH(HyperRecoTask, processDataWithCollID, "Data analysis with collision ID", false); void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { @@ -946,6 +953,7 @@ struct hyperRecoTask { int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), @@ -1004,10 +1012,10 @@ struct hyperRecoTask { } hyperCandidate hypCand; hypCand.pdgCode = mcPart.pdgCode(); - hypCand.isRecoMCCollision = recoCollisionIds[mcPart.mcCollisionId()] > 0; + hypCand.isRecoMCCollision = recoCollisionIds[mcPart.mcCollisionId()] >= 0; hypCand.isSurvEvSelection = isSurvEvSelCollision[mcPart.mcCollisionId()]; int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.gDecVtx.size(); i++) { hypCand.gDecVtx[i] = (isHeFound ? secVtx[i] : lastDaugVtx[i]) - primVtx[i]; hypCand.gMom[i] = momMother[i]; hypCand.gMomHe3[i] = momHe3[i]; @@ -1017,15 +1025,20 @@ struct hyperRecoTask { hypCand.isSignal = true; float centFT0A = -1, centFT0C = -1, centFT0M = -1; + int trackOccupancyInTimeRange = -1; + float ft0cOccupancyInTimeRange = -1.f; if (hypCand.isRecoMCCollision) { auto recoCollision = collisions.rawIteratorAt(recoCollisionIds[mcPart.mcCollisionId()]); centFT0A = recoCollision.centFT0A(); centFT0C = recoCollision.centFT0C(); centFT0M = recoCollision.centFT0M(); + trackOccupancyInTimeRange = recoCollision.trackOccupancyInTimeRange(); + ft0cOccupancyInTimeRange = recoCollision.ft0cOccupancyInTimeRange(); } outputMCTable(centFT0A, centFT0C, centFT0M, - -1, -1, -1, + trackOccupancyInTimeRange, ft0cOccupancyInTimeRange, + primVtx[0], primVtx[1], primVtx[2], mRunNumber, 0, -1, -1, -1, -1, -1, -1, @@ -1039,7 +1052,7 @@ struct hyperRecoTask { hypCand.isReco, -1, hypCand.isSignal, hypCand.isRecoMCCollision, hypCand.isSurvEvSelection, isHeFound, mcProcess); } } - PROCESS_SWITCH(hyperRecoTask, processMC, "MC analysis", false); + PROCESS_SWITCH(HyperRecoTask, processMC, "MC analysis", false); void processMCTracked(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, aod::TrackedV0s const& tV0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { @@ -1050,7 +1063,7 @@ struct hyperRecoTask { } processMC(collisions, mcCollisions, V0s, tracks, ambiTracks, bcs, trackLabelsMC, particlesMC); } - PROCESS_SWITCH(hyperRecoTask, processMCTracked, "MC analysis with tracked V0s", false); + PROCESS_SWITCH(HyperRecoTask, processMCTracked, "MC analysis with tracked V0s", false); template bool passEvtSel(const CollType& collision) @@ -1058,7 +1071,7 @@ struct hyperRecoTask { if (!collision.sel8()) return false; - if ((std::abs(collision.posZ())) > 10) + if ((std::abs(collision.posZ())) > MaxAbsVertexZ) return false; if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) @@ -1072,7 +1085,7 @@ struct hyperRecoTask { void processEventLossMC(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& GenParticles) { - if (std::abs(mcCollision.posZ()) > 10) { + if (std::abs(mcCollision.posZ()) > MaxAbsVertexZ) { return; } @@ -1175,12 +1188,12 @@ struct hyperRecoTask { } } } - PROCESS_SWITCH(hyperRecoTask, processEventLossMC, "Event loss analysis", false); + PROCESS_SWITCH(HyperRecoTask, processEventLossMC, "Event loss analysis", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx index 1fddbb346fa..da2ca3ee1ee 100644 --- a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx @@ -582,9 +582,9 @@ struct TrackedHypertritonRecoTask { std::array xyzpxpypz{}; trackHeliumCov.getPxPyPzGlo(pxpypz); trackHeliumCov.getXYZGlo(xyz); - for (int i = 0; i < 3; ++i) { + for (std::size_t i = 0; i < xyz.size(); ++i) { xyzpxpypz[i] = xyz[i]; - xyzpxpypz[i + 3] = pxpypz[i] * 2; + xyzpxpypz[i + xyz.size()] = pxpypz[i] * 2; } std::array cv{}; trackHeliumCov.getCovXYZPxPyPzGlo(cv); @@ -690,7 +690,7 @@ struct TrackedHypertritonRecoTask { // get SV position const auto& secondaryVertex = fitter2Body.getPCACandidate(); - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < v0.decayVertex.size(); i++) { v0.decayVertex[i] = secondaryVertex[i]; } v0.chi2 = std::sqrt(fitter2Body.getChi2AtPCACandidate()); @@ -744,6 +744,7 @@ struct TrackedHypertritonRecoTask { flags |= static_cast(piTrack.pidForTracking() & 0xf); fillCandidate(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), runNumber, heTrack.sign() > 0, std::hypot(v0.momHelium[0], v0.momHelium[1]), std::atan2(v0.momHelium[1], v0.momHelium[0]), RecoDecay::eta(v0.momHelium), @@ -910,13 +911,13 @@ struct TrackedHypertritonRecoTask { selectCollisions(collisions, skimmedProcessing); for (const auto& trackedV0 : trackedV0s) { - const auto v0 = trackedV0.v0_as(); - if (v0.collisionId() < 0 || !goodCollision[v0.collisionId()] || (skimmedProcessing && !zorroDecision[v0.collisionId()][kHe])) { + const auto inputV0 = trackedV0.v0_as(); + if (inputV0.collisionId() < 0 || !goodCollision[inputV0.collisionId()] || (skimmedProcessing && !zorroDecision[inputV0.collisionId()][kHe])) { continue; } - const auto collision = v0.collision_as(); - const auto positiveTrack = v0.posTrack_as(); - const auto negativeTrack = v0.negTrack_as(); + const auto collision = inputV0.collision_as(); + const auto positiveTrack = inputV0.posTrack_as(); + const auto negativeTrack = inputV0.negTrack_as(); const float nSigmaPositive = nSigmaHe3(positiveTrack); const float nSigmaNegative = nSigmaHe3(negativeTrack); const bool positiveTrackedAsHe = positiveTrack.pidForTracking() == o2::track::PID::Helium3 || positiveTrack.pidForTracking() == o2::track::PID::Alpha; @@ -992,13 +993,13 @@ struct TrackedHypertritonRecoTask { std::vector reconstructedThreeBody(mcParticles.size(), false); for (const auto& trackedV0 : trackedV0s) { - const auto v0 = trackedV0.v0_as(); - if (v0.collisionId() < 0 || !goodCollision[v0.collisionId()]) { + const auto inputV0 = trackedV0.v0_as(); + if (inputV0.collisionId() < 0 || !goodCollision[inputV0.collisionId()]) { continue; } - const auto collision = v0.collision_as(); - const auto positiveTrack = v0.posTrack_as(); - const auto negativeTrack = v0.negTrack_as(); + const auto collision = inputV0.collision_as(); + const auto positiveTrack = inputV0.posTrack_as(); + const auto negativeTrack = inputV0.negTrack_as(); const float nSigmaPositive = nSigmaHe3(positiveTrack); const float nSigmaNegative = nSigmaHe3(negativeTrack); const bool positiveTrackedAsHe = positiveTrack.pidForTracking() == o2::track::PID::Helium3 || positiveTrack.pidForTracking() == o2::track::PID::Alpha; @@ -1137,6 +1138,8 @@ struct TrackedHypertritonRecoTask { float centralityFT0A = -1.f; float centralityFT0C = -1.f; float centralityFT0M = -1.f; + int trackOccupancyInTimeRange = -1; + float ft0cOccupancyInTimeRange = -1.f; float primaryVertexX = -1.f; float primaryVertexY = -1.f; float primaryVertexZ = -1.f; @@ -1151,12 +1154,15 @@ struct TrackedHypertritonRecoTask { centralityFT0A = collision.centFT0A(); centralityFT0C = collision.centFT0C(); centralityFT0M = collision.centFT0M(); + trackOccupancyInTimeRange = collision.trackOccupancyInTimeRange(); + ft0cOccupancyInTimeRange = collision.ft0cOccupancyInTimeRange(); primaryVertexX = collision.posX(); primaryVertexY = collision.posY(); primaryVertexZ = collision.posZ(); } } mcHypCands(centralityFT0A, centralityFT0C, centralityFT0M, + trackOccupancyInTimeRange, ft0cOccupancyInTimeRange, primaryVertexX, primaryVertexY, primaryVertexZ, runNumber, mother.pdgCode() > 0, -1.f, -1.f, -1.f, diff --git a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx index 1d748682f6c..21e534db7fc 100644 --- a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx @@ -13,15 +13,15 @@ /// \brief Initializes variables for the resonance candidate producers /// /// \author Bong-Hwi Lim , Minjae Kim -/// \since Aug.18 2026 +/// \since Aug.31 2026 #include "PWGLF/DataModel/LFResonanceTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/mcCentrality.h" #include "PWGLF/Utils/collisionCuts.h" -#include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -40,10 +40,14 @@ #include #include #include -#include #include #include +#include +#include +#include + +#include #include #include #include @@ -73,23 +77,60 @@ using namespace o2::aod::rctsel; struct ResonanceModuleInitializer { static constexpr double BzOverrideThreshold = -990.; static constexpr double MinimumNonzeroBz = 1.e-5; - static constexpr double MinimumChargedParticleCharge = 3.; // ROOT particle charge is stored in units of e/3 - static constexpr int MCCentralityRecoEstimator = 0; - static constexpr int MCCentralityGeneratorEstimator = 1; - static constexpr int MCCentralityImpactParameterEstimator = 2; + static constexpr int CentralityFT0M = 0; + static constexpr int CentralityFT0C = 1; + static constexpr int CentralityFT0A = 2; + static constexpr int CentralityFV0A = 3; + static constexpr int MultiplicityNTracksPV = 0; + static constexpr int MultiplicityNTracksPVeta1 = 1; + static constexpr int MultiplicityNTracksPVetaHalf = 2; + static constexpr int MultiplicityFT0M = 3; + static constexpr int MultiplicityFT0A = 4; + static constexpr int MultiplicityFT0C = 5; + static constexpr int MultiplicityFV0A = 6; + static constexpr int DetailedQARCTStage = o2::analysis::CollisonCuts::kAllpassed + 1; + static constexpr int DetailedQAStages = DetailedQARCTStage + 1; static constexpr float MCVertexZMax = 10.f; - - int mRunNumber = 0; ///< Run number for the current data - int multEstimator = 0; ///< Multiplicity estimator type - float dBz = 0.f; ///< Magnetic field value - float centrality = 0.f; ///< Centrality value for the event - Service ccdb; ///< CCDB manager service - Service pdg; ///< PDG database service - - Produces resoCollisions; ///< Output table for resonance collisions - Produces resoCollisionColls; ///< Output table for collision references - Produces resoCollisionGroups; ///< Canonical original-collision grouping references - Produces resoMCCollisions; ///< Output table for MC resonance collisions + // PDG codes used by the persistent resonance-parent selection. Named O2/ROOT + // values are preferred where available; the remaining resonances are kept as + // local named constants because neither PDG_t nor PhysicsConstants defines them. + static constexpr int PdgKStar0 = o2::constants::physics::Pdg::kK0Star892; + static constexpr int PdgKStarCharged = o2::constants::physics::Pdg::kKPlusStar892; + static constexpr int PdgPhi = o2::constants::physics::Pdg::kPhi; + static constexpr int F0Code980 = 9010221; + static constexpr int F0Code1370 = 10221; + static constexpr int F0Code1500 = 9030221; + static constexpr int F0Code1710 = 10331; + static constexpr int F1Code1285 = 20223; + static constexpr int F1Code1420 = 20333; + static constexpr int F2PrimeCode1525 = 335; + static constexpr int PdgRho0 = PDG_t::kRho770_0; + static constexpr int PdgRhoCharged = PDG_t::kRho770Plus; + static constexpr int SigmaStarPlusCode = 3224; + static constexpr int PdgLambda1520 = o2::constants::physics::Pdg::kLambda1520_Py; + static constexpr int Xi1530Code = 3324; + static constexpr int PdgK1Plus1270 = o2::constants::physics::Pdg::kK1_1270Plus; + static constexpr int Xi1820NeutralCode = 123314; + static constexpr int Xi1820MinusCode = 123324; + static constexpr int Omega2012MinusCode = 123334; + static constexpr int PdgProton = PDG_t::kProton; + static constexpr int PdgLambda0 = PDG_t::kLambda0; + static constexpr int PdgXiMinus = PDG_t::kXiMinus; + static constexpr int PdgXi0 = o2::constants::physics::Pdg::kXi0; + static constexpr int PdgOmegaMinus = PDG_t::kOmegaMinus; + + int mRunNumber = 0; ///< Run number for the current data + int multEstimator = CentralityFT0M; ///< Centrality estimator type + float dBz = 0.f; ///< Magnetic field value + float centrality = 0.f; ///< Centrality value for the event + Service ccdb; ///< CCDB manager service + + Produces resoCollisions; ///< Output table for resonance collisions + Produces resoCollisionColls; ///< Optional source collision soft links + Produces resoCollisionGroups001; ///< Scalar original-collision grouping keys + Produces resoMCCollisions001; ///< Generator-only MC collision extension + Produces resoMCCollisionIds; ///< Optional source generator-collision soft links + Produces reso2mcparents; ///< Generated parents with scalar source-particle IDs // CCDB options struct : ConfigurableGroup { @@ -99,18 +140,21 @@ struct ResonanceModuleInitializer { Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable cfgFatalWhenNull{"cfgFatalWhenNull", true, "Fatal when null on ccdb access"}; - Configurable cfgBypassCollIndexFill{"cfgBypassCollIndexFill", false, "Unsupported in the modular workflow; must remain false"}; + Configurable cfgBypassCollIndexFill{"cfgBypassCollIndexFill", false, "Deprecated compatibility option; collision mapping tables are always written"}; } CCDB; // General event options struct : ConfigurableGroup { Configurable dBzInput{"dBzInput", -999, "bz field, -999 is automatic"}; Configurable cfgFillQA{"cfgFillQA", true, "Fill QA histograms"}; + Configurable cfgFillDetailedQA{"cfgFillDetailedQA", true, "Fill the Run 3 event-selection stage vs vertex-z vs centrality vs multiplicity THnSparse"}; Configurable cfgBypassCCDB{"cfgBypassCCDB", true, "Bypass loading CCDB part to save CPU time and memory"}; // will be affected to b_z value. - Configurable cfgMultName{"cfgMultName", "FT0M", "The name of multiplicity estimator"}; - Configurable cfgCentralityMC{"cfgCentralityMC", 0, "Centrality estimator for MC (0: Reco, 1: MC, 2: impact parameter)"}; - ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1.0, 5.0, 10., 15., 20., 30., 40., 50., 70., 100.0, 105.}, "Binning of the centrality axis"}; - ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -20, -15, -10, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 10, 15, 20}, "Mixing bins - z-vertex"}; + Configurable cfgMultName{"cfgMultName", "FT0M", "Centrality estimator: FT0M, FT0C, FT0A, or FV0A"}; + Configurable cfgMultiplicityEstimator{"cfgMultiplicityEstimator", 3, + "Stored multiplicity (NOT percentile): 0 -> NTracksPV, 1 -> NTracksPVeta1, 2 -> NTracksPVetaHalf, 3 -> FT0M, 4 -> FT0A, 5 -> FT0C, 6 -> FV0A"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1., 5., 10., 15., 20., 30., 40., 50., 60., 70., 80., 90., 100., 105.}, "Binning of the centrality axis"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {500, 0.f, 5000.f}, "Binning of the reconstructed multiplicity axis for detailed collision QA"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {400, -20.f, 20.f}, "Binning of the collision vertex-z axis for detailed QA"}; } EventConfig; /// Event cuts @@ -119,26 +163,86 @@ struct ResonanceModuleInitializer { Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; Configurable cfgEvtOccupancyInTimeRange{"cfgEvtOccupancyInTimeRange", -1, "Evt sel: maximum track occupancy"}; Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; - Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; - Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; - Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", false, "Evt sel: check for offline selection (sel8)"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", true, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", true, "Evt sel: apply TF border cut"}; Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; Configurable cfgEvtCollInTimeRangeNarrow{"cfgEvtCollInTimeRangeNarrow", false, "Evt sel: apply NoCollInTimeRangeNarrow"}; Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; - Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", true, "Evt sel: apply Run2 AliEventCuts"}; + Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", false, "Evt sel: apply Run2 AliEventCuts"}; Configurable cfgEvtRun2INELgtZERO{"cfgEvtRun2INELgtZERO", false, "Evt sel: apply Run2 INELgtZERO"}; - Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", true, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtBCRCT{"cfgEvtBCRCT", false, "Evt sel: check RCT on the nominal associated BCSEL instead of the collision EVSEL"}; Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + Configurable cfgEvtRCTCheckTableValidity{"cfgEvtRCTCheckTableValidity", false, "Evt sel: reject collisions when the RCT CCDB payload is unavailable"}; } EventCuts; - RCTFlagsChecker rctChecker; + RCTFlagsChecker recoRCTChecker; - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Generator-level event and resonance QA + struct : ConfigurableGroup { + Configurable cfgGenBCRCT{"cfgGenBCRCT", false, "GenEvent: apply the RCT flag checker to the associated BC"}; + Configurable cfgGenRCTCheckTableValidity{"cfgGenRCTCheckTableValidity", false, "GenEvent: reject MC collisions when the RCT CCDB payload is unavailable"}; + Configurable cfgGenMult05{"cfgGenMult05", true, "GenEvent: multiplicity in |eta| < 0.5"}; + Configurable cfgGenMult10{"cfgGenMult10", false, "GenEvent: multiplicity in |eta| < 1.0"}; + Configurable cfgGenMultFT0M{"cfgGenMultFT0M", false, "GenEvent: generated charged-particle multiplicity in the FT0A + FT0C acceptance"}; + Configurable cfgGenMultFT0C{"cfgGenMultFT0C", false, "GenEvent: generated charged-particle multiplicity in the FT0C acceptance"}; + Configurable cfgGenMultFV0A{"cfgGenMultFV0A", false, "GenEvent: generated charged-particle multiplicity in the FV0A acceptance"}; + Configurable cfgGenMultPercentile{"cfgGenMultPercentile", true, "Use the configured FT0M, FT0C, or FV0A percentile from the MC centrality wagon"}; + Configurable cfgFillMCCollisionSoftLink{"cfgFillMCCollisionSoftLink", false, + "Write the source MC-collision soft link; enable only with the original AO2D as linked parent"}; + Configurable isZvtxcutGen{"isZvtxcutGen", true, "Apply the generator-collision z-vertex cut"}; + Configurable cutzvertexGen{"cutzvertexGen", 10.f, "Maximum absolute generator-collision z vertex (cm)"}; + Configurable checkIsTrueINELgt0{"checkIsTrueINELgt0", true, "Classify true INEL>0 generator collisions"}; + ConfigurableAxis binsCentGen{"binsCentGen", + {VARIABLE_WIDTH, 0., 0.01, 0.1, 1., 5., 10., 15., 20., 30., 40., 50., 60., 70., 80., 90., 100., 105.}, + "Generator centrality axis"}; + ConfigurableAxis ptAxisGen{"ptAxisGen", {400, 0.f, 20.f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis multNTracksAxis{"multNTracksAxis", {500, 0.f, 5000.f}, "Number of charged particles"}; + ConfigurableAxis impactParameterAxis{"impactParameterAxis", {500, 0.f, 50.f}, "Impact parameter (fm)"}; + Configurable isDaughterCheck{"isDaughterCheck", true, "Require the configured two-body decay"}; + Configurable cfgRapidityCutMinGen{"cfgRapidityCutMinGen", -0.5f, "Minimum generated-particle rapidity"}; + Configurable cfgRapidityCutMaxGen{"cfgRapidityCutMaxGen", 0.5f, "Maximum generated-particle rapidity"}; + Configurable pdgTruthMother{"pdgTruthMother", static_cast(Xi1530Code), "Absolute PDG code of the generated mother"}; + Configurable pdgTruthDaughter1{"pdgTruthDaughter1", static_cast(PdgXiMinus), "Absolute PDG code of the first daughter"}; + Configurable pdgTruthDaughter2{"pdgTruthDaughter2", PDG_t::kPiPlus, "Absolute PDG code of the second daughter"}; + Configurable cfgDoSignalLoss{"cfgDoSignalLoss", false, "Save reference particles for mT-scaling signal-loss studies"}; + } GenCuts; + RCTFlagsChecker genRCTChecker; + + // Keep the established ResoMCParents content compatible with the legacy + // initializer. The additional stable-particle species are written only for + // signal-loss studies and are filtered in fillMCParents. + Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == PdgKStar0) // K*(892)0 + || (nabs(aod::mcparticle::pdgCode) == PdgKStarCharged) // K*(892)+ + || (nabs(aod::mcparticle::pdgCode) == PdgPhi) // phi(1020) + || (nabs(aod::mcparticle::pdgCode) == F0Code980) // f0(980) + || (nabs(aod::mcparticle::pdgCode) == F0Code1370) // f0(1370) + || (nabs(aod::mcparticle::pdgCode) == F0Code1500) // f0(1500) + || (nabs(aod::mcparticle::pdgCode) == F0Code1710) // f0(1710) + || (nabs(aod::mcparticle::pdgCode) == F1Code1285) // f1(1285) + || (nabs(aod::mcparticle::pdgCode) == F1Code1420) // f1(1420) + || (nabs(aod::mcparticle::pdgCode) == F2PrimeCode1525) // f2'(1525) + || (nabs(aod::mcparticle::pdgCode) == PdgRho0) // rho(770)0 + || (nabs(aod::mcparticle::pdgCode) == PdgRhoCharged) // rho(770)+ + || (nabs(aod::mcparticle::pdgCode) == SigmaStarPlusCode) // Sigma(1385)+ + || (nabs(aod::mcparticle::pdgCode) == PdgLambda1520) // Lambda(1520) + || (nabs(aod::mcparticle::pdgCode) == Xi1530Code) // Xi(1530)0 + || (nabs(aod::mcparticle::pdgCode) == PdgK1Plus1270) // K1(1270)+ + || (nabs(aod::mcparticle::pdgCode) == Xi1820NeutralCode) // Xi(1820)0 + || (nabs(aod::mcparticle::pdgCode) == Xi1820MinusCode) // Xi(1820)- + || (nabs(aod::mcparticle::pdgCode) == Omega2012MinusCode) // Omega(2012)- + || (nabs(aod::mcparticle::pdgCode) == PdgProton) // proton + || (nabs(aod::mcparticle::pdgCode) == PdgLambda0) // Lambda0 + || (nabs(aod::mcparticle::pdgCode) == PdgXiMinus) // Xi- + || (nabs(aod::mcparticle::pdgCode) == PdgXi0) // Xi0 + || (nabs(aod::mcparticle::pdgCode) == PdgOmegaMinus); // Omega- + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; - Filter collisionFilter = nabs(aod::collision::posZ) < EventCuts.cfgEvtZvtx; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; /** * @brief Initializes the task @@ -150,32 +254,65 @@ struct ResonanceModuleInitializer { mRunNumber = 0; dBz = 0; centrality = 0; - // Determine the multiplicity estimator based on the configuration - multEstimator = 0; + // Determine the centrality estimator based on the configuration. if (EventConfig.cfgMultName.value == "FT0M") { - multEstimator = 0; + multEstimator = CentralityFT0M; } else if (EventConfig.cfgMultName.value == "FT0C") { - multEstimator = 1; + multEstimator = CentralityFT0C; } else if (EventConfig.cfgMultName.value == "FT0A") { - multEstimator = 2; + multEstimator = CentralityFT0A; + } else if (EventConfig.cfgMultName.value == "FV0A") { + multEstimator = CentralityFV0A; + } else { + LOGF(fatal, "Unsupported cfgMultName '%s'; choose FT0M, FT0C, FT0A, or FV0A", EventConfig.cfgMultName.value.c_str()); + } + LOGF(info, "Centrality estimator: %d, %s", multEstimator, EventConfig.cfgMultName.value.c_str()); + if (EventConfig.cfgMultiplicityEstimator.value < MultiplicityNTracksPV || + EventConfig.cfgMultiplicityEstimator.value > MultiplicityFV0A) { + LOG(fatal) << "cfgMultiplicityEstimator must be in the range [0, 6]"; } - LOGF(info, "Mult estimator: %d, %s", multEstimator, EventConfig.cfgMultName.value.c_str()); + LOGF(info, "Stored collision multiplicity estimator: %d", EventConfig.cfgMultiplicityEstimator.value); - // Ensure that only one process type is active at a time - if (doprocessRun3 && doprocessRun2) { - LOG(fatal) << "You cannot run both Run2 and Run3 processes at the same time"; + // Run 2 and Run 3 callbacks require different event-selection semantics. + const bool anyRun2Process = doprocessRun2 || doprocessRun2MC; + const bool anyRun3Process = doprocessRun3 || doprocessRun3MC || doprocessMCgen; + if (anyRun2Process && anyRun3Process) { + LOG(fatal) << "Run 2 and Run 3 processes cannot be enabled in the same ResonanceModuleInitializer"; } - if (doprocessRun2MC && doprocessRun3MC) { - LOG(fatal) << "You cannot run both Run2 and Run3 MC processes at the same time"; + if (doprocessRun2 && doprocessRun2MC) { + LOG(fatal) << "processRun2MC writes both ResoCollisions and ResoMCCollisions_001; do not enable processRun2 with it"; } - if (CCDB.cfgBypassCollIndexFill) { - LOG(fatal) << "cfgBypassCollIndexFill is incompatible with ResonanceDaughterInitializer"; + if (doprocessRun3 && doprocessRun3MC) { + LOG(fatal) << "processRun3MC writes both ResoCollisions and ResoMCCollisions_001; do not enable processRun3 with it"; + } + const int enabledGenMultiplicityEstimators = static_cast(GenCuts.cfgGenMult05.value) + + static_cast(GenCuts.cfgGenMult10.value) + + static_cast(GenCuts.cfgGenMultFT0M.value) + + static_cast(GenCuts.cfgGenMultFT0C.value) + + static_cast(GenCuts.cfgGenMultFV0A.value); + if ((doprocessMCgen || doprocessRun2MC || doprocessRun3MC) && enabledGenMultiplicityEstimators > 1) { + LOG(fatal) << "Only one generator multiplicity estimator can be enabled: cfgGenMult05, cfgGenMult10, cfgGenMultFT0M, cfgGenMultFT0C, or cfgGenMultFV0A"; + } + if (doprocessMCgen) { + if (GenCuts.cfgGenMultPercentile && multEstimator != CentralityFT0M && + multEstimator != CentralityFT0C && multEstimator != CentralityFV0A) { + LOGF(fatal, "cfgGenMultPercentile supports cfgMultName=FT0M, FT0C, or FV0A"); + } + if (GenCuts.isZvtxcutGen && + (!std::isfinite(GenCuts.cutzvertexGen.value) || GenCuts.cutzvertexGen.value <= 0.f)) { + LOG(fatal) << "cutzvertexGen must be finite and positive when the generator vertex cut is enabled"; + } + if (!std::isfinite(GenCuts.cfgRapidityCutMinGen.value) || + !std::isfinite(GenCuts.cfgRapidityCutMaxGen.value) || + GenCuts.cfgRapidityCutMinGen.value >= GenCuts.cfgRapidityCutMaxGen.value) { + LOG(fatal) << "Generator rapidity limits must be finite and satisfy cfgRapidityCutMinGen < cfgRapidityCutMaxGen"; + } } // Initialize event selection cuts based on the process type - if (doprocessRun2) { + if (anyRun2Process) { colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, false); - } else if (doprocessRun3) { + } else if (anyRun3Process) { colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, true, false, EventCuts.cfgEvtOccupancyInTimeRange); } colCuts.init(&qaRegistry); @@ -189,7 +326,31 @@ struct ResonanceModuleInitializer { colCuts.setApplyRun2AliEventCuts(EventCuts.cfgEvtRun2AliEventCuts); colCuts.setApplyRun2INELgtZERO(EventCuts.cfgEvtRun2INELgtZERO); - rctChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, EventCuts.cfgEvtRCTFlagCheckerZDCCheck, EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + if (EventConfig.cfgFillDetailedQA && (doprocessRun3 || doprocessRun3MC)) { + AxisSpec selectionStageAxis{DetailedQAStages, -0.5f, static_cast(DetailedQAStages) - 0.5f, "Passed event-selection stage"}; + AxisSpec vertexAxis{EventConfig.cfgVtxBins, "Collision vertex z (cm)"}; + AxisSpec centralityAxis{EventConfig.binsCent, "Centrality (%)"}; + AxisSpec multiplicityAxis{EventConfig.binsMultiplicity, "Multiplicity"}; + qaRegistry.add("Event/h4EventSelectionDetail", "Event-selection cut flow", kTHnSparseD, + {selectionStageAxis, vertexAxis, centralityAxis, multiplicityAxis}); + + auto detailedQA = qaRegistry.get(HIST("Event/h4EventSelectionDetail")); + auto cutCounts = qaRegistry.get(HIST("CollCutCounts")); + for (int stage = o2::analysis::CollisonCuts::kAllEvent; + stage <= o2::analysis::CollisonCuts::kAllpassed; ++stage) { + detailedQA->GetAxis(0)->SetBinLabel(stage + 1, cutCounts->GetXaxis()->GetBinLabel(colCuts.binLabel(stage))); + } + detailedQA->GetAxis(0)->SetBinLabel(DetailedQARCTStage + 1, "RCT"); + } + + recoRCTChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, + EventCuts.cfgEvtRCTFlagCheckerZDCCheck, + EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad, + EventCuts.cfgEvtRCTCheckTableValidity.value); + genRCTChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, + EventCuts.cfgEvtRCTFlagCheckerZDCCheck, + EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad, + GenCuts.cfgGenRCTCheckTableValidity.value); // Configure CCDB access if not bypassed if (!EventConfig.cfgBypassCCDB) { @@ -201,11 +362,26 @@ struct ResonanceModuleInitializer { ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time } - // Initialize QA histograms if required - if (EventConfig.cfgFillQA && (doprocessRun3MC || doprocessRun2MC)) { - AxisSpec centAxis = {EventConfig.binsCent, "Centrality (%)"}; - AxisSpec idxMCAxis = {26, -0.5, 25.5, "Index"}; - qaRegistry.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {centAxis, idxMCAxis}); + if (doprocessMCgen) { + constexpr std::array MCEventLabels{"All", "z vertex", "BC RCT", "INEL", "INEL>0"}; + AxisSpec centAxisGen = {GenCuts.binsCentGen, "Centrality (%)"}; + AxisSpec eventTypeAxis = {2, 0.f, 2.f, "Event type"}; + qaRegistry.add("EventGen/hNEventsMC", "Generator event selection", kTH1D, {{5, 0.f, 5.f}}); + auto eventCounter = qaRegistry.get(HIST("EventGen/hNEventsMC")); + for (std::size_t i = 0; i < MCEventLabels.size(); ++i) { + eventCounter->GetXaxis()->SetBinLabel(static_cast(i + 1), MCEventLabels[i]); + } + qaRegistry.add("EventGen/h5ResonanceTruth", "Generated resonance", kTHnSparseD, + {eventTypeAxis, GenCuts.ptAxisGen, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/h5ResonanceTruthAnti", "Generated anti-resonance", kTHnSparseD, + {eventTypeAxis, GenCuts.ptAxisGen, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/hZCollisionGen", "Generator collision z vertex", kTH1D, {{100, -20.f, 20.f}}); + qaRegistry.add("EventGen/h4MultCent_genMC", "Generator-event multiplicity and centrality", kTHnSparseD, + {eventTypeAxis, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/h4MultCent_recMC", "Reconstructed-event multiplicity and centrality", kTHnSparseD, + {eventTypeAxis, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/h2CentralityVsMultMC", "Representative reconstructed centrality vs generator multiplicity", kTH2D, + {centAxisGen, GenCuts.multNTracksAxis}); } } @@ -214,7 +390,8 @@ struct ResonanceModuleInitializer { * * @param bc BC iterator */ - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // Simple copy from LambdaKzeroFinder.cxx + template + void initCCDB(BCType const& bc) // Simple copy from LambdaKzeroFinder.cxx { if (EventConfig.cfgBypassCCDB) { return; @@ -258,203 +435,352 @@ struct ResonanceModuleInitializer { LOGF(info, "Bz set to %f for run: ", dBz, mRunNumber); } - /** - * @brief Checks if the collision is INEL>0 - * - * @tparam MCPart Type of MC particles - * @param mcparts MC particles - * @return true if INEL>0, false otherwise - */ - template - bool isTrueINEL0(MCPart const& mcparts) - { - for (auto const& mcparticle : mcparts) { - if (!mcparticle.isPhysicalPrimary()) { - continue; - } - auto p = pdg->GetParticle(mcparticle.pdgCode()); - if (p != nullptr) { - if (std::abs(p->Charge()) >= MinimumChargedParticleCharge) { - if (std::abs(mcparticle.eta()) < 1) { - return true; - } - } - } - } - return false; - } - /** * @brief Centrality estimator selection * * @tparam ResoColl Type of resonance collision - * @tparam isMC Boolean indicating if it's MC * @param resoEvents Resonance events * @return Centrality value */ - template + template float centEst(ResoColl const& resoEvents) { - float returnValue = -999.0; switch (multEstimator) { - case 0: - returnValue = resoEvents.centFT0M(); - break; - case 1: - if constexpr (isMC) { - LOG(fatal) << "CentFT0C is not available for MC"; - return returnValue; - } else { - returnValue = resoEvents.centFT0C(); - break; - } - case 2: - if constexpr (isMC) { - LOG(fatal) << "CentFT0A is not available for MC"; - return returnValue; - } else { - returnValue = resoEvents.centFT0A(); - break; - } + case CentralityFT0M: + return resoEvents.centFT0M(); + case CentralityFT0C: + return resoEvents.centFT0C(); + case CentralityFT0A: + return resoEvents.centFT0A(); + case CentralityFV0A: + return resoEvents.centFV0A(); default: - returnValue = resoEvents.centFT0M(); - break; + return -999.f; + } + } + + /** + * @brief Returns the configured reconstructed multiplicity estimator + */ + template + float collisionMultiplicity(CollisionType const& collision) + { + switch (EventConfig.cfgMultiplicityEstimator.value) { + case MultiplicityNTracksPV: + return collision.multNTracksPV(); + case MultiplicityNTracksPVeta1: + return collision.multNTracksPVeta1(); + case MultiplicityNTracksPVetaHalf: + return collision.multNTracksPVetaHalf(); + case MultiplicityFT0M: + return collision.multFT0M(); + case MultiplicityFT0A: + return collision.multFT0A(); + case MultiplicityFT0C: + return collision.multFT0C(); + case MultiplicityFV0A: + return collision.multFV0A(); + default: + return -1.f; + } + } + + /// Fill the detailed Run 3 collision QA at one passed selection stage. + template + void fillDetailedCollisionQA(CollisionType const& collision, int selectionStage) + { + qaRegistry.fill(HIST("Event/h4EventSelectionDetail"), + selectionStage, + collision.posZ(), + centEst(collision), + collisionMultiplicity(collision)); + } + + /// Reproduce the configured Run 3 collision cut flow for detailed QA only. + /// The authoritative event decision remains CollisonCuts::isSelected(). + template + void fillDetailedRun3SelectionQA(CollisionType const& collision) + { + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kAllEvent); + if (std::abs(collision.posZ()) > EventCuts.cfgEvtZvtx.value) { + return; + } + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kFlagZvertex); + +// Keep this QA-only mapping synchronized with CollisonCuts without exposing +// its internal selection registry. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -- X-macro interface of EventSelectionFlagsMapping.def +#define EVSEL_FLAG(enumVal, member, defaultVal, evtSelEnum, setter, getter, label, desc) \ + if (colCuts.getSelection(o2::analysis::CollisonCuts::evtSelEnum)) { \ + if (!collision.selection_bit(o2::aod::evsel::enumVal)) { \ + return; \ + } \ + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::evtSelEnum); \ + } +#include "PWGLF/Utils/EventSelectionFlagsMapping.def" // NOLINT(build/include) +#undef EVSEL_FLAG + + if (EventCuts.cfgEvtOfflineCheck.value && !collision.sel8()) { + return; + } + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kFlagSel8); + + if (EventCuts.cfgEvtOccupancyInTimeRange.value > 0 && + collision.trackOccupancyInTimeRange() > EventCuts.cfgEvtOccupancyInTimeRange.value) { + return; } - return returnValue; + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kFlagOccupancy); + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kAllpassed); } - using GenMCCollisions = soa::Join; - float centEstMC(const GenMCCollisions::iterator& collision) { return centEst(collision); } + + using GenMCCollisions = soa::Join; + using Run3MCCollisions = soa::Join; + using Run2MCCollisions = soa::Join; + using GenRecoCollisions = soa::Join; + using BCsWithRCT = soa::Join; /** - * @brief Fills MC particles + * @brief Applies the configured RCT selection to a reconstructed collision * - * @tparam CollisionType Type of collision - * @tparam SelectedMCPartType Type of selected MC particles - * @tparam TotalMCParts Type of total MC particles - * @param collision Collision data - * @param mcParts Selected MC particles - * @param mcParticles Total MC particles + * The collision-level mode reads the RCT value stored in EVSEL. The BC-level + * mode reads the value directly from the nominal BC referenced by collision. */ - template - void fillMCParticles(CollisionType collision, SelectedMCPartType const& mcParts, TotalMCParts const& mcParticles) + template + bool isRecoRCTSelected(CollisionType const& collision) { - for (auto const& mcPart : mcParts) { - std::vector daughterPDGs; - if (mcPart.has_daughters()) { - auto daughter01 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); - auto daughter02 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); + if (!EventCuts.cfgEvtUseRCTFlagChecker.value) { + return true; + } + if (!EventCuts.cfgEvtBCRCT.value) { + return recoRCTChecker(collision); + } + const auto bc = collision.template bc_as(); + return recoRCTChecker(bc); + } + + /// Apply the reconstructed Run 3 event and RCT selections. Detailed cut-flow + /// QA is evaluated independently and never controls the event decision. + template + bool isRun3CollisionSelected(CollisionType const& collision) + { + if (EventConfig.cfgFillDetailedQA) { + fillDetailedRun3SelectionQA(collision); + } + if (!colCuts.isSelected(collision, EventConfig.cfgFillQA) || !isRecoRCTSelected(collision)) { + return false; + } + if (EventConfig.cfgFillDetailedQA) { + fillDetailedCollisionQA(collision, DetailedQARCTStage); + } + return true; + } + + /** + * @brief Fills generator-level resonance QA + * + * @tparam MCParticlesType Type of MC-particle group + * @param mcParticles MC particles grouped by generator collision + * @param generatorCentrality Generator or representative reconstructed centrality + * @param multiplicity Generator-level charged-particle multiplicity + * @param impactParameter Generator collision impact parameter + * @param eventType INEL/INEL>0 category + */ + template + void fillMCGenParticles(MCParticlesType const& mcParticles, + float generatorCentrality, + float multiplicity, + float impactParameter, + int eventType) + { + for (auto const& mcPart : mcParticles) { + if (std::abs(mcPart.pdgCode()) != std::abs(GenCuts.pdgTruthMother.value)) { + continue; + } + if (mcPart.y() <= GenCuts.cfgRapidityCutMinGen || mcPart.y() >= GenCuts.cfgRapidityCutMaxGen) { + continue; + } + + std::array daughterPDGs{-1, -1}; + const bool hasDaughters = mcPart.has_daughters(); + const auto daughterIds = mcPart.daughtersIds(); + if (hasDaughters) { + auto daughter01 = mcParticles.rawIteratorAt(daughterIds[0] - mcParticles.offset()); + auto daughter02 = mcParticles.rawIteratorAt(daughterIds[1] - mcParticles.offset()); daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; + } + if (GenCuts.isDaughterCheck) { + const int daughter1 = std::abs(GenCuts.pdgTruthDaughter1.value); + const int daughter2 = std::abs(GenCuts.pdgTruthDaughter2.value); + const int firstDaughterPDG = std::abs(daughterPDGs[0]); + const int secondDaughterPDG = std::abs(daughterPDGs[1]); + // Match the configured decay to two distinct daughter slots. This is + // important when both configured absolute PDGs are equal (e.g. K+K-): + // one matching daughter must not satisfy both requirements. + const bool matchesConfiguredDecay = + (firstDaughterPDG == daughter1 && secondDaughterPDG == daughter2) || + (firstDaughterPDG == daughter2 && secondDaughterPDG == daughter1); + if (!matchesConfiguredDecay) { + continue; + } + } + + if (mcPart.pdgCode() > 0) { + qaRegistry.fill(HIST("EventGen/h5ResonanceTruth"), eventType, mcPart.pt(), generatorCentrality, multiplicity, impactParameter); } else { - daughterPDGs = {-1, -1}; + qaRegistry.fill(HIST("EventGen/h5ResonanceTruthAnti"), eventType, mcPart.pt(), generatorCentrality, multiplicity, impactParameter); + } + } + } + + /** + * @brief Fills generated resonance parents for one reduced collision + * + * @tparam SelectedMCParticlesType Type of the selected MC-particle slice + * @tparam MCParticlesType Type of the complete MC-particle table + * @param reducedCollisionId Reduced collision referenced by the output rows + * @param selectedParents Selected parent particles in the associated MC collision + * @param mcParticles Complete MC-particle table used to resolve daughter indices + * + * The source MC-particle global index is persisted as a scalar in + * ResoMCParents_001; it is not a relation requiring McParticles at merge time. + */ + template + void fillMCParents(int64_t reducedCollisionId, + SelectedMCParticlesType const& selectedParents, + MCParticlesType const& mcParticles) + { + for (auto const& mcPart : selectedParents) { + if (!GenCuts.cfgDoSignalLoss) { + const int absPdg = std::abs(mcPart.pdgCode()); + if (absPdg == PdgProton || absPdg == PdgLambda0 || absPdg == PdgXiMinus || absPdg == PdgXi0 || absPdg == PdgOmegaMinus) { + continue; + } + } + + std::array daughterPDGs{-1, -1}; + if (mcPart.has_daughters()) { + const auto daughter1 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); + const auto daughter2 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); + daughterPDGs = {daughter1.pdgCode(), daughter2.pdgCode()}; } - reso2mcparents(collision.globalIndex(), + reso2mcparents(reducedCollisionId, mcPart.globalIndex(), mcPart.pdgCode(), - daughterPDGs[0], daughterPDGs[1], + daughterPDGs[0], + daughterPDGs[1], mcPart.isPhysicalPrimary(), mcPart.producedByGenerator(), mcPart.pt(), mcPart.px(), mcPart.py(), mcPart.pz(), - mcPart.eta(), - mcPart.phi(), - mcPart.y()); - daughterPDGs.clear(); + mcPart.y(), + mcPart.e(), + mcPart.statusCode()); } } /** - * @brief Fills MC collision data - * - * @tparam isRun2 Boolean indicating if it's Run2 - * @tparam MCCol Type of MC collision - * @tparam MCPart Type of MC particles - * @param mccol MC collision data - * @param mcparts MC particles + * @brief Returns the configured generator-level multiplicity estimator */ - template - void fillMCCollision(MCCol const& mccol, MCPart const& mcparts) - { - const auto& mcColg = mccol.template mcCollision_as(); - float mcCent = 999.0; - if constexpr (isRun2) { - if (EventConfig.cfgCentralityMC == MCCentralityRecoEstimator) { - mcCent = mccol.centRun2V0M(); - } else { - mcCent = mcColg.impactParameter(); - } - } else { - if (EventConfig.cfgCentralityMC == MCCentralityRecoEstimator) { - mcCent = centEst(mccol); - } else if (EventConfig.cfgCentralityMC == MCCentralityGeneratorEstimator) { - mcCent = centEstMC(mcColg); - } else if (EventConfig.cfgCentralityMC == MCCentralityImpactParameterEstimator) { - mcCent = mcColg.impactParameter(); - } + template + float getMCMultiplicity(MCCollision const& mcCollision) + { + if (GenCuts.cfgGenMult05) { + return mcCollision.multMCNParticlesEta05(); + } + if (GenCuts.cfgGenMult10) { + return mcCollision.multMCNParticlesEta10(); + } + if (GenCuts.cfgGenMultFT0M) { + return mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); + } + if (GenCuts.cfgGenMultFT0C) { + return mcCollision.multMCFT0C(); } - const bool inVtx10 = !(std::abs(mcColg.posZ()) > MCVertexZMax); - bool isTrueINELgt0 = isTrueINEL0(mcparts); - bool isTriggerTVX = mccol.selection_bit(aod::evsel::kIsTriggerTVX); - bool isSel8 = mccol.sel8(); - bool isSelected = colCuts.isSelected(mccol, EventConfig.cfgFillQA); - resoMCCollisions(inVtx10, isTrueINELgt0, isTriggerTVX, isSel8, isSelected, mcCent, -1.0f); + if (GenCuts.cfgGenMultFV0A) { + return mcCollision.multMCFV0A(); + } + return -1.f; + } - if (EventConfig.cfgFillQA) { - // QA for trigger efficiency - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINEL); - if (inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINEL10); - } - if (isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINELg0); - } - if (inVtx10 && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINELg010); - } + /** + * @brief Returns the configured generator-level centrality percentile + */ + template + float getMCCentrality(MCCollision const& mcCollision) const + { + if (!GenCuts.cfgGenMultPercentile.value) { + return 100.5f; + } + switch (multEstimator) { + case CentralityFT0M: + return mcCollision.centFT0M(); + case CentralityFT0C: + return mcCollision.centFT0C(); + case CentralityFV0A: + return mcCollision.centFV0A(); + default: + return 100.5f; + } + } - // TVX MB trigger - if (isTriggerTVX) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrig); - } - if (isTriggerTVX && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrig10); - } - if (isTriggerTVX && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrigINELg0); - } - if (isTriggerTVX && isTrueINELgt0 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrigINELg010); - } + /** + * @brief Fills the generator-only MC collision extension and optional source link + * + * Accepting only the generator collision here prevents reconstructed event + * selection state from accidentally entering ResoMCCollisions_001. + */ + template + void fillMCCollision001(MCCollision const& mcCollision) + { + const float mcMultiplicity = getMCMultiplicity(mcCollision); + const bool inTrueVtx10 = std::abs(mcCollision.posZ()) < MCVertexZMax; + // Keep the generator-level definition identical to MultsExtraMC: + // at least one physical-primary charged particle within |eta| < 1. + const bool isTrueINELgt0 = mcCollision.isInelGt0(); + resoMCCollisions001(inTrueVtx10, + isTrueINELgt0, + mcCollision.impactParameter(), + mcMultiplicity); + if (GenCuts.cfgFillMCCollisionSoftLink) { + resoMCCollisionIds(mcCollision.globalIndex()); + } + } - // Sel8 event selection - if (isSel8) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8); - } - if (isSel8 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel810); - } - if (isSel8 && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8INELg0); - } - if (isSel8 && isTrueINELgt0 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8INELg010); - } + /// Write the Run 3 base collision, optional soft link, and scalar grouping key. + template + void fillRun3Collision(CollisionType const& collision) + { + const bool isRecINELgt0 = collision.isInelGt0(); + centrality = centEst(collision); + resoCollisions(collisionMultiplicity(collision), + collision.posX(), + collision.posY(), + collision.posZ(), + centrality, + dBz, + isRecINELgt0); + resoCollisionColls(collision.globalIndex()); + resoCollisionGroups001(collision.globalIndex()); + } - // CollisionCuts selection - if (isSelected) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCuts); - } - if (isSelected && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCuts10); - } - if (isSelected && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCutsINELg0); - } - if (isSelected && isTrueINELgt0 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCutsINELg010); - } - } + /// Write the Run 2 base collision, optional soft link, and scalar grouping key. + template + void fillRun2Collision(CollisionType const& collision) + { + centrality = collision.centRun2V0M(); + // The configured Run 3 estimators are not available in the Run 2 input + // schema. Preserve the previous zero-filled Run 2 behaviour. + resoCollisions(0.f, + collision.posX(), + collision.posY(), + collision.posZ(), + centrality, + dBz, + 0); + resoCollisionColls(collision.globalIndex()); + resoCollisionGroups001(collision.globalIndex()); } /** @@ -473,27 +799,19 @@ struct ResonanceModuleInitializer { * @param collision Collision data * @param bc BC data */ - void processRun3(soa::Filtered::iterator const& collision, - aod::BCsWithTimestamps const&) + void processRun3(aod::ResoCollisionCandidates::iterator const& collision, + BCsWithRCT const&) { - auto bc = collision.bc_as(); + auto bc = collision.bc_as(); initCCDB(bc); // Default event selection - if (!colCuts.isSelected(collision, EventConfig.cfgFillQA)) { - return; - } - if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + if (!isRun3CollisionSelected(collision)) { return; } if (EventConfig.cfgFillQA) { colCuts.fillQA(collision); } - const bool isRecINELgt0 = collision.isInelGt0(); - centrality = centEst(collision); - - resoCollisions(collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz, isRecINELgt0); - resoCollisionColls(collision.globalIndex()); - resoCollisionGroups(collision.globalIndex()); + fillRun3Collision(collision); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun3, "Default process for RUN3", false); @@ -503,7 +821,7 @@ struct ResonanceModuleInitializer { * @param collision Collision data * @param bc BC data */ - void processRun2(soa::Filtered::iterator const& collision, + void processRun2(aod::ResoRun2CollisionCandidates::iterator const& collision, aod::BCsWithRun2Info const&) { // auto bc = collision.bc_as(); @@ -514,41 +832,154 @@ struct ResonanceModuleInitializer { if (EventConfig.cfgFillQA) { colCuts.fillQARun2(collision); } - centrality = collision.centRun2V0M(); - - resoCollisions(0, 0, 0, collision.posX(), collision.posY(), collision.posZ(), centrality, dBz, 0); - resoCollisionColls(collision.globalIndex()); - resoCollisionGroups(collision.globalIndex()); + fillRun2Collision(collision); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun2, "process for RUN2", false); + /** + * @brief Processes generator-level MC event and resonance QA + * + * The original MC collision is the grouping key. MC particles are therefore + * grouped automatically, while reconstructed collisions arrive as a 0..N + * SmallGroup through their McCollisionLabels relation. This auxiliary + * callback intentionally fills generator-level QA only and does not write + * reduced AOD tables. RCT quality is evaluated through the generator + * collision's associated BC because it is a run-condition property. + */ + void processMCgen(GenMCCollisions::iterator const& mcCollision, + aod::McParticles const& mcParticles, + soa::SmallGroups const& collisions, + BCsWithRCT const&) + { + auto bc = mcCollision.bc_as(); + initCCDB(bc); + + const auto getReconstructedCentrality = [&](auto const& collision) { + return centEst(collision); + }; + + const float generatorCentrality = getMCCentrality(mcCollision); + const float impactParameter = mcCollision.impactParameter(); + const float multiplicity = getMCMultiplicity(mcCollision); + + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 0.5); + if (GenCuts.isZvtxcutGen && std::abs(mcCollision.posZ()) > GenCuts.cutzvertexGen) { + return; + } + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 1.5); + if (GenCuts.cfgGenBCRCT && !genRCTChecker(bc)) { + return; + } + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 2.5); + qaRegistry.fill(HIST("EventGen/hZCollisionGen"), mcCollision.posZ()); + + int eventType = 0; + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 3.5); + if (GenCuts.checkIsTrueINELgt0 && mcCollision.isInelGt0()) { + eventType = 1; + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 4.5); + } + + bool hasSelectedRecoCollision = false; + int largestNContributors = -1; + float reconstructedCentrality = 100.5f; + for (auto const& collision : collisions) { + if (!isRecoRCTSelected(collision)) { + continue; + } + if (!colCuts.isSelected(collision, false)) { + continue; + } + const int nContributors = static_cast(collision.multPVTotalContributors()); + if (nContributors > largestNContributors) { + largestNContributors = nContributors; + reconstructedCentrality = getReconstructedCentrality(collision); + } + hasSelectedRecoCollision = true; + } + + if (GenCuts.cfgGenMultPercentile) { + fillMCGenParticles(mcParticles, generatorCentrality, multiplicity, impactParameter, eventType); + qaRegistry.fill(HIST("EventGen/h4MultCent_genMC"), eventType, generatorCentrality, multiplicity, impactParameter); + } else { + fillMCGenParticles(mcParticles, reconstructedCentrality, multiplicity, impactParameter, eventType); + qaRegistry.fill(HIST("EventGen/h4MultCent_genMC"), eventType, reconstructedCentrality, multiplicity, impactParameter); + qaRegistry.fill(HIST("EventGen/h2CentralityVsMultMC"), reconstructedCentrality, multiplicity); + } + if (hasSelectedRecoCollision) { + qaRegistry.fill(HIST("EventGen/h4MultCent_recMC"), eventType, reconstructedCentrality, multiplicity, impactParameter); + } + } + PROCESS_SWITCH(ResonanceModuleInitializer, processMCgen, "Process generator-level MC QA", false); + /** * @brief Processes Run3 MC data * + * Reconstructed collisions pass the same event selection and QA sequence as + * Run 3 data before the reduced collision and its MC extension are written. + * * @param collision Collision data - * @param mcParticles MC particles * @param mcCollisions MC collisions + * @param mcParticles MC particles used to fill reduced resonance parents */ - void processRun3MC(soa::Filtered::iterator const& collision, - aod::McParticles const& mcParticles, GenMCCollisions const&) + void processRun3MC(aod::ResoCollisionCandidatesMC::iterator const& collision, + Run3MCCollisions const&, + aod::McParticles const& mcParticles, + BCsWithRCT const&) { - if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + auto bc = collision.bc_as(); + initCCDB(bc); + if (!isRun3CollisionSelected(collision)) { return; } - fillMCCollision(collision, mcParticles); + if (EventConfig.cfgFillQA) { + colCuts.fillQA(collision); + } + if (!collision.has_mcCollision()) { + return; + } + const auto& mcCollision = collision.mcCollision_as(); + + // ResoMCCollisions_001 is a positional extension of ResoCollisions. When + // enabled, ResoMCCollisionIds is written in the same callback and is 1:1. + fillRun3Collision(collision); + const int64_t reducedCollisionId = resoCollisions.lastIndex(); + fillMCCollision001(mcCollision); + + // A generator collision can be associated with more than one reconstructed + // collision. Write one parent set for each reduced collision, as in the + // legacy collision-wise producer, so ResoCollisionId remains unambiguous. + auto selectedParents = selectedMCParticles->sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + fillMCParents(reducedCollisionId, selectedParents, mcParticles); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun3MC, "process MC for RUN3", false); /** * @brief Processes Run2 MC data * + * Reconstructed collisions pass the same event selection and QA sequence as + * Run 2 data before the reduced collision and its MC extension are written. + * * @param collision Collision data - * @param mcParticles MC particles */ - void processRun2MC(soa::Filtered::iterator const& collision, - aod::McParticles const& mcParticles) + void processRun2MC(aod::ResoRun2CollisionCandidatesMC::iterator const& collision, + Run2MCCollisions const&) { - fillMCCollision(collision, mcParticles); + if (!colCuts.isSelected(collision, EventConfig.cfgFillQA)) { + return; + } + if (EventConfig.cfgFillQA) { + colCuts.fillQARun2(collision); + } + if (!collision.has_mcCollision()) { + return; + } + const auto& mcCollision = collision.mcCollision_as(); + + // Keep the base and MC extension one-to-one; the optional source link is + // written by fillMCCollision001 in the same order. + fillRun2Collision(collision); + fillMCCollision001(mcCollision); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun2MC, "process MC for RUN2", false); }; @@ -572,8 +1003,107 @@ struct ResonanceDaughterInitializer { static constexpr int TrackSelectionGlobalWoDCA = 3; static constexpr int TrackSelectionQuality = 4; static constexpr int TrackSelectionInAcceptance = 5; + static constexpr int PairGateModeConfigured = 0; + static constexpr int PairGateModeEither = 1; static constexpr float MomentumQuantizationScale = 1000.f; static constexpr std::size_t StoredMCRelationCount = 2; + static constexpr std::size_t MaxCandidateDaughters = 3; + + /// Selected-candidate state and the optional global daughter-ID veto set. + /// By default only candidate existence is recorded and daughter reuse is + /// rejected later for each concrete pair through the stored trackId. + struct SelectedCandidateDaughters { + std::vector allDaughterIds; + bool hasSelectedCandidate = false; + bool useGlobalDaughterVeto = false; + + explicit SelectedCandidateDaughters(bool globalDaughterVeto = false) + : useGlobalDaughterVeto(globalDaughterVeto) + { + } + + void addCandidate() + { + hasSelectedCandidate = true; + } + + template + void addCandidate(std::array const& daughterIds) + { + static_assert(DaughterCount <= MaxCandidateDaughters); + allDaughterIds.insert(allDaughterIds.end(), daughterIds.begin(), daughterIds.end()); + hasSelectedCandidate = true; + } + + void finalize() + { + if (!useGlobalDaughterVeto) { + return; + } + std::sort(allDaughterIds.begin(), allDaughterIds.end()); + allDaughterIds.erase(std::unique(allDaughterIds.begin(), allDaughterIds.end()), allDaughterIds.end()); + } + + [[nodiscard]] bool accepts(int64_t trackId) const + { + if (!hasSelectedCandidate) { + return false; + } + if (useGlobalDaughterVeto) { + return !std::binary_search(allDaughterIds.begin(), allDaughterIds.end(), trackId); + } + return true; + } + }; + + /// Producer-side track retention for the candidate types enabled by a callback. + struct PairTrackSelection { + SelectedCandidateDaughters v0Candidates; + SelectedCandidateDaughters cascadeCandidates; + bool useV0Candidates = false; + bool useCascadeCandidates = false; + bool useGlobalDaughterVeto = false; + + explicit PairTrackSelection(bool globalDaughterVeto = false) + : v0Candidates(globalDaughterVeto), + cascadeCandidates(globalDaughterVeto), + useGlobalDaughterVeto(globalDaughterVeto) + { + } + + template + bool operator()(TrackType const& track) const + { + if (!useGlobalDaughterVeto) { + return (useV0Candidates && v0Candidates.hasSelectedCandidate) || + (useCascadeCandidates && cascadeCandidates.hasSelectedCandidate); + } + + const auto trackId = static_cast(track.globalIndex()); + bool hasCandidate = false; + if (useV0Candidates && v0Candidates.hasSelectedCandidate) { + hasCandidate = true; + if (!v0Candidates.accepts(trackId)) { + return false; + } + } + if (useCascadeCandidates && cascadeCandidates.hasSelectedCandidate) { + hasCandidate = true; + if (!cascadeCandidates.accepts(trackId)) { + return false; + } + } + return hasCandidate; + } + }; + + struct KeepAllTracks { + template + bool operator()(TrackType const&) const + { + return true; + } + }; UltraMicroPidSpecies ultraMicroPidSpecies = UltraMicroPidSpecies::Pion; bool warnedUltraMicroMomentumRange = false; @@ -586,8 +1116,9 @@ struct ResonanceDaughterInitializer { Preslice cascadesMCPerCollision = aod::cascdata::collisionId; Produces reso2trks; ///< Output table for resonance tracks Produces resoTrackTracks; ///< Output table for original track row IDs - Produces reso2microtrks; ///< Output table for resonance microtracks - Produces resoMicroTrackTracks; ///< Output table for original microtrack row IDs + Produces reso2microtrks; ///< Output table for resonance microtracks + Produces resoMicroTrackTracks; ///< Positional original-track soft links for microtracks + Produces reso2mcmicrotrks; ///< Positional MC extension for resonance microtracks Produces reso2ultramicrotrks; ///< Output table for resonance ultra-microtracks Produces resoUltraMicroTrackTracks; ///< Output table for original ultra-microtrack row IDs Produces reso2mctracks; ///< Output table for MC resonance tracks @@ -606,86 +1137,96 @@ struct ResonanceDaughterInitializer { struct : ConfigurableGroup { Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; Configurable cfgCutMinPt{"cfgCutMinPt", 0.1f, "Minimum pT for tracks (GeV/c)"}; - Configurable cfgCutMaxPt{"cfgCutMaxPt", 32.767f, "Maximum pT for tracks (GeV/c)"}; - Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC PID cut (loose, improve performance)"}; - Configurable mincrossedrows{"mincrossedrows", 70, "Minimum crossed rows for V0 daughter tracks"}; + Configurable cfgCutMaxPt{"cfgCutMaxPt", 999.0f, "Maximum pT for tracks (GeV/c)"}; + Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC PID half-width around the configured species mean (loose preselection)"}; + Configurable pidnSigmaPreSelectionCutTOF{"pidnSigmaPreSelectionCutTOF", 5.0f, "TOF PID half-width around the configured species mean (loose preselection)"}; + Configurable pidnSigmaPreSelectionMeanPion{"pidnSigmaPreSelectionMeanPion", 0.000f, "Offset for TPC PID mean for pions"}; + Configurable pidnSigmaPreSelectionMeanKaon{"pidnSigmaPreSelectionMeanKaon", 0.000f, "Offset for TPC PID mean for kaons"}; + Configurable pidnSigmaPreSelectionMeanProton{"pidnSigmaPreSelectionMeanProton", 0.000f, "Offset for TPC PID mean for protons"}; + Configurable pidnSigmaPreSelectionMeanTOFPion{"pidnSigmaPreSelectionMeanTOFPion", 0.000f, "Offset for TOF PID mean for pions"}; + Configurable pidnSigmaPreSelectionMeanTOFKaon{"pidnSigmaPreSelectionMeanTOFKaon", 0.000f, "Offset for TOF PID mean for kaons"}; + Configurable pidnSigmaPreSelectionMeanTOFProton{"pidnSigmaPreSelectionMeanTOFProton", 0.000f, "Offset for TOF PID mean for protons"}; + Configurable cfgUseTOFPIDPreSelection{"cfgUseTOFPIDPreSelection", false, + "Apply the TOF PID cut to tracks with TOF; false ignores TOF PID, and tracks without TOF use TPC only"}; Configurable trackSelection{"trackSelection", 3, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; - Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 2.0, "Track DCAr cut to PV Maximum"}; - Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; - Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5f, "Track DCAr cut to PV Maximum"}; + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 1.0f, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0f, "Track DCAz cut to PV Minimum"}; Configurable cfgApplyTightDCAPtDepSelection{"cfgApplyTightDCAPtDepSelection", true, "Apply the pT-dependent tight DCA selection"}; Configurable cfgTightDCAOffset{"cfgTightDCAOffset", 0.004f, "Constant term of the tight DCA threshold (cm)"}; Configurable cfgTightDCAPtCoefficient{"cfgTightDCAPtCoefficient", 0.013f, "Coefficient of the pT-dependent tight DCA threshold"}; Configurable cfgTightDCAPtPower{"cfgTightDCAPtPower", 1.f, "Power in tight DCA = offset + coefficient / pT^power"}; } TrackCuts; - // V0 and V0-daughter cuts + // V0 and V0-daughter cuts : based on loose cuts in V0s production analysis in pp 13.6 TeV struct : ConfigurableGroup { + Configurable mincrossedrowsV0s{"mincrossedrowsV0s", 70, "Minimum crossed rows for V0 daughter tracks"}; Configurable cMinV0PosDCArToPVcut{"cMinV0PosDCArToPVcut", 0.05f, "V0 Positive Track DCAr cut to PV Minimum"}; Configurable cMinV0NegDCArToPVcut{"cMinV0NegDCArToPVcut", 0.05f, "V0 Negative Track DCAr cut to PV Minimum"}; - Configurable cMinV0Radius{"cMinV0Radius", 0.0, "Minimum V0 radius from PV"}; - Configurable cMaxV0Radius{"cMaxV0Radius", 200.0, "Maximum V0 radius from PV"}; - Configurable cMinV0CosPA{"cMinV0CosPA", 0.995, "Minimum V0 CosPA to PV"}; + Configurable cMinV0Radius{"cMinV0Radius", 0.9f, "Minimum V0 radius from PV"}; + Configurable cMaxV0Radius{"cMaxV0Radius", 200.0f, "Maximum V0 radius from PV"}; + Configurable cMinV0CosPA{"cMinV0CosPA", 0.95f, "Minimum V0 CosPA to PV"}; } V0Cuts; - // Cascade and cascade-daughter cuts + // Additional K0s and Lambda0 selections not covered by V0Cuts: based on loose cuts in V0s production analysis in pp 13.6 TeV struct : ConfigurableGroup { - Configurable cfgMinCrossedRowsCascBach{"cfgMinCrossedRowsCascBach", 70, "min crossed rows for bachelor track from cascade"}; - Configurable cMinCascBachDCArToPVcut{"cMinCascBachDCArToPVcut", 0.05f, "Cascade Bachelor Track DCAr cut to PV Minimum"}; - Configurable cMaxCascBachDCArToPVcut{"cMaxCascBachDCArToPVcut", 999.0f, "Cascade Bachelor Track DCAr cut to PV Maximum"}; - Configurable cMaxCascDCAV0Daughters{"cMaxCascDCAV0Daughters", 1.6, "Cascade DCA between V0 daughters Maximum"}; - Configurable cMaxCascDCACascDaughters{"cMaxCascDCACascDaughters", 1.6, "Cascade DCA between Casc daughters Maximum"}; - Configurable cMinCascV0CosPA{"cMinCascV0CosPA", 0.97, "Minimum Cascade V0 CosPA to PV"}; - Configurable cMaxCascV0Radius{"cMaxCascV0Radius", 200.0, "Maximum Cascade V0 radius from PV"}; - Configurable cMinCascV0Radius{"cMinCascV0Radius", 0.0, "Minimum Cascade V0 radius from PV"}; - Configurable cMinCascRadius{"cMinCascRadius", 0.0, "Minimum Cascade radius from PV"}; - Configurable cMaxCascRadius{"cMaxCascRadius", 200.0, "Maximum Cascade radius from PV"}; - Configurable cMinCascCosPA{"cMinCascCosPA", 0.97, "Minimum Cascade CosPA to PV"}; - Configurable cCascMassResol{"cCascMassResol", 999, "Cascade mass resolution"}; + Configurable cfgSecondaryRequire{"cfgSecondaryRequire", true, "Secondary cuts on/off"}; + Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", false, "cut on Armenteros-Podolanski graph"}; + Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", false, "Bypass TPC PID preselection for V0 daughters"}; + Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 1.0f, "Maximum DCA between V0 daughters"}; + Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.0f, "Minimum transverse momentum of Secondary"}; + Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.5f, "Maximum rapidity of Secondary"}; + Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4f, "Maximum DCA Secondary to PV"}; + Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 40.f, "Maximum Secondary Lifetime"}; + Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2f, "parameter for Armenteros Cut"}; + Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03f, "Secondary inv mass selection window (GeV/c^2)"}; + Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.02f, "Secondary inv mass selection window with (anti)lambda hypothesis (GeV/c^2)"}; + } SecondaryCuts; + + // Cascade and cascade-daughter cuts: based on loose cuts in cascades production analysis in pp 13.6 TeV + struct : ConfigurableGroup { + Configurable cfgMinCrossedRowsCascBach{"cfgMinCrossedRowsCascBach", 50, "min crossed rows for bachelor track from cascade"}; + Configurable cMinCascBachDCArToPVcut{"cMinCascBachDCArToPVcut", 0.05f, "Cascade Bachelor Track DCAr cut to PV Minimum"}; + Configurable cMaxCascBachDCArToPVcut{"cMaxCascBachDCArToPVcut", 200.0f, "Cascade Bachelor Track DCAr cut to PV Maximum"}; + Configurable cMaxCascDCAV0Daughters{"cMaxCascDCAV0Daughters", 0.5f, "Cascade DCA between V0 daughters Maximum"}; + Configurable cMaxCascDCACascDaughters{"cMaxCascDCACascDaughters", 1.2f, "Cascade DCA between Casc daughters Maximum"}; + Configurable cMinCascV0CosPA{"cMinCascV0CosPA", 0.98f, "Minimum Cascade V0 CosPA to PV"}; + Configurable cMaxCascV0Radius{"cMaxCascV0Radius", 200.0f, "Maximum Cascade V0 radius from PV"}; + Configurable cMinCascV0Radius{"cMinCascV0Radius", 0.4f, "Minimum Cascade V0 radius from PV"}; + Configurable cMinCascRadius{"cMinCascRadius", 0.4f, "Minimum Cascade radius from PV"}; + Configurable cMaxCascRadius{"cMaxCascRadius", 200.0f, "Maximum Cascade radius from PV"}; + Configurable cMinCascCosPA{"cMinCascCosPA", 0.99, "Minimum Cascade CosPA to PV"}; + Configurable cMaxXiMassWindow{"cMaxXiMassWindow", 0.02f, "Xi mass Window (GeV/c^2)"}; } CascadeCuts; // Derived dataset selections struct : ConfigurableGroup { - Configurable cfgFillPionTracks{"cfgFillPionTracks", false, "Fill pion tracks"}; - Configurable cfgFillKaonTracks{"cfgFillKaonTracks", false, "Fill kaon tracks"}; - Configurable cfgFillProtonTracks{"cfgFillProtonTracks", false, "Fill proton tracks"}; - Configurable cfgFillPionMicroTracks{"cfgFillPionMicroTracks", false, "Fill pion micro tracks"}; - Configurable cfgFillKaonMicroTracks{"cfgFillKaonMicroTracks", false, "Fill kaon micro tracks"}; - Configurable cfgFillProtonMicroTracks{"cfgFillProtonMicroTracks", false, "Fill proton micro tracks"}; - Configurable cfgFillPionUltraMicroTracks{"cfgFillPionUltraMicroTracks", true, "Fill pion ultra micro tracks"}; - Configurable cfgFillKaonUltraMicroTracks{"cfgFillKaonUltraMicroTracks", false, "Fill kaon ultra micro tracks"}; - Configurable cfgFillProtonUltraMicroTracks{"cfgFillProtonUltraMicroTracks", false, "Fill proton ultra micro tracks"}; - Configurable cfgFillK0s{"cfgFillK0s", false, "Fill K0s"}; - Configurable cfgFillLambda0{"cfgFillLambda0", false, "Fill Lambda0"}; - Configurable cfgBypassNoPairV0s{"cfgBypassNoPairV0s", false, "In a *WithPairGate process, bypass track fill if no V0 passes the configured selections"}; - Configurable cfgBypassNoPairCascades{"cfgBypassNoPairCascades", true, "In a *WithPairGate process, bypass track fill if no cascade passes the configured selections"}; + Configurable cfgFillPionTracks{"cfgFillPionTracks", false, "Apply the pion PID filter to every enabled track table"}; + Configurable cfgFillKaonTracks{"cfgFillKaonTracks", false, "Apply the kaon PID filter to every enabled track table"}; + Configurable cfgFillProtonTracks{"cfgFillProtonTracks", false, "Apply the proton PID filter to every enabled track table"}; + Configurable cfgFillK0s{"cfgFillK0s", true, "Fill K0s"}; + Configurable cfgFillLambda0{"cfgFillLambda0", true, "Fill Lambda0"}; + Configurable cfgPairGateMode{"cfgPairGateMode", 0, + "Combined *WithPairGate mode: 0 -> require every enabled candidate type, " + "1 -> require a selected V0 or cascade"}; + Configurable cfgBypassNoPairV0s{"cfgBypassNoPairV0s", false, + "Require a selected V0 and at least one selected collision track in pair-gate mode 0"}; + Configurable cfgBypassNoPairCascades{"cfgBypassNoPairCascades", true, + "Require a selected cascade and at least one selected collision track in pair-gate mode 0"}; + Configurable cfgGlobalDaughterVeto{"cfgGlobalDaughterVeto", false, + "Pair-gate callbacks only: reject a track if its original ID is a daughter " + "of any selected V0 or cascade; false stores all selected collision tracks " + "for mandatory candidate-local rejection through trackId"}; Configurable cfgFillMicroTracks{"cfgFillMicroTracks", false, "Fill micro tracks"}; Configurable cfgFillUltraMicroTracks{"cfgFillUltraMicroTracks", false, "Fill ultra micro tracks"}; Configurable cfgBypassTrackFill{"cfgBypassTrackFill", false, "Bypass the full ResoTracks table fill"}; - Configurable cfgBypassTrackIndexFill{"cfgBypassTrackIndexFill", false, "Bypass original daughter ID table fill"}; + Configurable cfgBypassTrackIndexFill{"cfgBypassTrackIndexFill", false, + "Bypass optional source-object soft-link side tables; " + "ResoMicroTracks_001 keeps its inline scalar trackId, but Full/Ultra " + "outputs then cannot perform candidate-local daughter rejection"}; } FilterForDerivedTables; - // Secondary selections for K0s and Lambda0 - struct : ConfigurableGroup { - Configurable cfgSecondaryRequire{"cfgSecondaryRequire", false, "Secondary cuts on/off"}; - Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", false, "cut on Armenteros-Podolanski graph"}; - Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; - Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass TPC PID preselection for V0 daughters"}; - Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 0.2, "Maximum DCA Secondary daughters to PV"}; - Configurable cfgSecondaryDauPosDCAtoPVMin{"cfgSecondaryDauPosDCAtoPVMin", 0.0, "Minimum DCA Secondary positive daughters to PV"}; - Configurable cfgSecondaryDauNegDCAtoPVMin{"cfgSecondaryDauNegDCAtoPVMin", 0.0, "Minimum DCA Secondary negative daughters to PV"}; - Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; - Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.5, "Maximum rapidity of Secondary"}; - Configurable cfgSecondaryRadiusMin{"cfgSecondaryRadiusMin", 0.0, "Minimum transverse radius of Secondary"}; - Configurable cfgSecondaryRadiusMax{"cfgSecondaryRadiusMax", 999.9, "Maximum transverse radius of Secondary"}; - Configurable cfgSecondaryCosPAMin{"cfgSecondaryCosPAMin", 0.998, "Mininum cosine pointing angle of Secondary"}; - Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4, "Maximum DCA Secondary to PV"}; - Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 20., "Maximum Secondary Lifetime"}; - Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2, "parameter for Armenteros Cut"}; - Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03, "Secondary inv mass selection window"}; - Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.05, "Secondary inv mass selection window with (anti)lambda hypothesis"}; - } SecondaryCuts; - // Track selection filter based on configuration Filter trackFilter = (TrackCuts.trackSelection.node() == TrackSelectionNone) || ((TrackCuts.trackSelection.node() == TrackSelectionGlobal) && requireGlobalTrackInFilter()) || // kGlobalTrack = kQualityTracks | kPrimaryTracks | kInAcceptanceTracks @@ -698,11 +1239,17 @@ struct ResonanceDaughterInitializer { aod::track::pt <= TrackCuts.cfgCutMaxPt; HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - // The daughter task needs this row-wise mapping back to the original collision. - // Keep ResonanceModuleInitializer::cfgBypassCollIndexFill disabled and enable - // the matching Run 2/Run 3 base event process for MC workflows. - using ResoCollisionWithIndex = soa::Join; - using SelectedResoCollisions = soa::Join; + // The daughter task treats fIndexResoCollisions as a scalar v001 row ID. The + // data-model relation keeps its legacy v000 default target; v001 consumers + // must use resoCollision_as() with the exact bound v001 table type for + // dereferencing (aod::ResoCollisions_001 when the parent is not joined). + // Original-collision grouping is provided by the scalar-only version-1 + // ResoCollisionGroups_001 table, avoiding a hard source-AO2D relation. + // Collision mappings are always written; cfgBypassCollIndexFill is retained + // only so existing configuration files remain accepted. + using ResoCollisionWithIndex = soa::Join; + using SelectedResoCollisions = soa::Join; + PresliceUnsorted reducedCollisionsPerOriginalCollision = aod::resocollisiongroup001::originalCollisionId; /** * @brief Initializes the task @@ -711,36 +1258,107 @@ struct ResonanceDaughterInitializer { */ void init(InitContext&) { - const bool processTrackDataEnabled = doprocessData || doprocessDataHybrid || doprocessDataWithPairGate; - const bool processTrackMCEnabled = doprocessMC || doprocessMCWithPairGate; - const bool processV0DataEnabled = doprocessV0Data || doprocessV0DataHybrid; - const bool processCascDataEnabled = doprocessCascData || doprocessCascDataHybrid; + if (FilterForDerivedTables.cfgPairGateMode.value < PairGateModeConfigured || + FilterForDerivedTables.cfgPairGateMode.value > PairGateModeEither) { + LOGF(fatal, "cfgPairGateMode must be 0 (configured gates) or 1 (V0 or cascade)"); + } + const bool useEitherPairGate = FilterForDerivedTables.cfgPairGateMode.value == PairGateModeEither; + const bool processTrackDataEnabled = doprocessData || doprocessDataHybrid || doprocessDataWithPairGate || + doprocessDataWithV0PairGate || doprocessDataWithCascPairGate; + const bool processTrackMCEnabled = doprocessMC || doprocessMCWithPairGate || + doprocessMCWithV0PairGate || doprocessMCWithCascPairGate; + const bool pairTrackProcessEnabled = doprocessDataWithPairGate || doprocessDataWithV0PairGate || + doprocessDataWithCascPairGate || doprocessMCWithPairGate || + doprocessMCWithV0PairGate || doprocessMCWithCascPairGate; + const bool processV0DataEnabled = doprocessV0Data; + const bool processCascDataEnabled = doprocessCascData; + const bool anyDataProcessEnabled = processTrackDataEnabled || processV0DataEnabled || processCascDataEnabled; + const bool anyMCProcessEnabled = processTrackMCEnabled || doprocessV0MC || doprocessCascMC; const int enabledTrackProcesses = static_cast(doprocessData) + static_cast(doprocessDataHybrid) + static_cast(doprocessDataWithPairGate) + + static_cast(doprocessDataWithV0PairGate) + + static_cast(doprocessDataWithCascPairGate) + static_cast(doprocessMC) + - static_cast(doprocessMCWithPairGate); + static_cast(doprocessMCWithPairGate) + + static_cast(doprocessMCWithV0PairGate) + + static_cast(doprocessMCWithCascPairGate); if (enabledTrackProcesses > 1) { LOGF(fatal, "Only one track process can be enabled in ResonanceDaughterInitializer"); } - if (static_cast(doprocessV0Data) + static_cast(doprocessV0DataHybrid) + static_cast(doprocessV0MC) > 1) { + if (pairTrackProcessEnabled && + FilterForDerivedTables.cfgBypassTrackFill && + !FilterForDerivedTables.cfgFillMicroTracks && + !FilterForDerivedTables.cfgFillUltraMicroTracks) { + LOGF(fatal, "A pair-gate process requires at least one enabled Full, Micro, or UltraMicro track output"); + } + if (pairTrackProcessEnabled && !FilterForDerivedTables.cfgGlobalDaughterVeto && + FilterForDerivedTables.cfgBypassTrackIndexFill && + (!FilterForDerivedTables.cfgBypassTrackFill || FilterForDerivedTables.cfgFillUltraMicroTracks)) { + LOGF(warn, + "Default pair-gate mode defers daughter reuse rejection to analysis trackId comparisons, " + "but cfgBypassTrackIndexFill removes that ID from Full/Ultra track outputs"); + } + if (useEitherPairGate && + (doprocessDataWithV0PairGate || doprocessDataWithCascPairGate || + doprocessMCWithV0PairGate || doprocessMCWithCascPairGate)) { + LOGF(fatal, "cfgPairGateMode 1 requires the combined processDataWithPairGate or processMCWithPairGate callback"); + } + if (static_cast(doprocessV0Data) + static_cast(doprocessV0MC) > 1) { LOGF(fatal, "Only one V0 process can be enabled in ResonanceDaughterInitializer"); } - if (static_cast(doprocessCascData) + static_cast(doprocessCascDataHybrid) + static_cast(doprocessCascMC) > 1) { + if (static_cast(doprocessCascData) + static_cast(doprocessCascMC) > 1) { LOGF(fatal, "Only one cascade process can be enabled in ResonanceDaughterInitializer"); } if ((doprocessData || doprocessDataHybrid || doprocessMC) && - (FilterForDerivedTables.cfgBypassNoPairV0s || FilterForDerivedTables.cfgBypassNoPairCascades)) { + (useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairV0s || FilterForDerivedTables.cfgBypassNoPairCascades || + FilterForDerivedTables.cfgGlobalDaughterVeto)) { LOGF(warn, "Pair-gate options are ignored by processData/processDataHybrid/processMC; enable the matching *WithPairGate process to apply them"); } - if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairV0s && !processV0DataEnabled) { - LOGF(fatal, "cfgBypassNoPairV0s requires processV0Data or processV0DataHybrid so an accepted V0 is written for every retained collision"); - } - if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairCascades && !processCascDataEnabled) { - LOGF(fatal, "cfgBypassNoPairCascades requires processCascData or processCascDataHybrid so an accepted cascade is written for every retained collision"); + const auto validatePairGateOutputs = [&](bool pairProcessEnabled, + bool v0OutputEnabled, + bool cascadeOutputEnabled, + char const* processName) { + if (!pairProcessEnabled) { + return; + } + if (useEitherPairGate) { + if (!v0OutputEnabled || !cascadeOutputEnabled) { + LOGF(fatal, "%s with pair-gate mode 1 requires both V0 and cascade output processes", processName); + } + } else { + if (!FilterForDerivedTables.cfgBypassNoPairV0s && !FilterForDerivedTables.cfgBypassNoPairCascades) { + LOGF(fatal, "%s with pair-gate mode 0 requires at least one enabled V0/cascade gate", processName); + } + if (FilterForDerivedTables.cfgBypassNoPairV0s && !v0OutputEnabled) { + LOGF(fatal, "%s requires a V0 output process when cfgBypassNoPairV0s is enabled", processName); + } + if (FilterForDerivedTables.cfgBypassNoPairCascades && !cascadeOutputEnabled) { + LOGF(fatal, "%s requires a cascade output process when cfgBypassNoPairCascades is enabled", processName); + } + } + }; + validatePairGateOutputs(doprocessDataWithPairGate, + processV0DataEnabled, + processCascDataEnabled, + "processDataWithPairGate"); + validatePairGateOutputs(doprocessMCWithPairGate, + doprocessV0MC, + doprocessCascMC, + "processMCWithPairGate"); + if (doprocessDataWithV0PairGate && !processV0DataEnabled) { + LOGF(fatal, "processDataWithV0PairGate requires processV0Data"); + } + if (doprocessDataWithCascPairGate && !processCascDataEnabled) { + LOGF(fatal, "processDataWithCascPairGate requires processCascData"); + } + if (doprocessMCWithV0PairGate && !doprocessV0MC) { + LOGF(fatal, "processMCWithV0PairGate requires processV0MC"); + } + if (doprocessMCWithCascPairGate && !doprocessCascMC) { + LOGF(fatal, "processMCWithCascPairGate requires processCascMC"); } - if (!std::isfinite(TrackCuts.cfgCutMinPt.value) || !std::isfinite(TrackCuts.cfgCutMaxPt.value) || TrackCuts.cfgCutMinPt.value < 0.f || @@ -765,7 +1383,28 @@ struct ResonanceDaughterInitializer { TrackCuts.pidnSigmaPreSelectionCut.value < 0.f) { LOGF(fatal, "pidnSigmaPreSelectionCut must be finite and non-negative"); } - + const std::array tpcPidMeans{TrackCuts.pidnSigmaPreSelectionMeanPion.value, + TrackCuts.pidnSigmaPreSelectionMeanKaon.value, + TrackCuts.pidnSigmaPreSelectionMeanProton.value}; + if (!std::all_of(tpcPidMeans.begin(), tpcPidMeans.end(), [](float mean) { + return std::isfinite(mean); + })) { + LOGF(fatal, "All TPC PID preselection means must be finite"); + } + if (TrackCuts.cfgUseTOFPIDPreSelection.value) { + if (!std::isfinite(TrackCuts.pidnSigmaPreSelectionCutTOF.value) || + TrackCuts.pidnSigmaPreSelectionCutTOF.value < 0.f) { + LOGF(fatal, "pidnSigmaPreSelectionCutTOF must be finite and non-negative when TOF PID selection is enabled"); + } + const std::array tofPidMeans{TrackCuts.pidnSigmaPreSelectionMeanTOFPion.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFKaon.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFProton.value}; + if (!std::all_of(tofPidMeans.begin(), tofPidMeans.end(), [](float mean) { + return std::isfinite(mean); + })) { + LOGF(fatal, "All TOF PID preselection means must be finite when TOF PID selection is enabled"); + } + } if (TrackCuts.cfgApplyTightDCAPtDepSelection.value && (!std::isfinite(TrackCuts.cfgTightDCAOffset.value) || !std::isfinite(TrackCuts.cfgTightDCAPtCoefficient.value) || @@ -775,28 +1414,38 @@ struct ResonanceDaughterInitializer { TrackCuts.cfgTightDCAPtPower.value < 0.f)) { LOGF(fatal, "Tight-DCA offset, pT coefficient, and power must be finite and non-negative"); } - + if (!std::isfinite(V0Cuts.cMinV0CosPA.value) || + V0Cuts.cMinV0CosPA.value < -1. || V0Cuts.cMinV0CosPA.value >= 1.) { + LOGF(fatal, "cMinV0CosPA must be finite and satisfy -1 <= cMinV0CosPA < 1"); + } + if (!std::isfinite(CascadeCuts.cMinCascCosPA.value) || + CascadeCuts.cMinCascCosPA.value < -1. || CascadeCuts.cMinCascCosPA.value >= 1.) { + LOGF(fatal, "cMinCascCosPA must be finite and satisfy -1 <= cMinCascCosPA < 1"); + } + if (!std::isfinite(CascadeCuts.cMinCascRadius.value) || + !std::isfinite(CascadeCuts.cMaxCascRadius.value) || + CascadeCuts.cMinCascRadius.value < 0. || + CascadeCuts.cMaxCascRadius.value <= CascadeCuts.cMinCascRadius.value) { + LOGF(fatal, "Cascade radius limits must be finite and satisfy 0 <= cMinCascRadius < cMaxCascRadius"); + } if (FilterForDerivedTables.cfgFillUltraMicroTracks) { - constexpr float MaxQuantizedMomentum = static_cast(std::numeric_limits::max()) / MomentumQuantizationScale; - const float maxLongitudinalMomentum = TrackCuts.cfgCutMaxPt.value * std::sinh(TrackCuts.cfgCutEta.value); - if (TrackCuts.cfgCutMaxPt.value > MaxQuantizedMomentum || - !std::isfinite(maxLongitudinalMomentum) || - maxLongitudinalMomentum > MaxQuantizedMomentum) { - LOGF(fatal, "Ultra-micro cfgCutMaxPt/cfgCutEta allow momentum components beyond the int16_t quantization range"); - } int enabledUltraMicroSpecies = 0; - enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillPionUltraMicroTracks ? 1 : 0; - enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillKaonUltraMicroTracks ? 1 : 0; - enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillProtonUltraMicroTracks ? 1 : 0; + enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillPionTracks ? 1 : 0; + enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillKaonTracks ? 1 : 0; + enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillProtonTracks ? 1 : 0; if (enabledUltraMicroSpecies != 1) { - LOGF(fatal, "Exactly one pion/kaon/proton PID species must be enabled when filling ultra-micro tracks"); + LOGF(fatal, "Exactly one of cfgFillPionTracks, cfgFillKaonTracks, or cfgFillProtonTracks must be enabled when filling ultra-micro tracks"); } if (TrackCuts.pidnSigmaPreSelectionCut.value > o2::aod::resoultramicrodaughter::PidNSigma::MaxNSigma) { - LOGF(fatal, "Ultra-micro PID encoding requires pidnSigmaPreSelectionCut <= 5"); + LOGF(fatal, "Ultra-micro TPC PID encoding requires pidnSigmaPreSelectionCut <= 5"); } - if (FilterForDerivedTables.cfgFillKaonUltraMicroTracks) { + if (TrackCuts.cfgUseTOFPIDPreSelection.value && + TrackCuts.pidnSigmaPreSelectionCutTOF.value > o2::aod::resoultramicrodaughter::PidNSigma::MaxNSigma) { + LOGF(fatal, "Ultra-micro TOF PID encoding requires pidnSigmaPreSelectionCutTOF <= 5"); + } + if (FilterForDerivedTables.cfgFillKaonTracks) { ultraMicroPidSpecies = UltraMicroPidSpecies::Kaon; - } else if (FilterForDerivedTables.cfgFillProtonUltraMicroTracks) { + } else if (FilterForDerivedTables.cfgFillProtonTracks) { ultraMicroPidSpecies = UltraMicroPidSpecies::Proton; } else { ultraMicroPidSpecies = UltraMicroPidSpecies::Pion; @@ -804,29 +1453,14 @@ struct ResonanceDaughterInitializer { } if (cfgFillQA) { - AxisSpec idxAxis = {8, 0.0, 8.0, "Index"}; + AxisSpec idxAxis = {8, 0.0, 8.0, "Cumulative selection stage"}; AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; - // The DCA maps cover the full configured pT range in 0.1 GeV/c steps. - constexpr float DcaPtBinWidth = 0.1f; - const int maxDcaPtBin = static_cast(std::ceil(TrackCuts.cfgCutMaxPt.value / DcaPtBinWidth)); - const int nDcaPtBins = maxDcaPtBin + 1; - const float dcaPtAxisHalfBin = 0.5f * DcaPtBinWidth; - AxisSpec dcaPtAxis = {nDcaPtBins, - -dcaPtAxisHalfBin, - maxDcaPtBin * DcaPtBinWidth + dcaPtAxisHalfBin, - "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec dcaPtAxis = {300, 0.f, 30.f, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec etaAxis = {100, -1.0f, 1.0f, "#eta"}; - AxisSpec phiAxis = {100, 0.0f, TwoPI, "#phi"}; - // Keep the configured signed DCA limits at bin centres so tracks exactly - // on an accepted selection boundary are not moved to overflow. - constexpr int NDcaBins = 201; - constexpr float DcaAxisPaddingFraction = 1.f / 200.f; - const auto configuredDcaXYMax = static_cast(TrackCuts.cMaxDCArToPVcut.value); - const auto configuredDcaZMax = static_cast(TrackCuts.cMaxDCAzToPVcut.value); - const float dcaXYAxisHalfRange = configuredDcaXYMax > 0.f ? configuredDcaXYMax * (1.f + DcaAxisPaddingFraction) : 1.e-4f; - const float dcaZAxisHalfRange = configuredDcaZMax > 0.f ? configuredDcaZMax * (1.f + DcaAxisPaddingFraction) : 1.e-4f; - AxisSpec dcaXYAxis = {NDcaBins, -dcaXYAxisHalfRange, dcaXYAxisHalfRange, "DCA_{xy} (cm)"}; - AxisSpec dcaZAxis = {NDcaBins, -dcaZAxisHalfRange, dcaZAxisHalfRange, "DCA_{z} (cm)"}; + // Keep the azimuthal QA bins aligned with the 18 TPC sectors (10 bins per sector). + AxisSpec phiAxis = {180, 0.0f, TwoPI, "#phi"}; + AxisSpec dcaXYAxis = {1000, -0.5, 0.5, "DCA_{xy} (cm)"}; + AxisSpec dcaZAxis = {1000, -0.5, 0.5, "DCA_{z} (cm)"}; // Tiny PID has 255 discrete values from -6.35 to 6.35 in 0.05 steps. // Extend the histogram limits by half a step so every decoded value is // located at a bin centre instead of on a floating-point bin boundary. @@ -845,28 +1479,34 @@ struct ResonanceDaughterInitializer { if (processTrackDataEnabled || processTrackMCEnabled) { qaRegistry.add("QA/hGoodTrackIndices", "hGoodTrackIndices", kTH1D, {idxAxis}); + auto trackSelection = qaRegistry.get(HIST("QA/hGoodTrackIndices")); + trackSelection->GetXaxis()->SetBinLabel(1, "Before DCA cuts"); + trackSelection->GetXaxis()->SetBinLabel(2, "Finite DCA, |DCA_{xy}| #leq max"); + trackSelection->GetXaxis()->SetBinLabel(3, "min #leq |DCA_{z}| #leq max"); + trackSelection->GetXaxis()->SetBinLabel(8, "Pass DCA selection"); if (processTrackMCEnabled) { qaRegistry.add("QA/hGoodMCTrackIndices", "hGoodMCTrackIndices", kTH1D, {idxAxis}); + qaRegistry.get(HIST("QA/hGoodMCTrackIndices"))->GetXaxis()->SetBinLabel(1, "MC path: before DCA cuts"); } if (cfgDetailTrackQA) { if (!FilterForDerivedTables.cfgBypassTrackFill) { - qaRegistry.add("QA/h4TrackPtEtaPhi", "ResoTracks pT, eta, phi", kTH3F, {ptAxis, etaAxis, phiAxis}); - qaRegistry.add("QA/h2TrackDCAxyVsPt", "ResoTracks DCAxy vs pT", kTH2F, {dcaPtAxis, dcaXYAxis}); - qaRegistry.add("QA/h2TrackDCAzVsPt", "ResoTracks DCAz vs pT", kTH2F, {dcaPtAxis, dcaZAxis}); + qaRegistry.add("QA/h4TrackPtEtaPhi", "ResoTracks pT, eta, phi", kTHnSparseD, {ptAxis, etaAxis, phiAxis}); + qaRegistry.add("QA/h2TrackDCAxyVsPt", "ResoTracks DCAxy vs pT", kTH2D, {dcaPtAxis, dcaXYAxis}); + qaRegistry.add("QA/h2TrackDCAzVsPt", "ResoTracks DCAz vs pT", kTH2D, {dcaPtAxis, dcaZAxis}); qaRegistry.add("QA/h4TrackTPCnSigma", "ResoTracks TPC nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTPCAxis, nSigmaTPCAxis, nSigmaTPCAxis}); qaRegistry.add("QA/h4TrackTOFnSigma", "ResoTracks TOF nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTOFAxis, nSigmaTOFAxis, nSigmaTOFAxis}); } if (FilterForDerivedTables.cfgFillMicroTracks) { - qaRegistry.add("QA/h4MicroTrackPtEtaPhi", "ResoMicroTracks pT, eta, phi", kTH3F, {ptAxis, etaAxis, phiAxis}); - qaRegistry.add("QA/h2MicroTrackDCAxyVsPt", "ResoMicroTracks DCAxy vs pT", kTH2F, {dcaPtAxis, dcaXYAxis}); - qaRegistry.add("QA/h2MicroTrackDCAzVsPt", "ResoMicroTracks DCAz vs pT", kTH2F, {dcaPtAxis, dcaZAxis}); + qaRegistry.add("QA/h4MicroTrackPtEtaPhi", "ResoMicroTracks pT, eta, phi", kTHnSparseD, {ptAxis, etaAxis, phiAxis}); + qaRegistry.add("QA/h2MicroTrackDCAxyVsPt", "ResoMicroTracks DCAxy vs pT", kTH2D, {dcaPtAxis, dcaXYAxis}); + qaRegistry.add("QA/h2MicroTrackDCAzVsPt", "ResoMicroTracks DCAz vs pT", kTH2D, {dcaPtAxis, dcaZAxis}); qaRegistry.add("QA/h4MicroTrackTPCnSigma", "ResoMicroTracks TPC nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTPCAxis, nSigmaTPCAxis, nSigmaTPCAxis}); qaRegistry.add("QA/h4MicroTrackTOFnSigma", "ResoMicroTracks TOF nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTOFAxis, nSigmaTOFAxis, nSigmaTOFAxis}); } if (FilterForDerivedTables.cfgFillUltraMicroTracks) { - qaRegistry.add("QA/h4UltraMicroTrackPtEtaPhi", "ResoUltraMicroTracks pT, eta, phi", kTH3F, {ptAxis, etaAxis, phiAxis}); - qaRegistry.add("QA/h2UltraMicroTrackDCAxyVsPt", "ResoUltraMicroTracks DCAxy vs pT", kTH2F, {dcaPtAxis, dcaXYAxis}); - qaRegistry.add("QA/h2UltraMicroTrackDCAzVsPt", "ResoUltraMicroTracks DCAz vs pT", kTH2F, {dcaPtAxis, dcaZAxis}); + qaRegistry.add("QA/h4UltraMicroTrackPtEtaPhi", "ResoUltraMicroTracks pT, eta, phi", kTHnSparseD, {ptAxis, etaAxis, phiAxis}); + qaRegistry.add("QA/h2UltraMicroTrackDCAxyVsPt", "ResoUltraMicroTracks DCAxy vs pT", kTH2D, {dcaPtAxis, dcaXYAxis}); + qaRegistry.add("QA/h2UltraMicroTrackDCAzVsPt", "ResoUltraMicroTracks DCAz vs pT", kTH2D, {dcaPtAxis, dcaZAxis}); qaRegistry.add("QA/h4UltraMicroTrackTPCnSigma", "ResoUltraMicroTracks TPC nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTPCAxis, nSigmaTPCAxis, nSigmaTPCAxis}); qaRegistry.add("QA/h4UltraMicroTrackTOFnSigma", "ResoUltraMicroTracks TOF nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTOFAxis, nSigmaTOFAxis, nSigmaTOFAxis}); } @@ -875,24 +1515,33 @@ struct ResonanceDaughterInitializer { if (processV0DataEnabled || doprocessV0MC) { qaRegistry.add("QA/hGoodV0Indices", "hGoodV0Indices", kTH1D, {idxAxis}); + auto v0Selection = qaRegistry.get(HIST("QA/hGoodV0Indices")); + v0Selection->GetXaxis()->SetBinLabel(1, "Before V0 cuts"); + v0Selection->GetXaxis()->SetBinLabel(2, "Daughter TPC rows"); + v0Selection->GetXaxis()->SetBinLabel(3, "Daughter |DCA_{xy}| to PV"); + v0Selection->GetXaxis()->SetBinLabel(4, "V0 radius window"); + v0Selection->GetXaxis()->SetBinLabel(5, "V0 cosPA cut passed"); if (doprocessV0MC) { qaRegistry.add("QA/hGoodMCV0Indices", "hGoodMCV0Indices", kTH1D, {idxAxis}); + qaRegistry.get(HIST("QA/hGoodMCV0Indices"))->GetXaxis()->SetBinLabel(1, "Reco V0 cuts passed (MC)"); } - AxisSpec radiusAxis = {100, 0.0, 200.0, "V0 Radius"}; - AxisSpec cosPAAxis = {100, 0.995, 1.0, "V0 CosPA"}; - qaRegistry.add("QA/hV0Radius", "V0 Radius", kTH1F, {radiusAxis}); - qaRegistry.add("QA/hV0CosPA", "V0 CosPA", kTH1F, {cosPAAxis}); } if (processCascDataEnabled || doprocessCascMC) { - AxisSpec radiusAxis = {100, 0.0, 200.0, "Cascade Radius"}; - AxisSpec cosPAAxis = {100, 0.97, 1.0, "Cascade CosPA"}; qaRegistry.add("QA/hGoodCascIndices", "hGoodCascIndices", kTH1D, {idxAxis}); + auto cascadeSelection = qaRegistry.get(HIST("QA/hGoodCascIndices")); + cascadeSelection->GetXaxis()->SetBinLabel(1, "Before cascade cuts"); + cascadeSelection->GetXaxis()->SetBinLabel(2, "Bachelor TPC rows"); + cascadeSelection->GetXaxis()->SetBinLabel(3, "Bachelor DCA_{xy} window"); + cascadeSelection->GetXaxis()->SetBinLabel(4, "V0/cascade daughter DCA"); + cascadeSelection->GetXaxis()->SetBinLabel(5, "Cascade/V0 cosPA"); + cascadeSelection->GetXaxis()->SetBinLabel(6, "V0 radius window"); + cascadeSelection->GetXaxis()->SetBinLabel(7, "Cascade radius window"); + cascadeSelection->GetXaxis()->SetBinLabel(8, "#Xi mass window"); if (doprocessCascMC) { qaRegistry.add("QA/hGoodMCCascIndices", "hGoodMCCascIndices", kTH1D, {idxAxis}); + qaRegistry.get(HIST("QA/hGoodMCCascIndices"))->GetXaxis()->SetBinLabel(1, "Reco cascade cuts passed (MC)"); } - qaRegistry.add("QA/hCascRadius", "Cascade Radius", kTH1F, {radiusAxis}); - qaRegistry.add("QA/hCascCosPA", "Cascade CosPA", kTH1F, {cosPAAxis}); } } if (processTrackDataEnabled || processTrackMCEnabled) { @@ -905,52 +1554,29 @@ struct ResonanceDaughterInitializer { LOGF(info, "ResonanceDaughterInitializer initialized with cascades"); } - // Check if the module is initialized with both data and MC - if ((processTrackDataEnabled && processTrackMCEnabled) || (processV0DataEnabled && doprocessV0MC) || (processCascDataEnabled && doprocessCascMC)) { - LOGF(fatal, "ResonanceDaughterInitializer initialized with both data and MC"); - } // Check if none of the processes are enabled - if (!doprocessDummy && !processTrackDataEnabled && !processTrackMCEnabled && !processV0DataEnabled && !doprocessV0MC && !processCascDataEnabled && !doprocessCascMC) { + if (!doprocessDummy && !anyDataProcessEnabled && !anyMCProcessEnabled) { LOGF(fatal, "ResonanceDaughterInitializer not initialized, enable at least one process"); } } - template - bool filterMicroTrack(T const& track) + static bool passesCenteredPID(float nSigma, float mean, float cut) { - // if no selection is requested, return true - if (!FilterForDerivedTables.cfgFillPionMicroTracks && !FilterForDerivedTables.cfgFillKaonMicroTracks && !FilterForDerivedTables.cfgFillProtonMicroTracks) { - return true; - } - if (FilterForDerivedTables.cfgFillPionMicroTracks) { - if (std::abs(track.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } - } - if (FilterForDerivedTables.cfgFillKaonMicroTracks) { - if (std::abs(track.tpcNSigmaKa()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } - } - if (FilterForDerivedTables.cfgFillProtonMicroTracks) { - if (std::abs(track.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } - } - return false; + return std::isfinite(nSigma) && std::abs(nSigma - mean) < cut; } - template - bool filterUltraMicroTrack(T const& track) + bool passesPIDPreSelection(float tpcNSigma, + float tofNSigma, + bool hasTOF, + float tpcMean, + float tofMean, + float tpcCut, + float tofCut) const { - switch (ultraMicroPidSpecies) { - case UltraMicroPidSpecies::Pion: - return std::abs(track.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut; - case UltraMicroPidSpecies::Kaon: - return std::abs(track.tpcNSigmaKa()) < TrackCuts.pidnSigmaPreSelectionCut; - case UltraMicroPidSpecies::Proton: - return std::abs(track.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut; + if (!passesCenteredPID(tpcNSigma, tpcMean, tpcCut)) { + return false; } - return false; + return !TrackCuts.cfgUseTOFPIDPreSelection.value || + !hasTOF || passesCenteredPID(tofNSigma, tofMean, tofCut); } template @@ -960,20 +1586,25 @@ struct ResonanceDaughterInitializer { if (!FilterForDerivedTables.cfgFillPionTracks && !FilterForDerivedTables.cfgFillKaonTracks && !FilterForDerivedTables.cfgFillProtonTracks) { return true; } - if (FilterForDerivedTables.cfgFillPionTracks) { - if (std::abs(track.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } + const float tpcCut = TrackCuts.pidnSigmaPreSelectionCut.value; + const float tofCut = TrackCuts.pidnSigmaPreSelectionCutTOF.value; + if (FilterForDerivedTables.cfgFillPionTracks && + passesPIDPreSelection(track.tpcNSigmaPi(), track.tofNSigmaPi(), track.hasTOF(), + TrackCuts.pidnSigmaPreSelectionMeanPion.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFPion.value, tpcCut, tofCut)) { + return true; } - if (FilterForDerivedTables.cfgFillKaonTracks) { - if (std::abs(track.tpcNSigmaKa()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } + if (FilterForDerivedTables.cfgFillKaonTracks && + passesPIDPreSelection(track.tpcNSigmaKa(), track.tofNSigmaKa(), track.hasTOF(), + TrackCuts.pidnSigmaPreSelectionMeanKaon.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFKaon.value, tpcCut, tofCut)) { + return true; } - if (FilterForDerivedTables.cfgFillProtonTracks) { - if (std::abs(track.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } + if (FilterForDerivedTables.cfgFillProtonTracks && + passesPIDPreSelection(track.tpcNSigmaPr(), track.tofNSigmaPr(), track.hasTOF(), + TrackCuts.pidnSigmaPreSelectionMeanProton.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFProton.value, tpcCut, tofCut)) { + return true; } return false; } @@ -988,13 +1619,8 @@ struct ResonanceDaughterInitializer { return true; } if (v0.dcaV0daughters() > SecondaryCuts.cfgSecondaryDauDCAMax || - std::abs(v0.dcapostopv()) < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin || - std::abs(v0.dcanegtopv()) < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin || v0.pt() < SecondaryCuts.cfgSecondaryPtMin || - v0.v0radius() < SecondaryCuts.cfgSecondaryRadiusMin || - v0.v0radius() > SecondaryCuts.cfgSecondaryRadiusMax || - v0.dcav0topv() > SecondaryCuts.cfgSecondaryDCAtoPVMax || - v0.v0cosPA() < SecondaryCuts.cfgSecondaryCosPAMin) { + v0.dcav0topv() > SecondaryCuts.cfgSecondaryDCAtoPVMax) { return false; } if (SecondaryCuts.cfgSecondaryArmenterosCut && @@ -1006,11 +1632,12 @@ struct ResonanceDaughterInitializer { const auto posTrack = v0.template posTrack_as(); const auto negTrack = v0.template negTrack_as(); const bool bypassDaughterPID = SecondaryCuts.cfgByPassDauPIDSelection; + const float daughterPIDCut = TrackCuts.pidnSigmaPreSelectionCut.value; bool selected = false; if (FilterForDerivedTables.cfgFillK0s) { const bool passesK0DaughterPID = bypassDaughterPID || - (std::abs(posTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut && - std::abs(negTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut); + (passesCenteredPID(posTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut) && + passesCenteredPID(negTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut)); const bool passesK0 = std::fabs(v0.yK0Short()) <= SecondaryCuts.cfgSecondaryRapidityMax && decayLengthOverMomentum * MassK0Short <= SecondaryCuts.cfgSecondaryProperLifetimeMax && std::fabs(v0.mK0Short() - MassK0Short) <= SecondaryCuts.cfgSecondaryMassWindow && @@ -1022,11 +1649,11 @@ struct ResonanceDaughterInitializer { } if (FilterForDerivedTables.cfgFillLambda0) { const bool passesLambdaPID = bypassDaughterPID || - (std::abs(posTrack.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut && - std::abs(negTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut); + (passesCenteredPID(posTrack.tpcNSigmaPr(), TrackCuts.pidnSigmaPreSelectionMeanProton.value, daughterPIDCut) && + passesCenteredPID(negTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut)); const bool passesAntiLambdaPID = bypassDaughterPID || - (std::abs(posTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut && - std::abs(negTrack.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut); + (passesCenteredPID(posTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut) && + passesCenteredPID(negTrack.tpcNSigmaPr(), TrackCuts.pidnSigmaPreSelectionMeanProton.value, daughterPIDCut)); const bool passesLambdaMassAndPID = (std::fabs(v0.mLambda() - MassLambda0) <= SecondaryCuts.cfgSecondaryMassWindow && passesLambdaPID) || (std::fabs(v0.mAntiLambda() - MassLambda0Bar) <= SecondaryCuts.cfgSecondaryMassWindow && passesAntiLambdaPID); @@ -1057,9 +1684,9 @@ struct ResonanceDaughterInitializer { } template - bool isTrackSelected(CollisionType const&, TrackType const& track) + bool isTrackSelected(CollisionType const&, TrackType const& track, bool fillSelectionQA = true) { - if (cfgFillQA) { + if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 0.5); if constexpr (isMC) { qaRegistry.fill(HIST("QA/hGoodMCTrackIndices"), 0.5); @@ -1071,13 +1698,13 @@ struct ResonanceDaughterInitializer { if (std::fabs(track.dcaXY()) > TrackCuts.cMaxDCArToPVcut) { return false; } - if (cfgFillQA) { + if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 1.5); } if (std::fabs(track.dcaZ()) > TrackCuts.cMaxDCAzToPVcut || std::fabs(track.dcaZ()) < TrackCuts.cMinDCAzToPVcut) { return false; } - if (cfgFillQA) { + if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 2.5); qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 7.5); } @@ -1093,7 +1720,7 @@ struct ResonanceDaughterInitializer { auto posTrack = v0.template posTrack_as(); auto negTrack = v0.template negTrack_as(); - if (posTrack.tpcNClsCrossedRows() < TrackCuts.mincrossedrows || negTrack.tpcNClsCrossedRows() < TrackCuts.mincrossedrows) { + if (posTrack.tpcNClsCrossedRows() < V0Cuts.mincrossedrowsV0s || negTrack.tpcNClsCrossedRows() < V0Cuts.mincrossedrowsV0s) { return false; } if (cfgFillQA && fillSelectionQA) { @@ -1173,7 +1800,7 @@ struct ResonanceDaughterInitializer { if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodCascIndices"), 6.5); } - if (std::abs(casc.mXi() - MassXiMinus) > CascadeCuts.cCascMassResol) { + if (std::abs(casc.mXi() - MassXiMinus) > CascadeCuts.cMaxXiMassWindow) { return false; } if (cfgFillQA && fillSelectionQA) { @@ -1185,28 +1812,122 @@ struct ResonanceDaughterInitializer { return true; } - /// @brief Check whether a collision has at least one V0 that would be written + /// @brief Find a selected V0 and collect daughter IDs only for the optional global veto template - bool hasSelectedV0(CollisionType const& collision, V0Type const& v0s, TrackType const& tracks) + SelectedCandidateDaughters collectSelectedV0Daughters(CollisionType const& collision, + V0Type const& v0s, + TrackType const& tracks, + bool useGlobalDaughterVeto) { + SelectedCandidateDaughters selectedCandidates{useGlobalDaughterVeto}; for (auto const& v0 : v0s) { - if (isV0Selected(collision, v0, tracks, false) && filterV0(collision, v0, tracks)) { - return true; + if (!isV0Selected(collision, v0, tracks, false) || + !filterV0(collision, v0, tracks)) { + continue; + } + if (!useGlobalDaughterVeto) { + selectedCandidates.addCandidate(); + break; } + selectedCandidates.addCandidate( + std::array{static_cast(v0.posTrackId()), + static_cast(v0.negTrackId())}); } - return false; + selectedCandidates.finalize(); + return selectedCandidates; } - /// @brief Check whether a collision has at least one cascade that would be written + /// @brief Find a selected cascade and collect daughter IDs only for the optional global veto template - bool hasSelectedCascade(CollisionType const& collision, CascType const& cascades, TrackType const& tracks) + SelectedCandidateDaughters collectSelectedCascadeDaughters(CollisionType const& collision, + CascType const& cascades, + TrackType const& tracks, + bool useGlobalDaughterVeto) { + SelectedCandidateDaughters selectedCandidates{useGlobalDaughterVeto}; for (auto const& casc : cascades) { - if (isCascSelected(collision, casc, tracks, false)) { - return true; + if (!isCascSelected(collision, casc, tracks, false)) { + continue; + } + if (!useGlobalDaughterVeto) { + selectedCandidates.addCandidate(); + break; } + selectedCandidates.addCandidate( + std::array{static_cast(casc.posTrackId()), + static_cast(casc.negTrackId()), + static_cast(casc.bachelorId())}); } - return false; + selectedCandidates.finalize(); + return selectedCandidates; + } + + /// @brief Build the per-track selection while preserving the configured collision gate + template + bool preparePairTrackSelection(CollisionType const& collision, + TrackType const& tracks, + V0Type const& v0s, + CascType const& cascades, + V0PresliceType const& v0Preslice, + CascPresliceType const& cascPreslice, + PairTrackSelection& selection) + { + const bool useEitherPairGate = FilterForDerivedTables.cfgPairGateMode.value == PairGateModeEither; + selection.useV0Candidates = useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairV0s; + selection.useCascadeCandidates = useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairCascades; + + if (selection.useV0Candidates) { + auto v0sThisCollision = v0s.sliceBy(v0Preslice, collision.collisionId()); + selection.v0Candidates = + collectSelectedV0Daughters(collision, v0sThisCollision, tracks, selection.useGlobalDaughterVeto); + } + if (selection.useCascadeCandidates && + (!useEitherPairGate || selection.useGlobalDaughterVeto || !selection.v0Candidates.hasSelectedCandidate)) { + auto cascadesThisCollision = cascades.sliceBy(cascPreslice, collision.collisionId()); + selection.cascadeCandidates = + collectSelectedCascadeDaughters(collision, cascadesThisCollision, tracks, selection.useGlobalDaughterVeto); + } + + if (useEitherPairGate) { + return selection.v0Candidates.hasSelectedCandidate || + selection.cascadeCandidates.hasSelectedCandidate; + } + + if (FilterForDerivedTables.cfgBypassNoPairV0s && !selection.v0Candidates.hasSelectedCandidate) { + return false; + } + if (FilterForDerivedTables.cfgBypassNoPairCascades && !selection.cascadeCandidates.hasSelectedCandidate) { + return false; + } + return true; + } + + /// @brief Round and saturate a floating-point value into a persistent integer column + template + static Integer quantizeSaturated(float value, double scale) + { + constexpr Integer LowerLimit = std::numeric_limits::lowest(); + constexpr Integer UpperLimit = std::numeric_limits::max(); + if (std::isnan(value)) { + return UpperLimit; + } + if (!std::isfinite(value)) { + return std::signbit(value) ? LowerLimit : UpperLimit; + } + const double rounded = std::round(static_cast(value) * scale); + if (rounded <= static_cast(LowerLimit)) { + return LowerLimit; + } + if (rounded >= static_cast(UpperLimit)) { + return UpperLimit; + } + return static_cast(rounded); } static bool quantizeP(float p, int16_t& quantized) @@ -1237,28 +1958,137 @@ struct ResonanceDaughterInitializer { return std::isfinite(threshold) ? threshold : -1.f; } - template - void fillUltraMicroTracks(CollisionType const& collision, TrackType const& tracks) + template + bool evaluatePtDependentDCA(TrackType const& track, + bool& passedPtDependentDCAxy, + bool& passedPtDependentDCAz) const { - // Loop over tracks + passedPtDependentDCAxy = false; + passedPtDependentDCAz = false; + if (!TrackCuts.cfgApplyTightDCAPtDepSelection.value) { + return true; + } + const float dcaThreshold = tightDCAThreshold(track.pt()); + if (dcaThreshold < 0.f) { + return false; + } + passedPtDependentDCAxy = std::isfinite(track.dcaXY()) && std::abs(track.dcaXY()) < dcaThreshold; + passedPtDependentDCAz = std::isfinite(track.dcaZ()) && std::abs(track.dcaZ()) < dcaThreshold; + return passedPtDependentDCAxy && passedPtDependentDCAz; + } + + template + bool isFullTrackOutputSelected(CollisionType const& collision, + TrackType const& track, + bool fillSelectionQA = true) + { + return isTrackSelected(collision, track, fillSelectionQA) && filterTrack(track); + } + + template + bool isMicroTrackOutputSelected(CollisionType const& collision, + TrackType const& track, + bool& passedPtDependentDCAxy, + bool& passedPtDependentDCAz) + { + return isMicroTrackSelected(collision, track) && + filterTrack(track) && + evaluatePtDependentDCA(track, passedPtDependentDCAxy, passedPtDependentDCAz); + } + + template + bool isUltraMicroTrackOutputSelected(CollisionType const& collision, TrackType const& track) + { + return isMicroTrackSelected(collision, track) && + filterTrack(track) && + o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaXY()) && + o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaZ()); + } + + template + static bool quantizeUltraMicroMomentum(TrackType const& track, + int16_t& px1000, + int16_t& py1000, + int16_t& pz1000) + { + return quantizeP(track.px(), px1000) && + quantizeP(track.py(), py1000) && + quantizeP(track.pz(), pz1000); + } + + /// Check that every enabled track output will receive at least one row. + template + bool hasTracksForEnabledOutputs(CollisionType const& collision, + TrackTableType const& tracks, + TrackPredicate const& keepTrack) + { + constexpr uint8_t FullTrackOutput = 1u << 0; + constexpr uint8_t MicroTrackOutput = 1u << 1; + constexpr uint8_t UltraMicroTrackOutput = 1u << 2; + uint8_t requiredOutputs = 0; + if (!FilterForDerivedTables.cfgBypassTrackFill.value) { + requiredOutputs |= FullTrackOutput; + } + if (FilterForDerivedTables.cfgFillMicroTracks.value) { + requiredOutputs |= MicroTrackOutput; + } + if (FilterForDerivedTables.cfgFillUltraMicroTracks.value) { + requiredOutputs |= UltraMicroTrackOutput; + } + + uint8_t availableOutputs = 0; for (auto const& track : tracks) { - if (!isMicroTrackSelected(collision, track)) { + if (!keepTrack(track)) { continue; } - if (!filterUltraMicroTrack(track)) { + if ((requiredOutputs & FullTrackOutput) != 0 && + (availableOutputs & FullTrackOutput) == 0 && + isFullTrackOutputSelected(collision, track, false)) { + availableOutputs |= FullTrackOutput; + } + if ((requiredOutputs & MicroTrackOutput) != 0 && + (availableOutputs & MicroTrackOutput) == 0) { + bool passedPtDependentDCAxy = false; + bool passedPtDependentDCAz = false; + if (isMicroTrackOutputSelected(collision, track, + passedPtDependentDCAxy, + passedPtDependentDCAz)) { + availableOutputs |= MicroTrackOutput; + } + } + if ((requiredOutputs & UltraMicroTrackOutput) != 0 && + (availableOutputs & UltraMicroTrackOutput) == 0 && + isUltraMicroTrackOutputSelected(collision, track)) { + int16_t px1000 = 0; + int16_t py1000 = 0; + int16_t pz1000 = 0; + if (quantizeUltraMicroMomentum(track, px1000, py1000, pz1000)) { + availableOutputs |= UltraMicroTrackOutput; + } + } + if (availableOutputs == requiredOutputs) { + return true; + } + } + return false; + } + + template + void fillUltraMicroTracks(CollisionType const& collision, TrackType const& tracks, TrackPredicate const& keepTrack) + { + // Loop over tracks + for (auto const& track : tracks) { + if (!keepTrack(track)) { continue; } - if (!o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaXY()) || - !o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaZ())) { + if (!isUltraMicroTrackOutputSelected(collision, track)) { continue; } o2::aod::resoultramicrodaughter::DCAEncoding dcaEncoding(track.dcaXY(), track.dcaZ()); int16_t px1000 = 0; int16_t py1000 = 0; int16_t pz1000 = 0; - if (!quantizeP(track.px(), px1000) || - !quantizeP(track.py(), py1000) || - !quantizeP(track.pz(), pz1000)) { + if (!quantizeUltraMicroMomentum(track, px1000, py1000, pz1000)) { if (!warnedUltraMicroMomentumRange) { LOGF(warn, "Skipping ultra-micro tracks with non-finite or out-of-range momentum components"); warnedUltraMicroMomentumRange = true; @@ -1318,28 +2148,36 @@ struct ResonanceDaughterInitializer { * @tparam CollisionType Type of collision * @param collision Collision data * @param tracks Track data + * @note ResoMicroTracks_001 is intended for fixed producer-side selections. + * Exact downstream cuts on its decoded values require zero-centred + * strict PID windows |nSigma| < C with + * C in {2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5}, and strict DCA windows + * |DCA| < C with C = N * 0.025 cm (N = 1, ..., 6). The listed PID + * guarantee assumes a zero mean; shifted PID windows require both + * interval edges to align with encoding boundaries and separate + * validation. PID cuts below 2 sigma and off-grid DCA/PID cuts cannot + * be reconstructed exactly. In particular, pT-dependent DCA cuts must + * be applied to the unquantised values here via + * cfgApplyTightDCAPtDepSelection; consumers should retain that producer + * decision rather than retune the decoded lower-edge DCA values. */ - template - void fillMicroTracks(CollisionType const& collision, TrackType const& tracks) + template + void fillMicroTracks(CollisionType const& collision, TrackType const& tracks, TrackPredicate const& keepTrack) { // Loop over tracks for (auto const& track : tracks) { - if (!isMicroTrackSelected(collision, track)) { + if (!keepTrack(track)) { continue; } - if (!filterMicroTrack(track)) { + bool passedPtDependentDCAxy = false; + bool passedPtDependentDCAz = false; + if (!isMicroTrackOutputSelected(collision, track, + passedPtDependentDCAxy, + passedPtDependentDCAz)) { continue; } - o2::aod::resomicrodaughter::ResoMicroTrackSelFlag trackSelFlag(track.dcaXY(), track.dcaZ()); - if (TrackCuts.cfgApplyTightDCAPtDepSelection) { - const float dcaThreshold = tightDCAThreshold(track.pt()); - if (dcaThreshold >= 0.f && std::abs(track.dcaXY()) < dcaThreshold) { - trackSelFlag.setDCAxy0(); - } - if (dcaThreshold >= 0.f && std::abs(track.dcaZ()) < dcaThreshold) { - trackSelFlag.setDCAz0(); - } - } + const o2::aod::resomicrodaughter001::DCAEncoding trackSelFlag( + track.dcaXY(), track.dcaZ(), passedPtDependentDCAxy, passedPtDependentDCAz); uint8_t trackFlags = (track.passedITSRefit() << 0) | (track.passedTPCRefit() << 1) | (track.isGlobalTrackWoDCA() << 2) | @@ -1358,17 +2196,21 @@ struct ResonanceDaughterInitializer { } } reso2microtrks(collision.globalIndex(), + track.globalIndex(), track.px(), track.py(), track.pz(), - static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaPi()), std::abs(track.tofNSigmaPi()), track.hasTOF())), - static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaKa()), std::abs(track.tofNSigmaKa()), track.hasTOF())), - static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaPr()), std::abs(track.tofNSigmaPr()), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter001::PidNSigma(track.tpcNSigmaPi(), track.tofNSigmaPi(), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter001::PidNSigma(track.tpcNSigmaKa(), track.tofNSigmaKa(), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter001::PidNSigma(track.tpcNSigmaPr(), track.tofNSigmaPr(), track.hasTOF())), static_cast(trackSelFlag), trackFlags); if (!FilterForDerivedTables.cfgBypassTrackIndexFill) { resoMicroTrackTracks(track.globalIndex()); } + if constexpr (isMC) { + fillMCTrack(track, reso2mcmicrotrks); + } } } @@ -1381,18 +2223,18 @@ struct ResonanceDaughterInitializer { * @param collision Collision data * @param tracks Track data */ - template - void fillTracks(CollisionType const& collision, TrackType const& tracks) + template + void fillTracks(CollisionType const& collision, TrackType const& tracks, TrackPredicate const& keepTrack) { if (FilterForDerivedTables.cfgBypassTrackFill) { return; } // Loop over tracks for (auto const& track : tracks) { - if (!isTrackSelected(collision, track)) { + if (!keepTrack(track)) { continue; } - if (!filterTrack(track)) { + if (!isFullTrackOutputSelected(collision, track)) { continue; } uint8_t trackFlags = (track.passedITSRefit() << 0) | @@ -1419,21 +2261,21 @@ struct ResonanceDaughterInitializer { track.pz(), static_cast(track.tpcNClsCrossedRows()), static_cast(track.tpcNClsFound()), - static_cast(std::round(track.dcaXY() * 10000)), - static_cast(std::round(track.dcaZ() * 10000)), - static_cast(std::round(track.tpcNSigmaPi() * 10)), - static_cast(std::round(track.tpcNSigmaKa() * 10)), - static_cast(std::round(track.tpcNSigmaPr() * 10)), - static_cast(std::round(track.tofNSigmaPi() * 10)), - static_cast(std::round(track.tofNSigmaKa() * 10)), - static_cast(std::round(track.tofNSigmaPr() * 10)), - static_cast(std::round(track.tpcSignal() * 100)), + quantizeSaturated(track.dcaXY(), 10000.), + quantizeSaturated(track.dcaZ(), 10000.), + quantizeSaturated(track.tpcNSigmaPi(), 10.), + quantizeSaturated(track.tpcNSigmaKa(), 10.), + quantizeSaturated(track.tpcNSigmaPr(), 10.), + quantizeSaturated(track.tofNSigmaPi(), 10.), + quantizeSaturated(track.tofNSigmaKa(), 10.), + quantizeSaturated(track.tofNSigmaPr(), 10.), + quantizeSaturated(track.tpcSignal(), 100.), trackFlags); if (!FilterForDerivedTables.cfgBypassTrackIndexFill) { resoTrackTracks(track.globalIndex()); } if constexpr (isMC) { - fillMCTrack(track); + fillMCTrack(track, reso2mctracks); } } } @@ -1442,10 +2284,12 @@ struct ResonanceDaughterInitializer { * @brief Fills MC track data * * @tparam TrackType Type of track + * @tparam MCOutputTable Type of positional MC extension to fill * @param track Track data + * @param output Positional MC extension writer */ - template - void fillMCTrack(TrackType const& track) + template + void fillMCTrack(TrackType const& track, Produces& output) { // ------ Temporal lambda function to prevent error in build auto getMothersIndeces = [&](auto const& theMcParticle) { @@ -1498,20 +2342,20 @@ struct ResonanceDaughterInitializer { if (siblingsTemp.size() > 1) { siblings[1] = siblingsTemp[1]; } - reso2mctracks(particle.pdgCode(), - mothers[0], - motherPDGs[0], - siblings.data(), - particle.isPhysicalPrimary(), - particle.producedByGenerator()); + output(particle.pdgCode(), + mothers[0], + motherPDGs[0], + siblings.data(), + particle.isPhysicalPrimary(), + particle.producedByGenerator()); } else { // No MC particle associated - reso2mctracks(0, - mothers[0], - motherPDGs[0], - siblings.data(), - 0, - 0); + output(0, + mothers[0], + motherPDGs[0], + siblings.data(), + 0, + 0); } } @@ -1536,10 +2380,8 @@ struct ResonanceDaughterInitializer { if (!filterV0(collision, v0, tracks)) { continue; } - if (cfgFillQA) { - qaRegistry.fill(HIST("QA/hV0Radius"), v0.v0radius()); - qaRegistry.fill(HIST("QA/hV0CosPA"), v0.v0cosPA()); - } + const auto posTrack = v0.template posTrack_as(); + const auto negTrack = v0.template negTrack_as(); const std::array childIDs{v0.posTrackId(), v0.negTrackId()}; // Original track IDs for downstream pair-level shared-daughter rejection reso2v0s(collision.globalIndex(), v0.pt(), @@ -1547,25 +2389,25 @@ struct ResonanceDaughterInitializer { v0.py(), v0.pz(), childIDs.data(), - (int8_t)(v0.template posTrack_as().tpcNSigmaPi() * 10), - (int8_t)(v0.template posTrack_as().tpcNSigmaKa() * 10), - (int8_t)(v0.template posTrack_as().tpcNSigmaPr() * 10), - (int8_t)(v0.template negTrack_as().tpcNSigmaPi() * 10), - (int8_t)(v0.template negTrack_as().tpcNSigmaKa() * 10), - (int8_t)(v0.template negTrack_as().tpcNSigmaPr() * 10), - (int8_t)(v0.template posTrack_as().tofNSigmaPi() * 10), - (int8_t)(v0.template posTrack_as().tofNSigmaKa() * 10), - (int8_t)(v0.template posTrack_as().tofNSigmaPr() * 10), - (int8_t)(v0.template negTrack_as().tofNSigmaPi() * 10), - (int8_t)(v0.template negTrack_as().tofNSigmaKa() * 10), - (int8_t)(v0.template negTrack_as().tofNSigmaPr() * 10), + quantizeSaturated(posTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(posTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(posTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(negTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(posTrack.tofNSigmaPi(), 10.), + quantizeSaturated(posTrack.tofNSigmaKa(), 10.), + quantizeSaturated(posTrack.tofNSigmaPr(), 10.), + quantizeSaturated(negTrack.tofNSigmaPi(), 10.), + quantizeSaturated(negTrack.tofNSigmaKa(), 10.), + quantizeSaturated(negTrack.tofNSigmaPr(), 10.), v0.v0cosPA(), v0.dcaV0daughters(), v0.dcapostopv(), v0.dcanegtopv(), v0.dcav0topv(), - static_cast(v0.template posTrack_as().tpcNClsCrossedRows()), - static_cast(v0.template negTrack_as().tpcNClsCrossedRows()), + static_cast(posTrack.tpcNClsCrossedRows()), + static_cast(negTrack.tpcNClsCrossedRows()), v0.mLambda(), v0.mAntiLambda(), v0.mK0Short(), @@ -1661,9 +2503,9 @@ struct ResonanceDaughterInitializer { daughters = getDaughtersIndeces(v0mc); daughterPDGs = getDaughtersPDGCodes(v0mc); } - if (daughters.size() > StoredMCRelationCount) { - LOGF(info, "daughters.size() is larger than 2"); - } + // if (daughters.size() > StoredMCRelationCount) { + // LOGF(info, "daughters.size() is larger than 2"); + // } daughters.resize(StoredMCRelationCount, -1); daughterPDGs.resize(StoredMCRelationCount, -1); reso2mcv0s(v0mc.pdgCode(), @@ -1710,10 +2552,9 @@ struct ResonanceDaughterInitializer { if (!isCascSelected(collision, casc, tracks)) { continue; } - if (cfgFillQA) { - qaRegistry.fill(HIST("QA/hCascRadius"), casc.cascradius()); - qaRegistry.fill(HIST("QA/hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); - } + const auto posTrack = casc.template posTrack_as(); + const auto negTrack = casc.template negTrack_as(); + const auto bachelor = casc.template bachelor_as(); const std::array childIDs{casc.posTrackId(), casc.negTrackId(), casc.bachelorId()}; // Original track IDs for downstream pair-level shared-daughter rejection reso2cascades(collision.globalIndex(), casc.pt(), @@ -1721,24 +2562,24 @@ struct ResonanceDaughterInitializer { casc.py(), casc.pz(), childIDs.data(), - (int8_t)(casc.template posTrack_as().tpcNSigmaPi() * 10), - (int8_t)(casc.template posTrack_as().tpcNSigmaKa() * 10), - (int8_t)(casc.template posTrack_as().tpcNSigmaPr() * 10), - (int8_t)(casc.template negTrack_as().tpcNSigmaPi() * 10), - (int8_t)(casc.template negTrack_as().tpcNSigmaKa() * 10), - (int8_t)(casc.template negTrack_as().tpcNSigmaPr() * 10), - (int8_t)(casc.template bachelor_as().tpcNSigmaPi() * 10), - (int8_t)(casc.template bachelor_as().tpcNSigmaKa() * 10), - (int8_t)(casc.template bachelor_as().tpcNSigmaPr() * 10), - (int8_t)(casc.template posTrack_as().tofNSigmaPi() * 10), - (int8_t)(casc.template posTrack_as().tofNSigmaKa() * 10), - (int8_t)(casc.template posTrack_as().tofNSigmaPr() * 10), - (int8_t)(casc.template negTrack_as().tofNSigmaPi() * 10), - (int8_t)(casc.template negTrack_as().tofNSigmaKa() * 10), - (int8_t)(casc.template negTrack_as().tofNSigmaPr() * 10), - (int8_t)(casc.template bachelor_as().tofNSigmaPi() * 10), - (int8_t)(casc.template bachelor_as().tofNSigmaKa() * 10), - (int8_t)(casc.template bachelor_as().tofNSigmaPr() * 10), + quantizeSaturated(posTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(posTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(posTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(negTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(bachelor.tpcNSigmaPi(), 10.), + quantizeSaturated(bachelor.tpcNSigmaKa(), 10.), + quantizeSaturated(bachelor.tpcNSigmaPr(), 10.), + quantizeSaturated(posTrack.tofNSigmaPi(), 10.), + quantizeSaturated(posTrack.tofNSigmaKa(), 10.), + quantizeSaturated(posTrack.tofNSigmaPr(), 10.), + quantizeSaturated(negTrack.tofNSigmaPi(), 10.), + quantizeSaturated(negTrack.tofNSigmaKa(), 10.), + quantizeSaturated(negTrack.tofNSigmaPr(), 10.), + quantizeSaturated(bachelor.tofNSigmaPi(), 10.), + quantizeSaturated(bachelor.tofNSigmaKa(), 10.), + quantizeSaturated(bachelor.tofNSigmaPr(), 10.), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), casc.dcaV0daughters(), @@ -1750,9 +2591,9 @@ struct ResonanceDaughterInitializer { casc.dcaXYCascToPV(), casc.dcaZCascToPV(), casc.sign(), - static_cast(casc.template posTrack_as().tpcNClsCrossedRows()), - static_cast(casc.template negTrack_as().tpcNClsCrossedRows()), - static_cast(casc.template bachelor_as().tpcNClsCrossedRows()), + static_cast(posTrack.tpcNClsCrossedRows()), + static_cast(negTrack.tpcNClsCrossedRows()), + static_cast(bachelor.tpcNClsCrossedRows()), casc.mLambda(), casc.mXi(), casc.v0radius(), casc.cascradius(), casc.x(), casc.y(), casc.z()); @@ -1846,9 +2687,9 @@ struct ResonanceDaughterInitializer { daughters = getDaughtersIndeces(cascmc); daughterPDGs = getDaughtersPDGCodes(cascmc); } - if (daughters.size() > StoredMCRelationCount) { - LOGF(info, "daughters.size() is larger than 2"); - } + // if (daughters.size() > StoredMCRelationCount) { + // LOGF(info, "daughters.size() is larger than 2"); + // } daughters.resize(StoredMCRelationCount, -1); daughterPDGs.resize(StoredMCRelationCount, -1); reso2mccascades(cascmc.pdgCode(), @@ -1882,7 +2723,7 @@ struct ResonanceDaughterInitializer { * * @param collision Collision data */ - void processDummy(aod::ResoCollision const&) + void processDummy(aod::ResoCollisions_001::iterator const&) { } PROCESS_SWITCH(ResonanceDaughterInitializer, processDummy, "Process dummy", true); @@ -1894,18 +2735,24 @@ struct ResonanceDaughterInitializer { * @param collision Reduced collision used as the output foreign key * @param tracks Tracks belonging to the corresponding original collision */ - template - void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks) + template + void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks, TrackPredicate const& keepTrack) { - fillTracks(collision, tracks); + fillTracks(collision, tracks, keepTrack); if (FilterForDerivedTables.cfgFillMicroTracks) { - fillMicroTracks(collision, tracks); + fillMicroTracks(collision, tracks, keepTrack); } if (FilterForDerivedTables.cfgFillUltraMicroTracks) { - fillUltraMicroTracks(collision, tracks); + fillUltraMicroTracks(collision, tracks, keepTrack); } } + template + void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks) + { + fillTrackTables(collision, tracks, KeepAllTracks{}); + } + /** * @brief Fills track tables for one original collision * @@ -1939,49 +2786,94 @@ struct ResonanceDaughterInitializer { /** * @brief Processes data tracks using the two-stage hybrid grouping * - * The canonical fIndexCollisions column in ResoCollisionGroups lets - * GroupSlicer associate both reduced collisions and tracks to the same - * original aod::Collision. The tracks argument is therefore already the - * selected slice for this collision and must not be sliced again. + * GroupSlicer associates tracks automatically to the original + * aod::Collision. Reduced collisions retain a scalar original-collision row + * number and are explicitly sliced from the much smaller mapping table. The + * tracks argument is already the selected slice and must not be sliced again. */ - void processDataHybrid(aod::Collision const&, - soa::SmallGroups const& reducedCollisions, + void processDataHybrid(aod::Collision const& originalCollision, + SelectedResoCollisions const& reducedCollisions, soa::Filtered const& tracks) { - if (reducedCollisions.size() == 0) { + auto reducedCollisionsThisCollision = reducedCollisions.sliceBy(reducedCollisionsPerOriginalCollision, originalCollision.globalIndex()); + if (reducedCollisionsThisCollision.size() == 0) { return; } - if (reducedCollisions.size() != 1) { - LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size()); + if (reducedCollisionsThisCollision.size() > 1) { + LOGF(error, "Found %zu reduced collisions for one original collision; skipping the ambiguous association", reducedCollisionsThisCollision.size()); + return; } - auto reducedCollision = reducedCollisions.begin(); + auto reducedCollision = reducedCollisionsThisCollision.begin(); fillTrackTables(reducedCollision, tracks); } PROCESS_SWITCH(ResonanceDaughterInitializer, processDataHybrid, "Process data tracks with the two-stage hybrid grouping", false); /** - * @brief Processes data tracks with configurable selected-V0 and selected-cascade gates + * @brief Processes data tracks with configurable selected V0 and cascade gates */ void processDataWithPairGate(ResoCollisionWithIndex::iterator const& collision, soa::Filtered const& tracks, aod::ResoV0Candidates const& v0s, aod::ResoCascadesCandidates const& cascades) { - if (FilterForDerivedTables.cfgBypassNoPairV0s) { - auto v0sThisCollision = v0s.sliceBy(v0sPerCollision, collision.collisionId()); - if (!hasSelectedV0(collision, v0sThisCollision, tracks)) { - return; - } + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + if (!preparePairTrackSelection(collision, tracks, v0s, cascades, + v0sPerCollision, cascadesPerCollision, pairSelection)) { + return; } - if (FilterForDerivedTables.cfgBypassNoPairCascades) { - auto cascadesThisCollision = cascades.sliceBy(cascadesPerCollision, collision.collisionId()); - if (!hasSelectedCascade(collision, cascadesThisCollision, tracks)) { - return; - } + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; } - fillTrackTablesForCollision(collision, tracks, tracksPerCollision); + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithPairGate, "Process data tracks with the configured pair-gate mode", false); + + /** + * @brief Processes data tracks when a selectex0 and collision track exist + * + * This dedicated callback deliberately has no cascade input, so enabling + * the V0 pair gate does not activate the cascade upstream dependency. + */ + void processDataWithV0PairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoV0Candidates const& v0s) + { + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.collisionId()); + auto v0sThisCollision = v0s.sliceBy(v0sPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useV0Candidates = true; + pairSelection.v0Candidates = + collectSelectedV0Daughters(collision, v0sThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; + } + fillTrackTables(collision, tracksThisCollision, pairSelection); } - PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithPairGate, "Process data tracks with configurable pair gates", false); + PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithV0PairGate, "Process data tracks requiring a selected V0", false); + + /** + * @brief Processes data tracks when a selected cascade and collision track exist + * + * This dedicated callback deliberately has no V0 input, so enabling the + * cascade pair gate does not activate the V0 upstream dependency. + */ + void processDataWithCascPairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoCascadesCandidates const& cascades) + { + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.collisionId()); + auto cascadesThisCollision = cascades.sliceBy(cascadesPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useCascadeCandidates = true; + pairSelection.cascadeCandidates = + collectSelectedCascadeDaughters(collision, cascadesThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; + } + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithCascPairGate, "Process data tracks requiring a selected cascade", false); /** * @brief Processes MC tracks @@ -1999,7 +2891,7 @@ struct ResonanceDaughterInitializer { PROCESS_SWITCH(ResonanceDaughterInitializer, processMC, "Process tracks for MC", false); /** - * @brief Processes MC tracks with configurable V0 and cascade candidate gates + * @brief Processes MC tracks with configurable selected V0 and cascade gates */ void processMCWithPairGate(ResoCollisionWithIndex::iterator const& collision, soa::Filtered const& tracks, @@ -2007,17 +2899,60 @@ struct ResonanceDaughterInitializer { aod::ResoCascadesCandidatesMC const& cascades, aod::McParticles const&) { + auto tracksThisCollision = tracks.sliceBy(tracksMCPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + if (!preparePairTrackSelection(collision, tracks, v0s, cascades, + v0sMCPerCollision, cascadesMCPerCollision, pairSelection)) { + return; + } + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; + } + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithPairGate, "Process MC tracks with the configured pair-gate mode", false); + + /** + * @brief Processes MC tracks when a selected V0 and collision track exist + */ + void processMCWithV0PairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoV0CandidatesMC const& v0s, + aod::McParticles const&) + { + auto tracksThisCollision = tracks.sliceBy(tracksMCPerCollision, collision.collisionId()); auto v0sThisCollision = v0s.sliceBy(v0sMCPerCollision, collision.collisionId()); - if (FilterForDerivedTables.cfgBypassNoPairV0s && v0sThisCollision.size() < 1) { + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useV0Candidates = true; + pairSelection.v0Candidates = + collectSelectedV0Daughters(collision, v0sThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { return; } + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithV0PairGate, "Process MC tracks requiring a selected V0", false); + + /** + * @brief Processes MC tracks when a selected cascade and collision track exist + */ + void processMCWithCascPairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoCascadesCandidatesMC const& cascades, + aod::McParticles const&) + { + auto tracksThisCollision = tracks.sliceBy(tracksMCPerCollision, collision.collisionId()); auto cascadesThisCollision = cascades.sliceBy(cascadesMCPerCollision, collision.collisionId()); - if (FilterForDerivedTables.cfgBypassNoPairCascades && cascadesThisCollision.size() < 1) { + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useCascadeCandidates = true; + pairSelection.cascadeCandidates = + collectSelectedCascadeDaughters(collision, cascadesThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { return; } - fillTrackTablesForCollision(collision, tracks, tracksMCPerCollision); + fillTrackTables(collision, tracksThisCollision, pairSelection); } - PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithPairGate, "Process MC tracks with configurable pair gates", false); + PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithCascPairGate, "Process MC tracks requiring a selected cascade", false); /** * @brief Processes V0 data @@ -2033,29 +2968,6 @@ struct ResonanceDaughterInitializer { } PROCESS_SWITCH(ResonanceDaughterInitializer, processV0Data, "Process V0s for data", false); - /** - * @brief Processes data V0s grouped automatically by their original collision - * - * Both V0s and tracks are already restricted to the current original - * aod::Collision by GroupSlicer. The unfiltered track table is required for - * resolving the positive and negative daughter indices. - */ - void processV0DataHybrid(aod::Collision const&, - soa::SmallGroups const& reducedCollisions, - aod::ResoV0Candidates const& v0s, - aod::ResoTrackCandidates const& tracks) - { - if (reducedCollisions.size() == 0) { - return; - } - if (reducedCollisions.size() != 1) { - LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size()); - } - auto reducedCollision = reducedCollisions.begin(); - fillV0s(reducedCollision, v0s, tracks); - } - PROCESS_SWITCH(ResonanceDaughterInitializer, processV0DataHybrid, "Process data V0s with the two-stage hybrid grouping", false); - /** * @brief Processes MC V0 data * @@ -2084,29 +2996,6 @@ struct ResonanceDaughterInitializer { } PROCESS_SWITCH(ResonanceDaughterInitializer, processCascData, "Process Cascades for data", false); - /** - * @brief Processes data cascades grouped automatically by their original collision - * - * Cascades and tracks arrive as original-collision groups. Keeping this as a - * separate callback from V0 processing avoids enabling either upstream input - * dependency unless its process switch is selected. - */ - void processCascDataHybrid(aod::Collision const&, - soa::SmallGroups const& reducedCollisions, - aod::ResoCascadesCandidates const& cascades, - aod::ResoTrackCandidates const& tracks) - { - if (reducedCollisions.size() == 0) { - return; - } - if (reducedCollisions.size() != 1) { - LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size()); - } - auto reducedCollision = reducedCollisions.begin(); - fillCascades(reducedCollision, cascades, tracks); - } - PROCESS_SWITCH(ResonanceDaughterInitializer, processCascDataHybrid, "Process data cascades with the two-stage hybrid grouping", false); - /** * @brief Processes MC cascade data * diff --git a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx index f5cac87074d..7db5fc99876 100644 --- a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx @@ -811,6 +811,7 @@ struct cascadeFlow { invMassLambda = v0.mAntiLambda(); else invMassLambda = v0.mLambda(); + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * o2::constants::physics::MassLambda0; analysisLambdaSample(coll.centFT0C(), hasEventPlane, hasSpectatorPlane, @@ -819,6 +820,7 @@ struct cascadeFlow { v0.phi(), v0.eta(), invMassLambda, + ctauLambda, v0.v0radius(), v0.dcapostopv(), v0.dcanegtopv(), diff --git a/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx index b1dc464905b..021fee63251 100644 --- a/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx +++ b/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx @@ -49,6 +49,7 @@ #include #include #include +#include #include using namespace o2; @@ -158,6 +159,7 @@ struct doubleOmegaTreeCreator { OutputObj zorroSummary{"zorroSummary"}; Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable cfgApplyEventSelection{"cfgApplyEventSelection", true, "Apply the standard collision event selection"}; Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Material correction for the raw V0/cascade fits"}; @@ -188,6 +190,7 @@ struct doubleOmegaTreeCreator { Configurable mXiWindow{"mXiWindow", 0.02f, "Xi mass window used by the cascade compatibility mode"}; Configurable mOmegaWindow{"mOmegaWindow", 0.01f, "Omega mass window"}; Configurable mLambdaWindow{"mLambdaWindow", 0.01f, "Lambda mass window"}; + Configurable maxDoubleOmegaMass{"maxDoubleOmegaMass", 3.6f, "Maximum double-Omega invariant mass (GeV/c^2)"}; Configurable minCosPAOmega{"minCosPAOmega", -1.f, "Minimum Omega cosPA relative to the double-Omega decay vertex"}; Configurable minCosPADirectLambda{"minCosPADirectLambda", -1.f, "Minimum direct-Lambda cosPA relative to the double-Omega decay vertex"}; Configurable minCosPADoubleOmega{"minCosPADoubleOmega", -1.f, "Minimum double-Omega cosPA relative to the primary vertex"}; @@ -586,16 +589,17 @@ struct doubleOmegaTreeCreator { cand.dcaZDirectLambdaToPV = dcaDirectLambda[1]; cand.dcaXYDirectKaonToPV = dcaDirectKaon[0]; cand.dcaZDirectKaonToPV = dcaDirectKaon[1]; + cand.mass = std::sqrt(std::max(0.f, massSquared)); if (cand.cosPAOmega < minCosPAOmega || cand.cosPADirectLambda < minCosPADirectLambda || cand.cosPADoubleOmega < minCosPADoubleOmega || std::hypot(decayVertex[0], decayVertex[1]) < minDoubleOmegaDecayRadius || std::abs(cand.dcaXYOmegaToPV) < dcaOmegaToPV || std::abs(cand.dcaXYDirectLambdaToPV) < dcaDirectLambdaToPV || - std::abs(cand.dcaXYDirectKaonToPV) < dcaKaonToPV) { + std::abs(cand.dcaXYDirectKaonToPV) < dcaKaonToPV || + cand.mass > maxDoubleOmegaMass) { return false; } - cand.mass = std::sqrt(std::max(0.f, massSquared)); cand.massOmega = omega.massOmega; cand.massXi = omega.massXi; return true; @@ -899,7 +903,7 @@ struct doubleOmegaTreeCreator { const std::array sourceTrackIds{ lambdaKaonSource.posTrackId(), lambdaKaonSource.negTrackId(), lambdaKaonSource.bachelorId()}; bool sharesTrack = false; - for (const auto omegaTrackId : omegaTrackIds) { + for (const auto& omegaTrackId : omegaTrackIds) { if (std::find(sourceTrackIds.begin(), sourceTrackIds.end(), omegaTrackId) != sourceTrackIds.end()) { sharesTrack = true; break; @@ -932,10 +936,11 @@ struct doubleOmegaTreeCreator { auto bc = collision.template bc_as(); initCCDB(bc); - if (!collision.sel8() || - std::abs(collision.posZ()) > zVtxMax || - !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || - !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (cfgApplyEventSelection && + (!collision.sel8() || + std::abs(collision.posZ()) > zVtxMax || + !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || + !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { return false; } if (cfgSkimmedProcessing) { diff --git a/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx b/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx index b7815ea2499..e3fc686d597 100644 --- a/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx +++ b/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx @@ -245,10 +245,10 @@ struct strangenesstofpid { TH1 *hMeanNegOmPr = nullptr, *hSigmaNegOmPr = nullptr; TH1 *hMeanBachOmKa = nullptr, *hSigmaBachOmKa = nullptr; - int mRunNumber; - float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation + int mRunNumber = 0; + float d_bz = 0.; + float maxSnp = 0.85; // max sine phi for propagation + float maxStep = 2.00; // max step size (cm) for propagation // enum to keep track of the TOF-related properties for V0s enum tofEnum { kLength = 0, @@ -850,16 +850,31 @@ struct strangenesstofpid { float nSigmaOmKa = o2::aod::cascdata::kNoTOFValue; // n sigma with wrong hypothesis - float nSigmaXiLaEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiLaKa = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiKa = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiPr = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmLaEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmLaKa = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmPi = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorPr = o2::aod::cascdata::kNoTOFValue; + + float nSigmaOmPositiveLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmPositiveLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmPositiveLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmPositiveLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorPr = o2::aod::cascdata::kNoTOFValue; }; struct trackTofInfo { // holds input track info @@ -1330,15 +1345,6 @@ struct strangenesstofpid { } else { casctof.nSigmaXiLaPr = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); casctof.nSigmaOmLaPr = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - - // wrong hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaPi = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaPi = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); } } else { if (useNsigmaCalibStrTOF) { @@ -1349,15 +1355,21 @@ struct strangenesstofpid { } else { casctof.nSigmaXiLaPi = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); casctof.nSigmaOmLaPi = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + } + } + if (calculateCascadesNSigmaAll.value > 0) { + if (!useNsigmaCalibStrTOF) { // wrong hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaPr = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaPr = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaEl = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaPi = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaKa = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaPr = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + + casctof.nSigmaOmPositiveLaEl = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaOmPositiveLaPi = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaOmPositiveLaKa = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaOmPositiveLaPr = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); } } @@ -1451,15 +1463,6 @@ struct strangenesstofpid { } else { casctof.nSigmaXiLaPi = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); casctof.nSigmaOmLaPi = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - - // wrogn hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaPr = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaPr = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); } } else { if (useNsigmaCalibStrTOF) { @@ -1470,15 +1473,21 @@ struct strangenesstofpid { } else { casctof.nSigmaXiLaPr = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); casctof.nSigmaOmLaPr = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + } + } + if (calculateCascadesNSigmaAll.value > 0) { + if (!useNsigmaCalibStrTOF) { // wrong hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaPi = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaPi = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaEl = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaPi = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaKa = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaPr = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + + casctof.nSigmaOmNegativeLaEl = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaOmNegativeLaPi = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaOmNegativeLaKa = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaOmNegativeLaPr = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); } } @@ -1569,15 +1578,21 @@ struct strangenesstofpid { } else { casctof.nSigmaXiPi = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); casctof.nSigmaOmKa = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + } - // wrong hypothesis - casctof.nSigmaXiEl = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaXiKa = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaXiPr = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - - casctof.nSigmaOmEl = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaOmPi = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaOmPr = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + if (calculateCascadesNSigmaAll.value > 0) { + if (!useNsigmaCalibStrTOF) { + // wrong hypothesis + casctof.nSigmaXiBachelorEl = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaXiBachelorPi = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaXiBachelorKa = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaXiBachelorPr = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + + casctof.nSigmaOmBachelorEl = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaOmBachelorPi = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaOmBachelorKa = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaOmBachelorPr = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + } } // do QA histograms (calibration / QC) @@ -1624,9 +1639,6 @@ struct strangenesstofpid { return casctof; } - std::unordered_map mapCollisionTime; - std::unordered_map mapCollisionTimeError; - void processStandardData(/*aod::BCs const& bcs,*/ aod::Collisions const& collisions, V0OriginalDatas const& V0s, CascOriginalDatas const& cascades, TracksWithAllExtras const& tracks, aod::BCsWithTimestamps const& bcs) { // Fire up CCDB with first collision in record. If no collisions, bypass @@ -1640,14 +1652,6 @@ struct strangenesstofpid { mTOFResponse->processSetup(bcs.iteratorAt(0)); - for (const auto& track : tracks) { - if (mapCollisionTime.find(track.collisionId()) == mapCollisionTime.end()) { - // LOGF(info, "track.collisionId() = %d, track.tofEvTime() = %f, track.tofEvTimeErr() = %f", track.collisionId(), track.tofEvTime(), track.tofEvTimeErr()); - mapCollisionTime[track.collisionId()] = track.tofEvTime(); - mapCollisionTimeError[track.collisionId()] = track.tofEvTimeErr(); - } - } - //________________________________________________________________________ // estimate event times (only necessary for original data) std::vector collisionEventTime(collisions.size(), 0.0); @@ -1705,8 +1709,6 @@ struct strangenesstofpid { pTof.hasTPC = pTra.hasTPC(); pTof.hasTOF = pTra.hasTOF(); pTof.tofExpMom = pTra.tofExpMom(); - // pTof.tofEvTime = reassociateTracks ? mapCollisionTime[V0.collisionId()] : pTra.tofEvTime(); - // pTof.tofEvTimeErr = reassociateTracks ? mapCollisionTimeError[V0.collisionId()] : pTra.tofEvTimeErr(); pTof.tofEvTime = reassociateTracks ? collisionEventTime[V0.collisionId()] : pTra.tofEvTime(); pTof.tofEvTimeErr = reassociateTracks ? collisionEventTimeErr[V0.collisionId()] : pTra.tofEvTimeErr(); // pTof.tofSignal = pTra.tofSignal() + (doBCshift ? deltaTimePos : 0.0f); @@ -1721,8 +1723,6 @@ struct strangenesstofpid { nTof.hasTPC = nTra.hasTPC(); nTof.hasTOF = nTra.hasTOF(); nTof.tofExpMom = nTra.tofExpMom(); - // nTof.tofEvTime = reassociateTracks ? mapCollisionTime[V0.collisionId()] : nTra.tofEvTime(); - // nTof.tofEvTimeErr = reassociateTracks ? mapCollisionTimeError[V0.collisionId()] : nTra.tofEvTimeErr(); nTof.tofEvTime = reassociateTracks ? collisionEventTime[V0.collisionId()] : nTra.tofEvTime(); nTof.tofEvTimeErr = reassociateTracks ? collisionEventTimeErr[V0.collisionId()] : nTra.tofEvTimeErr(); // nTof.tofSignal = nTra.tofSignal() + (doBCshift ? deltaTimeNeg : 0.0f); @@ -1876,10 +1876,14 @@ struct strangenesstofpid { if (calculateCascadesNSigmaAll.value > 0) { casctofnsigmasall( - casctof.nSigmaXiLaEl, casctof.nSigmaXiEl, casctof.nSigmaOmLaEl, casctof.nSigmaOmEl, - casctof.nSigmaXiLaPi, casctof.nSigmaXiPi, casctof.nSigmaOmLaPi, casctof.nSigmaOmPi, - casctof.nSigmaXiLaKa, casctof.nSigmaXiKa, casctof.nSigmaOmLaKa, casctof.nSigmaOmKa, - casctof.nSigmaXiLaPr, casctof.nSigmaXiPr, casctof.nSigmaOmLaPr, casctof.nSigmaOmPr); + casctof.nSigmaXiPositiveLaEl, casctof.nSigmaXiNegativeLaEl, casctof.nSigmaXiBachelorEl, + casctof.nSigmaOmPositiveLaEl, casctof.nSigmaOmNegativeLaEl, casctof.nSigmaOmBachelorEl, + casctof.nSigmaXiPositiveLaPi, casctof.nSigmaXiNegativeLaPi, casctof.nSigmaXiBachelorPi, + casctof.nSigmaOmPositiveLaPi, casctof.nSigmaOmNegativeLaPi, casctof.nSigmaOmBachelorPi, + casctof.nSigmaXiPositiveLaKa, casctof.nSigmaXiNegativeLaKa, casctof.nSigmaXiBachelorKa, + casctof.nSigmaOmPositiveLaKa, casctof.nSigmaOmNegativeLaKa, casctof.nSigmaOmBachelorKa, + casctof.nSigmaXiPositiveLaPr, casctof.nSigmaXiNegativeLaPr, casctof.nSigmaXiBachelorPr, + casctof.nSigmaOmPositiveLaPr, casctof.nSigmaOmNegativeLaPr, casctof.nSigmaOmBachelorPr); } } if (calculateCascTOFPIDs.value) { @@ -1891,9 +1895,6 @@ struct strangenesstofpid { } } } - - mapCollisionTime.clear(); - mapCollisionTimeError.clear(); } void processDerivedData(soa::Join const& collisions, V0DerivedDatas const& V0s, CascDerivedDatas const& cascades, dauTracks const& dauTrackTable, aod::DauTrackTOFPIDs const& dauTrackTOFPIDs) @@ -1922,6 +1923,8 @@ struct strangenesstofpid { initCCDB(collision.runNumber()); } + mTOFResponse->processSetup(collisions.iteratorAt(0)); + // hold indices std::vector tofIndices(dauTrackTable.size(), -1); @@ -2010,6 +2013,18 @@ struct strangenesstofpid { v0tof.nSigmaPositiveLambdaPr, v0tof.nSigmaNegativeLambdaPi, v0tof.nSigmaNegativeLambdaPr, v0tof.nSigmaPositiveLambdaPi, v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaNegativeK0ShortPi); + + if (calculateV0sNSigmaAll.value > 0) { + v0tofnsigmasall( + v0tof.nSigmaPositivePhotonEl, v0tof.nSigmaPositiveK0ShortEl, v0tof.nSigmaPositiveLambdaEl, + v0tof.nSigmaNegativePhotonEl, v0tof.nSigmaNegativeK0ShortEl, v0tof.nSigmaNegativeLambdaEl, + v0tof.nSigmaPositivePhotonPi, v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaPositiveLambdaPi, + v0tof.nSigmaNegativePhotonPi, v0tof.nSigmaNegativeK0ShortPi, v0tof.nSigmaNegativeLambdaPi, + v0tof.nSigmaPositivePhotonKa, v0tof.nSigmaPositiveK0ShortEl, v0tof.nSigmaPositiveLambdaEl, + v0tof.nSigmaNegativePhotonKa, v0tof.nSigmaNegativeK0ShortEl, v0tof.nSigmaNegativeLambdaEl, + v0tof.nSigmaPositivePhotonPr, v0tof.nSigmaPositiveK0ShortPr, v0tof.nSigmaPositiveLambdaPr, + v0tof.nSigmaNegativePhotonPr, v0tof.nSigmaNegativeK0ShortPr, v0tof.nSigmaNegativeLambdaPr); + } } if (calculateV0TOFPIDs.value) { v0tofpid(v0tof.deltaTimePositiveLambdaPi, v0tof.deltaTimePositiveLambdaPr, @@ -2106,6 +2121,18 @@ struct strangenesstofpid { casctofnsigmas( casctof.nSigmaXiLaPi, casctof.nSigmaXiLaPr, casctof.nSigmaXiPi, casctof.nSigmaOmLaPi, casctof.nSigmaOmLaPr, casctof.nSigmaOmKa); + + if (calculateCascadesNSigmaAll.value > 0) { + casctofnsigmasall( + casctof.nSigmaXiPositiveLaEl, casctof.nSigmaXiNegativeLaEl, casctof.nSigmaXiBachelorEl, + casctof.nSigmaOmPositiveLaEl, casctof.nSigmaOmNegativeLaEl, casctof.nSigmaOmBachelorEl, + casctof.nSigmaXiPositiveLaPi, casctof.nSigmaXiNegativeLaPi, casctof.nSigmaXiBachelorPi, + casctof.nSigmaOmPositiveLaPi, casctof.nSigmaOmNegativeLaPi, casctof.nSigmaOmBachelorPi, + casctof.nSigmaXiPositiveLaKa, casctof.nSigmaXiNegativeLaKa, casctof.nSigmaXiBachelorKa, + casctof.nSigmaOmPositiveLaKa, casctof.nSigmaOmNegativeLaKa, casctof.nSigmaOmBachelorKa, + casctof.nSigmaXiPositiveLaPr, casctof.nSigmaXiNegativeLaPr, casctof.nSigmaXiBachelorPr, + casctof.nSigmaOmPositiveLaPr, casctof.nSigmaOmNegativeLaPr, casctof.nSigmaOmBachelorPr); + } } if (calculateCascTOFPIDs.value) { casctofpids( diff --git a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx index fda62b2f5e8..a3462b9ed52 100644 --- a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx +++ b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx @@ -188,7 +188,7 @@ struct HadronNucleiCorrelation { ccdb->setFatalWhenNull(false); if (doCorrection) { - GetCorrection(ccdb, TString(fCorrectionPath), TString(fCorrectionHisto)); + getCorrection(ccdb, TString(fCorrectionPath), TString(fCorrectionHisto)); } const AxisSpec ptBinnedAxis = {pTBins, "#it{p}_{T} of #bar{p} (GeV/#it{c})"}; @@ -246,17 +246,17 @@ struct HadronNucleiCorrelation { const TString ptTag = Form("pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10); const TString ptInterval = Form("(%.1f(Form("hEtaPhi_%s_SE_pt%s", name.Data(), ptTag.Data()), "Raw #Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); - hEtaPhiMixdEv.push_back(registry.add(Form("hEtaPhi_%s_ME_pt%s", name.Data(), ptTag.Data()), "Raw #Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); + hEtaPhiSameEv.push_back(registry.add(Form("hEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "Raw #Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); + hEtaPhiMixdEv.push_back(registry.add(Form("hEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "Raw #Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); - hCorrEtaPhiSameEv.push_back(registry.add(Form("hCorrEtaPhi_%s_SE_pt%s", name.Data(), ptTag.Data()), "#Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); - hCorrEtaPhiMixdEv.push_back(registry.add(Form("hCorrEtaPhi_%s_ME_pt%s", name.Data(), ptTag.Data()), "#Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); + hCorrEtaPhiSameEv.push_back(registry.add(Form("hCorrEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "#Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); + hCorrEtaPhiMixdEv.push_back(registry.add(Form("hCorrEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "#Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); } else { - hEtaPhiSameEv.push_back(registry.add(Form("hEtaPhi_%s_SE_pt%s", name.Data(), ptTag.Data()), "Raw #Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); - hEtaPhiMixdEv.push_back(registry.add(Form("hEtaPhi_%s_ME_pt%s", name.Data(), ptTag.Data()), "Raw #Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); + hEtaPhiSameEv.push_back(registry.add(Form("hEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "Raw #Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); + hEtaPhiMixdEv.push_back(registry.add(Form("hEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "Raw #Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); - hCorrEtaPhiSameEv.push_back(registry.add(Form("hCorrEtaPhi_%s_SE_pt%s", name.Data(), ptTag.Data()), "#Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); - hCorrEtaPhiMixdEv.push_back(registry.add(Form("hCorrEtaPhi_%s_ME_pt%s", name.Data(), ptTag.Data()), "#Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); + hCorrEtaPhiSameEv.push_back(registry.add(Form("hCorrEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "#Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); + hCorrEtaPhiMixdEv.push_back(registry.add(Form("hCorrEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "#Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); } } } @@ -613,7 +613,7 @@ struct HadronNucleiCorrelation { } template - void fillHistogramsGen(T1 const& part0, T1 const& part1, bool ME) + void fillHistogramsGen(T1 const& part0, T1 const& part1, const bool ME) { float deltaEta = part0.eta() - part1.eta(); @@ -635,7 +635,7 @@ struct HadronNucleiCorrelation { } // nBinspT loop } - void GetCorrection(o2::framework::Service const& ccdbObj, const TString& filepath, const TString& histname) + void getCorrection(o2::framework::Service const& ccdbObj, const TString& filepath, const TString& histname) { auto* l = ccdbObj->get(filepath.Data()); if (!l) { diff --git a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx index 0b384e52179..2020bacdaa4 100644 --- a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx +++ b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx @@ -585,9 +585,9 @@ struct Chargedkstaranalysis { histosMc.add("h3ChaKstarInvMassDSMcGen", "h3ChaKstarInvMassDSMcGen", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassDSMcRec", "h3ChaKstarInvMassDSMcRec", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassDSMcRecClosure", "h3ChaKstarInvMassDSMcRecClosure", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); + histosMc.add("sigLoss_den_pri_threeD", "sigLoss_den_pri_threeD", kTHnSparseF, {centAxis, ptAxis, thnAxisPOL}, true); if (mcCfgs.doBkgMc) { - histosMc.add("h3ChaKstarInvMassRotMcGen", "h3ChaKstarInvMassRotMcGen", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassRotMcRec", "h3ChaKstarInvMassRotMcRec", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassRotMcRecClosure", "h3ChaKstarInvMassRotMcRecClosure", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); } @@ -604,8 +604,6 @@ struct Chargedkstaranalysis { histos.add("Correction/sigLoss_num_pri", "Gen primary Kstar (|y|<0.5, selected events) in reco class", HistType::kTH2F, {ptAxis, centAxis}); histos.add("Correction/EF_den", "Gen events (truth class)", HistType::kTH1F, {centAxis}); histos.add("Correction/EF_num", "Reco events (selected events)", HistType::kTH1F, {centAxis}); - histos.add("sigLoss_den_pri_threeD", "sigLoss_den_pri_threeD", kTHnSparseF, {centAxis, ptAxis, thnAxisPOL}, true); - histos.add("sigLoss_den_pri_threeD_rot", "sigLoss_den_pri_threeD_rot", kTHnSparseF, {centAxis, ptAxis, thnAxisPOL}, true); histos.add("Correction/hNEventsMCTruth", "hNEventsMCTruth", HistType::kTH1F, {AxisSpec{nSteps, 0.5, nSteps + 0.5, ""}}); auto hstep = histos.get(HIST("Correction/hNEventsMCTruth")); hstep->GetXaxis()->SetBinLabel(1, "All"); @@ -849,18 +847,10 @@ struct Chargedkstaranalysis { if (currentIsGen) { if (sigLossDen) { // Fill ONLY the Signal Loss Denominator 3D Histograms - if (isRot) { - histos.fill(HIST("sigLoss_den_pri_threeD_rot"), multiplicity, mother.Pt(), cosTheta); - } else { - histos.fill(HIST("sigLoss_den_pri_threeD"), multiplicity, mother.Pt(), cosTheta); - } + histosMc.fill(HIST("sigLoss_den_pri_threeD"), multiplicity, mother.Pt(), cosTheta); } else { // Fill standard 4D MC Gen Histograms - if (isRot) { - histosMc.fill(HIST("h3ChaKstarInvMassRotMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } else { - histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } + histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); } return; } @@ -926,7 +916,7 @@ struct Chargedkstaranalysis { auto phiCS = std::atan2(yAxisCS.Dot(v1CM), xAxisCS.Dot(v1CM)); phiCS = RecoDecay::constrainAngle(phiCS, 0.0); - bool doRotation = !doprocessMC || mcCfgs.doBkgMc; + bool doRotation = !doprocessMC || (!currentIsGen && mcCfgs.doBkgMc); // if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { if (helicityCfgs.activateHelicityFrame) { // helicityVec = mother.Vect(); // 3 vector of mother in COM frame @@ -1465,10 +1455,10 @@ struct Chargedkstaranalysis { const float lCentrality = getCentrality(coll); refCentByMcId.emplace(mcid, lCentrality); } - + currentIsGen = true; + sigLossDen = false; // Calculating the generated Kstar for (const auto& part : mcParticles) { - currentIsGen = true; if (!part.has_mcCollision()) { continue; } @@ -1559,9 +1549,102 @@ struct Chargedkstaranalysis { } } } + sigLossDen = true; + // To calculate the denominator -> To check the all the events have chk892 + for (auto const& part : mcParticles) { + if (!part.has_mcCollision()) { + continue; + } + if (std::abs(part.pdgCode()) != kKstarPlus) { + continue; + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { + continue; + } + + const auto mcid = part.mcCollisionId(); + if (!refClassIds.contains(mcid)) { + continue; + } + + auto iter = refCentByMcId.find(mcid); + if (iter == refCentByMcId.end()) { + continue; + } + + const float lCentrality = iter->second; + + histos.fill(HIST("Correction/sigLoss_den"), part.pt(), lCentrality); + if (part.vt() == 0) { + histos.fill(HIST("Correction/sigLoss_den_pri"), part.pt(), lCentrality); + } + LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; + lResoKstar = LorentzVectorSetXYZM(part.px(), part.py(), part.pz(), MassKPlusStar892); + const int pionWanted = (part.pdgCode() > 0) ? +kPiPlus : -kPiPlus; + bool hasRightPion = false; + bool hasK0sToPipi = false; + for (const auto& d1 : part.template daughters_as()) { + const int pdg1 = d1.pdgCode(); + if (pdg1 == pionWanted) { + lDecayDaughter_bach = LorentzVectorSetXYZM(d1.px(), d1.py(), d1.pz(), MassPionCharged); + if (helicityCfgs.genKinematicsChecks) { + if (lDecayDaughter_bach.pt() <= trackCutCfgs.cMinPtcut || std::abs(lDecayDaughter_bach.eta()) >= trackCutCfgs.cMaxEtacut) { + continue; + } + } + hasRightPion = true; + } else if (std::abs(pdg1) == kPDGK0) { + for (const auto& d2 : d1.template daughters_as()) { + if (std::abs(d2.pdgCode()) == kPDGK0s) { + if (helicityCfgs.genKinematicsChecks) { + if (d2.pt() <= secondaryCutsCfgs.cSecondaryPtMin || std::abs(d2.eta()) >= secondaryCutsCfgs.cSecondaryRapidityMax) { + continue; + } + } + bool seenPip = false, seenPim = false; + for (const auto& d3 : d2.template daughters_as()) { + if (d3.pdgCode() == +kPiPlus) { + if (helicityCfgs.genKinematicsChecks) { + if (d3.pt() <= trackCutCfgs.cMinPtcut || std::abs(d3.eta()) >= trackCutCfgs.cMaxEtacut) { + continue; + } + } + seenPip = true; + } else if (d3.pdgCode() == -kPiPlus) { + if (helicityCfgs.genKinematicsChecks) { + if (d3.pt() <= trackCutCfgs.cMinPtcut || std::abs(d3.eta()) >= trackCutCfgs.cMaxEtacut) { + continue; + } + } + seenPim = true; + } + } + if (seenPip && seenPim) { + lResoSecondary = LorentzVectorSetXYZM(d2.px(), d2.py(), d2.pz(), MassK0Short); + hasK0sToPipi = true; + break; + } + } + } + } + if (hasRightPion && hasK0sToPipi) { + break; + } + } + + if (!(hasRightPion && hasK0sToPipi)) { + continue; + } + if (helicityCfgs.cCosWithKShot) { + fillInvMass(lResoKstar, lCentrality, lResoSecondary, lDecayDaughter_bach, eventCutCfgs.confIsMix); + } else { + fillInvMass(lResoKstar, lCentrality, lDecayDaughter_bach, lResoSecondary, eventCutCfgs.confIsMix); + } + } + + currentIsGen = false; // To store the recoKstar for (const auto& v0 : v0s) { - currentIsGen = false; auto coll = v0.template collision_as(); if (!coll.has_mcCollision()) { @@ -1703,98 +1786,6 @@ struct Chargedkstaranalysis { histos.fill(HIST("Correction/sigLoss_num_pri"), part.pt(), lCentrality); } } - sigLossDen = true; - // To calculate the denominator -> To check the all the events have chk892 - for (auto const& part : mcParticles) { - if (!part.has_mcCollision()) { - continue; - } - if (std::abs(part.pdgCode()) != kKstarPlus) { - continue; - } - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { - continue; - } - - const auto mcid = part.mcCollisionId(); - if (!refClassIds.contains(mcid)) { - continue; - } - - auto iter = refCentByMcId.find(mcid); - if (iter == refCentByMcId.end()) { - continue; - } - - const float lCentrality = iter->second; - - histos.fill(HIST("Correction/sigLoss_den"), part.pt(), lCentrality); - if (part.vt() == 0) { - histos.fill(HIST("Correction/sigLoss_den_pri"), part.pt(), lCentrality); - } - LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; - lResoKstar = LorentzVectorSetXYZM(part.px(), part.py(), part.pz(), MassKPlusStar892); - const int pionWanted = (part.pdgCode() > 0) ? +kPiPlus : -kPiPlus; - bool hasRightPion = false; - bool hasK0sToPipi = false; - for (const auto& d1 : part.template daughters_as()) { - const int pdg1 = d1.pdgCode(); - if (pdg1 == pionWanted) { - lDecayDaughter_bach = LorentzVectorSetXYZM(d1.px(), d1.py(), d1.pz(), MassPionCharged); - if (helicityCfgs.genKinematicsChecks) { - if (lDecayDaughter_bach.pt() <= trackCutCfgs.cMinPtcut || std::abs(lDecayDaughter_bach.eta()) >= trackCutCfgs.cMaxEtacut) { - continue; - } - } - hasRightPion = true; - } else if (std::abs(pdg1) == kPDGK0) { - for (const auto& d2 : d1.template daughters_as()) { - if (std::abs(d2.pdgCode()) == kPDGK0s) { - if (helicityCfgs.genKinematicsChecks) { - if (d2.pt() <= secondaryCutsCfgs.cSecondaryPtMin || std::abs(d2.eta()) >= secondaryCutsCfgs.cSecondaryRapidityMax) { - continue; - } - } - bool seenPip = false, seenPim = false; - for (const auto& d3 : d2.template daughters_as()) { - if (d3.pdgCode() == +kPiPlus) { - if (helicityCfgs.genKinematicsChecks) { - if (d3.pt() <= trackCutCfgs.cMinPtcut || std::abs(d3.eta()) >= trackCutCfgs.cMaxEtacut) { - continue; - } - } - seenPip = true; - } else if (d3.pdgCode() == -kPiPlus) { - if (helicityCfgs.genKinematicsChecks) { - if (d3.pt() <= trackCutCfgs.cMinPtcut || std::abs(d3.eta()) >= trackCutCfgs.cMaxEtacut) { - continue; - } - } - seenPim = true; - } - } - if (seenPip && seenPim) { - lResoSecondary = LorentzVectorSetXYZM(d2.px(), d2.py(), d2.pz(), MassK0Short); - hasK0sToPipi = true; - break; - } - } - } - } - if (hasRightPion && hasK0sToPipi) { - break; - } - } - - if (!(hasRightPion && hasK0sToPipi)) { - continue; - } - if (helicityCfgs.cCosWithKShot) { - fillInvMass(lResoKstar, lCentrality, lResoSecondary, lDecayDaughter_bach, eventCutCfgs.confIsMix); - } else { - fillInvMass(lResoKstar, lCentrality, lDecayDaughter_bach, lResoSecondary, eventCutCfgs.confIsMix); - } - } // To calculate the event fraction correction for (const auto& mcid : refClassIds) { histos.fill(HIST("Correction/EF_den"), refCentByMcId[mcid]); diff --git a/PWGLF/Tasks/Resonances/deltaAnalysis.cxx b/PWGLF/Tasks/Resonances/deltaAnalysis.cxx index 263886c0eb5..0d39c167ce7 100644 --- a/PWGLF/Tasks/Resonances/deltaAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/deltaAnalysis.cxx @@ -100,6 +100,7 @@ struct DeltaAnalysis { Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 0, "Centrality estimator: 0=FT0M 1=FT0A 2=FT0C 3=FV0A 4=NTPV"}; Configurable cfgCentMin{"cfgCentMin", 0.f, "Minimum centrality percentile"}; Configurable cfgCentMax{"cfgCentMax", 100.f, "Maximum centrality percentile"}; + Configurable cfgUseMCTruthCentrality{"cfgUseMCTruthCentrality", false, "Use MC truth centrality for generated Delta histograms"}; } evSel; struct : ConfigurableGroup { @@ -189,7 +190,6 @@ struct DeltaAnalysis { struct : ConfigurableGroup { ConfigurableAxis cfgPtAxis{"cfgPtAxis", {VARIABLE_WIDTH, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.0, 5.0, 7.0, 10.0}, "#it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis cfgCentAxis{"cfgCentAxis", {VARIABLE_WIDTH, 0.f, 10.f, 20.f, 30.f, 40.f, 50.f, 60.f, 70.f, 80.f, 90.f, 100.f}, "Centrality (%)"}; - Configurable cfgCentDistBins{"cfgCentDistBins", 1500, "Number of bins for centrality distribution"}; ConfigurableAxis cfgVtxAxis{"cfgVtxAxis", {VARIABLE_WIDTH, -12.f, -10.f, -9.f, -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 12.f}, "Vertex z [cm]"}; ConfigurableAxis cfgRapAxis{"cfgRapAxis", {20, -1.0, 1.0}, "Rapidity y"}; } axes; @@ -241,7 +241,6 @@ struct DeltaAnalysis { const AxisSpec ptAxis{200, 0., 10., "p_{T} (GeV/c)"}; const AxisSpec massAxis{trackCuts.numberOfInvMassBins, 1.0, 8.0, "M_{inv} (GeV/#it{c}^{2})"}; const AxisSpec centAxis{axes.cfgCentAxis, "Centrality (%)"}; - const AxisSpec centDistAxis{axes.cfgCentDistBins, 0., 105., "Centrality (%)"}; const AxisSpec vtxAxis{axes.cfgVtxAxis, "Vertex z [cm]"}; const AxisSpec rapAxis{axes.cfgRapAxis, "Rapidity y"}; const AxisSpec nSigmaTPCaxis{100, -10., 10., "n#sigma^{TPC}"}; @@ -260,7 +259,7 @@ struct DeltaAnalysis { histos.add("Event/hNcontributor", "PV contributors; N", kTH1F, {{2001, -0.5f, 2000.5f}}); histos.add("Event/hCentrality", "Centrality", kTH1F, {centAxis}); histos.add("Event/hOccupancy", "Occupancy in time range", kTH1F, {occupancyAxis}); - histos.add("Event/centralitydistribution", "Centrality distribution (Data);vCentFT0M;Entries", kTH1F, {centDistAxis}); + histos.add("Event/centralitydistribution", "Centrality distribution (Data);vCentFT0M;Entries", kTH1F, {centAxis}); histos.add("CentQA/hCentralityVsVtxZ", "Centrality vs vertex z", kTH2F, {vtxAxis, centAxis}); histos.add("CentQA/hCentralityVsOccupancy", "Centrality vs occupancy", kTH2F, {occupancyAxis, centAxis}); @@ -430,7 +429,7 @@ struct DeltaAnalysis { histos.add("QAMC/hEtaPhi_rec", "MC Reco #eta vs #varphi; #eta; #varphi", kTH2F, {etaAxis, {72, 0, 6.2832}}); histos.add("MCRecoEvent/hRecoEvents", "Reconstructed INEL>0 events (Nrec, MC reco)", kTH1F, {centAxis}); - histos.add("MCRecoEvent/centralitydistribution", "Centrality distribution (MC);vCentFT0M;Entries", kTH1F, {centDistAxis}); + histos.add("MCRecoEvent/centralitydistribution", "Centrality distribution (MC);vCentFT0M;Entries", kTH1F, {centAxis}); } // ── MC reconstructed event mixing: histograms (gated by the dedicated MC mixing switch, @@ -1899,15 +1898,23 @@ struct DeltaAnalysis { histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 4.f); // Final generated event histos.fill(HIST("EfficiencyQA/hGeneratedEventCutFlow"), 3.f); // Final generated event + // ── MODIFIED BLOCK (per user request): centrality-source switch for generated Delta ──── + // Added: evSel.cfgUseMCTruthCentrality (see Configurable added in evSel group above). bool hasAcceptedReco = false; - float genCentrality = mcCollision.centFT0M(); // fallback: MC-truth centrality proxy (see note above) + float genCentrality = mcCollision.centFT0M(); + for (auto const& collision : collisions) { if (passesEventSelection(collision)) { hasAcceptedReco = true; - genCentrality = getCentrality(collision); // real reconstructed centrality of an accepted associated collision + + if (!evSel.cfgUseMCTruthCentrality) { + genCentrality = getCentrality(collision); + } + break; } } + if (hasAcceptedReco) { histos.fill(HIST("EfficiencyQA/hGeneratedEventCutFlow"), 4.f); // Associated reconstructed event accepted } diff --git a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx index 1489f7109f6..0feda126a09 100644 --- a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx @@ -15,6 +15,7 @@ #include "PWGLF/Utils/rsnOutput.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -40,11 +41,14 @@ #include #include +#include +#include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include #include #include #include +#include #include @@ -62,42 +66,47 @@ struct PhianalysisTHnSparse { SliceCache cache; struct : ConfigurableGroup { - Configurable produceQA{"produceQA", false, "Produce qa histograms."}; - Configurable produceStats{"produceStats", false, "Produce statistics histograms."}; - Configurable produceTrue{"produceTrue", false, "Produce True and Gen histograms."}; + Configurable produceMC{"produceMC", false, "Produce True and Gen histograms."}; Configurable produceLikesign{"produceLikesign", false, "Produce Like sign histograms."}; Configurable eventMixing{"eventMixing", "none", "Produce Event Mixing histograms of type."}; Configurable produceRotational{"produceRotational", false, "Produce Rotational histograms."}; } produce; - Configurable daughterPos{"daughterPos", 3, "Particle type of the positive dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; - Configurable daughterNeg{"daughterNeg", 3, "Particle type of the negative dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable daughterPos{"daughterPos", 3, "Particle type of the positive daughter according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable daughterNeg{"daughterNeg", 3, "Particle type of the negative daughter according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; Configurable motherPDG{"motherPDG", 333, "PDG code of mother particle."}; - Configurable daughterPosPDG{"daughterPosPDG", 321, "PDG code of positive dauther particle."}; - Configurable daughterNegPDG{"daughterNegPDG", 321, "PDG code of negative dauther particle."}; + Configurable daughterPosPDG{"daughterPosPDG", 321, "PDG code of positive daughter particle."}; + Configurable daughterNegPDG{"daughterNegPDG", 321, "PDG code of negative daughter particle."}; struct : ConfigurableGroup { - Configurable tpcnSigmaPos{"tpcnSigmaPos", 3.0f, "TPC NSigma cut of the positive particle."}; - Configurable tpcnSigmaNeg{"tpcnSigmaNeg", 3.0f, "TPC NSigma cut of the negative particle."}; - Configurable tpcPidOnly{"tpcPidOnly", false, "Use TPC only for PID."}; - Configurable combinedNSigma{"combinedNSigma", 3.0f, "Combined NSigma cut for combined TPC and TOF NSigma cut."}; - Configurable ptTOFThreshold{"ptTOFThreshold", 0.5f, "Threshold for applying TOF."}; - Configurable rapidity{"rapidity", 0.5f, "Rapidity cut (maximum)."}; - Configurable etatrack{"etatrack", 0.8f, "Eta cut for track."}; - Configurable pt{"pt", 0.15f, "Cut: Minimal value of tracks pt."}; - Configurable dcaXY{"dcaXY", 1.0f, "Cut: Maximal value of tracks DCA XY."}; - Configurable dcaZ{"dcaZ", 1.0f, "Cut: Maximal value of tracks DCA Z."}; - Configurable globalTrack{"globalTrack", false, "Use global track selection."}; - Configurable inelGrater0{"inelGrater0", true, "Select events with INEL>0."}; - Configurable tpcNClsFound{"tpcNClsFound", 70, "Cut: Minimal value of found TPC clasters"}; + Configurable isTriggerTVX{"isTriggerTVX", false, "Apply IsTriggerTVX cut."}; + Configurable noTimeFrameBorder{"noTimeFrameBorder", false, "Apply NoTimeFrameBorder cut."}; + Configurable noITSROFrameBorder{"noITSROFrameBorder", false, "Apply NoITSROFrameBorder cut."}; + Configurable sel8{"sel8", false, "Apply Sel8 cut."}; + Configurable inelGt0{"inelGt0", false, "Select events with INEL>0."}; Configurable vzCut{"vzCut", 10.0f, "Cut: Maximal value of Z vertex position."}; - } cut; + Configurable noSameBunchPileup{"noSameBunchPileup", false, "Apply no same bunch pileup cut."}; + Configurable isVertexITSTPC{"isVertexITSTPC", false, "Apply IsVertexITSTPC cut."}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, "Apply IsGoodZvtxFT0vsPV cut."}; + } eventCuts; struct : ConfigurableGroup { - Configurable verboselevel{"verboselevel", 0, "Verbose level"}; - Configurable refresh{"refresh", 0, "Freqency of print event information."}; - Configurable refreshIndex{"refreshIndex", 0, "Freqency of print event information index."}; - } verbose; + Configurable pt{"pt", 0.15f, "Cut: Minimal value of tracks pt."}; + Configurable etatrack{"etatrack", 1.0f, "Cut: Maximal value of tracks eta."}; + Configurable dcaXY{"dcaXY", 1.0f, "Cut: Maximal value of tracks DCA XY."}; + Configurable dcaZ{"dcaZ", 1.0f, "Cut: Maximal value of tracks DCA Z."}; + Configurable tpcnSigmaPos{"tpcnSigmaPos", 10.0f, "Cut: Maximal value of TPC NSigma of the positive particle."}; + Configurable tpcnSigmaNeg{"tpcnSigmaNeg", 10.0f, "Cut: Maximal value of TPC NSigma of the negative particle."}; + Configurable tpcPidOnly{"tpcPidOnly", false, "Use TPC only for PID."}; + Configurable combinedNSigma{"combinedNSigma", 3.0f, "Cut: Maximal value of NSigma for combined TPC and TOF NSigma cut."}; + Configurable ptTOFThreshold{"ptTOFThreshold", 0.5f, "Cut: Minimal value of tracks pt for using TOF PID."}; + Configurable tpcNClsFound{"tpcNClsFound", 155, "Cut: Minimal value of found TPC clusters"}; + Configurable tpcNClsCrossedRows{"tpcNClsCrossedRows", 155, "Cut: Minimal value of crossed rows in TPC"}; + Configurable globalTrack{"globalTrack", false, "Use isGlobalTrack track selection."}; + Configurable primaryTrack{"primaryTrack", false, "Use isPrimaryTrack track selection."}; + Configurable pvContributor{"pvContributor", false, "Use isPVContributor track selection."}; + Configurable rapidity{"rapidity", 0.5f, "Cut: Maximal value of particle rapidity."}; + } trackCuts; Configurable> sparseAxes{"sparseAxes", std::vector{o2::analysis::rsn::pair_axis::names}, "Axes."}; Configurable> sysAxes{"sysAxes", std::vector{o2::analysis::rsn::systematic_axis::names}, "Axes."}; @@ -107,69 +116,68 @@ struct PhianalysisTHnSparse { ConfigurableAxis vzaxis{"vzaxis", {40, -20., 20.}, "Z vertex position axis binning."}; ConfigurableAxis multiplicityaxis{"multiplicityaxis", {50, 0., 5000.}, "Multiplicity axis binning."}; ConfigurableAxis centralityaxis{"centralityaxis", {20, 0., 100.}, "Centrality axis binning."}; - ConfigurableAxis etaaxis{"etaaxis", {16., -1.0 * static_cast(cut.etatrack), static_cast(cut.etatrack)}, "Pseudorapidity axis binning."}; - ConfigurableAxis rapidityaxis{"rapidityaxis", {10., -1.0 * static_cast(cut.rapidity), static_cast(cut.rapidity)}, "Rapidity axis binning."}; - ConfigurableAxis nsigmaaxisPos{"nsigmaaxisPos", {1, -static_cast(cut.tpcnSigmaPos), static_cast(cut.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; - ConfigurableAxis nsigmaaxisNeg{"nsigmaaxisNeg", {1, -static_cast(cut.tpcnSigmaNeg), static_cast(cut.tpcnSigmaNeg)}, "NSigma of negative particle axis binning in THnSparse."}; + ConfigurableAxis etaaxis{"etaaxis", {16., -1.0 * static_cast(trackCuts.etatrack), static_cast(trackCuts.etatrack)}, "Pseudorapidity axis binning."}; + ConfigurableAxis rapidityaxis{"rapidityaxis", {10., -1.0 * static_cast(trackCuts.rapidity), static_cast(trackCuts.rapidity)}, "Rapidity axis binning."}; + ConfigurableAxis nsigmaaxisPos{"nsigmaaxisPos", {1, -static_cast(trackCuts.tpcnSigmaPos), static_cast(trackCuts.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; + ConfigurableAxis nsigmaaxisNeg{"nsigmaaxisNeg", {1, -static_cast(trackCuts.tpcnSigmaNeg), static_cast(trackCuts.tpcnSigmaNeg)}, "NSigma of negative particle axis binning in THnSparse."}; // mixing - using BinningTypeVzMu = ColumnBinningPolicy>; + using BinningTypeVzMu = ColumnBinningPolicy>; using BinningTypeVzCe = ColumnBinningPolicy; - Configurable numberofMixedEvents{"numberofMixedEvents", 5, "Number of events that should be mixed."}; + Configurable nMixedEvents{"nMixedEvents", 5, "Number of events that should be mixed."}; ConfigurableAxis axisVertexMixing{"axisVertexMixing", {5, -10, 10}, "Z vertex axis binning for mixing"}; - ConfigurableAxis axisMultiplicityMixing{"axisMultiplicityMixing", {5, 0, 5000}, "TPC multiplicity for bin"}; - ConfigurableAxis axisCentralityMixing{"axisCentralityMixing", {10, 0, 100}, "Multiplicity percentil binning for mixing"}; + ConfigurableAxis axisMultiplicityMixing{"axisMultiplicityMixing", {5, 0, 5000}, "FT0M amplitude binning for event mixing."}; + ConfigurableAxis axisCentralityMixing{"axisCentralityMixing", {10, 0, 100}, "FT0M centrality percentile binning for event mixing."}; // rotational - Configurable numberofRotations{"numberofRotations", 1, "Number of rotations for rotational background estimation."}; + Configurable nRotations{"nRotations", 1, "Number of rotations for rotational background estimation."}; Configurable startingAngle{"startingAngle", 0, "Starting angle for rotational background estimation."}; // other axes - ConfigurableAxis axisNch{"axisNch", {1000, 0.0f, +1000.0f}, "Number of charged particles."}; - ConfigurableAxis axisResolutionPt{"axisResolutionPt", {1001, -1.0f, +1.0f}, "Resolution of Pt."}; - ConfigurableAxis axisResolutionPtPhi{"axisResolutionPtPhi", {1001, -0.01f, +0.01f}, "Resolution of Pt and Phi."}; - ConfigurableAxis axisResolutionMass{"axisResolutionMass", {1001, -0.01f, +0.01f}, "Resolution of Mass."}; - ConfigurableAxis axisResolutionVz{"axisResolutionVz", {1001, -3.0f, +3.0f}, "Resolution of Vz."}; - ConfigurableAxis massShiftAxis{"massShiftAxis", {1001, -0.02f, 0.02f}, "Mass correction axis."}; + ConfigurableAxis axisNch{"axisNch", {1000, 0.0, +1000.0}, "Number of charged particles."}; + ConfigurableAxis axisResolutionPt{"axisResolutionPt", {1001, -1.0, +1.0}, "Resolution of Pt."}; + ConfigurableAxis axisResolutionPtPhi{"axisResolutionPtPhi", {1001, -0.01, +0.01}, "Resolution of Pt and Phi."}; + ConfigurableAxis axisResolutionMass{"axisResolutionMass", {1001, -0.01, +0.01}, "Resolution of Mass."}; + ConfigurableAxis axisResolutionVz{"axisResolutionVz", {1001, -3.0, +3.0}, "Resolution of Vz."}; + ConfigurableAxis axisQAPt{"axisQAPt", {15, 0.0, 15.0}, "QA Pt axis binning."}; + ConfigurableAxis axisQAMult{"axisQAMult", {10, 0.0, 100.0}, "QA Multiplicity axis binning."}; + ConfigurableAxis axisQACent{"axisQACent", {101, 0.0f, 101.0f}, "QA Centrality axis binning."}; // Axes specifications - AxisSpec posZaxis = {400, -20., 20., "V_{z} (cm)"}; - AxisSpec dcaXYaxis = {1000, -1.0, 1.0, "DCA_{xy} (cm)"}; - AxisSpec dcaZaxis = {1000, -1.0, 1.0, "DCA_{z} (cm)"}; - AxisSpec etaQAaxis = {1000, -1.0, 1.0, "#eta"}; - AxisSpec tpcNClsFoundQAaxis = {110, 50., 160., "tpcNClsFound"}; - AxisSpec massShiftRelAxis = {101, -0.03f, 0.03f, ""}; + AxisSpec vzQAaxis = {200, -20., 20., "V_{z} (cm)"}; + AxisSpec dcaXYQAaxis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; + AxisSpec dcaZQAaxis = {200, -0.5, 0.5, "DCA_{z} (cm)"}; + AxisSpec etaQAaxis = {200, -1.0, 1.0, "#eta"}; + AxisSpec rapidityQAaxis = {200, -1.0, 1.0, "y"}; + AxisSpec tpcNClsQAaxis = {200, 0., 200., "TPC NClusters"}; + AxisSpec nSigmaTPCQAaxis = {200, -10., 10., "n#sigma_{TPC} K^{#pm}"}; + AxisSpec nSigmaTOFQAaxis = {200, -10., 10., "n#sigma_{TOF} K^{#pm}"}; + AxisSpec pQAaxis = {1490, 0.1, 15.0, "p (GeV/c)"}; + AxisSpec dEdxQAaxis = {2000, 0., 200., "dE/dx (a.u.)"}; + AxisSpec betaQAaxis = {700, 0.5, 1.2, "#beta"}; + AxisSpec dPhiQAaxis = {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI, "#Delta#phi (rad)"}; + AxisSpec dThetaQAaxis = {100, -o2::constants::math::PI, o2::constants::math::PI, "#Delta#theta (rad)"}; + AxisSpec dEtaQAaxis = {200, -1.0, 1.0, "#Delta#eta"}; HistogramRegistry registry{"registry"}; o2::analysis::rsn::Output* rsnOutput = nullptr; - Service pdg; + Service pdg{}; - int n = 0; float massPos = o2::track::PID::getMass(3); float massNeg = o2::track::PID::getMass(3); int pion = 2; int kaon = 3; int proton = 4; double* pointPair = nullptr; - double* pointSys = nullptr; ROOT::Math::PxPyPzMVector d1, d2, mother, motherGen; - bool produceTrue, produceLikesign, produceQA, produceStats, produceRotational, dataQA, MCTruthQA, globalTrack, inelGrater0, tpcPidOnly = false; - float tpcnSigmaPos = 100.0f; - float tpcnSigmaNeg = 100.0f; - float combinedNSigma = 100.0f; - float ptTOFThreshold = 0.5f; - int tpcNClsFound = 70; + bool dataQA = false; int dauSize = 2; - float vzCut = 10.0f; rsn::MixingType mixingType = rsn::MixingType::none; - Filter triggerFilter = (o2::aod::evsel::sel8 == true); - Filter vtxFilter = (nabs(o2::aod::collision::posZ) < vzCut); - using EventCandidates = soa::Join; using EventCandidate = EventCandidates::iterator; - using TrackCandidates = soa::Join; + using TrackCandidates = soa::Join; using EventCandidatesMC = soa::Join; using TrackCandidatesMC = soa::Join; @@ -194,13 +202,18 @@ struct PhianalysisTHnSparse { LOGF(info, " Positive: %d, mass: %f", static_cast(daughterPos), massPos); LOGF(info, " Negative: %d, mass: %f", static_cast(daughterNeg), massNeg); + AxisSpec centQAAxis = {axisQACent, "FT0M (%)"}; + AxisSpec nchQAAxis = {axisNch, "N_{ch}"}; + AxisSpec multQAAxis = {axisQAMult, "FT0M (%)"}; + AxisSpec ptQAAxis = {axisQAPt, "p_{T} (GeV/c)"}; + // Sparse axes AxisSpec invAxis = {invaxis, "Inv. mass (GeV/c^{2})", "im"}; AxisSpec ptAxis = {ptaxis, "p_{T} (GeV/c)", "pt"}; - AxisSpec muAxis = {multiplicityaxis, "N", "mu"}; - AxisSpec mumAxis = {multiplicityaxis, "N", "mum"}; - AxisSpec ceAxis = {centralityaxis, "N", "ce"}; - AxisSpec cemAxis = {centralityaxis, "N", "cem"}; + AxisSpec muAxis = {multiplicityaxis, "FT0M (Ampl.)", "mu"}; + AxisSpec mumAxis = {multiplicityaxis, "FT0M (Ampl.)", "mum"}; + AxisSpec ceAxis = {centralityaxis, "FT0M (%)", "ce"}; + AxisSpec cemAxis = {centralityaxis, "FT0M (%)", "cem"}; AxisSpec etaAxis = {etaaxis, "#eta", "eta"}; AxisSpec yAxis = {rapidityaxis, "y", "y"}; AxisSpec nsAxisPos = {nsigmaaxisPos, fmt::format("nSigma of positive particle ({})", massPos), "ns1"}; @@ -216,55 +229,43 @@ struct PhianalysisTHnSparse { std::vector allAxes = {invAxis, ptAxis, muAxis, ceAxis, nsAxisPos, nsAxisNeg, etaAxis, yAxis, vzAxis, mumAxis, cemAxis, vzmAxis}; std::vector allAxesSys = {tpcNClsFoundAxis}; - produceQA = static_cast(produce.produceQA); - produceStats = static_cast(produce.produceStats); - produceTrue = static_cast(produce.produceTrue); - produceLikesign = static_cast(produce.produceLikesign); mixingType = rsn::mixingTypeName(static_cast(produce.eventMixing)); - produceRotational = static_cast(produce.produceRotational); - tpcnSigmaPos = static_cast(cut.tpcnSigmaPos); - tpcnSigmaNeg = static_cast(cut.tpcnSigmaNeg); - tpcNClsFound = static_cast(cut.tpcNClsFound); - globalTrack = static_cast(cut.globalTrack); - inelGrater0 = static_cast(cut.inelGrater0); - combinedNSigma = static_cast(cut.combinedNSigma); - tpcPidOnly = static_cast(cut.tpcPidOnly); - ptTOFThreshold = static_cast(cut.ptTOFThreshold); - vzCut = static_cast(cut.vzCut); pointPair = new double[static_cast(o2::analysis::rsn::PairAxisType::unknown)]; - pointSys = new double[static_cast(o2::analysis::rsn::SystematicsAxisType::unknown)]; rsnOutput = new o2::analysis::rsn::OutputSparse(); - rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxesSys, produceTrue, mixingType, produceLikesign, produceRotational, ®istry); + rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxesSys, static_cast(produce.produceMC), mixingType, static_cast(produce.produceLikesign), static_cast(produce.produceRotational), ®istry); // Print summary of configuration LOGF(info, "=== PhianalysisTHnSparse configuration summary ==="); - LOGF(info, "produceQA: %s", produceQA ? "true" : "false"); - LOGF(info, "produceStats: %s", produceStats ? "true" : "false"); - LOGF(info, "produceTrue: %s", static_cast(produce.produceTrue) ? "true" : "false"); + LOGF(info, "produceMC: %s", static_cast(produce.produceMC) ? "true" : "false"); LOGF(info, "produceLikesign: %s", static_cast(produce.produceLikesign) ? "true" : "false"); LOGF(info, "produceRotational: %s", static_cast(produce.produceRotational) ? "true" : "false"); LOGF(info, "eventMixing: %s", static_cast(produce.eventMixing).c_str()); + LOGF(info, "inelGt0: %s", static_cast(eventCuts.inelGt0) ? "true" : "false"); + LOGF(info, "noSameBunchPileup: %s", static_cast(eventCuts.noSameBunchPileup) ? "true" : "false"); + LOGF(info, "isVertexITSTPC: %s", static_cast(eventCuts.isVertexITSTPC) ? "true" : "false"); + LOGF(info, "isGoodZvtxFT0vsPV: %s", static_cast(eventCuts.isGoodZvtxFT0vsPV) ? "true" : "false"); + LOGF(info, "vzCut: %.2f", static_cast(eventCuts.vzCut)); LOGF(info, "daughterPos: %d (PDG: %d)", static_cast(daughterPos), static_cast(daughterPosPDG)); LOGF(info, "daughterNeg: %d (PDG: %d)", static_cast(daughterNeg), static_cast(daughterNegPDG)); LOGF(info, "motherPDG: %d", static_cast(motherPDG)); - LOGF(info, "tpcnSigmaPos: %.2f", tpcnSigmaPos); - LOGF(info, "tpcnSigmaNeg: %.2f", tpcnSigmaNeg); - LOGF(info, "tpcPidOnly: %s", tpcPidOnly ? "true" : "false"); - LOGF(info, "combinedNSigma: %.2f", combinedNSigma); - LOGF(info, "ptTOFThreshold: %.2f", ptTOFThreshold); - LOGF(info, "rapidity: %.2f", static_cast(cut.rapidity)); - LOGF(info, "etatrack: %.2f", static_cast(cut.etatrack)); - LOGF(info, "pt (min): %.2f", static_cast(cut.pt)); - LOGF(info, "dcaXY: %.2f", static_cast(cut.dcaXY)); - LOGF(info, "dcaZ: %.2f", static_cast(cut.dcaZ)); - LOGF(info, "globalTrack: %s", globalTrack ? "true" : "false"); - LOGF(info, "inelGrater0: %s", inelGrater0 ? "true" : "false"); - LOGF(info, "tpcNClsFound: %d", tpcNClsFound); - LOGF(info, "vzCut: %.2f", vzCut); - LOGF(info, "mixingType: %d", static_cast(mixingType)); - LOGF(info, "numberofMixedEvents: %d", static_cast(numberofMixedEvents)); - LOGF(info, "numberofRotations: %d", static_cast(numberofRotations)); + LOGF(info, "pt (min): %.2f", static_cast(trackCuts.pt)); + LOGF(info, "eta (max): %.2f", static_cast(trackCuts.etatrack)); + LOGF(info, "dcaXY: %.2f", static_cast(trackCuts.dcaXY)); + LOGF(info, "dcaZ: %.2f", static_cast(trackCuts.dcaZ)); + LOGF(info, "tpcnSigmaPos: %.2f", static_cast(trackCuts.tpcnSigmaPos)); + LOGF(info, "tpcnSigmaNeg: %.2f", static_cast(trackCuts.tpcnSigmaNeg)); + LOGF(info, "tpcPidOnly: %s", static_cast(trackCuts.tpcPidOnly) ? "true" : "false"); + LOGF(info, "combinedNSigma: %.2f", static_cast(trackCuts.combinedNSigma)); + LOGF(info, "ptTOFThreshold: %.2f", static_cast(trackCuts.ptTOFThreshold)); + LOGF(info, "tpcNClsFound: %d", static_cast(trackCuts.tpcNClsFound)); + LOGF(info, "tpcNClsCrossedRows: %d", static_cast(trackCuts.tpcNClsCrossedRows)); + LOGF(info, "globalTrack: %s", static_cast(trackCuts.globalTrack) ? "true" : "false"); + LOGF(info, "primaryTrack: %s", static_cast(trackCuts.primaryTrack) ? "true" : "false"); + LOGF(info, "pvContributor: %s", static_cast(trackCuts.pvContributor) ? "true" : "false"); + LOGF(info, "rapidity: %.2f", static_cast(trackCuts.rapidity)); + LOGF(info, "nMixedEvents: %d", static_cast(nMixedEvents)); + LOGF(info, "nRotations: %d", static_cast(nRotations)); LOGF(info, "startingAngle: %d", static_cast(startingAngle)); LOGF(info, "sparseAxes: "); for (const auto& axis : static_cast>(sparseAxes)) { @@ -276,222 +277,274 @@ struct PhianalysisTHnSparse { } LOGF(info, "==============================================="); - if (produceQA) { - // Event QA - registry.add("QAEvent/hSelection", "Event selection statistics", kTH1D, {{4, 0.0f, 4.0f}}); - auto hEvent = registry.get(HIST("QAEvent/hSelection")); - - hEvent->GetXaxis()->SetBinLabel(1, "all events"); - hEvent->GetXaxis()->SetBinLabel(2, "Events passing trigger sel8"); - hEvent->GetXaxis()->SetBinLabel(3, "Events passing |V_{z}| cut"); - hEvent->GetXaxis()->SetBinLabel(4, "Events passing INEL>0 cut"); - hEvent->SetMinimum(0.1); - - registry.add("QAEvent/hVtxZ", "Vertex position along the z-axis", kTH1F, {posZaxis}); - registry.add("QAEvent/hCent", "Distribution of multiplicity percentile", kTH1F, {{101, 0., 101.}}); - registry.add("QAEvent/hMult", "Multiplicity (amplitude of non-zero channels in the FT0A + FT0C) ", kTH1F, {{300, 0., 30000.}}); - - // Track QA - registry.add("QATrack/hSelection", "Tracks statistics", kTH1D, {{9, 0.0f, 9.0f}}); - auto hTrack = registry.get(HIST("QATrack/hSelection")); - hTrack->GetXaxis()->SetBinLabel(1, "all tracks"); - hTrack->GetXaxis()->SetBinLabel(2, "passed pT cut"); - hTrack->GetXaxis()->SetBinLabel(3, "passed eta cut"); - hTrack->GetXaxis()->SetBinLabel(4, "passed DCA cut"); - hTrack->GetXaxis()->SetBinLabel(5, "passed PID cut"); - hTrack->GetXaxis()->SetBinLabel(6, "passed tpcNClsFound cut"); - hTrack->GetXaxis()->SetBinLabel(7, "passed isPrimaryTrack cut"); - hTrack->GetXaxis()->SetBinLabel(8, "passed isPVContributor cut"); - hTrack->GetXaxis()->SetBinLabel(9, "passed all cuts"); - hTrack->SetMinimum(0.1); - - registry.add("QATrack/hRapidity", "Rapidity distribution of K^{+} and K^{-}", kTH1F, {{200, -1, 1}}); - registry.add("QATrack/hEta", "Pseudorapidity distribution of K^{+} and K^{-}", kTH1F, {{200, -1, 1}}); - registry.add("QATrack/hTPCNClsFound", "Distribution of TPC NClsFound of K^{+} and K^{-}", kTH1F, {tpcNClsFoundQAaxis}); - registry.add("QATrack/hDCAxy", "Distribution of DCA_{xy} of K^{+} and K^{-}", kTH1F, {dcaXYaxis}); - registry.add("QATrack/hDCAz", "Distribution of DCA_{z} of K^{+} and K^{-}", kTH1F, {dcaZaxis}); - registry.add("QATrack/hPt", "Distribution of p_{T} of K^{+} and K^{-}", kTH1F, {ptaxis}); - - // Phi candidate QA - registry.add("QAPhi/hRapidity", "Rapidity distribution of #Phi candidates", kTH1F, {{200, -1, 1}}); - registry.add("QAPhi/hEta", "Pseudorapidity distribution of #Phi candidates", kTH1F, {{200, -1, 1}}); - registry.add("QAPhi/hdPhi", "Azimuthal distribution (#Delta#phi) of #Phi candidates", kTH1F, {{100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto hdPhi = registry.get(HIST("QAPhi/hdPhi")); - hdPhi->GetXaxis()->SetTitle("#Delta#phi (rad)"); - - registry.add("QAPhi/h2dPhiPt", "Azimuthal distribution (#Delta#phi) of #Phi candidates vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto h2dPhiPt = registry.get(HIST("QAPhi/h2dPhiPt")); - h2dPhiPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2dPhiPt->GetYaxis()->SetTitle("#Delta#phi (rad)"); - - registry.add("QAPhi/hTheta", "Polar distribution of #Phi candidates", kTH1F, {{100, 0.0f, o2::constants::math::PI}}); - auto hTheta = registry.get(HIST("QAPhi/hTheta")); - hTheta->GetXaxis()->SetTitle("#theta (rad)"); - - registry.add("QAPhi/h2dThetaPt", "Polar distribution (#Delta#theta) of #Phi candidates vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); - - auto h2dThetaPt = registry.get(HIST("QAPhi/h2dThetaPt")); - h2dThetaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2dThetaPt->GetYaxis()->SetTitle("#Delta#theta (rad)"); - - // Rotational background QA - if (produceRotational) { - registry.add("QARotational/hRapidity", "Rapidity distribution of #Phi candidates from rotational background", kTH1F, {{200, -1, 1}}); - registry.add("QARotational/hEta", "Pseudorapidity distribution of #Phi candidates from rotational background", kTH1F, {{200, -1, 1}}); - registry.add("QARotational/hdPhi", "Rotational background: Azimuthal distribution (#Delta#phi)", kTH1F, {{100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto hRPhi = registry.get(HIST("QARotational/hdPhi")); - hRPhi->GetXaxis()->SetTitle("#Delta#phi"); - - registry.add("QARotational/h2dPhiPt", "Rotational background: Azimuthal distribution (#Delta#phi) vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto hR2dPhiPt = registry.get(HIST("QARotational/h2dPhiPt")); - hR2dPhiPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - hR2dPhiPt->GetYaxis()->SetTitle("#Delta#phi"); - - registry.add("QARotational/hTheta", "Rotational background: Polar distribution (#theta)", kTH1F, {{100, 0.0f, o2::constants::math::PI}}); - auto hRdTheta = registry.get(HIST("QARotational/hTheta")); - hRdTheta->GetXaxis()->SetTitle("#theta (rad)"); - - registry.add("QARotational/h2dThetaPt", "Rotational background: Polar distribution (#Delta#theta) vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); - auto hR2dThetaPt = registry.get(HIST("QARotational/h2dThetaPt")); - hR2dThetaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - hR2dThetaPt->GetYaxis()->SetTitle("#Delta#theta"); - } + // ------------------- Event QA ------------------- + registry.add("QA/Event/hSelection", "Event selection statistics", kTH1D, {{11, 0.0f, 11.0f}}); + auto hEvent = registry.get(HIST("QA/Event/hSelection")); + hEvent->GetXaxis()->SetBinLabel(1, "all events"); + hEvent->GetXaxis()->SetBinLabel(2, "isTriggerTVX"); + hEvent->GetXaxis()->SetBinLabel(3, "noTimeFrameBorder"); + hEvent->GetXaxis()->SetBinLabel(4, "noITSROFrameBorder"); + hEvent->GetXaxis()->SetBinLabel(5, "sel8"); + hEvent->GetXaxis()->SetBinLabel(6, "IsVertexITSTPC"); + hEvent->GetXaxis()->SetBinLabel(7, "noSameBunchPileup"); + hEvent->GetXaxis()->SetBinLabel(8, "IsGoodZvtxFT0vsPV"); + hEvent->GetXaxis()->SetBinLabel(9, Form("|V_{z}| < %0.0f cm", static_cast(eventCuts.vzCut))); + hEvent->GetXaxis()->SetBinLabel(10, "INEL"); + hEvent->GetXaxis()->SetBinLabel(11, "INEL>0"); + hEvent->SetMinimum(0.1); + + registry.add("QA/Event/hVtxZ", "Vertex position along the z-axis", kTH1F, {vzQAaxis}); + auto hVtxZ = registry.get(HIST("QA/Event/hVtxZ")); + + registry.add("QA/Event/hCent", "FT0M (%)", kTH1F, {{101, 0., 101.}}); + auto hCent = registry.get(HIST("QA/Event/hCent")); + hCent->GetXaxis()->SetTitle("FT0M (%)"); + + registry.add("QA/Event/hMult", "Amplitude of non-zero channels in the FT0A + FT0C) ", kTH1F, {{300, 0., 30000.}}); + auto hMult = registry.get(HIST("QA/Event/hMult")); + hMult->GetXaxis()->SetTitle("FT0M Ampl."); + + registry.add("QA/Event/hCentNch", "Event centrality vs multiplicity", kTH2F, {centQAAxis, nchQAAxis}); + + // ----------------------- Track QA ----------------------- + registry.add("QA/Track/hSelection", "Track selection statistics", kTH1D, {{9, 0.0f, 9.0f}}); + auto hTrack = registry.get(HIST("QA/Track/hSelection")); + hTrack->GetXaxis()->SetBinLabel(1, "all tracks"); + hTrack->GetXaxis()->SetBinLabel(2, Form("pT > %.2f", static_cast(trackCuts.pt))); + hTrack->GetXaxis()->SetBinLabel(3, Form("eta < %.1f", static_cast(trackCuts.etatrack))); + hTrack->GetXaxis()->SetBinLabel(4, "DCA cuts"); + hTrack->GetXaxis()->SetBinLabel(5, "PID cuts"); + hTrack->GetXaxis()->SetBinLabel(6, Form("tpcNClsFound > %d", static_cast(trackCuts.tpcNClsFound))); + hTrack->GetXaxis()->SetBinLabel(7, Form("tpcNClsCrossedRows > %d", static_cast(trackCuts.tpcNClsCrossedRows))); + hTrack->GetXaxis()->SetBinLabel(8, Form("%s", static_cast(trackCuts.globalTrack) ? "isGlobalTrack" : "isPrimaryTrack")); + hTrack->GetXaxis()->SetBinLabel(9, "isPVContributor"); + hTrack->SetMinimum(0.1); + + registry.add("QA/Track/hRapidity", "Rapidity distribution of Tracks", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Track/hEta", "Pseudorapidity distribution of Tracks", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Track/hTPCNClsFound", "Number of found TPC clusters of Tracks", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Track/hTPCNClsCrossedRows", "Number of crossed rows in TPC of Tracks", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Track/hDCAxy", "Distribution of DCA_{xy} of Tracks", kTH3F, {ptQAAxis, multQAAxis, dcaXYQAaxis}); + registry.add("QA/Track/hDCAz", "Distribution of DCA_{z} of Tracks", kTH3F, {ptQAAxis, multQAAxis, dcaZQAaxis}); + registry.add("QA/Track/hPt", "Distribution of p_{T} of Tracks", kTH2F, {ptQAAxis, multQAAxis}); + + registry.add("QA/Kaon/hRapidity", "Rapidity distribution of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Kaon/hEta", "Pseudorapidity distribution of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Kaon/hTPCNClsFound", "Number of found TPC clusters of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Kaon/hTPCNClsCrossedRows", "Number of crossed rows in TPC of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Kaon/hDCAxy", "Distribution of DCA_{xy} of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, dcaXYQAaxis}); + registry.add("QA/Kaon/hDCAz", "Distribution of DCA_{z} of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, dcaZQAaxis}); + registry.add("QA/Kaon/hPt", "Distribution of p_{T} of K^{+} and K^{-}", kTH2F, {ptQAAxis, multQAAxis}); + + // ---------------------- PID QA ---------------------- + + registry.add("QA/PID/hTPCNSigma", "Distribution of TPC nSigma", kTH3F, {ptQAAxis, multQAAxis, nSigmaTPCQAaxis}); + registry.add("QA/PID/hTPCNSigmaK", "Distribution of TPC nSigma of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, nSigmaTPCQAaxis}); + registry.add("QA/PID/hTOFNSigma", "Distribution of TOF nSigma", kTH3F, {ptQAAxis, multQAAxis, nSigmaTOFQAaxis}); + registry.add("QA/PID/hTOFNSigmaK", "Distribution of TOF nSigma of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, nSigmaTOFQAaxis}); + registry.add("QA/PID/hTPCTOFnSigma", "", kTH3F, {ptQAAxis, nSigmaTPCQAaxis, nSigmaTOFQAaxis}); + + registry.add("QA/PID/hTPCdEdxP", "dE/dx vs p of charged particles", kTH2F, {pQAaxis, dEdxQAaxis}); + registry.add("QA/PID/hTPCdEdxPK", "dE/dx vs p of K^{+} and K^{-}", kTH2F, {pQAaxis, dEdxQAaxis}); + registry.add("QA/PID/hTOFBetaP", "TOF #beta vs p of charged particles", kTH2F, {pQAaxis, betaQAaxis}); + registry.add("QA/PID/hTOFBetaPK", "TOF #beta vs p of K^{+} and K^{-}", kTH2F, {pQAaxis, betaQAaxis}); + + // ------------------------- MC QA ------------------------- + if (static_cast(produce.produceMC)) { + // Rec + registry.add("QAMC/Rec/hSelection", "MC Rec True Event statistics", kTH1F, {{2, 0.0f, 2.0f}}); + auto hMCEventTruth = registry.get(HIST("QAMC/Rec/hSelection")); + hMCEventTruth->GetXaxis()->SetBinLabel(1, "Full MC Rec event statistics"); + hMCEventTruth->GetXaxis()->SetBinLabel(2, "MC Rec events passing event selection"); + hMCEventTruth->SetMinimum(0.1); + + // Gen + registry.add("QAMC/Gen/hSelection", "MC Gen Event statistics", kTH1F, {{3, 0.0f, 3.0f}}); + auto hMCEventGen = registry.get(HIST("QAMC/Gen/hSelection")); + hMCEventGen->GetXaxis()->SetBinLabel(1, "Generated collisions"); + hMCEventGen->GetXaxis()->SetBinLabel(2, "Generated collisions with at least one reconstructed collision"); + hMCEventGen->GetXaxis()->SetBinLabel(3, "Generated collisions passing event selection"); + hMCEventGen->SetMinimum(0.1); + + // Factors + registry.add("QAMC/Factors/hGenEvents", "Generated events", HistType::kTH2F, {nchQAAxis, {4, 0, 4}}); + auto hGenEvents = registry.get(HIST("QAMC/Factors/hGenEvents")); + hGenEvents->GetYaxis()->SetBinLabel(1, "All generated events"); + hGenEvents->GetYaxis()->SetBinLabel(2, "All reconstructed events"); + hGenEvents->GetYaxis()->SetBinLabel(3, "Generated events with at least one reconstructed event"); + hGenEvents->GetYaxis()->SetBinLabel(4, "Generated events passing event selection"); + + registry.add("QAMC/Factors/hRecEvents", "Reconstructed events", HistType::kTH2F, {centQAAxis, {2, 0, 2}}); + auto hRecEvents = registry.get(HIST("QAMC/Factors/hRecEvents")); + hRecEvents->GetYaxis()->SetBinLabel(1, "All reconstructed events"); + hRecEvents->GetYaxis()->SetBinLabel(2, "Passing event selection"); + + registry.add("QAMC/Factors/hGenALORESelEvents", "Centrality vs. Multiplicity of Generated Events with at least one reconstructed event passing event selection", kTH2F, {centQAAxis, nchQAAxis}); + registry.add("QAMC/Factors/hGenEventsCentNch", "Event centrality vs MC multiplicity", kTH2F, {centQAAxis, nchQAAxis}); + registry.add("QAMC/Factors/hNrecInGen", "Number of collisions in MC", kTH1F, {{10, -0.5, 9.5}}); + + registry.add("QAMC/Factors/hGenPhi", "Generated #Phi", kTH3D, {nchQAAxis, centQAAxis, ptAxis}); + registry.add("QAMC/Factors/hGenALOREPhi", "Generated #Phi in collisions with at least one reconstructed collision", kTH3F, {nchQAAxis, centQAAxis, ptAxis}); + registry.add("QAMC/Factors/hRecPhi", "Reconstructed #Phi", kTH2F, {centQAAxis, ptAxis}); + + // Resolution + registry.add("QAMC/Resolution/h2ResolutionVz", "Resolution of collision V_{z}", kTH2F, {vzaxis, axisResolutionVz}); + auto hResVz = registry.get(HIST("QAMC/Resolution/h2ResolutionVz")); + hResVz->GetXaxis()->SetTitle("V_{z}^{rec} (cm)"); + hResVz->GetYaxis()->SetTitle("#DeltaV_{z} = V_{z}^{rec} - V_{z}^{gen} (cm)"); + + registry.add("QAMC/Resolution/h2ResolutionPt", "Resolution of charged particles p_{T}", kTH2F, {ptQAAxis, axisResolutionPt}); + auto hResPt = registry.get(HIST("QAMC/Resolution/h2ResolutionPt")); + hResPt->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); + hResPt->GetYaxis()->SetTitle("#Deltap_{T} = p_{T}^{rec} - p_{T}^{gen} (GeV/c)"); + + registry.add("QAMC/Resolution/h2ResolutionPtPhi", "p_{T} resolution vs p_{T}^{rec}", kTH2F, {ptQAAxis, axisResolutionPtPhi}); + auto hResPtPhi = registry.get(HIST("QAMC/Resolution/h2ResolutionPtPhi")); + hResPtPhi->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); + hResPtPhi->GetYaxis()->SetTitle("#Deltap_{T} = p_{T}^{rec} - p_{T}^{gen} (GeV/c)"); + + registry.add("QAMC/Resolution/h2MassResolution", "Mass resolution vs p_{T}^{rec}", kTH2F, {ptQAAxis, axisResolutionMass}); + auto hResMass = registry.get(HIST("QAMC/Resolution/h2MassResolution")); + hResMass->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); + hResMass->GetYaxis()->SetTitle("#Deltam = m^{gen}_{KK} - m^{rec}_{KK} (GeV/c^{2})"); + } - // Mixing QA - if (mixingType != rsn::MixingType::none) { - registry.add("QAMixing/hSelection", "Event mixing selection statistics", kTH1D, {{1, 0.0f, 1.0f}}); - auto hEM = registry.get(HIST("QAMixing/hSelection")); - hEM->GetXaxis()->SetBinLabel(1, "Full event mixing statistics"); - hEM->SetMinimum(0.1); - - registry.add("QAMixing/h2mu1_mu2", "Event Mixing Multiplicity", kTH2F, {axisMultiplicityMixing, axisMultiplicityMixing}); - auto h2EMmu = registry.get(HIST("QAMixing/h2mu1_mu2")); - h2EMmu->GetXaxis()->SetTitle("1.Event multiplicity"); - h2EMmu->GetYaxis()->SetTitle("2.Event multiplicity"); - - registry.add("QAMixing/h2ce1_ce2", "Event Mixing Centrality", kTH2F, {axisCentralityMixing, axisCentralityMixing}); - auto h2EMce = registry.get(HIST("QAMixing/h2ce1_ce2")); - h2EMce->GetXaxis()->SetTitle("1.Event centrality"); - h2EMce->GetYaxis()->SetTitle("2.Event centrality"); - - registry.add("QAMixing/h2vz1_vz2", "Event Mixing Vertex z", kTH2F, {axisVertexMixing, axisVertexMixing}); - auto hEMTvz = registry.get(HIST("QAMixing/h2vz1_vz2")); - hEMTvz->GetXaxis()->SetTitle("1.Event V_{z}"); - hEMTvz->GetYaxis()->SetTitle("2.Event V_{z}"); - } + // ----------------------- Phi candidate QA ----------------------- + registry.add("QA/Phi/hRapidity", "Rapidity distribution of #Phi candidates", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Phi/hEta", "Pseudorapidity distribution of #Phi candidates", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Phi/hdPhi", "Azimuthal distribution (#Delta#phi) of #Phi candidates", kTH3F, {ptQAAxis, multQAAxis, dPhiQAaxis}); + registry.add("QA/Phi/hdPhideta", "Azimuthal distribution (#Delta#phi) of #Phi candidates vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + registry.add("QA/Phi/hdTheta", "Polar distribution (#Delta#theta) of #Phi candidates vs p_{T}", kTH3F, {ptQAAxis, multQAAxis, dThetaQAaxis}); + + // Rotational background QA + if (static_cast(produce.produceRotational)) { + // Rotation around z axis + registry.add("QA/RotationZ/hRapidity", "Rapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/RotationZ/hEta", "Pseudorapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/RotationZ/hdPhi", "Rotational background: Azimuthal distribution (#Delta#phi)", kTH3F, {ptQAAxis, multQAAxis, dPhiQAaxis}); + registry.add("QA/RotationZ/hdPhideta", "Rotational background: Azimuthal distribution (#Delta#phi) vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + registry.add("QA/RotationZ/hdTheta", "Rotational background: Polar distribution (#Delta#theta) vs p_{T}", kTH3F, {ptQAAxis, multQAAxis, dThetaQAaxis}); + // Momentum-axis rotation + registry.add("QA/Rotation/hRapidity", "Rapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Rotation/hEta", "Pseudorapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Rotation/hdPhi", "Rotational background: Azimuthal distribution (#Delta#phi)", kTH3F, {ptQAAxis, multQAAxis, dPhiQAaxis}); + registry.add("QA/Rotation/hdPhideta", "Rotational background: Azimuthal distribution (#Delta#phi) vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + registry.add("QA/Rotation/hdTheta", "Rotational background: Polar distribution (#Delta#theta) vs p_{T}", kTH3F, {ptQAAxis, multQAAxis, dThetaQAaxis}); + } - // PID QA - // TPC - registry.add("QAPID/hTPCnSigma", "Distribution of TPC nSigma of K^{+} and K^{-}", kTH1F, {{200, -10, 10}}); - auto hTPCnSigma = registry.get(HIST("QAPID/hTPCnSigma")); - hTPCnSigma->GetXaxis()->SetTitle("n#sigma_{TPC} K^{#pm}"); - - registry.add("QAPID/h2TPCnSigma", "", kTH2F, {{200, -10, 10}, {200, -10, 10}}); - auto h2TPCnSigma = registry.get(HIST("QAPID/h2TPCnSigma")); - h2TPCnSigma->GetXaxis()->SetTitle("n#sigma_{TPC} K^{+}"); - h2TPCnSigma->GetYaxis()->SetTitle("n#sigma_{TPC} K^{-}"); - - registry.add("QAPID/h2TPCnSigmaPt", "", kTH2F, {ptaxis, {200, -10, 10}}); - auto h2TPCnSigmaPt = registry.get(HIST("QAPID/h2TPCnSigmaPt")); - h2TPCnSigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2TPCnSigmaPt->GetYaxis()->SetTitle("n#sigma_{TPC} K^{#pm}"); - - // TOF - registry.add("QAPID/hTOFnSigma", "Distribution of TOF nSigma of K^{+} and K^{-}", kTH1F, {{200, -10, 10}}); - auto hTOFnSigma = registry.get(HIST("QAPID/hTOFnSigma")); - hTOFnSigma->GetXaxis()->SetTitle("n#sigma_{TOF} K^{#pm}"); - - registry.add("QAPID/h2TOFnSigma", "", kTH2F, {{200, -10, 10}, {200, -10, 10}}); - auto h2TOFnSigma = registry.get(HIST("QAPID/h2TOFnSigma")); - h2TOFnSigma->GetXaxis()->SetTitle("n#sigma_{TOF} K^{+}"); - h2TOFnSigma->GetYaxis()->SetTitle("n#sigma_{TOF} K^{-}"); - - registry.add("QAPID/h2TOFnSigmaPt", "", kTH2F, {ptaxis, {200, -10, 10}}); - auto h2TOFnSigmaPt = registry.get(HIST("QAPID/h2TOFnSigmaPt")); - h2TOFnSigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2TOFnSigmaPt->GetYaxis()->SetTitle("n#sigma_{TOF} K^{#pm}"); - - // MC - if (static_cast(produce.produceTrue)) { - // Rec - registry.add("QAMC/Rec/hSelection", "MC Rec Event statistics", kTH1F, {{5, 0.0f, 5.0f}}); - auto hMCEventTruth = registry.get(HIST("QAMC/Rec/hSelection")); - hMCEventTruth->GetXaxis()->SetBinLabel(1, "Full MC Rec event statistics"); - hMCEventTruth->GetXaxis()->SetBinLabel(2, "MC Rec events passing sel8 cut"); - hMCEventTruth->GetXaxis()->SetBinLabel(3, "MC Rec events passing V_{z} cut"); - hMCEventTruth->GetXaxis()->SetBinLabel(4, "MC Rec events with V_{z} cut and INEL>0"); - hMCEventTruth->GetXaxis()->SetBinLabel(5, "Reconstructed #Phi candidates matched to true #Phi"); - hMCEventTruth->SetMinimum(0.1); - - registry.add("QAMC/Rec/hInvMassTrueFalse", "", kTH1F, {invAxis}); // not written events in True distribution due to repetition of mothers - - // Gen - registry.add("QAMC/Gen/hSelection", "MC Gen Event statistics", kTH1F, {{4, 0.0f, 4.0f}}); - auto hMCEventGen = registry.get(HIST("QAMC/Gen/hSelection")); - hMCEventGen->GetXaxis()->SetBinLabel(1, "Full MC Gen event statistics"); - hMCEventGen->GetXaxis()->SetBinLabel(2, "MC Gen events within V_{z} cut"); - hMCEventGen->GetXaxis()->SetBinLabel(3, "MC Gen events with V_{z} cut and INEL>0"); - hMCEventGen->GetXaxis()->SetBinLabel(4, "Generated #Phi candidates"); - hMCEventGen->SetMinimum(0.1); - - // Resolution - registry.add("Factors/h2ResolutionVz", "Resolution of collision V_{z}", kTH2F, {vzaxis, axisResolutionVz}); - auto hResVz = registry.get(HIST("Factors/h2ResolutionVz")); - hResVz->GetXaxis()->SetTitle("V_{z}^{rec} (cm)"); - hResVz->GetYaxis()->SetTitle("#DeltaV_{z} = V_{z}^{rec} - V_{z}^{gen} (cm)"); - registry.add("Factors/h2ResolutionPt", "Resolution of charged particles p_{T}", kTH2F, {ptaxis, axisResolutionPt}); - auto hResPt = registry.get(HIST("Factors/h2ResolutionPt")); - - hResPt->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hResPt->GetYaxis()->SetTitle("#Deltap_{T} = p_{T}^{rec} - p_{T}^{gen} (GeV/c)"); - registry.add("Factors/h2ResolutionPtPhi", "p_{T} resolution vs p_{T}^{rec}", kTH2F, {ptaxis, axisResolutionPtPhi}); - auto hResPtPhi = registry.get(HIST("Factors/h2ResolutionPtPhi")); - hResPtPhi->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hResPtPhi->GetYaxis()->SetTitle("#Deltap_{T} = p_{T}^{rec} - p_{T}^{gen} (GeV/c)"); - - registry.add("Factors/h2MassResolution", "Mass resolution vs p_{T}^{rec}", kTH2F, {ptaxis, axisResolutionMass}); - auto hResMass = registry.get(HIST("Factors/h2MassResolution")); - hResMass->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hResMass->GetYaxis()->SetTitle("#Deltam = m^{gen}_{KK} - m^{rec}_{KK} (GeV/c^{2})"); - - registry.add("Factors/h2MassShift", "Mass shift vs p_{T}^{rec}", kTH2F, {ptaxis, massShiftAxis}); - auto hResMassGen = registry.get(HIST("Factors/h2MassShift")); - hResMassGen->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hResMassGen->GetYaxis()->SetTitle("#Deltam = m^{gen}_{#phi} - m^{gen}_{KK} (GeV/c^{2})"); - - registry.add("Factors/h2MassShiftRel", "Relative mass shift vs p_{T}^{rec}", kTH2F, {ptaxis, massShiftRelAxis}); - auto hMassCorr = registry.get(HIST("Factors/h2MassShiftRel")); - hMassCorr->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hMassCorr->GetYaxis()->SetTitle("m^{gen}_{#phi} - m^{gen}_{KK}/m^{gen}_{#phi}"); - } + // Mixing QA + if (mixingType != rsn::MixingType::none) { + + registry.add("QA/Mixing/h2mu1_mu2", "Event Mixing Multiplicity", kTH2F, {axisMultiplicityMixing, axisMultiplicityMixing}); + auto h2EMmu = registry.get(HIST("QA/Mixing/h2mu1_mu2")); + h2EMmu->GetXaxis()->SetTitle("1.Event multiplicity"); + h2EMmu->GetYaxis()->SetTitle("2.Event multiplicity"); + + registry.add("QA/Mixing/h2ce1_ce2", "Event Mixing Centrality", kTH2F, {axisCentralityMixing, axisCentralityMixing}); + auto h2EMce = registry.get(HIST("QA/Mixing/h2ce1_ce2")); + h2EMce->GetXaxis()->SetTitle("1.Event centrality"); + h2EMce->GetYaxis()->SetTitle("2.Event centrality"); + + registry.add("QA/Mixing/h2vz1_vz2", "Event Mixing Vertex z", kTH2F, {axisVertexMixing, axisVertexMixing}); + auto hEMTvz = registry.get(HIST("QA/Mixing/h2vz1_vz2")); + hEMTvz->GetXaxis()->SetTitle("1.Event V_{z}"); + hEMTvz->GetYaxis()->SetTitle("2.Event V_{z}"); + + registry.add("QA/Mixing/hdPhideta", "Mixing background: Azimuthal distribution (#Delta#phi) vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); } - // Factors - registry.add("Factors/hCentralityVsMultMC", "Event centrality vs MC multiplicity", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); - registry.add("Factors/hCentralityVsMult", "Event centrality vs multiplicity", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); - registry.add("Factors/hEventCentrality", "Event centrality", kTH1F, {{101, 0, 101}}); - registry.add("Factors/hNrecInGen", "Number of collisions in MC", kTH1F, {{3, -0.5, 2.5}}); - registry.add("Factors/hGenEvents", "Generated events", HistType::kTH2F, {{axisNch}, {4, 0, 4}}); - auto hGenEvents = registry.get(HIST("Factors/hGenEvents")); - hGenEvents->GetYaxis()->SetBinLabel(1, "All generated events"); - hGenEvents->GetYaxis()->SetBinLabel(2, "Generated events passing V_{z} cut"); - hGenEvents->GetYaxis()->SetBinLabel(3, "Generated events passing INEL>0"); - hGenEvents->GetYaxis()->SetBinLabel(4, "Generated events with at least one reconstructed event"); - registry.add("Factors/h2dGenPhi", "Centrality vs p_{T}", kTH2D, {{101, 0.0f, 101.0f}, ptaxis}); - registry.add("Factors/h3dGenPhiVsMultMCVsCentrality", "MC multiplicity vs centrality vs p_{T}", kTH3D, {axisNch, {101, 0.0f, 101.0f}, ptaxis}); } + template + bool selectedEvent(const T& collision) + { + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 0.5); // all events + } + + if (static_cast(eventCuts.isTriggerTVX) && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 1.5); // events passing trigger TVX cut + } + + if (static_cast(eventCuts.noTimeFrameBorder) && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 2.5); // events passing no time frame border cut + } + + if (static_cast(eventCuts.noITSROFrameBorder) && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 3.5); // events passing no ITS RO frame border cut + } + + if (static_cast(eventCuts.sel8) && !collision.sel8()) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 4.5); // events passing sel8 cut (contains all the previous cuts) + } + + if (static_cast(eventCuts.isVertexITSTPC) && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 5.5); // events passing IsVertexITSTPC cut + } + + if (static_cast(eventCuts.noSameBunchPileup) && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 6.5); // events passing no same bunch pileup cut + } + if (static_cast(eventCuts.isGoodZvtxFT0vsPV) && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 7.5); // events passing IsGoodZvtxFT0vsPV cut + } + + if (std::abs(collision.posZ()) > static_cast(eventCuts.vzCut)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 8.5); // events passing V_{z} cut + } + + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 9.5); // INEL + } + + if (static_cast(eventCuts.inelGt0) && !collision.isInelGt0()) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 10.5); // events passing INEL>0 cut + registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); + registry.fill(HIST("QA/Event/hMult"), getMultiplicity(collision)); + registry.fill(HIST("QA/Event/hCent"), getCentrality(collision)); + } + + return true; + } template float tpcNsigma(const T& track) { float tpcNsigma = 0.0f; int particleType = (track.sign() > 0) ? static_cast(daughterPos) : static_cast(daughterNeg); - if (particleType == pion) + if (particleType == pion) { tpcNsigma = track.tpcNSigmaPi(); - else if (particleType == kaon) + } else if (particleType == kaon) { tpcNsigma = track.tpcNSigmaKa(); - else if (particleType == proton) + } else if (particleType == proton) { tpcNsigma = track.tpcNSigmaPr(); + } return tpcNsigma; } template @@ -500,77 +553,92 @@ struct PhianalysisTHnSparse { float tofNsigma = 0.0f; int particleType = (track.sign() > 0) ? static_cast(daughterPos) : static_cast(daughterNeg); - if (particleType == pion) + if (particleType == pion) { tofNsigma = track.tofNSigmaPi(); - else if (particleType == kaon) + } else if (particleType == kaon) { tofNsigma = track.tofNSigmaKa(); - else if (particleType == proton) + } else if (particleType == proton) { tofNsigma = track.tofNSigmaPr(); + } return tofNsigma; } template bool selectedTrack(const T& track, bool isPositive) { - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 0.5); // all tracks + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 0.5); + } - // Apply pT cut - if (track.pt() < static_cast(cut.pt)) + if (track.pt() < static_cast(trackCuts.pt)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 1.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 1.5); + } - // Apply eta cut - if (std::abs(track.eta()) >= static_cast(cut.etatrack)) + if (std::abs(track.eta()) >= static_cast(trackCuts.etatrack)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 2.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 2.5); + } - // Apply DCA cuts - if (std::abs(track.dcaXY()) >= static_cast(cut.dcaXY) || - std::abs(track.dcaZ()) >= static_cast(cut.dcaZ)) + if (std::abs(track.dcaXY()) >= static_cast(trackCuts.dcaXY) || + std::abs(track.dcaZ()) >= static_cast(trackCuts.dcaZ)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 3.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 3.5); + } // PID selection: TPC-only for pt < threshold value, TPC+TOF for pt >= threshold value and have TOF, else TPC-only - float nSigmaCut = isPositive ? tpcnSigmaPos : tpcnSigmaNeg; - if (track.pt() < ptTOFThreshold || !track.hasTOF() || tpcPidOnly) { - if (std::abs(tpcNsigma(track)) >= nSigmaCut) + float nSigmaCut = isPositive ? static_cast(trackCuts.tpcnSigmaPos) : static_cast(trackCuts.tpcnSigmaNeg); + if (track.pt() < static_cast(trackCuts.ptTOFThreshold) || !track.hasTOF() || static_cast(trackCuts.tpcPidOnly)) { + if (std::abs(tpcNsigma(track)) >= nSigmaCut) { return false; + } } else { - if (std::sqrt(tpcNsigma(track) * tpcNsigma(track) + tofNsigma(track) * tofNsigma(track)) >= combinedNSigma) + if (std::sqrt(tpcNsigma(track) * tpcNsigma(track) + tofNsigma(track) * tofNsigma(track)) >= static_cast(trackCuts.combinedNSigma)) { return false; + } + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 4.5); + } + + if (track.tpcNClsFound() < static_cast(trackCuts.tpcNClsFound)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 5.5); } - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 4.5); - // Apply tpcNClsFound cut - if (track.tpcNClsFound() < tpcNClsFound) + if (track.tpcNClsCrossedRows() < static_cast(trackCuts.tpcNClsCrossedRows)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 5.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 6.5); + } - if (globalTrack) { - // Apply Global track cuts - if (!track.isGlobalTrack()) + if (static_cast(trackCuts.globalTrack)) { + if (!track.isGlobalTrack()) { return false; - } else { - // Apply Primary track cuts - if (!track.isPrimaryTrack()) + } + } else if (static_cast(trackCuts.primaryTrack)) { + if (!track.isPrimaryTrack()) { return false; + } + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 7.5); } - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 6.5); - // Apply PV Contributor cuts - if (!track.isPVContributor()) + if (static_cast(trackCuts.pvContributor) && !track.isPVContributor()) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 7.5); - - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 8.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 8.5); + } return true; } @@ -581,11 +649,9 @@ struct PhianalysisTHnSparse { d2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massNeg); return d1 + d2; } - bool seletectedMother(const ROOT::Math::PxPyPzMVector& mother) + bool selectedMother(const ROOT::Math::PxPyPzMVector& motherCandidate) { - if (std::abs(mother.Rapidity()) > static_cast(cut.rapidity)) - return false; - return true; + return std::abs(motherCandidate.Rapidity()) <= static_cast(trackCuts.rapidity); } template float getMultiplicity(const T& collision) @@ -617,107 +683,99 @@ struct PhianalysisTHnSparse { return pointPair; } - void processData(EventCandidate const& collision, TrackCandidates const& /*tracks*/) + void processQA(EventCandidate const& collision, TrackCandidates const& tracks) { - auto posDaughters = positive->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto negDaughters = negative->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + dataQA = true; + bool selected = selectedEvent(collision); + dataQA = false; - int nch = 0; + if (!selected) { + return; + } - if (produceQA) - registry.fill(HIST("QAEvent/hSelection"), 0.5); + double centrality = getCentrality(collision); - if (!collision.sel8()) - return; + int nch = 0; + for (const auto& track : tracks) { - if (produceQA) - registry.fill(HIST("QAEvent/hSelection"), 1.5); + registry.fill(HIST("QA/Track/hEta"), track.pt(), centrality, track.eta()); + registry.fill(HIST("QA/Track/hPt"), track.pt(), centrality); + registry.fill(HIST("QA/Track/hDCAxy"), track.pt(), centrality, track.dcaXY()); + registry.fill(HIST("QA/Track/hDCAz"), track.pt(), centrality, track.dcaZ()); + registry.fill(HIST("QA/Track/hTPCNClsFound"), track.pt(), centrality, track.tpcNClsFound()); + registry.fill(HIST("QA/Track/hTPCNClsCrossedRows"), track.pt(), centrality, track.tpcNClsCrossedRows()); + registry.fill(HIST("QA/Track/hRapidity"), track.pt(), centrality, track.sign() > 0 ? track.rapidity(massPos) : track.rapidity(massNeg)); - if (std::abs(collision.posZ()) > vzCut) - return; + registry.fill(HIST("QA/PID/hTPCNSigma"), track.pt(), centrality, tpcNsigma(track)); + registry.fill(HIST("QA/PID/hTPCdEdxP"), track.p(), track.tpcSignal()); - if (produceQA) - registry.fill(HIST("QAEvent/hSelection"), 2.5); + if (track.hasTOF()) { + registry.fill(HIST("QA/PID/hTOFNSigma"), track.pt(), centrality, tofNsigma(track)); + registry.fill(HIST("QA/PID/hTOFBetaP"), track.p(), track.beta()); + } - if (inelGrater0 && !collision.isInelGt0()) - return; + if (track.isPrimaryTrack() && std::abs(track.eta()) < static_cast(trackCuts.etatrack)) { + nch++; + } - registry.fill(HIST("Factors/hEventCentrality"), collision.centFT0M()); + dataQA = true; + bool selectedTrackCandidate = selectedTrack(track, track.sign() > 0); + dataQA = false; - if (produceQA) { - registry.fill(HIST("QAEvent/hSelection"), 3.5); - registry.fill(HIST("QAEvent/hVtxZ"), collision.posZ()); - registry.fill(HIST("QAEvent/hMult"), getMultiplicity(collision)); - registry.fill(HIST("QAEvent/hCent"), getCentrality(collision)); + if (!selectedTrackCandidate) { + continue; + } - if (produceStats) { - dataQA = true; - for (const auto& track : posDaughters) { - if (track.isPrimaryTrack() && std::abs(track.eta()) >= static_cast(cut.etatrack)) - nch++; - selectedTrack(track, true); - } - for (const auto& track : negDaughters) { - if (track.isPrimaryTrack() && std::abs(track.eta()) >= static_cast(cut.etatrack)) - nch++; - selectedTrack(track, false); - } - dataQA = false; + registry.fill(HIST("QA/Kaon/hEta"), track.pt(), centrality, track.eta()); + registry.fill(HIST("QA/Kaon/hPt"), track.pt(), centrality); + registry.fill(HIST("QA/Kaon/hDCAxy"), track.pt(), centrality, track.dcaXY()); + registry.fill(HIST("QA/Kaon/hDCAz"), track.pt(), centrality, track.dcaZ()); + registry.fill(HIST("QA/Kaon/hTPCNClsFound"), track.pt(), centrality, track.tpcNClsFound()); + registry.fill(HIST("QA/Kaon/hTPCNClsCrossedRows"), track.pt(), centrality, track.tpcNClsCrossedRows()); + registry.fill(HIST("QA/Kaon/hRapidity"), track.pt(), centrality, track.sign() > 0 ? track.rapidity(massPos) : track.rapidity(massNeg)); + + registry.fill(HIST("QA/PID/hTPCNSigmaK"), track.pt(), centrality, tpcNsigma(track)); + registry.fill(HIST("QA/PID/hTPCdEdxPK"), track.p(), track.tpcSignal()); + + if (track.hasTOF()) { + registry.fill(HIST("QA/PID/hTOFNSigmaK"), track.pt(), centrality, tofNsigma(track)); + registry.fill(HIST("QA/PID/hTOFBetaPK"), track.p(), track.beta()); + registry.fill(HIST("QA/PID/hTPCTOFnSigma"), track.pt(), tpcNsigma(track), tofNsigma(track)); } - registry.fill(HIST("Factors/hCentralityVsMult"), getCentrality(collision), nch); } + registry.fill(HIST("QA/Event/hCentNch"), getCentrality(collision), nch); + } + PROCESS_SWITCH(PhianalysisTHnSparse, processQA, "Process Event for Data", true); + + void processData(EventCandidate const& collision, TrackCandidates const& /*tracks*/) + { + auto posDaughters = positive->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negDaughters = negative->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - if (static_cast(verbose.verboselevel) > 0 && static_cast(verbose.refresh) > 0 && collision.globalIndex() % static_cast(verbose.refresh) == static_cast(verbose.refreshIndex)) - LOGF(info, "%d pos=%lld neg=%lld, Z vertex position: %f [cm]", collision.globalIndex(), posDaughters.size(), negDaughters.size(), collision.posZ()); + if (!selectedEvent(collision)) { + return; + } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughters, negDaughters))) { - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; - - if (produceQA) { - registry.fill(HIST("QAPID/h2TPCnSigma"), tpcNsigma(track1), tpcNsigma(track2)); - registry.fill(HIST("QAPID/h2TPCnSigmaPt"), track1.pt(), tpcNsigma(track1)); - registry.fill(HIST("QAPID/h2TPCnSigmaPt"), track2.pt(), tpcNsigma(track2)); - - registry.fill(HIST("QAPID/h2TOFnSigma"), tofNsigma(track1), tofNsigma(track2)); - registry.fill(HIST("QAPID/h2TOFnSigmaPt"), track1.pt(), tofNsigma(track1)); - registry.fill(HIST("QAPID/h2TOFnSigmaPt"), track2.pt(), tofNsigma(track2)); - - registry.fill(HIST("QAPID/hTPCnSigma"), tpcNsigma(track1)); - registry.fill(HIST("QAPID/hTPCnSigma"), tpcNsigma(track2)); - if (track1.hasTOF()) - registry.fill(HIST("QAPID/hTOFnSigma"), tofNsigma(track1)); - if (track2.hasTOF()) - registry.fill(HIST("QAPID/hTOFnSigma"), tofNsigma(track2)); - - registry.fill(HIST("QATrack/hEta"), track1.eta()); - registry.fill(HIST("QATrack/hEta"), track2.eta()); - registry.fill(HIST("QATrack/hPt"), track1.pt()); - registry.fill(HIST("QATrack/hPt"), track2.pt()); - registry.fill(HIST("QATrack/hDCAxy"), track1.dcaXY()); - registry.fill(HIST("QATrack/hDCAxy"), track2.dcaXY()); - registry.fill(HIST("QATrack/hDCAz"), track1.dcaZ()); - registry.fill(HIST("QATrack/hDCAz"), track2.dcaZ()); - registry.fill(HIST("QATrack/hTPCNClsFound"), track1.tpcNClsFound()); - registry.fill(HIST("QATrack/hTPCNClsFound"), track2.tpcNClsFound()); - registry.fill(HIST("QATrack/hRapidity"), track1.rapidity(massPos)); - registry.fill(HIST("QATrack/hRapidity"), track2.rapidity(massNeg)); - - registry.fill(HIST("QAPhi/hRapidity"), mother.Rapidity()); - registry.fill(HIST("QAPhi/hEta"), mother.Eta()); - registry.fill(HIST("QAPhi/hdPhi"), track1.phi() - track2.phi()); - registry.fill(HIST("QAPhi/h2dPhiPt"), mother.Pt(), track1.phi() - track2.phi()); - registry.fill(HIST("QAPhi/hTheta"), mother.Theta()); - registry.fill(HIST("QAPhi/h2dThetaPt"), mother.Pt(), d1.Theta() - d2.Theta()); } + registry.fill(HIST("QA/Phi/hRapidity"), mother.Pt(), getCentrality(collision), mother.Rapidity()); + registry.fill(HIST("QA/Phi/hEta"), mother.Pt(), getCentrality(collision), mother.Eta()); + registry.fill(HIST("QA/Phi/hdPhi"), mother.Pt(), getCentrality(collision), track1.phi() - track2.phi()); + registry.fill(HIST("QA/Phi/hdPhideta"), track1.eta() - track2.eta(), track1.phi() - track2.phi()); + registry.fill(HIST("QA/Phi/hdTheta"), mother.Pt(), getCentrality(collision), d1.Theta() - d2.Theta()); + pointPair = fillPointPair(mother.M(), mother.Pt(), getMultiplicity(collision), @@ -732,55 +790,167 @@ struct PhianalysisTHnSparse { 0); rsnOutput->fillUnlikepm(pointPair); - if (produceRotational) { - for (int i = 1; i <= static_cast(numberofRotations); i++) { + if (static_cast(produce.produceRotational)) { + + // Rotational background with rotation of track2 around track1 + for (int i = 1; i <= static_cast(nRotations); i++) { float starting = static_cast(startingAngle) * TMath::DegToRad(); - float angle = starting + i * ((o2::constants::math::TwoPI - 2 * starting) / (static_cast(numberofRotations) + 1)); + float angle = starting + i * ((o2::constants::math::TwoPI - 2 * starting) / (static_cast(nRotations) + 1)); float px2new = track2.px() * std::cos(angle) - track2.py() * std::sin(angle); float py2new = track2.px() * std::sin(angle) + track2.py() * std::cos(angle); - d2 = ROOT::Math::PxPyPzMVector(px2new, py2new, track2.pz(), massNeg); - mother = d1 + d2; - - if (produceQA) { - registry.fill(HIST("QARotational/hRapidity"), mother.Rapidity()); - registry.fill(HIST("QARotational/hEta"), mother.Eta()); - registry.fill(HIST("QARotational/hdPhi"), d1.Phi() - d2.Phi()); - registry.fill(HIST("QARotational/h2dPhiPt"), mother.Pt(), d1.Phi() - d2.Phi()); - registry.fill(HIST("QARotational/hTheta"), mother.Theta()); - registry.fill(HIST("QARotational/h2dThetaPt"), mother.Pt(), d1.Theta() - d2.Theta()); - } - pointPair = fillPointPair(mother.M(), - mother.Pt(), + ROOT::Math::PxPyPzMVector d2rot(px2new, py2new, track2.pz(), massNeg); + auto motherRotZ = d1 + d2rot; + + registry.fill(HIST("QA/RotationZ/hRapidity"), motherRotZ.Pt(), getCentrality(collision), motherRotZ.Rapidity()); + registry.fill(HIST("QA/RotationZ/hEta"), motherRotZ.Pt(), getCentrality(collision), motherRotZ.Eta()); + registry.fill(HIST("QA/RotationZ/hdPhi"), motherRotZ.Pt(), getCentrality(collision), d1.Phi() - d2rot.Phi()); + registry.fill(HIST("QA/RotationZ/hdPhideta"), d1.Eta() - d2rot.Eta(), d1.Phi() - d2rot.Phi()); + registry.fill(HIST("QA/RotationZ/hdTheta"), motherRotZ.Pt(), getCentrality(collision), d1.Theta() - d2rot.Theta()); + + pointPair = fillPointPair(motherRotZ.M(), + motherRotZ.Pt(), getMultiplicity(collision), getCentrality(collision), tpcNsigma(track1), tpcNsigma(track2), - mother.Eta(), - mother.Rapidity(), + motherRotZ.Eta(), + motherRotZ.Rapidity(), collision.posZ(), 0, 0, 0); - rsnOutput->fillRotationpm(pointPair); + rsnOutput->fillRotationZ(pointPair); + } + + // Rotational background with rotation of 90 degrees around mother momentum axis + ROOT::Math::AxisAngle rotationAxis(mother.Vect(), constants::math::PIHalf); + ROOT::Math::Rotation3D rotationMatrix(rotationAxis); + + const auto rotD1 = rotationMatrix * d1; + const auto rotD2 = rotationMatrix * d2; + + if (negDaughters.size() > 1) { + for (const auto& track3 : negDaughters) { + if (track3.globalIndex() == track1.globalIndex() || track3.globalIndex() == track2.globalIndex()) { + continue; + } + if (!selectedTrack(track3, false)) { + continue; + } + ROOT::Math::PxPyPzMVector d3(track3.px(), track3.py(), track3.pz(), massNeg); + auto motherRot = rotD1 + d3; + + registry.fill(HIST("QA/Rotation/hRapidity"), motherRot.Pt(), getCentrality(collision), motherRot.Rapidity()); + registry.fill(HIST("QA/Rotation/hEta"), motherRot.Pt(), getCentrality(collision), motherRot.Eta()); + registry.fill(HIST("QA/Rotation/hdPhi"), motherRot.Pt(), getCentrality(collision), rotD1.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdPhideta"), rotD1.Eta() - d3.Eta(), rotD1.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdTheta"), motherRot.Pt(), getCentrality(collision), rotD1.Theta() - d3.Theta()); + + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + getMultiplicity(collision), + getCentrality(collision), + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + collision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillRotation(pointPair); + + // Likesign rotation for negative daughters + motherRot = rotD2 + d3; + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + getMultiplicity(collision), + getCentrality(collision), + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + collision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillRotationLike(pointPair); + } + } + + if (posDaughters.size() > 1) { + for (const auto& track3 : posDaughters) { + + if (track3.globalIndex() == track1.globalIndex() || track3.globalIndex() == track2.globalIndex()) { + continue; + } + + if (!selectedTrack(track3, true)) { + continue; + } + + ROOT::Math::PxPyPzMVector d3(track3.px(), track3.py(), track3.pz(), massPos); + + auto motherRot = rotD2 + d3; + + registry.fill(HIST("QA/Rotation/hRapidity"), motherRot.Pt(), getCentrality(collision), motherRot.Rapidity()); + registry.fill(HIST("QA/Rotation/hEta"), motherRot.Pt(), getCentrality(collision), motherRot.Eta()); + registry.fill(HIST("QA/Rotation/hdPhi"), motherRot.Pt(), getCentrality(collision), rotD2.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdPhideta"), rotD2.Eta() - d3.Eta(), rotD2.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdTheta"), motherRot.Pt(), getCentrality(collision), rotD2.Theta() - d3.Theta()); + + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + getMultiplicity(collision), + getCentrality(collision), + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + collision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillRotation(pointPair); + + // Likesign rotation for positive daughters + motherRot = rotD1 + d3; + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + getMultiplicity(collision), + getCentrality(collision), + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + collision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillRotationLike(pointPair); + } } } } - - if (produceLikesign) { + if (static_cast(produce.produceLikesign)) { for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(posDaughters, posDaughters))) { - if (!selectedTrack(track1, true)) // both positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, true)) // both positive + } + if (!selectedTrack(track2, true)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; - - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Like-sign positive: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.M()); + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -799,17 +969,17 @@ struct PhianalysisTHnSparse { } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(negDaughters, negDaughters))) { - if (!selectedTrack(track1, false)) // both negative + if (!selectedTrack(track1, false)) { continue; - if (!selectedTrack(track2, false)) // both negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; - - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Like-sign negative: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.M()); + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -832,107 +1002,92 @@ struct PhianalysisTHnSparse { void processTrue(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { - if (!static_cast(produce.produceTrue)) + if (!static_cast(produce.produceMC)) { return; + } registry.fill(HIST("QAMC/Rec/hSelection"), 0.5); + registry.fill(HIST("QAMC/Factors/hRecEvents"), getCentrality(collision), 0.5); - if (!collision.sel8()) + if (!selectedEvent(collision)) { return; + } - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 1.5); + registry.fill(HIST("QAMC/Rec/hSelection"), 1.5); + registry.fill(HIST("QAMC/Factors/hRecEvents"), getCentrality(collision), 1.5); auto posDaughtersMC = positiveMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negDaughtersMC = negativeMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); if (!collision.has_mcCollision()) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(warning, "No MC collision for this collision, skip..."); return; } - auto mcCollision = collision.mcCollision(); - registry.fill(HIST("Factors/h2ResolutionVz"), collision.posZ(), (collision.posZ() - mcCollision.posZ())); - if (std::abs(mcCollision.posZ()) > vzCut) - return; - - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 2.5); - - if (inelGrater0 && !collision.isInelGt0()) - return; - - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 3.5); + auto mcCollision = collision.mcCollision(); + registry.fill(HIST("QAMC/Resolution/h2ResolutionVz"), collision.posZ(), (collision.posZ() - mcCollision.posZ())); for (const auto& track : tracks) { if (track.has_mcParticle()) { auto mctrack = track.mcParticle(); - registry.fill(HIST("Factors/h2ResolutionPt"), track.pt(), (track.pt() - mctrack.pt())); + registry.fill(HIST("QAMC/Resolution/h2ResolutionPt"), track.pt(), (track.pt() - mctrack.pt())); } } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersMC, negDaughtersMC))) { if (!track1.has_mcParticle()) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(warning, "No MC particle for track, skip..."); continue; } - if (!track2.has_mcParticle()) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(warning, "No MC particle for track, skip..."); continue; } - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } const auto mctrack1 = track1.mcParticle(); const auto mctrack2 = track2.mcParticle(); int track1PDG = std::abs(mctrack1.pdgCode()); int track2PDG = std::abs(mctrack2.pdgCode()); - if (!(track1PDG == daughterPosPDG && track2PDG == daughterNegPDG)) { + if (track1PDG != daughterPosPDG || track2PDG != daughterNegPDG) { continue; } - n = 0; + + int n = 0; for (const auto& mothertrack1 : mctrack1.mothers_as()) { for (const auto& mothertrack2 : mctrack2.mothers_as()) { - if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { continue; + } - if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { continue; + } - if (std::abs(mothertrack1.y()) > static_cast(cut.rapidity)) + if (std::abs(mothertrack1.y()) > static_cast(trackCuts.rapidity)) { continue; + } - if (std::abs(mothertrack1.pdgCode()) != motherPDG) + if (std::abs(mothertrack1.pdgCode()) != motherPDG) { continue; + } mother = calculateMother(track1, track2); motherGen = calculateMother(mctrack1, mctrack2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } if (n > 0) { - if (produceQA) - registry.fill(HIST("QAMC/Rec/hInvMassTrueFalse"), mother.M()); continue; } - if (static_cast(verbose.verboselevel) > 1) { - LOGF(info, "Collision: %ld True: %d, d1=%d (%ld), d2=%d (%ld), mother=%d (%ld)", collision.globalIndex(), n, mctrack1.pdgCode(), mctrack1.globalIndex(), mctrack2.pdgCode(), mctrack2.globalIndex(), mothertrack1.pdgCode(), mothertrack1.globalIndex()); - LOGF(info, "Track %d px: %f, py=%f, pz=%f, px: %f, py=%f, pz=%f", n, track1.px(), track1.py(), track1.pz(), track2.px(), track2.py(), track2.pz()); - LOGF(info, "mcTrack %d px: %f, py=%f, pz=%f, px: %f, py=%f, pz=%f", n, mctrack1.px(), mctrack1.py(), mctrack1.pz(), mctrack2.px(), mctrack2.py(), mctrack2.pz()); - } - pointPair = fillPointPair(mother.M(), mother.Pt(), getMultiplicity(collision), @@ -946,22 +1101,10 @@ struct PhianalysisTHnSparse { 0, 0); - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 4.5); - - auto phiP = mothertrack1.p(); - auto phiE = mothertrack1.e(); - auto massGen = std::sqrt(phiE * phiE - phiP * phiP); - - registry.fill(HIST("Factors/h2ResolutionPtPhi"), mother.Pt(), (mother.Pt() - mothertrack1.pt())); - registry.fill(HIST("Factors/h2MassResolution"), mother.Pt(), (motherGen.M() - mother.M())); - registry.fill(HIST("Factors/h2MassShift"), mother.Pt(), (massGen - motherGen.M())); - registry.fill(HIST("Factors/h2MassShiftRel"), mother.Pt(), (massGen - motherGen.M()) / massGen); + registry.fill(HIST("QAMC/Resolution/h2ResolutionPtPhi"), mother.Pt(), (mother.Pt() - mothertrack1.pt())); + registry.fill(HIST("QAMC/Resolution/h2MassResolution"), mother.Pt(), (motherGen.M() - mother.M())); - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "mother.M()=%f, motherGen.M()=%f, massGen =%f", mother.M(), motherGen.M(), massGen); - - rsnOutput->fillUnliketrue(pointPair); + rsnOutput->fillUnlikeTrueRec(pointPair); pointPair = fillPointPair(motherGen.M(), motherGen.Pt(), @@ -976,7 +1119,9 @@ struct PhianalysisTHnSparse { 0, 0); - rsnOutput->fillUnlikegenOld(pointPair); + rsnOutput->fillUnlikeTrueGen(pointPair); + + registry.fill(HIST("QAMC/Factors/hRecPhi"), getCentrality(collision), motherGen.Pt()); n++; } @@ -987,120 +1132,181 @@ struct PhianalysisTHnSparse { void processGen(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) { - if (!static_cast(produce.produceTrue)) + if (!static_cast(produce.produceMC)) { return; + } - if (produceQA) - registry.fill(HIST("QAMC/Gen/hSelection"), 0.5); - - if (std::abs(mcCollision.posZ()) > vzCut) - return; + registry.fill(HIST("QAMC/Factors/hNrecInGen"), collisions.size()); + registry.fill(HIST("QAMC/Gen/hSelection"), 0.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 0.5); - if (produceQA) + if (collisions.size() > 0) { registry.fill(HIST("QAMC/Gen/hSelection"), 1.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 2.5); + } - if (inelGrater0 && !mcCollision.isInelGt0()) - return; + int nContributors = -1; + bool hasSelectedCollision = false; + float centrality = 100.5f; + float multiplicity = 0.f; - if (produceQA) - registry.fill(HIST("QAMC/Gen/hSelection"), 2.5); + for (const auto& collision : collisions) { + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 1.5); + if (!selectedEvent(collision)) { + continue; + } - if (collisions.size() == 0) - return; + if (collision.numContrib() > nContributors) { + nContributors = collision.numContrib(); + centrality = getCentrality(collision); + multiplicity = getMultiplicity(collision); + hasSelectedCollision = true; + } + } - for (const auto& collision : collisions) { - auto centralityGen = getCentrality(collision); - auto multiplicityGen = getMultiplicity(collision); + registry.fill(HIST("QAMC/Factors/hGenEventsCentNch"), centrality, mcCollision.multMCNParticlesEta05()); - for (const auto& particle : mcParticles) { + // All generated Phi mesons + for (const auto& particle : mcParticles) { - if (std::abs(particle.y()) > static_cast(cut.rapidity)) - continue; + if (std::abs(particle.y()) > static_cast(trackCuts.rapidity)) { + continue; + } - if (particle.pdgCode() == motherPDG) { + if (particle.pdgCode() == motherPDG) { - auto daughters = particle.daughters_as(); - if (daughters.size() != dauSize) - continue; + auto daughters = particle.daughters_as(); + if (daughters.size() != dauSize) { + continue; + } - auto daup = false; - auto daun = false; + auto daup = false; + auto daun = false; - for (const auto& dau : daughters) { - if (dau.pdgCode() == daughterPosPDG) { - daup = true; - d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); - } else if (dau.pdgCode() == -daughterNegPDG) { - daun = true; - d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); - } + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); } - if (!daup || !daun) - continue; + } + if (!daup || !daun) { + continue; + } - mother = d1 + d2; + mother = d1 + d2; - pointPair = fillPointPair(mother.M(), - mother.Pt(), - multiplicityGen, - centralityGen, - 0, - 0, - mother.Eta(), - mother.Rapidity(), - mcCollision.posZ(), - 0, - 0, - 0); + registry.fill(HIST("QAMC/Factors/hGenPhi"), mcCollision.multMCNParticlesEta05(), centrality, particle.pt()); + } + } + + if (!hasSelectedCollision) { + return; + } - rsnOutput->fillUnlikegen(pointPair); - if (produceQA) - registry.fill(HIST("QAMC/Gen/hSelection"), 3.5); + registry.fill(HIST("QAMC/Gen/hSelection"), 2.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 3.5); + registry.fill(HIST("QAMC/Factors/hGenALORESelEvents"), centrality, mcCollision.multMCNParticlesEta05()); + + // Generated Phi mesons in selected collisions + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) > static_cast(trackCuts.rapidity)) { + continue; + } + + if (mcParticle.pdgCode() == motherPDG) { + auto daughters = mcParticle.daughters_as(); + if (daughters.size() != dauSize) { + continue; + } + + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); + } } + + if (!daup || !daun) { + continue; + } + + mother = d1 + d2; + + pointPair = fillPointPair(mother.M(), + mother.Pt(), + multiplicity, + centrality, + 0, + 0, + mother.Eta(), + mother.Rapidity(), + mcCollision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillUnlikeGen(pointPair); + + registry.fill(HIST("QAMC/Factors/hGenALOREPhi"), mcCollision.multMCNParticlesEta05(), centrality, mother.Pt()); } } } + PROCESS_SWITCH(PhianalysisTHnSparse, processGen, "Process MC Generated.", false); - void processMixed(soa::Filtered const& collisions, TrackCandidates const& tracks) + void processMixed(EventCandidates const& collisions, TrackCandidates const& tracks) { - if (mixingType == rsn::MixingType::none) + if (mixingType == rsn::MixingType::none) { return; + } auto tracksTuple = std::make_tuple(tracks); BinningTypeVzCe binningVzCe{{axisVertexMixing, axisCentralityMixing}, true}; - SameKindPair pairVzCe{binningVzCe, static_cast(numberofMixedEvents), -1, collisions, tracksTuple, &cache}; + SameKindPair pairVzCe{binningVzCe, static_cast(nMixedEvents), -1, collisions, tracksTuple, &cache}; BinningTypeVzMu binningVzMu{{axisVertexMixing, axisMultiplicityMixing}, true}; - SameKindPair pairVzMu{binningVzMu, static_cast(numberofMixedEvents), -1, collisions, tracksTuple, &cache}; + SameKindPair pairVzMu{binningVzMu, static_cast(nMixedEvents), -1, collisions, tracksTuple, &cache}; if (mixingType == rsn::MixingType::ce) { for (const auto& [c1, tracks1, c2, tracks2] : pairVzCe) { - if (produceQA) - registry.fill(HIST("QAMixing/hSelection"), 0.5); + if (!selectedEvent(c1) || !selectedEvent(c2)) { + continue; + } auto posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); auto negDaughtersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); - if (produceQA) { - registry.fill(HIST("QAMixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); - registry.fill(HIST("QAMixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); - registry.fill(HIST("QAMixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); - } + registry.fill(HIST("QA/Mixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); + registry.fill(HIST("QA/Mixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); + registry.fill(HIST("QA/Mixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc1, negDaughtersc2))) { - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } + + registry.fill(HIST("QA/Mixing/hdPhideta"), track1.eta() - track2.eta(), track1.phi() - track2.phi()); pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -1120,14 +1326,17 @@ struct PhianalysisTHnSparse { for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc2, negDaughtersc1))) { - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -1148,31 +1357,33 @@ struct PhianalysisTHnSparse { } if (mixingType == rsn::MixingType::mu) { for (const auto& [c1, tracks1, c2, tracks2] : pairVzMu) { - if (produceQA) - registry.fill(HIST("QAMixing/hSelection"), 0.5); + if (!selectedEvent(c1) || !selectedEvent(c2)) { + continue; + } auto posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); auto negDaughtersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); - if (produceQA) { - registry.fill(HIST("QAMixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); - registry.fill(HIST("QAMixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); - registry.fill(HIST("QAMixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); - } + registry.fill(HIST("QA/Mixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); + registry.fill(HIST("QA/Mixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); + registry.fill(HIST("QA/Mixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc1, negDaughtersc2))) { - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; + } - if (!selectedTrack(track2, false)) // track2 is negative + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -1192,15 +1403,17 @@ struct PhianalysisTHnSparse { for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc2, negDaughtersc1))) { - if (!selectedTrack(track1, true)) - + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -1221,68 +1434,6 @@ struct PhianalysisTHnSparse { } } PROCESS_SWITCH(PhianalysisTHnSparse, processMixed, "Process Mixing Event.", false); - - void processFactors(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) - { - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 0.5); - - if (std::abs(mcCollision.posZ()) > vzCut) - return; - - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 1.5); - - if (inelGrater0 && !mcCollision.isInelGt0()) - return; - - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 2.5); - - float centrality = 100.5f; - for (auto const& collision : collisions) { - centrality = collision.centFT0M(); - } - - registry.fill(HIST("Factors/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta08()); - registry.fill(HIST("Factors/hNrecInGen"), collisions.size()); - - for (const auto& particle : mcParticles) { - - if (std::abs(particle.y()) > static_cast(cut.rapidity)) - continue; - - if (particle.pdgCode() == motherPDG) { - - auto daughters = particle.daughters_as(); - if (daughters.size() != dauSize) - continue; - - auto daup = false; - auto daun = false; - - for (const auto& dau : daughters) { - if (dau.pdgCode() == daughterPosPDG) { - daup = true; - d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); - } else if (dau.pdgCode() == -daughterNegPDG) { - daun = true; - d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); - } - } - if (!daup || !daun) - continue; - - mother = d1 + d2; - - registry.fill(HIST("Factors/h2dGenPhi"), centrality, mother.Pt()); - registry.fill(HIST("Factors/h3dGenPhiVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta08(), centrality, mother.Pt()); - } - } - - if (collisions.size() == 0) - return; - - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 3.5); - } - PROCESS_SWITCH(PhianalysisTHnSparse, processFactors, "Process to obtain normalization factors from MC.", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx b/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx index b61d588c047..2650c19d5ae 100644 --- a/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx @@ -124,6 +124,9 @@ struct forwardlambdakzeroanalysis { Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + // propagation option + Configurable useNewPropagationToVtx{"useNewPropagationToVtx", true, "Use propagation to vtx based on propagateToDCAhelix (most recent) instead of the one based on propagateToVtxhelixWithMCS"}; + struct : ConfigurableGroup { std::string prefix = "eventSelections"; // JSON group name Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; @@ -140,6 +143,8 @@ struct forwardlambdakzeroanalysis { Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds (Run 3 only)"}; Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold (Run 3 only)"}; Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF (Run 3 only)"}; + Configurable requireNoHighMultCollInPrevRof{"requireNoHighMultCollInPrevRof", false, "reject collisions if previous ROF has high multiplicity (Run 3 only)"}; + Configurable requireIsGoodITSLayersAll{"requireIsGoodITSLayersAll", false, "require that the number of inactive chips on all ITS layers is below the maximum allowed values"}; Configurable requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; @@ -158,6 +163,15 @@ struct forwardlambdakzeroanalysis { static constexpr float DefaultLifetimeCuts[1][3] = {{20., 30., 20.}}; + // Armenteros-Podolanski elliptic band: inner and outer ellipse half-axes, in units of the ideal + // two-body ones. The alpha and qT axes are scaled independently, so the band can be made much + // wider in alpha than in qT (the resolution smears the two very differently, in particular for + // Lambda, whose ideal alpha half-width is only ~0.18). A zero inner scale means "no inner ellipse". + // Columns: alphaScaleMin, qtScaleMin, alphaScaleMax, qtScaleMax + static constexpr float DefaultArmPodBand[3][4] = {{0.60, 0.60, 1.15, 1.35}, // K0Short + {0.00, 0.00, 2.00, 1.50}, // Lambda + {0.00, 0.00, 1.30, 1.30}}; // D0 + struct : ConfigurableGroup { std::string prefix = "v0Selections"; // JSON group name @@ -186,6 +200,7 @@ struct forwardlambdakzeroanalysis { Configurable minPseudolifetime{"minPseudolifetime", -1e+09, "minimum V0 pseudo-proper lifetime (cm)"}; Configurable maxPseudolifetime{"maxPseudolifetime", 1e+09, "maximum V0 pseudo-proper lifetime (cm)"}; Configurable> lifetimeCut{"lifetimeCut", {DefaultLifetimeCuts[0], 3, {"lifetimecutD0", "lifetimecutLambda", "lifetimecutK0S"}}, "lifetimeCut"}; + Configurable rejectFailedPropagation{"rejectFailedPropagation", true, "Reject tracks which could not be propagated to the primary vertex (DCA = DefaultDCA = 999.)"}; // invariant mass selection Configurable compMassRejectionK0Short{"compMassRejectionK0Short", -1, "Competing K^{0}_{S} mass rejection (GeV/#it{c}^{2})"}; @@ -194,6 +209,27 @@ struct forwardlambdakzeroanalysis { // Additional selection on the AP plot (exclusive for K0Short) // original equation: lArmPt*5>TMath::Abs(lArmAlpha) Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + Configurable minQt{"minQt", -1, "Min Arm. Qt. Negative value means not cut"}; + Configurable maxQt{"maxQt", 1e+09, "Max Arm Qt."}; + Configurable minAlpha{"minAlpha", -1e+09, "Min Arm. Alpha."}; + Configurable maxAlpha{"maxAlpha", 1e+09, "Max Arm Alpha."}; + + // Armenteros-Podolanski elliptic band: keeps only the two-body decay arc of a given species. + // A decay M -> pos + neg populates the ellipse + // ((alpha - alphaCenter) / alphaHalfWidth)^2 + (qT / qStar)^2 = 1 + // with, in the mother rest frame, qStar the daughter momentum (= maximum qT), + // alphaCenter = (E*_pos - E*_neg) / M and alphaHalfWidth = 2 qStar / (beta M). + // The band is the crescent between two ellipses concentric with that one, each with its two + // half-axes scaled independently (the reconstructed distribution is smeared much more along + // alpha than along qT, so a single scale factor for both axes does not describe it): + // qT_up (alpha) = qtScaleMax * qStar * sqrt(1 - ((alpha - alphaCenter) / (alphaScaleMax * alphaHalfWidth))^2) + // qT_low(alpha) = qtScaleMin * qStar * sqrt(1 - ((alpha - alphaCenter) / (alphaScaleMin * alphaHalfWidth))^2) + // (square roots set to zero where their argument is negative). A candidate is kept if it lies + // inside the outer ellipse and outside the inner one; setting an inner scale to zero drops the + // inner ellipse altogether, i.e. keeps the whole filled outer ellipse. + Configurable useArmPodBand{"useArmPodBand", false, "Select the Armenteros-Podolanski arc with an elliptic band (per-species)"}; + Configurable armPodBandUseBeta{"armPodBandUseBeta", true, "Scale the alpha half-width by 1/beta of the candidate (exact ellipse). If false, use the beta -> 1 limit"}; + Configurable> armPodBand{"armPodBand", {DefaultArmPodBand[0], 3, 4, {"K0Short", "Lambda", "D0"}, {"alphaScaleMin", "qtScaleMin", "alphaScaleMax", "qtScaleMax"}}, "Arm.-Pod. band: inner and outer ellipse half-axes, in units of the ideal ones"}; // Track quality Configurable minMFTclusters{"minMFTclusters", -1, "minimum MFT clusters"}; @@ -420,6 +456,10 @@ struct forwardlambdakzeroanalysis { selD0PseudoLifetimeMin, selD0PseudoLifetimeMax, selK0ShortArmenteros, + selLambdaArmenteros, + selAntiLambdaArmenteros, + selD0Armenteros, + selAntiD0Armenteros, selPosGoodMFTTrack, selNegGoodMFTTrack, selConsiderK0Short, // for mc tagging @@ -493,6 +533,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskLambdaSpecific, selLambdaPseudoLifetimeMax); BITSET(maskLambdaSpecific, selConsiderLambda); BITSET(maskLambdaSpecific, selK0ShortMassRejection); + BITSET(maskLambdaSpecific, selLambdaArmenteros); // Mask for specifically selecting AntiLambda maskAntiLambdaSpecific = 0; BITSET(maskAntiLambdaSpecific, selLambdaRapidityMin); @@ -502,6 +543,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskAntiLambdaSpecific, selLambdaPseudoLifetimeMax); BITSET(maskAntiLambdaSpecific, selConsiderAntiLambda); BITSET(maskAntiLambdaSpecific, selK0ShortMassRejection); + BITSET(maskAntiLambdaSpecific, selAntiLambdaArmenteros); // Mask for specifically selecting D0 maskD0Specific = 0; BITSET(maskD0Specific, selD0RapidityMin); @@ -511,6 +553,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskD0Specific, selD0PseudoLifetimeMax); BITSET(maskD0Specific, selConsiderD0); BITSET(maskD0Specific, selK0ShortMassRejection); + BITSET(maskD0Specific, selD0Armenteros); BITSET(maskD0Specific, selLambdaMassRejection); // Mask for specifically selecting D0 maskAntiD0Specific = 0; @@ -521,6 +564,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskAntiD0Specific, selD0PseudoLifetimeMax); BITSET(maskAntiD0Specific, selConsiderAntiD0); BITSET(maskAntiD0Specific, selK0ShortMassRejection); + BITSET(maskAntiD0Specific, selAntiD0Armenteros); BITSET(maskAntiD0Specific, selLambdaMassRejection); // ask for specific TPC/TOF PID selections @@ -549,7 +593,7 @@ struct forwardlambdakzeroanalysis { rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); // Event Counters - histos.add("hEventSelection", "hEventSelection", kTH1D, {{23, -0.5f, +22.5f}}); + histos.add("hEventSelection", "hEventSelection", kTH1D, {{25, -0.5f, +24.5f}}); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); @@ -566,13 +610,15 @@ struct forwardlambdakzeroanalysis { histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min occup."); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max occup."); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(21, "Below min IR"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(22, "Above max IR"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(23, "RCT flags"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "kNoHighMultCollInPrevRof"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "kIsGoodITSLayersAll"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "INEL>1"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(21, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(22, "Above max occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(23, "Below min IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(24, "Above max IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(25, "RCT flags"); histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisConfigurations.axisCentralityFine}); histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisNch}); @@ -633,7 +679,11 @@ struct forwardlambdakzeroanalysis { hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaPseudoLifetimeMax + 2, "#Lambda pseudo-time max"); hSelectionV0s->GetXaxis()->SetBinLabel(selD0PseudoLifetimeMin + 2, "D^{0} pseudo-time min"); hSelectionV0s->GetXaxis()->SetBinLabel(selD0PseudoLifetimeMax + 2, "D^{0} pseudo-time max"); - hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortArmenteros + 2, "Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortArmenteros + 2, "K^{0}_{S} Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaArmenteros + 2, "#Lambda Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selAntiLambdaArmenteros + 2, "#bar{#Lambda} Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selD0Armenteros + 2, "D^{0} Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selAntiD0Armenteros + 2, "#bar{D}^{0} Arm. pod. cut"); hSelectionV0s->GetXaxis()->SetBinLabel(selPosGoodMFTTrack + 2, "Pos. good MFT track"); hSelectionV0s->GetXaxis()->SetBinLabel(selNegGoodMFTTrack + 2, "Neg. good MFT track"); hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderK0Short + 2, "True K^{0}_{S}"); @@ -786,8 +836,8 @@ struct forwardlambdakzeroanalysis { } if (analyseK0Short) { histos.add("K0Short/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("K0Short/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("K0Short/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("K0Short/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("K0Short/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("K0Short/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("K0Short/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("K0Short/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -836,8 +886,8 @@ struct forwardlambdakzeroanalysis { } if (analyseLambda) { histos.add("Lambda/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("Lambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("Lambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("Lambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("Lambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("Lambda/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("Lambda/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -885,8 +935,8 @@ struct forwardlambdakzeroanalysis { } if (analyseAntiLambda) { histos.add("AntiLambda/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("AntiLambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("AntiLambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiLambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiLambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiLambda/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("AntiLambda/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -934,8 +984,8 @@ struct forwardlambdakzeroanalysis { } if (analyseD0) { histos.add("D0/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("D0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("D0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("D0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("D0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("D0/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("D0/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("D0/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -983,8 +1033,8 @@ struct forwardlambdakzeroanalysis { } if (analyseAntiD0) { histos.add("AntiD0/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("AntiD0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("AntiD0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiD0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiD0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiD0/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiD0/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("AntiD0/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -1191,6 +1241,50 @@ struct forwardlambdakzeroanalysis { fitter.setBz(magField); } + // Ideal Armenteros-Podolanski ellipse of a two-body decay hypothesis: centre and half-axes + struct ArmenterosEllipse { + float alphaCenter; // (E*_pos - E*_neg) / M, vanishes for symmetric decays + float alphaHalfWidth; // 2 qStar / (beta M) + float qStar; // daughter momentum in the mother rest frame = maximum qT + }; + + ArmenterosEllipse armenterosEllipse(float pTot, float massMother, float massPositive, float massNegative) + { + const float energyPositive = (massMother * massMother + massPositive * massPositive - massNegative * massNegative) / (2.f * massMother); + const float qStar = std::sqrt(std::max(0.f, energyPositive * energyPositive - massPositive * massPositive)); + float alphaHalfWidth = 2.f * qStar / massMother; // beta -> 1 limit + if (v0Selections.armPodBandUseBeta && pTot > 1e-3f) { + alphaHalfWidth *= std::hypot(pTot, massMother) / pTot; // 1 / beta of the candidate + } + return ArmenterosEllipse{2.f * energyPositive / massMother - 1.f, alphaHalfWidth, qStar}; + } + + // Normalised distance to the centre of the ideal ellipse, measured with its two half-axes scaled + // independently: 1 on the scaled ellipse itself, smaller inside it, larger outside it. + float armenterosDistance(ArmenterosEllipse const& ellipse, float alphaArm, float qtArm, float alphaScale, float qtScale) + { + return std::hypot((alphaArm - ellipse.alphaCenter) / (alphaScale * ellipse.alphaHalfWidth), qtArm / (qtScale * ellipse.qStar)); + } + + // Crescent-shaped band around the two-body decay arc in the Armenteros-Podolanski plane + template + bool passesArmenterosBand(TV0 const& v0, float massMother, float massPositive, float massNegative, const char* species) + { + if (!v0Selections.useArmPodBand) { + return true; + } + const ArmenterosEllipse ellipse = armenterosEllipse(v0.pTot, massMother, massPositive, massNegative); + if (armenterosDistance(ellipse, v0.AlphaArm, v0.QtArm, v0Selections.armPodBand->get(species, "alphaScaleMax"), v0Selections.armPodBand->get(species, "qtScaleMax")) > 1.f) { + return false; // outside the outer ellipse + } + const float alphaScaleMin = v0Selections.armPodBand->get(species, "alphaScaleMin"); + const float qtScaleMin = v0Selections.armPodBand->get(species, "qtScaleMin"); + if (alphaScaleMin < 1e-4f || qtScaleMin < 1e-4f) { + return true; // no inner ellipse requested: the whole outer ellipse is kept + } + return armenterosDistance(ellipse, v0.AlphaArm, v0.QtArm, alphaScaleMin, qtScaleMin) > 1.f; + } + template uint64_t computeReconstructionBitmap(TV0 const& v0, float rapK0s, float rapLambda, float rapD0) // precalculate this information so that a check is one mask operation, not many @@ -1214,17 +1308,21 @@ struct forwardlambdakzeroanalysis { BITSET(bitMap, selZmax); } // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses - if (std::fabs(v0.dcaPosToPVxy) > v0Selections.dcaPosToPVxy) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaPosToPVxy) < o2::track::DefaultDCA) && + std::fabs(v0.dcaPosToPVxy) > v0Selections.dcaPosToPVxy) { BITSET(bitMap, selDCAPosToPVxy); } - if (std::fabs(v0.dcaNegToPVxy) > v0Selections.dcaNegToPVxy) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaNegToPVxy) < o2::track::DefaultDCA) && + std::fabs(v0.dcaNegToPVxy) > v0Selections.dcaNegToPVxy) { BITSET(bitMap, selDCANegToPVxy); } // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses - if (std::fabs(v0.dcaPosToPVz) > v0Selections.dcaPosToPVz) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaPosToPVz) < o2::track::DefaultDCA) && + std::fabs(v0.dcaPosToPVz) > v0Selections.dcaPosToPVz) { BITSET(bitMap, selDCAPosToPVz); } - if (std::fabs(v0.dcaNegToPVz) > v0Selections.dcaNegToPVz) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaNegToPVz) < o2::track::DefaultDCA) && + std::fabs(v0.dcaNegToPVz) > v0Selections.dcaNegToPVz) { BITSET(bitMap, selDCANegToPVz); } // V0 cosine of pointing angle @@ -1329,9 +1427,26 @@ struct forwardlambdakzeroanalysis { // // armenteros - if (v0Selections.armPodCut < 1e-4 || v0.QtArm * v0Selections.armPodCut > std::abs(v0.AlphaArm)) { + // legacy K0Short "V" cut, plus an optional box and the optional elliptic band around the decay arc + const bool armPodVCut = (v0Selections.armPodCut < 1e-4 || v0.QtArm * v0Selections.armPodCut > std::abs(v0.AlphaArm)); + const bool armPodBox = (v0.QtArm > v0Selections.minQt && v0.QtArm < v0Selections.maxQt && + v0.AlphaArm > v0Selections.minAlpha && v0.AlphaArm < v0Selections.maxAlpha); + if (armPodVCut && armPodBox && + passesArmenterosBand(v0, o2::constants::physics::MassK0Short, o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiMinus, "K0Short")) { BITSET(bitMap, selK0ShortArmenteros); } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassLambda0, o2::constants::physics::MassProton, o2::constants::physics::MassPiMinus, "Lambda")) { + BITSET(bitMap, selLambdaArmenteros); + } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassLambda0, o2::constants::physics::MassPiPlus, o2::constants::physics::MassProtonBar, "Lambda")) { + BITSET(bitMap, selAntiLambdaArmenteros); + } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassD0, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiMinus, "D0")) { + BITSET(bitMap, selD0Armenteros); + } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus, o2::constants::physics::MassKMinus, "D0")) { + BITSET(bitMap, selAntiD0Armenteros); + } return bitMap; } @@ -1964,18 +2079,32 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); } + if (eventSelections.requireNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 16 /* veto an event if FT0C amplitude in previous ITS ROF is above threshold */); + } + + if (eventSelections.requireIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 17 /* numbers of inactive chips on all ITS layers are below maximum allowed values */); + } + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + histos.fill(HIST("hEventSelection"), 18 /* INEL > 0 */); } if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + histos.fill(HIST("hEventSelection"), 19 /* INEL > 1 */); } float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); @@ -1983,14 +2112,14 @@ struct forwardlambdakzeroanalysis { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 18 /* Below min occupancy */); + histos.fill(HIST("hEventSelection"), 20 /* Below min occupancy */); } if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 19 /* Above max occupancy */); + histos.fill(HIST("hEventSelection"), 21 /* Above max occupancy */); } // Fetch interaction rate only if required (in order to limit ccdb calls) @@ -2000,21 +2129,21 @@ struct forwardlambdakzeroanalysis { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 20 /* Below min IR */); + histos.fill(HIST("hEventSelection"), 22 /* Below min IR */); } if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 21 /* Above max IR */); + histos.fill(HIST("hEventSelection"), 23 /* Above max IR */); } if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 22 /* Pass CBT condition */); + histos.fill(HIST("hEventSelection"), 24 /* Pass CBT condition */); } return true; } @@ -2201,13 +2330,34 @@ struct forwardlambdakzeroanalysis { //___________________________________________________________________ // Taken from https://github.com/AliceO2Group/AliceO2/blob/be5a2bb6c1be6757b7a496f9e90d470304d98fe7/Common/DCAFitter/include/DCAFitter/FwdDCAFitterN.h#L1281 // Re-adapted for this task - bool propagateToVtx(o2::track::TrackParCovFwd& t, const std::array& PV, const std::array& PVcov) const + template + void propagateToVtx(o2::track::TrackParCovFwd& t, TCollision const& collision, std::array& dca) const { + dca[0] = o2::track::DefaultDCA; + dca[1] = o2::track::DefaultDCA; + dca[2] = o2::track::DefaultDCA; + // propagate track to vertex including MCS effects if material budget included, simple propagation to Z otherwise float x2x0 = 0; - auto mb = lut->getMatBudget(t.getX(), t.getY(), t.getZ(), PV[0], PV[1], PV[2]); + auto mb = lut->getMatBudget(t.getX(), t.getY(), t.getZ(), collision.posX(), collision.posY(), collision.posZ()); x2x0 = static_cast(mb.meanX2X0); - return t.propagateToVtxhelixWithMCS(PV[2], {PV[0], PV[1]}, PVcov, magField, x2x0); + t.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, std::array{collision.covXX(), collision.covYY()}, magField, x2x0); + + dca[0] = t.getX() - collision.posX(); + dca[1] = t.getY() - collision.posY(); + dca[2] = t.getZ() - collision.posZ(); + } + + //___________________________________________________________________ + // Taken from https://github.com/AliceO2Group/O2Physics/blob/master/Common/Core/fwdtrackUtilities.h#L183 + // Re-adapted for this task + template + void propagateToVtxNew(o2::track::TrackParCovFwd& t, TCollision const& collision, std::array& dca) const + { + dca[0] = o2::track::DefaultDCA; + dca[1] = o2::track::DefaultDCA; + dca[2] = o2::track::DefaultDCA; + t.propagateToDCAhelix(magField, {collision.posX(), collision.posY(), collision.posZ()}, dca); } template @@ -2263,15 +2413,15 @@ struct forwardlambdakzeroanalysis { o2::track::TrackParCovFwd pars2{mftNegative.z(), tpars2, tcovs2, mftNegative.chi2()}; o2::track::TrackParCovFwd pars2Copy{mftNegative.z(), tpars2, tcovs2, mftNegative.chi2()}; - propagateToVtx(pars1Copy, std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{collision.covXX(), collision.covYY()}); - propagateToVtx(pars2Copy, std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{collision.covXX(), collision.covYY()}); - float dcaPosToPVx = pars1Copy.getX() - collision.posX(); - float dcaPosToPVy = pars1Copy.getY() - collision.posY(); - float dcaPosToPVz = pars1Copy.getZ() - collision.posZ(); - - float dcaNegToPVx = pars2Copy.getX() - collision.posX(); - float dcaNegToPVy = pars2Copy.getY() - collision.posY(); - float dcaNegToPVz = pars2Copy.getZ() - collision.posZ(); + std::array dcaPosToPV{o2::track::DefaultDCA, o2::track::DefaultDCA, o2::track::DefaultDCA}; + std::array dcaNegToPV{o2::track::DefaultDCA, o2::track::DefaultDCA, o2::track::DefaultDCA}; + if (useNewPropagationToVtx) { + propagateToVtxNew(pars1Copy, collision, dcaPosToPV); + propagateToVtxNew(pars2Copy, collision, dcaNegToPV); + } else { + propagateToVtx(pars1Copy, collision, dcaPosToPV); + propagateToVtx(pars2Copy, collision, dcaNegToPV); + } // Move close to minima int nCand = 0; @@ -2303,10 +2453,10 @@ struct forwardlambdakzeroanalysis { pairInfo.Z = vtx[2]; // get daughter DCA to PV - pairInfo.dcaPosToPVxy = std::sqrt(dcaPosToPVx * dcaPosToPVx + dcaPosToPVy * dcaPosToPVy); - pairInfo.dcaNegToPVxy = std::sqrt(dcaNegToPVx * dcaNegToPVx + dcaNegToPVy * dcaNegToPVy); - pairInfo.dcaPosToPVz = dcaPosToPVz; - pairInfo.dcaNegToPVz = dcaNegToPVz; + pairInfo.dcaPosToPVxy = std::hypot(dcaPosToPV[0], dcaPosToPV[1]); + pairInfo.dcaNegToPVxy = std::hypot(dcaNegToPV[0], dcaNegToPV[1]); + pairInfo.dcaPosToPVz = dcaPosToPV[2]; + pairInfo.dcaNegToPVz = dcaNegToPV[2]; // get daughter momenta pairInfo.positiveMomentum[0] = lTrack1.getPx(); diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index 8549d7c9dea..acab9d529d8 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -129,6 +129,7 @@ struct HStrangeCorrelation { Configurable selectINELgtONE{"selectINELgtONE", false, "select INEL>1 events (at least 2 charged particles in |eta| < 1)"}; Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; Configurable requireAllGoodITSLayers{"requireAllGoodITSLayers", false, " require that in the event all ITS are good"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions associated with the same found-by-T0 bunch crossing"}; Configurable requireGoodTriggerTVX{"requireGoodTriggerTVX", false, " require acceptable FT0C-FT0A time difference"}; Configurable requireGoodZvtxFT0vsPV{"requireGoodZvtxFT0vsPV", false, " require small difference between z-vertex from PV and from FT0"}; Configurable skipUnderOverflowInTHn{"skipUnderOverflowInTHn", false, "skip under/overflow in THns"}; @@ -3227,6 +3228,10 @@ struct HStrangeCorrelation { if (!collision.sel8()) { return false; } + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && masterConfigurations.requireGoodTriggerTVX) { + // FT0 vertex (acceptable FT0C-FT0A time difference) collisions + return false; + } if (std::abs(collision.posZ()) > masterConfigurations.zVertexCut) { return false; } @@ -3242,6 +3247,15 @@ struct HStrangeCorrelation { if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && masterConfigurations.requireAllGoodITSLayers) { return false; } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && masterConfigurations.requireGoodZvtxFT0vsPV) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup) && masterConfigurations.rejectSameBunchPileup) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + return false; + } if (zorroMask.value != "") { auto bc = collision.template bc_as(); initZorro(bc); @@ -4195,6 +4209,9 @@ struct HStrangeCorrelation { bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; bool bestCollisionINELgtONE = false; + bool bestCollisionNoSameBunchPileup = false; + bool bestCollisionGoodTriggerTVX = false; + bool bestCollisionGoodZvtxFT0vsPV = false; bool isCollisionSelect = false; uint32_t bestCollisionTriggerPresenceMap = 0; @@ -4211,6 +4228,9 @@ struct HStrangeCorrelation { bestCollisionVtxZ = collision.posZ(); bestCollisionINELgtZERO = collision.isInelGt0(); bestCollisionINELgtONE = collision.isInelGt1(); + bestCollisionNoSameBunchPileup = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + bestCollisionGoodTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); + bestCollisionGoodZvtxFT0vsPV = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); } if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex()]; @@ -4262,6 +4282,15 @@ struct HStrangeCorrelation { if (masterConfigurations.selectINELgtONE && !bestCollisionINELgtONE) { return; } + if (masterConfigurations.rejectSameBunchPileup && !bestCollisionNoSameBunchPileup) { + return; + } + if (masterConfigurations.requireGoodTriggerTVX && !bestCollisionGoodTriggerTVX) { + return; + } + if (masterConfigurations.requireGoodZvtxFT0vsPV && !bestCollisionGoodZvtxFT0vsPV) { + return; + } } histos.fill(HIST("hClosureTestEventCounter"), 3.5f); @@ -4706,6 +4735,9 @@ struct HStrangeCorrelation { bool genBestCollisionSel8 = false; bool genBestCollisionINELgtZERO = false; bool genBestCollisionINELgtONE = false; + bool genBestCollisionNoSameBunchPileup = false; + bool genBestCollisionGoodTriggerTVX = false; + bool genBestCollisionGoodZvtxFT0vsPV = false; bool genCollisionSelected = false; int genLargestNContributors = -1; uint32_t genBestCollisionTriggerPresenceMap = 0; @@ -4723,6 +4755,9 @@ struct HStrangeCorrelation { genBestCollisionVtxZ = recCollision.posZ(); genBestCollisionINELgtZERO = recCollision.isInelGt0(); genBestCollisionINELgtONE = recCollision.isInelGt1(); + genBestCollisionNoSameBunchPileup = recCollision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + genBestCollisionGoodTriggerTVX = recCollision.selection_bit(aod::evsel::kIsTriggerTVX); + genBestCollisionGoodZvtxFT0vsPV = recCollision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); } if (triggerPresenceMap.size() > 0) { genBestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; @@ -4734,6 +4769,9 @@ struct HStrangeCorrelation { } else if (masterConfigurations.doGenEventSelection) { genEventSelected = genEventSelected && genBestCollisionSel8 && std::abs(genBestCollisionVtxZ) <= masterConfigurations.zVertexCut && genBestCollisionINELgtZERO && (!masterConfigurations.selectINELgtONE || genBestCollisionINELgtONE) && + (!masterConfigurations.rejectSameBunchPileup || genBestCollisionNoSameBunchPileup) && + (!masterConfigurations.requireGoodTriggerTVX || genBestCollisionGoodTriggerTVX) && + (!masterConfigurations.requireGoodZvtxFT0vsPV || genBestCollisionGoodZvtxFT0vsPV) && genBestCollisionMultiplicity >= axisRanges[5][0] && genBestCollisionMultiplicity <= axisRanges[5][1]; } @@ -5660,21 +5698,19 @@ struct HStrangeCorrelation { // recomputed from raw tracks so that this stage cannot drift away from the // reconstructed analysis it exists to be compared against. // - // The sets are built per reconstructed collision and a pair is required to be - // final within one and the same collision: the reconstructed same-event - // correlation only ever pairs a trigger with a V0 sitting in the same vertex, - // so a pair split across two reconstructed vertices of one MC collision must - // not count as final here either. - // - // N.B.: the reconstructed autocorrelation rejection (trigger track identical - // to a V0 daughter track) is deliberately not replicated. It is a no-op as - // soon as the trigger is required to be a physical primary, because - // mcTrue(IndexK0) forces the daughters to be genuine -- hence secondary -- - // K0 decay products. - std::vector, std::unordered_set>> pairLossFinalPerCollision; + // The stage is restricted to the best reconstructed collision and keeps the + // reconstructed kinematics of every matched object, so that the pair test below + // can also impose the reconstructed-coordinate angular range and the + // reconstructed autocorrelation rejection. Both are conditions the reconstructed + // same-event correlation imposes as well, so this Final stage is by construction + // the same object as PairLossK0/Comparison/Final: the truth pairs that really do + // end up in the reconstructed correlation. + PairLossTrackMap pairLossFinalTriggers; + PairLossV0Map pairLossFinalV0s; for (auto const& collision : recCollisions) { - std::unordered_set finalTriggerMcIds; - std::unordered_set finalK0McIds; + if (static_cast(collision.globalIndex()) != pairLossBestCollisionId) { + continue; + } const auto finalTriggerSlice = triggerTracks.sliceBy(collisionSliceTracks, collision.globalIndex()); for (auto const& triggerEntry : finalTriggerSlice) { @@ -5691,7 +5727,7 @@ struct HStrangeCorrelation { if (masterConfigurations.doTriggPhysicalPrimary && !triggerEntry.mcPhysicalPrimary()) { continue; } - finalTriggerMcIds.insert(track.mcParticleId()); + pairLossFinalTriggers[track.mcParticleId()].push_back(makePairLossTrackInfo(track)); } const auto finalV0Slice = associatedV0s.sliceBy(collisionSliceV0s, collision.globalIndex()); @@ -5735,34 +5771,54 @@ struct HStrangeCorrelation { if (!passesFinalSelection) { continue; } - finalK0McIds.insert(v0MC.particleIdMC()); + pairLossFinalV0s[v0MC.particleIdMC()].push_back(PairLossV0Info{ + .globalIndex = static_cast(v0.globalIndex()), + .positiveTrackId = static_cast(positiveTrack.globalIndex()), + .negativeTrackId = static_cast(negativeTrack.globalIndex()), + .pt = v0.pt(), + .eta = v0.eta(), + .phi = v0.phi(), + .radius = v0.v0radius(), + .cosPA = v0.v0cosPA(), + .dcaDaughters = v0.dcaV0daughters(), + .massNSigma = assocEntry.invMassNSigma(IndexK0)}); } - - pairLossFinalPerCollision.emplace_back(std::move(finalTriggerMcIds), std::move(finalK0McIds)); } - // Object-level membership, used only for the single-particle spectra: at - // least one collision in which the object is fully selected. The pair - // histogram uses pairLossHasFinalPair() instead, which is stricter. + // Object-level membership, used only for the single-particle spectra: the object + // has a fully selected reconstructed counterpart in the best collision. The pair + // histogram uses pairLossHasFinalPair() instead, which is stricter: it also + // requires the reconstructed pair itself to fall in the reconstructed angular + // range and to survive the reconstructed autocorrelation rejection. auto pairLossHasFinalTrigger = [&](int64_t mcId) { - for (auto const& perCollision : pairLossFinalPerCollision) { - if (perCollision.first.count(mcId) > 0) { - return true; - } - } - return false; + return pairLossFinalTriggers.find(mcId) != pairLossFinalTriggers.end(); }; auto pairLossHasFinalK0 = [&](int64_t mcId) { - for (auto const& perCollision : pairLossFinalPerCollision) { - if (perCollision.second.count(mcId) > 0) { - return true; - } - } - return false; + return pairLossFinalV0s.find(mcId) != pairLossFinalV0s.end(); }; auto pairLossHasFinalPair = [&](int64_t triggerMcId, int64_t k0McId) { - for (auto const& perCollision : pairLossFinalPerCollision) { - if (perCollision.first.count(triggerMcId) > 0 && perCollision.second.count(k0McId) > 0) { + const auto triggerMatches = pairLossFinalTriggers.find(triggerMcId); + if (triggerMatches == pairLossFinalTriggers.end()) { + return false; + } + const auto v0Matches = pairLossFinalV0s.find(k0McId); + if (v0Matches == pairLossFinalV0s.end()) { + return false; + } + for (auto const& reconstructedTrigger : triggerMatches->second) { + for (auto const& reconstructedV0 : v0Matches->second) { + float reconstructedDeltaEta = reconstructedTrigger.eta - reconstructedV0.eta; + if (masterConfigurations.doMirroringInDelataEta) { + reconstructedDeltaEta = std::abs(reconstructedDeltaEta); + } + const float reconstructedDeltaPhi = computeDeltaPhi(reconstructedTrigger.phi, reconstructedV0.phi); + if (reconstructedDeltaPhi < axisRanges[0][0] || reconstructedDeltaPhi > axisRanges[0][1] || + reconstructedDeltaEta < axisRanges[1][0] || reconstructedDeltaEta > axisRanges[1][1]) { + continue; + } + if (doAutocorrelationRejection && (reconstructedTrigger.globalIndex == reconstructedV0.positiveTrackId || reconstructedTrigger.globalIndex == reconstructedV0.negativeTrackId)) { + continue; + } return true; } } @@ -5960,6 +6016,9 @@ struct HStrangeCorrelation { bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; bool bestCollisionINELgtONE = false; + bool bestCollisionNoSameBunchPileup = false; + bool bestCollisionGoodTriggerTVX = false; + bool bestCollisionGoodZvtxFT0vsPV = false; bool isCollisionSelect = false; int biggestNContribs = -1; uint32_t bestCollisionTriggerPresenceMap = 0; @@ -5975,6 +6034,9 @@ struct HStrangeCorrelation { bestCollisionVtxZ = recCollision.posZ(); bestCollisionINELgtZERO = recCollision.isInelGt0(); bestCollisionINELgtONE = recCollision.isInelGt1(); + bestCollisionNoSameBunchPileup = recCollision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + bestCollisionGoodTriggerTVX = recCollision.selection_bit(aod::evsel::kIsTriggerTVX); + bestCollisionGoodZvtxFT0vsPV = recCollision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); } if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; @@ -6005,6 +6067,15 @@ struct HStrangeCorrelation { if (masterConfigurations.selectINELgtONE && !bestCollisionINELgtONE) { return; } + if (masterConfigurations.rejectSameBunchPileup && !bestCollisionNoSameBunchPileup) { + return; + } + if (masterConfigurations.requireGoodTriggerTVX && !bestCollisionGoodTriggerTVX) { + return; + } + if (masterConfigurations.requireGoodZvtxFT0vsPV && !bestCollisionGoodZvtxFT0vsPV) { + return; + } if (bestCollisionCentpercentile > axisRanges[5][1] || bestCollisionCentpercentile < axisRanges[5][0]) { return; } diff --git a/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx index ec76c05b8e1..05c71967ed5 100644 --- a/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx +++ b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx @@ -27,6 +27,7 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include #include #include #include @@ -40,13 +41,14 @@ #include #include -#include +#include #include +#include +#include #include #include #include -#include #include #include #include @@ -100,34 +102,47 @@ struct Lambdak0sflattenicity { OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rCharged{ + "charged", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; - static constexpr int kNEstimators = 8; + static constexpr int kNEstimators = 7; // forward detector segmentation static constexpr int kNChannelsPerT0Sector = 4; static constexpr int kNSectorsT0A = 24; static constexpr int kNSectorsT0C = 28; + // One lattice cell per FT0 readout channel: the four channels of a sector are + // separate quadrants. Gain and vertex maps stay per sector, as CCDB holds them. + static constexpr int kNChannelsFT0A = kNSectorsT0A * kNChannelsPerT0Sector; + static constexpr int kNChannelsFT0C = kNSectorsT0C * kNChannelsPerT0Sector; static constexpr int kNChannelsPerFV0Ring = 8; static constexpr int kNFV0EtaRings = 5; static constexpr int kOuterFV0RingIndex = kNFV0EtaRings - 1; static constexpr int kNSectorsFV0OuterRing = 16; // TParticlePDG::Charge() is in units of e/3 static constexpr float kMinCharge = 0.01f; - // rapidity window for generated particles - static constexpr float kMcRapidityWindow = 0.5f; + // eFV0FT0C is the weighted amplitude sum, a multiplicity estimator, not a 1-rho static constexpr std::array kHEst = { "eGlobaltrack", "eFV0", "e1flatencityFV0", "eFT0", - "e1flatencityFT0", "eFV0FT0C", "e1flatencityFV0FT0C", "ePtTrig"}; + "e1flatencityFT0", "eFV0FT0C", "ePtTrig"}; static constexpr std::array kTEst = { "GlobalTrk", "FV0", "1-flatencity_FV0", "FT0", - "1-flatencityFT0", "FV0_FT0C", "1-flatencity_FV0_FT0C", "PtTrig"}; + "1-flatencityFT0", "FV0_FT0C", "PtTrig"}; static constexpr std::array kHPtEst = { "ptVsGlobaltrack", "ptVsFV0", "ptVs1flatencityFV0", "ptVsFT0", "ptVs1flatencityFT0", "ptVsFV0FT0C", - "ptVs1flatencityFV0FT0C", "pTVsPtTrig"}; + "pTVsPtTrig"}; - // Histogram binning + // Histogram binning. The pT and 1-rho axes are ConfigurableAxis: pass + // {nbins, lo, hi} for uniform bins or {VARIABLE_WIDTH, e0, e1, ...} for the + // edges of the published binning. The 1-rho edges are meant to be the + // percentile class boundaries measured by the processFlatDist* pass, so that + // one class is exactly one bin and no rebinning happens downstream. struct : ConfigurableGroup { std::string prefix = "binning"; Configurable nBinsVz{"nBinsVz", 100, "N bins in Vz"}; @@ -138,8 +153,21 @@ struct Lambdak0sflattenicity { Configurable kK0sEPshiftfromMass{"kK0sEPshiftfromMass", 0.1, "distance of K0s Inv mass histogram start and end points from PDG mass"}; Configurable kLambdaEPshiftfromMass{"kLambdaEPshiftfromMass", 0.05, "distance of Lambda Inv mass histogram start and end points from PDG mass"}; Configurable kXiEPshiftfromMass{"kXiEPshiftfromMass", 0.05, "distance of Xi Inv mass histogram start and end points from PDG mass"}; - Configurable nBinspT{"nBinspT", 250, "N bins in pT"}; - Configurable nBinsFlattenicity{"nBinsFlattenicity", 100, "N bins in Flattenicity"}; + ConfigurableAxis axisPtK0s{"axisPtK0s", {250, 0.0f, 25.0f}, "#it{p}_{T} of K0s"}; + ConfigurableAxis axisPtLambda{"axisPtLambda", {250, 0.0f, 25.0f}, "#it{p}_{T} of Lambda and AntiLambda"}; + ConfigurableAxis axisPtXi{"axisPtXi", {250, 0.0f, 25.0f}, "#it{p}_{T} of Xi"}; + ConfigurableAxis axisPtCharged{"axisPtCharged", {250, 0.0f, 25.0f}, "#it{p}_{T} of charged particles"}; + ConfigurableAxis axisPtPid{"axisPtPid", {250, 0.0f, 25.0f}, "#it{p}_{TPC} of the daughter tracks"}; + ConfigurableAxis axisFlat{"axisFlat", {100, 0.0f, 1.0f}, "1-#rho_{ch} of the spectra"}; + // detector effects move the percentiles, so the closure denominator needs + // its own class edges, taken from hFlatDistGen + ConfigurableAxis axisFlatTrue{"axisFlatTrue", {100, 0.0f, 1.0f}, "true 1-#rho_{ch}"}; + ConfigurableAxis axisFlatFine{"axisFlatFine", {2000, 0.0f, 1.0f}, "1-#rho_{ch} used to locate the percentiles"}; + ConfigurableAxis axisCent{"axisCent", {100, 0.0f, 100.0f}, "FT0M percentile"}; + ConfigurableAxis axisNch{"axisNch", {150, -0.5f, 149.5f}, "N_{ch} in the tracking acceptance"}; + ConfigurableAxis axisDcaXy{"axisDcaXy", {200, -1.0f, 1.0f}, "DCA_{xy} (cm)"}; + ConfigurableAxis axisDcaV0ToPv{"axisDcaV0ToPv", {200, 0.0f, 2.0f}, "DCA of the V0 to the PV (cm)"}; + ConfigurableAxis axisPtRes{"axisPtRes", {200, -0.5f, 0.5f}, "(#it{p}_{T}^{rec} - #it{p}_{T}^{gen})/#it{p}_{T}^{gen}"}; } binning; // Event selection @@ -170,22 +198,51 @@ struct Lambdak0sflattenicity { struct : ConfigurableGroup { std::string prefix = "flatSel"; Configurable flattenicityQA{"flattenicityQA", true, "Store Flattenicity QA plots"}; - Configurable applyCalibCh{"applyCalibCh", false, "equalize FV0"}; + // Both corrections reshape the lattice and therefore move the flattenicity. + // With both off nothing is read from CCDB at all. + Configurable applyCalibCh{"applyCalibCh", false, + "equalize the per-channel gain, from CCDB"}; Configurable applyCalibVtx{"applyCalibVtx", false, - "equalize FV0 vs vtx"}; + "equalize the per-cell z-vertex dependence, from CCDB"}; Configurable applyNorm{"applyNorm", false, "normalization to eta"}; Configurable isflattenicitywithFV0{"isflattenicitywithFV0", true, "Calculate Flattenicity with FV0"}; Configurable isflattenicitywithFT0{"isflattenicitywithFT0", true, "Calculate Flattenicity with FT0"}; - Configurable isflattenicitywithFV0FT0C{"isflattenicitywithFV0FT0C", true, - "Calculate Flattenicity with FV0+FT0C"}; Configurable flattenicityforanalysis{"flattenicityforanalysis", 0, - "Which Flattenicity to be used for analysis, 0 for FV0, 1 for FT0, 2 for FV0+FT0C"}; + "Which Flattenicity to be used for analysis, 0 for FV0, 1 for FT0"}; + // On a sparse lattice sigma/ is quantised -- one lit cell gives exactly + // sqrt((N-1)/N) whatever the amplitude -- which puts spikes in 1-rho. Tune + // against the hNActiveCells* histograms. 0 disables. + Configurable minLitCellsFV0{"minLitCellsFV0", 0, + "Minimum lit FV0 cells (of 48), applied when flattenicityforanalysis=0"}; + Configurable minLitCellsFT0A{"minLitCellsFT0A", 0, + "Minimum lit FT0A cells (of 96), applied when flattenicityforanalysis=1"}; + Configurable minLitCellsFT0C{"minLitCellsFT0C", 0, + "Minimum lit FT0C cells (of 112), applied when flattenicityforanalysis=1"}; Configurable flattenicityforLossCorrRec{"flattenicityforLossCorrRec", true, "Flattenicity from Rec Tracks are used for Signal and Event loss calculations"}; + // FV0 only: same cell convention as the detector lattice, so gen vs rec is + // a detector effect and not a difference of definitions + Configurable genFlatDetectorLikeNorm{"genFlatDetectorLikeNorm", true, + "Weight the generator-level FV0 cells the way the detector lattice does"}; } flatSel; + // Calibration objects, read per run and only when the corresponding switch is + // on. Same layout as PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx, so + // the objects are interchangeable between the two tasks: the gain is a + // std::vector indexed by the raw detector channel, the z-vertex + // equalization a TProfile2D of (lattice cell, z_vtx). + struct : ConfigurableGroup { + std::string prefix = "ccdbConf"; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", + "url of the ccdb repository"}; + Configurable gainEqPath{"gainEqPath", "Users/s/sprasad/flattenicity/GainEq", + "CCDB directory holding FV0, FT0A and FT0C gain vectors"}; + Configurable vtxEqPath{"vtxEqPath", "Users/s/sprasad/flattenicity/ZvtxEq", + "CCDB directory holding the FV0, FT0A and FT0C z-vertex maps"}; + } ccdbConf; + // V0 selection struct : ConfigurableGroup { std::string prefix = "v0Sel"; @@ -233,6 +290,12 @@ struct Lambdak0sflattenicity { "Half width of the K0s mass window used for the PID QA plots"}; Configurable pidQAWindowLambda{"pidQAWindowLambda", 0.1, "Half width of the Lambda mass window used for the PID QA plots"}; + // negative values disable a cut, so the defaults reproduce the previous selection + Configurable minCrossedRowsOverFindable{"minCrossedRowsOverFindable", -1.f, + "Minimum TPC crossed rows over findable clusters"}; + Configurable maxTpcChi2NCl{"maxTpcChi2NCl", -1.f, "Maximum TPC chi2 per cluster"}; + Configurable maxItsChi2NCl{"maxItsChi2NCl", -1.f, "Maximum ITS chi2 per cluster"}; + Configurable minItsNCls{"minItsNCls", -1, "Minimum number of ITS clusters"}; } trkPid; // Cascade selection @@ -258,7 +321,6 @@ struct Lambdak0sflattenicity { // values for flattenicityforanalysis static constexpr int kFlatFromFV0 = 0; static constexpr int kFlatFromFT0 = 1; - static constexpr int kFlatFromFV0FT0C = 2; // FT0M percentile class: run once over the full range for MB and once with a // narrow window for HM. Grouped because the framework only decomposes 100 @@ -269,12 +331,25 @@ struct Lambdak0sflattenicity { "Select events in a FT0M percentile window"}; Configurable cfgCentMin{"cfgCentMin", 0.0f, "Minimum FT0M percentile"}; Configurable cfgCentMax{"cfgCentMax", 100.0f, "Maximum FT0M percentile"}; - Configurable nBinsCent{"nBinsCent", 100, "N bins in FT0M percentile"}; + // the processFlatDist* pass fills the MB and the HM 1-rho distributions + // together, so this window is applied to a histogram and not to the event + Configurable cfgCentMaxHM{"cfgCentMaxHM", 1.0f, + "Upper FT0M percentile of the high-multiplicity class"}; // keep only primaries in the MC-matched spectra, the rest go to the // feed-down histograms Configurable requirePrimaryMC{"requirePrimaryMC", true, "Require isPhysicalPrimary() on the MC-matched candidate"}; + Configurable genFlatPrimariesOnly{"genFlatPrimariesOnly", true, + "Use only primaries in the generator-level flattenicity"}; + Configurable fillChargedQA{"fillChargedQA", true, + "Fill the charged-particle histograms used for and Qpp"}; + Configurable cfgEtaChargedCut{"cfgEtaChargedCut", 0.8f, + "Eta window of the charged-particle measurement"}; + // mothers outside the Lambda window still feed it, so the matrix is + // normalised in a wider one + Configurable cfgFeedDownMotherRapidity{"cfgFeedDownMotherRapidity", 1.5f, + "Rapidity window of the generated feed-down mothers"}; } eventClass; // Configurable v0daughter_etacut{"V0DaughterEtaCut", 0.8, @@ -282,15 +357,40 @@ struct Lambdak0sflattenicity { // Configurable v0etacut{"v0etacut", 0.8, "v0etacut"}; int nbin = 1; - // hEventsSelected bin for the flattenicity requirement, -1 if not applied + // hEventsSelected bins for the stages inside estimateFlattenicity(), -1 if unused + int nbinFlatDetHit = -1; + int nbinFlatOccupancy = -1; int nbinFlattenicity = -1; + + // how far estimateFlattenicity() got, so its rejections show in the cut flow + static constexpr int kFlatStageNoDetector = 0; + static constexpr int kFlatStageLowOccupancy = 1; + static constexpr int kFlatStageNoSignal = 2; + static constexpr int kFlatStageOk = 3; + int flatStage = kFlatStageNoDetector; // do not fill the detector QA twice when processGenMC runs with a rec-level process bool fillFlattenicityQAInGenMC = true; - // vertex equalization curves, built once in init() - static constexpr int kNDetVtx = 3; - static constexpr int kNVtxPoints = 30; - std::array gVtx; + // the per-event histograms are shared by every rec-level process function, + // so only the one designated in init() fills them + static constexpr int kOwnerNone = -1; + static constexpr int kOwnerFlatDistData = 0; + static constexpr int kOwnerFlatDistMC = 1; + static constexpr int kOwnerRecMCV0 = 2; + static constexpr int kOwnerDataV0 = 3; + static constexpr int kOwnerRecMCCasc = 4; + static constexpr int kOwnerDataCasc = 5; + int eventHistOwner = kOwnerNone; + + // calibration objects, refreshed when the run changes + Service ccdb{}; + int mRunNumber = -1; + std::vector gainFV0; + std::vector gainFT0A; + std::vector gainFT0C; + TProfile2D* vtxEqFV0 = nullptr; + TProfile2D* vtxEqFT0A = nullptr; + TProfile2D* vtxEqFT0C = nullptr; void init(InitContext const&) { @@ -308,24 +408,30 @@ struct Lambdak0sflattenicity { o2::constants::physics::MassXiMinus + binning.kXiEPshiftfromMass, "#it{M}_{#Lambda#pi} [GeV/#it{c}^{2}]"}; AxisSpec vertexZAxis = {binning.nBinsVz, -15., 15., "vrtx_{Z} [cm]"}; - AxisSpec ptAxis = {binning.nBinspT, 0.0f, 25.0f, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec pTPCAxis = {binning.nBinspT, 0.0f, 25.0f, "#it{p}_{TPC} (GeV/#it{c})"}; + AxisSpec ptK0sAxis = {binning.axisPtK0s, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptLambdaAxis = {binning.axisPtLambda, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptXiAxis = {binning.axisPtXi, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptChargedAxis = {binning.axisPtCharged, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pTPCAxis = {binning.axisPtPid, "#it{p}_{TPC} (GeV/#it{c})"}; AxisSpec decayRadiusAxis = {100, 0.0f, 100.0f, "Decay Radius (cm)"}; - AxisSpec flatAxis = {binning.nBinsFlattenicity, 0.0f, 1.0f, "1-#rho_{ch}"}; - AxisSpec centAxis = {eventClass.nBinsCent, 0.0f, 100.0f, "FT0M percentile"}; - - std::array nBinsEst = {100, 500, 102, 500, 102, 500, 102, 150}; - std::array lowEdgeEst = {-0.5, -0.5, -0.01, -0.5, -0.01, -0.5, -0.01, .0}; - std::array upEdgeEst = {99.5, 49999.5, 1.01, 499.5, 1.01, 499.5, 1.01, 150.0}; - - gVtx[0].SetName("gAmpV0"); - gVtx[1].SetName("gAmpT0A"); - gVtx[2].SetName("gAmpT0C"); - for (int iVtx = 0; iVtx < kNVtxPoints; ++iVtx) { - gVtx[0].SetPoint(iVtx, kBiningVtxt[iVtx], kCalibFV0vtx[iVtx]); - gVtx[1].SetPoint(iVtx, kBiningVtxt[iVtx], kCalibFT0Avtx[iVtx]); - gVtx[2].SetPoint(iVtx, kBiningVtxt[iVtx], kCalibFT0Cvtx[iVtx]); - } + AxisSpec flatAxis = {binning.axisFlat, "1-#rho_{ch}"}; + AxisSpec flatTrueAxis = {binning.axisFlatTrue, "true 1-#rho_{ch}"}; + AxisSpec flatFineAxis = {binning.axisFlatFine, "1-#rho_{ch}"}; + AxisSpec centAxis = {binning.axisCent, "FT0M percentile"}; + AxisSpec nchAxis = {binning.axisNch, "#it{N}_{ch}"}; + AxisSpec dcaXyAxis = {binning.axisDcaXy, "DCA_{xy} (cm)"}; + AxisSpec dcaV0ToPvAxis = {binning.axisDcaV0ToPv, "DCA_{V0-PV} (cm)"}; + AxisSpec ptResAxis = {binning.axisPtRes, "(#it{p}_{T}^{rec} - #it{p}_{T}^{gen})/#it{p}_{T}^{gen}"}; + AxisSpec motherAxis = {kNFeedDownMothers, -0.5, kNFeedDownMothers - 0.5, "mother"}; + + std::array nBinsEst = {100, 500, 102, 500, 102, 500, 150}; + std::array lowEdgeEst = {-0.5, -0.5, -0.01, -0.5, -0.01, -0.5, .0}; + std::array upEdgeEst = {99.5, 49999.5, 1.01, 499.5, 1.01, 499.5, 150.0}; + + ccdb->setURL(ccdbConf.ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); // Histograms // Event selection @@ -362,9 +468,15 @@ struct Lambdak0sflattenicity { if (evSel.isINELgt0) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "INEL>0"); } - // events without FV0/FT0 are rejected below, they need their own counter + // estimateFlattenicity() drops events on three grounds: no detector record, + // too few lit cells, undefined 1-rho. One counter each. if (doprocessDataRun3LambdaK0s || doprocessRecMCLambdaK0s || - doprocessDataRun3Cascade || doprocessRecMCRun3Cascade) { + doprocessDataRun3Cascade || doprocessRecMCRun3Cascade || + doprocessFlatDistData || doprocessFlatDistMC) { + nbinFlatDetHit = nbin; + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "flatDetHit"); + nbinFlatOccupancy = nbin; + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "flatOccupancy"); nbinFlattenicity = nbin; rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "flattenicity"); } @@ -374,15 +486,75 @@ struct Lambdak0sflattenicity { rEventSelection.add("hCentFT0M", "hCentFT0M", {HistType::kTH1D, {centAxis}}); rEventSelection.add("hCentFT0MvsFlattenicity", "hCentFT0MvsFlattenicity", {HistType::kTH2D, {centAxis, flatAxis}}); - if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessGenMC) { + + // 1-rho on the fine axis, the input to the percentile boundaries of + // binning.axisFlat. Filled once per accepted collision, by the owner. + rEventSelection.add("hFlatDistRec", "hFlatDistRec", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistRecINELgt0", "hFlatDistRecINELgt0", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistRecHM", "hFlatDistRecHM", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hCentFT0MFine", "hCentFT0MFine", {HistType::kTH1D, {{1000, 0.0f, 100.0f, "FT0M percentile"}}}); + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessGenMC || + doprocessFlatDistMC) { + // one entry per generated collision, the sample the closure denominator + // lives in: binning.axisFlatTrue has to be set from this one, or the + // numerator and the denominator do not share a class definition + rEventSelection.add("hFlatDistGen", "hFlatDistGen", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenINELgt0", "hFlatDistGenINELgt0", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenHM", "hFlatDistGenHM", {HistType::kTH1D, {flatFineAxis}}); + // same, restricted to accepted reconstructed collisions: the ratio to + // hFlatDistGen is the event selection bias on the class assignment + rEventSelection.add("hFlatDistGenInRec", "hFlatDistGenInRec", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenInRecINELgt0", "hFlatDistGenInRecINELgt0", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenInRecHM", "hFlatDistGenInRecHM", {HistType::kTH1D, {flatFineAxis}}); + } + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessGenMC || + doprocessFlatDistMC) { rEventSelection.add("hTrueFV0amplvsFlat", "TrueFV0MvsFlat", HistType::kTH2D, - {{500, -0.5, +499.5, "True Nch in FV0 region"}, flatAxis}); - } - if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade) { + {{500, -0.5, +499.5, "True Nch in FV0 region"}, flatTrueAxis}); + rEventSelection.add("hTrueFT0amplvsFlat", "TrueFT0MvsFlat", HistType::kTH2D, + {{500, -0.5, +499.5, "True Nch in FT0 region"}, flatTrueAxis}); + rEventSelection.add("hNActiveCellsFT0AMCGen", "hNActiveCellsFT0AMCGen", HistType::kTH1D, + {{kNChannelsFT0A + 1, -0.5, kNChannelsFT0A + 0.5, "occupied generated FT0A cells"}}); + rEventSelection.add("hNActiveCellsFT0CMCGen", "hNActiveCellsFT0CMCGen", HistType::kTH1D, + {{kNChannelsFT0C + 1, -0.5, kNChannelsFT0C + 0.5, "occupied generated FT0C cells"}}); + } + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessFlatDistMC) { rEventSelection.add("hFlattenicityDistributionMCGen_Rec", "hFlattenicityDistributionMCGen_Rec", - {HistType::kTH1D, {flatAxis}}); + {HistType::kTH1D, {flatTrueAxis}}); rEventSelection.add("hFlattenicity_Corr_Gen_vs_Rec", "hFlattenicity_Corr_Gen_vs_Rec", - {HistType::kTH2D, {flatAxis, flatAxis}}); + {HistType::kTH2D, {flatTrueAxis, flatAxis}}); + // migration of the class assignment, needed pT-differentially to unfold + rEventSelection.add("hFlatGenVsRecFine", "hFlatGenVsRecFine", + {HistType::kTH2D, {flatFineAxis, flatFineAxis}}); + } + + // Charged particles in |eta| < cfgEtaChargedCut: per class is + // the scale factor of Qpp, and the DCAxy templates give the secondary + // contamination the same way the published analysis obtains it. + if (eventClass.fillChargedQA) { + rCharged.add("hNchVsFlat", "hNchVsFlat", {HistType::kTH2D, {nchAxis, flatAxis}}); + rCharged.add("hPtChVsFlat", "hPtChVsFlat", {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessFlatDistMC) { + rCharged.add("hPtChVsFlatRecPrim", "hPtChVsFlatRecPrim", + {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + rCharged.add("hPtChVsFlatGenInRec", "hPtChVsFlatGenInRec", + {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + rCharged.add("hNchVsFlatGenInRec", "hNchVsFlatGenInRec", {HistType::kTH2D, {nchAxis, flatAxis}}); + rCharged.add("hDcaXyPtChPrim", "hDcaXyPtChPrim", + {HistType::kTH3D, {dcaXyAxis, ptChargedAxis, flatAxis}}); + rCharged.add("hDcaXyPtChSec", "hDcaXyPtChSec", + {HistType::kTH3D, {dcaXyAxis, ptChargedAxis, flatAxis}}); + } + if (doprocessDataRun3LambdaK0s || doprocessDataRun3Cascade || doprocessFlatDistData) { + rCharged.add("hDcaXyPtCh", "hDcaXyPtCh", + {HistType::kTH3D, {dcaXyAxis, ptChargedAxis, flatAxis}}); + } + if (doprocessGenMC) { + rCharged.add("hPtChVsFlatGen", "hPtChVsFlatGen", {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + rCharged.add("hNchVsFlatGen", "hNchVsFlatGen", {HistType::kTH2D, {nchAxis, flatAxis}}); + rCharged.add("hPtChVsTrueFlatGen", "hPtChVsTrueFlatGen", {HistType::kTH2D, {ptChargedAxis, flatTrueAxis}}); + rCharged.add("hNchVsTrueFlatGen", "hNchVsTrueFlatGen", {HistType::kTH2D, {nchAxis, flatTrueAxis}}); + } } if (doprocessDataRun3LambdaK0s || doprocessRecMCLambdaK0s) { @@ -408,17 +580,17 @@ struct Lambdak0sflattenicity { rKzeroShort.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rKzeroShort.add("hMassK0spT", "hMassK0spT", - {HistType::kTH2D, {{k0sMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{k0sMassAxis}, {ptK0sAxis}}}); rKzeroShort.add("hMassK0spTFlat", "hMassK0spTFlat", - {HistType::kTH3D, {{k0sMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{k0sMassAxis}, {ptK0sAxis}, {flatAxis}}}); rKzeroShort.add("hArmPodoAlphavsQTK0sAfterCut", "hArmPodoAlphavsQTK0sAfterCut", {HistType::kTH2D, {{200, -1, 1, "#alpha"}, {70, 0, 0.35, "Q_{T}"}}}); if (doprocessRecMCLambdaK0s) { rKzeroShort.add("Generated_MCRecoCollCheck_INEL_K0Short", "Generated_MCRecoCollCheck_INEL_K0Short", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptK0sAxis}, {flatAxis}}}); rKzeroShort.add("Generated_MCRecoCollCheck_INELgt0_K0Short", "Generated_MCRecoCollCheck_INELgt0_K0Short", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptK0sAxis}, {flatAxis}}}); } // Lambda reconstruction Mass @@ -443,24 +615,31 @@ struct Lambdak0sflattenicity { rLambda.add("h2DdecayRadiusLambda", "h2DdecayRadiusLambda", {HistType::kTH1D, {decayRadiusAxis}}); rLambda.add("hMassLambdapT", "hMassLambdapT", - {HistType::kTH2D, {{lambdaMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{lambdaMassAxis}, {ptLambdaAxis}}}); rLambda.add("hMassLambdapTFlat", "hMassLambdapTFlat", - {HistType::kTH3D, {{lambdaMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{lambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); if (doprocessRecMCLambdaK0s) { rLambda.add("Generated_MCRecoCollCheck_INEL_Lambda", "Generated_MCRecoCollCheck_INEL_Lambda", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); rLambda.add("Generated_MCRecoCollCheck_INELgt0_Lambda", "Generated_MCRecoCollCheck_INELgt0_Lambda", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); rLambda.add("hMassFeedDownLambdapTFlat", "hMassFeedDownLambdapTFlat", - {HistType::kTH3D, {{lambdaMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{lambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); rLambda.add("hFeedDownLambdaPtVsMotherPt", "hFeedDownLambdaPtVsMotherPt", - {HistType::kTH2D, {{ptAxis}, {ptAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {ptLambdaAxis}}}); + rLambda.add("hFeedDownLambdaMatrix", "hFeedDownLambdaMatrix", + {HistType::kTHnSparseF, {{ptLambdaAxis}, {ptLambdaAxis}, {flatAxis}, {motherAxis}}}); rLambda.add("hFeedDownLambdaMotherPdg", "hFeedDownLambdaMotherPdg", - {HistType::kTH1D, {{kNFeedDownMothers, -0.5, kNFeedDownMothers - 0.5, "mother"}}}); + {HistType::kTH1D, {{motherAxis}}}); rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(1, "#Xi^{-}"); rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(2, "#Xi^{0}"); rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(3, "#Omega^{-}"); rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(4, "other"); + // generated mothers in the same events and classes as + // hFeedDownLambdaMatrix, so the matrix is a probability per mother that + // folds with the measured Xi. Xi0 is not measurable and only lives here. + rLambda.add("hGenFeedDownMotherPtFlat", "hGenFeedDownMotherPtFlat", + {HistType::kTHnSparseF, {{ptLambdaAxis}, {flatAxis}, {motherAxis}}}); } // AntiLambda reconstruction @@ -488,20 +667,22 @@ struct Lambdak0sflattenicity { rAntiLambda.add("h2DdecayRadiusAntiLambda", "h2DdecayRadiusAntiLambda", {HistType::kTH1D, {decayRadiusAxis}}); rAntiLambda.add("hMassAntiLambdapT", "hMassAntiLambdapT", - {HistType::kTH2D, {{antilambdaMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{antilambdaMassAxis}, {ptLambdaAxis}}}); rAntiLambda.add("hMassAntiLambdapTFlat", "hMassAntiLambdapTFlat", - {HistType::kTH3D, {{antilambdaMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{antilambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); if (doprocessRecMCLambdaK0s) { rAntiLambda.add("Generated_MCRecoCollCheck_INEL_AntiLambda", "Generated_MCRecoCollCheck_INEL_AntiLambda", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); rAntiLambda.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda", "Generated_MCRecoCollCheck_INELgt0_AntiLambda", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); rAntiLambda.add("hMassFeedDownAntiLambdapTFlat", "hMassFeedDownAntiLambdapTFlat", - {HistType::kTH3D, {{antilambdaMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{antilambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); rAntiLambda.add("hFeedDownAntiLambdaPtVsMotherPt", "hFeedDownAntiLambdaPtVsMotherPt", - {HistType::kTH2D, {{ptAxis}, {ptAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {ptLambdaAxis}}}); + rAntiLambda.add("hFeedDownAntiLambdaMatrix", "hFeedDownAntiLambdaMatrix", + {HistType::kTHnSparseF, {{ptLambdaAxis}, {ptLambdaAxis}, {flatAxis}, {motherAxis}}}); rAntiLambda.add("hFeedDownAntiLambdaMotherPdg", "hFeedDownAntiLambdaMotherPdg", - {HistType::kTH1D, {{kNFeedDownMothers, -0.5, kNFeedDownMothers - 0.5, "mother"}}}); + {HistType::kTH1D, {{motherAxis}}}); rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(1, "#Xi^{-}"); rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(2, "#Xi^{0}"); rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(3, "#Omega^{-}"); @@ -510,6 +691,42 @@ struct Lambdak0sflattenicity { rCommonHist.add("hArmPodoAlphavsQT", "hArmPodoAlphavsQT", {HistType::kTH2D, {{200, -1, 1, "#alpha"}, {70, 0, 0.35, "Q_{T}"}}}); + + // DCA of the V0 to the PV: primaries peak at zero, feed-down does not, so + // the data distribution can be fitted with the two MC templates + rLambda.add("hDcaV0ToPVLambda", "hDcaV0ToPVLambda", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hDcaV0ToPVAntiLambda", "hDcaV0ToPVAntiLambda", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + if (doprocessRecMCLambdaK0s) { + rLambda.add("hDcaV0ToPVLambdaPrim", "hDcaV0ToPVLambdaPrim", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rLambda.add("hDcaV0ToPVLambdaSec", "hDcaV0ToPVLambdaSec", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hDcaV0ToPVAntiLambdaPrim", "hDcaV0ToPVAntiLambdaPrim", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hDcaV0ToPVAntiLambdaSec", "hDcaV0ToPVAntiLambdaSec", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + + rKzeroShort.add("hPtResK0s", "hPtResK0s", {HistType::kTH2D, {{ptK0sAxis}, {ptResAxis}}}); + rLambda.add("hPtResLambda", "hPtResLambda", {HistType::kTH2D, {{ptLambdaAxis}, {ptResAxis}}}); + rAntiLambda.add("hPtResAntiLambda", "hPtResAntiLambda", {HistType::kTH2D, {{ptLambdaAxis}, {ptResAxis}}}); + + // numerator classified by the measured 1-rho, denominator by the true + // one: the pair is the MC closure + rKzeroShort.add("Generated_MCRecoCollCheck_INELgt0_K0Short_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {{ptK0sAxis}, {flatTrueAxis}}}); + rLambda.add("Generated_MCRecoCollCheck_INELgt0_Lambda_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {{ptLambdaAxis}, {flatTrueAxis}}}); + rAntiLambda.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {{ptLambdaAxis}, {flatTrueAxis}}}); + rKzeroShort.add("hMassK0spTTrueFlat", "hMassK0spTTrueFlat", + {HistType::kTH3D, {{k0sMassAxis}, {ptK0sAxis}, {flatTrueAxis}}}); + rLambda.add("hMassLambdapTTrueFlat", "hMassLambdapTTrueFlat", + {HistType::kTH3D, {{lambdaMassAxis}, {ptLambdaAxis}, {flatTrueAxis}}}); + rAntiLambda.add("hMassAntiLambdapTTrueFlat", "hMassAntiLambdapTTrueFlat", + {HistType::kTH3D, {{antilambdaMassAxis}, {ptLambdaAxis}, {flatTrueAxis}}}); + } } if (doprocessRecMCRun3Cascade || doprocessDataRun3Cascade) { @@ -535,24 +752,32 @@ struct Lambdak0sflattenicity { rXi.add("hNSigmaBachPionFromXi", "hNSigmaBachPionFromXi", {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rXi.add("hMassXipT", "hMassXipT", - {HistType::kTH2D, {{xiMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{xiMassAxis}, {ptXiAxis}}}); rXi.add("hMassXipTFlat", "hMassXipTFlat", - {HistType::kTH3D, {{xiMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{xiMassAxis}, {ptXiAxis}, {flatAxis}}}); if (doprocessRecMCRun3Cascade) { rXi.add("Generated_MCRecoCollCheck_INEL_Xi", "Generated_MCRecoCollCheck_INEL_Xi", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptXiAxis}, {flatAxis}}}); rXi.add("Generated_MCRecoCollCheck_INELgt0_Xi", "Generated_MCRecoCollCheck_INELgt0_Xi", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptXiAxis}, {flatAxis}}}); rXi.add("hMassFeedDownXipTFlat", "hMassFeedDownXipTFlat", - {HistType::kTH3D, {{xiMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{xiMassAxis}, {ptXiAxis}, {flatAxis}}}); rXi.add("hFeedDownXiPtVsMotherPt", "hFeedDownXiPtVsMotherPt", - {HistType::kTH2D, {{ptAxis}, {ptAxis}}}); + {HistType::kTH2D, {{ptXiAxis}, {ptXiAxis}}}); + rXi.add("hFeedDownXiMatrix", "hFeedDownXiMatrix", + {HistType::kTHnSparseF, {{ptXiAxis}, {ptXiAxis}, {flatAxis}, {motherAxis}}}); rXi.add("hFeedDownXiMotherPdg", "hFeedDownXiMotherPdg", - {HistType::kTH1D, {{kNFeedDownMothers, -0.5, kNFeedDownMothers - 0.5, "mother"}}}); + {HistType::kTH1D, {{motherAxis}}}); rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(1, "#Xi^{-}"); rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(2, "#Xi^{0}"); rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(3, "#Omega^{-}"); rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(4, "other"); + + rXi.add("hPtResXi", "hPtResXi", {HistType::kTH2D, {{ptXiAxis}, {ptResAxis}}}); + rXi.add("Generated_MCRecoCollCheck_INELgt0_Xi_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {{ptXiAxis}, {flatTrueAxis}}}); + rXi.add("hMassXipTTrueFlat", "hMassXipTTrueFlat", + {HistType::kTH3D, {{xiMassAxis}, {ptXiAxis}, {flatTrueAxis}}}); } } if (doprocessGenMC) { @@ -563,7 +788,7 @@ struct Lambdak0sflattenicity { {HistType::kTH1D, {vertexZAxis}}); rEventSelection.add("hFlattenicityDistributionMCGen", "hFlattenicityDistributionMCGen", - {HistType::kTH1D, {flatAxis}}); + {HistType::kTH1D, {flatTrueAxis}}); rEventSelection.add("hFlattenicityDistributionRecMCGen", "hFlattenicityDistributionRecMCGen", {HistType::kTH1D, {flatAxis}}); @@ -586,56 +811,89 @@ struct Lambdak0sflattenicity { rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(2, "pass ev sel"); rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(3, "INELgt0"); rKzeroShort.add("pGen_MCGenRecoColl_INEL_K0Short", "pGen_MCGenRecoColl_INEL_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("Generated_MCRecoColl_INEL_K0Short", "Generated_MCRecoColl_INEL_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("pGen_MCGenColl_INEL_K0Short", "pGen_MCGenColl_INEL_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("pGen_MCGenRecoColl_INELgt0_K0Short", "pGen_MCGenRecoColl_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("Generated_MCRecoColl_INELgt0_K0Short", "Generated_MCRecoColl_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("pGen_MCGenColl_INELgt0_K0Short", "pGen_MCGenColl_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rLambda.add("pGen_MCGenRecoColl_INEL_Lambda", "pGen_MCGenRecoColl_INEL_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("Generated_MCRecoColl_INEL_Lambda", "Generated_MCRecoColl_INEL_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("pGen_MCGenColl_INEL_Lambda", "pGen_MCGenColl_INEL_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("pGen_MCGenRecoColl_INELgt0_Lambda", "pGen_MCGenRecoColl_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("Generated_MCRecoColl_INELgt0_Lambda", "Generated_MCRecoColl_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("pGen_MCGenColl_INELgt0_Lambda", "pGen_MCGenColl_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenRecoColl_INEL_AntiLambda", "pGen_MCGenRecoColl_INEL_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("Generated_MCRecoColl_INEL_AntiLambda", "Generated_MCRecoColl_INEL_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenColl_INEL_AntiLambda", "pGen_MCGenColl_INEL_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenRecoColl_INELgt0_AntiLambda", "pGen_MCGenRecoColl_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("Generated_MCRecoColl_INELgt0_AntiLambda", "Generated_MCRecoColl_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenColl_INELgt0_AntiLambda", "pGen_MCGenColl_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rXi.add("pGen_MCGenRecoColl_INEL_Xi", "pGen_MCGenRecoColl_INEL_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("Generated_MCRecoColl_INEL_Xi", "Generated_MCRecoColl_INEL_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("pGen_MCGenColl_INEL_Xi", "pGen_MCGenColl_INEL_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("pGen_MCGenRecoColl_INELgt0_Xi", "pGen_MCGenRecoColl_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("Generated_MCRecoColl_INELgt0_Xi", "Generated_MCRecoColl_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("pGen_MCGenColl_INELgt0_Xi", "pGen_MCGenColl_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); + + // The same INEL>0 counters against the true 1-rho. Together with the + // reconstructed ones above they give the closure without a second job. + rEventSelection.add("hFlat_RecoColl_MC_INELgt0_TrueFlat", "hFlat_RecoColl_MC_INELgt0_TrueFlat", + {HistType::kTH1D, {flatTrueAxis}}); + rEventSelection.add("hFlat_GenRecoColl_MC_INELgt0_TrueFlat", "hFlat_GenRecoColl_MC_INELgt0_TrueFlat", + {HistType::kTH1D, {flatTrueAxis}}); + rEventSelection.add("hFlat_GenColl_MC_INELgt0_TrueFlat", "hFlat_GenColl_MC_INELgt0_TrueFlat", + {HistType::kTH1D, {flatTrueAxis}}); + rKzeroShort.add("pGen_MCGenRecoColl_INELgt0_K0Short_TrueFlat", "pGen_MCGenRecoColl_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {ptK0sAxis, flatTrueAxis}}); + rKzeroShort.add("Generated_MCRecoColl_INELgt0_K0Short_TrueFlat", "Generated_MCRecoColl_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {ptK0sAxis, flatTrueAxis}}); + rKzeroShort.add("pGen_MCGenColl_INELgt0_K0Short_TrueFlat", "pGen_MCGenColl_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {ptK0sAxis, flatTrueAxis}}); + rLambda.add("pGen_MCGenRecoColl_INELgt0_Lambda_TrueFlat", "pGen_MCGenRecoColl_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rLambda.add("Generated_MCRecoColl_INELgt0_Lambda_TrueFlat", "Generated_MCRecoColl_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rLambda.add("pGen_MCGenColl_INELgt0_Lambda_TrueFlat", "pGen_MCGenColl_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rAntiLambda.add("pGen_MCGenRecoColl_INELgt0_AntiLambda_TrueFlat", "pGen_MCGenRecoColl_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rAntiLambda.add("Generated_MCRecoColl_INELgt0_AntiLambda_TrueFlat", "Generated_MCRecoColl_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rAntiLambda.add("pGen_MCGenColl_INELgt0_AntiLambda_TrueFlat", "pGen_MCGenColl_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rXi.add("pGen_MCGenRecoColl_INELgt0_Xi_TrueFlat", "pGen_MCGenRecoColl_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {ptXiAxis, flatTrueAxis}}); + rXi.add("Generated_MCRecoColl_INELgt0_Xi_TrueFlat", "Generated_MCRecoColl_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {ptXiAxis, flatTrueAxis}}); + rXi.add("pGen_MCGenColl_INELgt0_Xi_TrueFlat", "pGen_MCGenColl_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {ptXiAxis, flatTrueAxis}}); } if (flatSel.flattenicityQA) { @@ -651,6 +909,16 @@ struct Lambdak0sflattenicity { {{2000, -0.5, 1999.5, "FT0C amplitude per channel"}}); rFlattenicity.add("hFT0A", "FT0A", HistType::kTH1D, {{2000, -0.5, 1999.5, "FT0A amplitude per channel"}}); + // lattice occupancy, what the minLitCells cuts are tuned on + rFlattenicity.add("hNActiveFT0Channels", "hNActiveFT0Channels", HistType::kTH1D, + {{kNChannelsFT0 + 1, -0.5, kNChannelsFT0 + 0.5, + "FT0 channels with amplitude > 0"}}); + rFlattenicity.add("hNActiveCellsFV0", "hNActiveCellsFV0", HistType::kTH1D, + {{kNCells + 1, -0.5, kNCells + 0.5, "occupied FV0 lattice cells"}}); + rFlattenicity.add("hNActiveCellsFT0A", "hNActiveCellsFT0A", HistType::kTH1D, + {{kNChannelsFT0A + 1, -0.5, kNChannelsFT0A + 0.5, "occupied FT0A lattice cells"}}); + rFlattenicity.add("hNActiveCellsFT0C", "hNActiveCellsFT0C", HistType::kTH1D, + {{kNChannelsFT0C + 1, -0.5, kNChannelsFT0C + 0.5, "occupied FT0C lattice cells"}}); rFlattenicity.add("hFV0amplvsFlat", "FV0MvsFlat", HistType::kTH2D, {{4000, -0.5, +49999.5, "FV0 amplitude"}, flatAxis}); @@ -728,18 +996,35 @@ struct Lambdak0sflattenicity { LOGF(fatal, "Can not run MCGen and Data process functions together. Try one of these at a time"); } - fillFlattenicityQAInGenMC = !(doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade); + // the spectra passes come first, their event counts normalise the yields + if (doprocessRecMCLambdaK0s) { + eventHistOwner = kOwnerRecMCV0; + } else if (doprocessDataRun3LambdaK0s) { + eventHistOwner = kOwnerDataV0; + } else if (doprocessRecMCRun3Cascade) { + eventHistOwner = kOwnerRecMCCasc; + } else if (doprocessDataRun3Cascade) { + eventHistOwner = kOwnerDataCasc; + } else if (doprocessFlatDistMC) { + eventHistOwner = kOwnerFlatDistMC; + } else if (doprocessFlatDistData) { + eventHistOwner = kOwnerFlatDistData; + } - // the estimator used for the analysis has to be computed - if (flatSel.flattenicityforanalysis == kFlatFromFV0 && !flatSel.isflattenicitywithFV0 && !flatSel.isflattenicitywithFV0FT0C) { - LOGF(fatal, "flattenicityforanalysis=0 (FV0) needs isflattenicitywithFV0 or isflattenicitywithFV0FT0C enabled"); + // tied to the owner so a new process function cannot bring the double fill back + fillFlattenicityQAInGenMC = (eventHistOwner == kOwnerNone); + + // both estimators have a generator-level counterpart, so only check the switch + if (flatSel.flattenicityforanalysis != kFlatFromFV0 && + flatSel.flattenicityforanalysis != kFlatFromFT0) { + LOGF(fatal, "flattenicityforanalysis must be 0 (FV0) or 1 (FT0)"); + } + if (flatSel.flattenicityforanalysis == kFlatFromFV0 && !flatSel.isflattenicitywithFV0) { + LOGF(fatal, "flattenicityforanalysis=0 (FV0) needs isflattenicitywithFV0 enabled"); } if (flatSel.flattenicityforanalysis == kFlatFromFT0 && !flatSel.isflattenicitywithFT0) { LOGF(fatal, "flattenicityforanalysis=1 (FT0) needs isflattenicitywithFT0 enabled"); } - if (flatSel.flattenicityforanalysis == kFlatFromFV0FT0C && !(flatSel.isflattenicitywithFV0FT0C || (flatSel.isflattenicitywithFV0 && flatSel.isflattenicitywithFT0))) { - LOGF(fatal, "flattenicityforanalysis=2 (FV0+FT0C) needs isflattenicitywithFV0FT0C enabled"); - } } // FT0 sectors group kNChannelsPerT0Sector consecutive channels @@ -777,7 +1062,7 @@ struct Lambdak0sflattenicity { float getFlatenicity(std::span signals) { int entries = signals.size(); - float flat = 9999; + float flat = kFlatUndefined; float mRho = 0; for (int iCell = 0; iCell < entries; ++iCell) { mRho += 1.0 * signals[iCell]; @@ -796,54 +1081,18 @@ struct Lambdak0sflattenicity { } return flat; } - // V0A signal and flatenicity calculation - static constexpr std::array kCalib = { - 1.01697, 1.122, 1.03854, 1.108, 1.11634, 1.14971, 1.19321, - 1.06866, 0.954675, 0.952695, 0.969853, 0.957557, 0.989784, 1.01549, - 1.02182, 0.976005, 1.01865, 1.06871, 1.06264, 1.02969, 1.07378, - 1.06622, 1.15057, 1.0433, 0.83654, 0.847178, 0.890027, 0.920814, - 0.888271, 1.04662, 0.8869, 0.856348, 0.863181, 0.906312, 0.902166, - 1.00122, 1.03303, 0.887866, 0.892437, 0.906278, 0.884976, 0.864251, - 0.917221, 1.10618, 1.04028, 0.893184, 0.915734, 0.892676}; - // calibration T0C - static constexpr std::array kCalibT0C = { - 0.949829, 1.05408, 1.00681, 1.00724, 0.990663, 0.973571, 0.9855, - 1.03726, 1.02526, 1.00467, 0.983008, 0.979349, 0.952352, 0.985775, - 1.013, 1.01721, 0.993948, 0.996421, 0.971871, 1.02921, 0.989641, - 1.01885, 1.01259, 0.929502, 1.03969, 1.02496, 1.01385, 1.01711}; - // calibration T0A - static constexpr std::array kCalibT0A = { - 0.86041, 1.10607, 1.17724, 0.756397, 1.14954, 1.0879, - 0.829438, 1.09014, 1.16515, 0.730077, 1.06722, 0.906344, - 0.824167, 1.14716, 1.20692, 0.755034, 1.11734, 1.00556, - 0.790522, 1.09138, 1.16225, 0.692458, 1.12428, 1.01127}; - // calibration factor MFT vs vtx - static constexpr std::array kBiningVtxt = { - -14.5, -13.5, -12.5, -11.5, -10.5, -9.5, -8.5, -7.5, -6.5, -5.5, - -4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, - 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5}; - - // calibration factor FV0 vs vtx - static constexpr std::array kCalibFV0vtx = { - 0.907962, 0.934607, 0.938929, 0.950987, 0.950817, 0.966362, // o2-linter: disable=pdg/explicit-mass (these are not masses but calibration values) - 0.968509, 0.972741, 0.982412, 0.984872, 0.994543, 0.996003, - 0.99435, 1.00266, 0.998245, 1.00584, 1.01078, 1.01003, - 1.00726, 1.00872, 1.01726, 1.02015, 1.0193, 1.01106, - 1.02229, 1.02104, 1.03435, 1.00822, 1.01921, 1.01736}; - // calibration FT0A vs vtx - static constexpr std::array kCalibFT0Avtx = { - 0.924334, 0.950988, 0.959604, 0.965607, 0.970016, 0.979057, - 0.978384, 0.982005, 0.992825, 0.990048, 0.998588, 0.997338, - 1.00102, 1.00385, 0.99492, 1.01083, 1.00703, 1.00494, - 1.00063, 1.0013, 1.00777, 1.01238, 1.01179, 1.00577, - 1.01028, 1.017, 1.02975, 1.0085, 1.00856, 1.01662}; - // calibration FT0C vs vtx - static constexpr std::array kCalibFT0Cvtx = { - 1.02096, 1.01245, 1.02148, 1.03605, 1.03561, 1.03667, - 1.04229, 1.0327, 1.03674, 1.02764, 1.01828, 1.02331, - 1.01864, 1.015, 1.01197, 1.00615, 0.996845, 0.993051, - 0.985635, 0.982883, 0.981914, 0.964635, 0.967812, 0.95475, - 0.956687, 0.932816, 0.92773, 0.914892, 0.891724, 0.872382}; + // occupied cells of a flattenicity lattice + template + static int countActiveCells(TArray const& lattice) + { + int nActive = 0; + for (const auto& cell : lattice) { + if (cell > 0.f) { + nActive++; + } + } + return nActive; + } static constexpr int kNeta5 = 2; // FT0C + FT0A static constexpr std::array kWeigthsEta5 = {0.0490638, 0.010958415}; @@ -858,8 +1107,10 @@ struct Lambdak0sflattenicity { static constexpr float kMinEtaFV0 = 2.2; static constexpr float kDetaFV0 = (kMaxEtaFV0 - kMinEtaFV0) / 5.0; - // no FV0/FT0 information + // 1-rho not available for this collision static constexpr float kInvalidFlattenicity = -1.f; + // lattice carries no signal, sigma/ undefined + static constexpr float kFlatUndefined = 9999.f; static constexpr int kNCells = 48; // 48 sectors in FV0 static constexpr std::array kFV0PhiIndex = { @@ -873,10 +1124,21 @@ struct Lambdak0sflattenicity { std::array rhoLatticeFV0AMC{}; std::array ampchannel{}; std::array ampchannelBefore{}; - static constexpr int kNCellsT0A = 24; - std::array rhoLatticeT0A{}; - static constexpr int kNCellsT0C = 28; - std::array rhoLatticeT0C{}; + std::array rhoLatticeT0A{}; + std::array rhoLatticeT0C{}; + std::array rhoLatticeFT0AMC{}; + std::array rhoLatticeFT0CMC{}; + static constexpr int kNChannelsFT0 = kNChannelsFT0A + kNChannelsFT0C; + + // Generator-level FT0 lattice: detector cell counts and acceptance. The real + // channel map is not an eta-phi grid, so cell shapes are approximate. + static constexpr float kMinEtaFT0A = 3.5f; + static constexpr float kMaxEtaFT0A = 4.9f; + static constexpr float kMinEtaFT0C = -3.3f; + static constexpr float kMaxEtaFT0C = -2.1f; + static constexpr int kNEtaBinsFT0MC = 4; + static constexpr int kNPhiBinsFT0AMC = kNChannelsFT0A / kNEtaBinsFT0MC; + static constexpr int kNPhiBinsFT0CMC = kNChannelsFT0C / kNEtaBinsFT0MC; std::array estimator{}; @@ -989,12 +1251,234 @@ struct Lambdak0sflattenicity { return true; } + // Daughter track acceptance and quality. The quality cuts are off by default + // and exist so a systematic variation can move them from the JSON. + template + bool isSelectedDaughterTrack(TTrack const& track, float minCrossedRows) + { + if (std::abs(track.eta()) > trkPid.cfgTrkEtaCut || track.pt() < trkPid.cfgTrkLowPtCut) { + return false; + } + if (track.tpcNClsCrossedRows() < minCrossedRows) { + return false; + } + if (trkPid.minCrossedRowsOverFindable > 0.f && + track.tpcCrossedRowsOverFindableCls() < trkPid.minCrossedRowsOverFindable) { + return false; + } + if (trkPid.maxTpcChi2NCl > 0.f && track.tpcChi2NCl() > trkPid.maxTpcChi2NCl) { + return false; + } + if (trkPid.maxItsChi2NCl > 0.f && track.itsChi2NCl() > trkPid.maxItsChi2NCl) { + return false; + } + if (trkPid.minItsNCls > 0 && static_cast(track.itsNCls()) < trkPid.minItsNCls) { + return false; + } + return true; + } + + // cut-flow bins for the stages inside estimateFlattenicity(); without these + // the events it drops leave no trace + void fillFlattenicityStages() + { + if (nbinFlatDetHit > 0 && flatStage >= kFlatStageLowOccupancy) { + rEventSelection.fill(HIST("hEventsSelected"), nbinFlatDetHit - 0.5); + } + if (nbinFlatOccupancy > 0 && flatStage >= kFlatStageNoSignal) { + rEventSelection.fill(HIST("hEventsSelected"), nbinFlatOccupancy - 0.5); + } + if (nbinFlattenicity > 0 && flatStage == kFlatStageOk) { + rEventSelection.fill(HIST("hEventsSelected"), nbinFlattenicity - 0.5); + } + } + + // 1-rho on the fine axis for the percentile boundaries, inclusive, INEL>0 and + // in the top FT0M class + void fillFlatDistRec(float flattenicity, float centFT0M, bool isInelGt0) + { + rEventSelection.fill(HIST("hFlatDistRec"), flattenicity); + rEventSelection.fill(HIST("hCentFT0MFine"), centFT0M); + if (isInelGt0) { + rEventSelection.fill(HIST("hFlatDistRecINELgt0"), flattenicity); + if (centFT0M < eventClass.cfgCentMaxHM) { + rEventSelection.fill(HIST("hFlatDistRecHM"), flattenicity); + } + } + } + + // processGenMC only. A negative centFT0M means no accepted reconstructed + // counterpart, so the collision has no FT0M class and stays out of the HM one. + void fillFlatDistGen(float flattenicityGen, float centFT0M, bool isInelGt0) + { + rEventSelection.fill(HIST("hFlatDistGen"), flattenicityGen); + if (isInelGt0) { + rEventSelection.fill(HIST("hFlatDistGenINELgt0"), flattenicityGen); + if (centFT0M >= 0.f && centFT0M < eventClass.cfgCentMaxHM) { + rEventSelection.fill(HIST("hFlatDistGenHM"), flattenicityGen); + } + } + } + + // the same from the rec-level process functions, diagnostic only + void fillFlatDistGenInRec(float flattenicityGen, float centFT0M, bool isInelGt0) + { + rEventSelection.fill(HIST("hFlatDistGenInRec"), flattenicityGen); + if (isInelGt0) { + rEventSelection.fill(HIST("hFlatDistGenInRecINELgt0"), flattenicityGen); + if (centFT0M >= 0.f && centFT0M < eventClass.cfgCentMaxHM) { + rEventSelection.fill(HIST("hFlatDistGenInRecHM"), flattenicityGen); + } + } + } + + // Charged tracks in the tracking acceptance: per class is the + // scale factor of Qpp, and the DCAxy distribution carries the secondary + // contamination. + template + int fillChargedRec(TTracks const& tracks, float flattenicity) + { + if (!eventClass.fillChargedQA) { + return 0; + } + int nch = 0; + for (const auto& track : tracks) { + if (!track.isGlobalTrack() || std::abs(track.eta()) > eventClass.cfgEtaChargedCut) { + continue; + } + nch++; + rCharged.fill(HIST("hPtChVsFlat"), track.pt(), flattenicity); + if constexpr (isMC) { + if (!track.has_mcParticle()) { + continue; + } + const auto& mcParticle = track.mcParticle(); + if (mcParticle.isPhysicalPrimary()) { + rCharged.fill(HIST("hPtChVsFlatRecPrim"), track.pt(), flattenicity); + rCharged.fill(HIST("hDcaXyPtChPrim"), track.dcaXY(), track.pt(), flattenicity); + } else { + rCharged.fill(HIST("hDcaXyPtChSec"), track.dcaXY(), track.pt(), flattenicity); + } + } else { + rCharged.fill(HIST("hDcaXyPtCh"), track.dcaXY(), track.pt(), flattenicity); + } + } + rCharged.fill(HIST("hNchVsFlat"), nch, flattenicity); + return nch; + } + + template + int fillChargedGen(TMcParticles const& mcParticles, float flattenicity, bool trueFlat) + { + if (!eventClass.fillChargedQA) { + return 0; + } + int nch = 0; + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || std::abs(mcParticle.eta()) > eventClass.cfgEtaChargedCut) { + continue; + } + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!(pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge)) { + continue; + } + nch++; + if (trueFlat) { + rCharged.fill(HIST("hPtChVsTrueFlatGen"), mcParticle.pt(), flattenicity); + } else { + rCharged.fill(HIST("hPtChVsFlatGen"), mcParticle.pt(), flattenicity); + } + } + if (trueFlat) { + rCharged.fill(HIST("hNchVsTrueFlatGen"), nch, flattenicity); + } else { + rCharged.fill(HIST("hNchVsFlatGen"), nch, flattenicity); + } + return nch; + } + + // ================= Calibration objects from CCDB ==================== // + // A missing or malformed object falls back to unity, so a run without + // calibration is left uncorrected instead of being equalized with somebody + // else's constants. + + std::vector fetchGainEq(const std::string& path, int run, std::size_t nChannels) + { + const auto* obj = ccdb->getForRun>(path, run); + if (!obj || obj->size() != nChannels) { + LOGF(warning, "No gain equalization of size %zu at %s for run %d, using unity", + nChannels, path.c_str(), run); + return std::vector(nChannels, 1.f); + } + return *obj; + } + + TProfile2D* fetchVtxEq(const std::string& path, int run) + { + auto* obj = ccdb->getForRun(path, run); + if (!obj) { + LOGF(warning, "No z-vertex equalization at %s for run %d, lattice left uncorrected", + path.c_str(), run); + } + return obj; + } + + // called per collision, does nothing unless a correction is switched on + template + void initCcdb(TBC const& bc) + { + const int run = bc.runNumber(); + if (run == mRunNumber) { + return; + } + mRunNumber = run; + if (flatSel.applyCalibCh) { + gainFV0 = fetchGainEq(ccdbConf.gainEqPath.value + "/FV0", run, kNCells); + gainFT0A = fetchGainEq(ccdbConf.gainEqPath.value + "/FT0A", run, kNSectorsT0A); + gainFT0C = fetchGainEq(ccdbConf.gainEqPath.value + "/FT0C", run, kNSectorsT0C); + } + if (flatSel.applyCalibVtx) { + vtxEqFV0 = fetchVtxEq(ccdbConf.vtxEqPath.value + "/FV0", run); + vtxEqFT0A = fetchVtxEq(ccdbConf.vtxEqPath.value + "/FT0A", run); + vtxEqFT0C = fetchVtxEq(ccdbConf.vtxEqPath.value + "/FT0C", run); + } + } + + // the gain is divided out, the convention of flattenictyPikp + static float gainEqFactor(std::vector const& gain, std::size_t channel) + { + if (channel >= gain.size() || !(gain[channel] > 0.f)) { + return 1.f; + } + return gain[channel]; + } + + // 1 for a missing map or an empty bin, so a bad bin never zeroes a cell + static float vtxEqFactor(TProfile2D const* map, int cell, float vtxZ) + { + if (!map) { + return 1.f; + } + const float factor = map->GetBinContent(map->GetXaxis()->FindBin(cell), + map->GetYaxis()->FindBin(vtxZ)); + return (factor > 0.f) ? factor : 1.f; + } + // ============== Flattenicity estimation begins ===================== // // fillQA=false skips the QA registry, for callers that would fill it twice template float estimateFlattenicity(TCollision const& collision, Tracks const& tracks, bool fillQA = true) { const bool flattenicityQAhere = flatSel.flattenicityQA && fillQA; + flatStage = kFlatStageNoDetector; + // a detector contributes only if it has a record and the config reads it + const bool hasFV0 = collision.has_foundFV0(); + const bool hasFT0 = collision.has_foundFT0(); + const bool fv0Read = flatSel.isflattenicitywithFV0 && hasFV0; + const bool ft0Read = flatSel.isflattenicitywithFT0 && hasFT0; + if (flatSel.applyCalibCh || flatSel.applyCalibVtx) { + initCcdb(collision.template bc_as>()); + } std::array ampl5 = {0, 0}; std::array ampl6 = {0, 0}; @@ -1002,13 +1486,14 @@ struct Lambdak0sflattenicity { float sumAmpFV0 = 0; float sumAmpFV01to4Ch = 0; + // gain-equalized but not yet vertex-equalized, the input to the z-vertex QA + float sumAmpFV0BeforeVtx = 0; ampchannel.fill(0.0); ampchannelBefore.fill(0.0); rhoLattice.fill(0); - if ((flatSel.isflattenicitywithFV0 || flatSel.isflattenicitywithFV0FT0C) && - collision.has_foundFV0()) { + if (fv0Read) { auto fv0 = collision.foundFV0(); for (std::size_t ich = 0; ich < fv0.amplitude().size(); ich++) { @@ -1026,7 +1511,11 @@ struct Lambdak0sflattenicity { } ampchannelBefore[channelv0phi] = amplCh; if (flatSel.applyCalibCh) { - amplCh *= kCalib[channelv0phi]; + amplCh /= gainEqFactor(gainFV0, channelv0); + } + sumAmpFV0BeforeVtx += amplCh; + if (flatSel.applyCalibVtx) { + amplCh *= vtxEqFactor(vtxEqFV0, channelv0phi, vtxZ); } sumAmpFV0 += amplCh; @@ -1045,19 +1534,13 @@ struct Lambdak0sflattenicity { } if (flattenicityQAhere) { - rFlattenicity.fill(HIST("hAmpV0vsVtxBeforeCalibration"), vtxZ, sumAmpFV0); - } - if (flatSel.applyCalibVtx) { - sumAmpFV0 *= gVtx[0].Eval(vtxZ); - sumAmpFV01to4Ch *= gVtx[0].Eval(vtxZ); - } - if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hAmpV0vsVtxBeforeCalibration"), vtxZ, sumAmpFV0BeforeVtx); rFlattenicity.fill(HIST("hAmpV0vsVtx"), vtxZ, sumAmpFV0); } } - float flattenicityfv0 = 9999; - if (flatSel.isflattenicitywithFV0 || flatSel.isflattenicitywithFV0FT0C) { + float flattenicityfv0 = kFlatUndefined; + if (fv0Read) { flattenicityfv0 = getFlatenicity({rhoLattice.data(), rhoLattice.size()}); } @@ -1077,82 +1560,106 @@ struct Lambdak0sflattenicity { // FT0 float sumAmpFT0A = 0.f; float sumAmpFT0C = 0.f; + int nActiveFT0Ch = 0; + float sumAmpFT0ABeforeVtx = 0.f; + float sumAmpFT0CBeforeVtx = 0.f; rhoLatticeT0A.fill(0); rhoLatticeT0C.fill(0); - if ((flatSel.isflattenicitywithFT0 || flatSel.isflattenicitywithFV0FT0C) && - collision.has_foundFT0()) { + if (ft0Read) { auto ft0 = collision.foundFT0(); - if (flatSel.isflattenicitywithFT0) { - for (std::size_t i_a = 0; i_a < ft0.amplitudeA().size(); i_a++) { - float amplitude = ft0.amplitudeA()[i_a]; - uint8_t channel = ft0.channelA()[i_a]; - int sector = getT0ASector(channel); - if (sector >= 0 && sector < kNCellsT0A) { - if (flattenicityQAhere) { - rFlattenicity.fill(HIST("hAmpT0AVsChBeforeCalibration"), sector, - amplitude); - } - if (flatSel.applyCalibCh) { - amplitude *= kCalibT0A[sector]; - } - if (flattenicityQAhere) { - rFlattenicity.fill(HIST("hAmpT0AVsCh"), sector, amplitude); - } - rhoLatticeT0A[sector] += amplitude; + for (std::size_t i_a = 0; i_a < ft0.amplitudeA().size(); i_a++) { + float amplitude = ft0.amplitudeA()[i_a]; + const int channel = ft0.channelA()[i_a]; + if (amplitude > 0.f) { + nActiveFT0Ch++; + } + const int sector = getT0ASector(channel); + float amplitudeBeforeVtx = amplitude; + if (channel >= 0 && channel < kNChannelsFT0A && sector >= 0) { + if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hAmpT0AVsChBeforeCalibration"), sector, + amplitude); + } + if (flatSel.applyCalibCh) { + amplitude /= gainEqFactor(gainFT0A, sector); } - sumAmpFT0A += amplitude; if (flattenicityQAhere) { - rFlattenicity.fill(HIST("hFT0A"), amplitude); + rFlattenicity.fill(HIST("hAmpT0AVsCh"), sector, amplitude); + } + amplitudeBeforeVtx = amplitude; + if (flatSel.applyCalibVtx) { + amplitude *= vtxEqFactor(vtxEqFT0A, sector, vtxZ); } + rhoLatticeT0A[channel] += amplitude; + } + sumAmpFT0A += amplitude; + sumAmpFT0ABeforeVtx += amplitudeBeforeVtx; + if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hFT0A"), amplitude); } } for (std::size_t i_c = 0; i_c < ft0.amplitudeC().size(); i_c++) { float amplitude = ft0.amplitudeC()[i_c]; - uint8_t channel = ft0.channelC()[i_c]; - int sector = getT0CSector(channel); - if (sector >= 0 && sector < kNCellsT0C) { + const int channel = ft0.channelC()[i_c]; + if (amplitude > 0.f) { + nActiveFT0Ch++; + } + const int sector = getT0CSector(channel); + float amplitudeBeforeVtx = amplitude; + if (channel >= 0 && channel < kNChannelsFT0C && sector >= 0) { if (flattenicityQAhere) { rFlattenicity.fill(HIST("hAmpT0CVsChBeforeCalibration"), sector, amplitude); } if (flatSel.applyCalibCh) { - amplitude *= kCalibT0C[sector]; + amplitude /= gainEqFactor(gainFT0C, sector); } if (flattenicityQAhere) { rFlattenicity.fill(HIST("hAmpT0CVsCh"), sector, amplitude); } - rhoLatticeT0C[sector] += amplitude; + amplitudeBeforeVtx = amplitude; + if (flatSel.applyCalibVtx) { + amplitude *= vtxEqFactor(vtxEqFT0C, sector, vtxZ); + } + rhoLatticeT0C[channel] += amplitude; } sumAmpFT0C += amplitude; + sumAmpFT0CBeforeVtx += amplitudeBeforeVtx; if (flattenicityQAhere) { rFlattenicity.fill(HIST("hFT0C"), amplitude); } } if (flattenicityQAhere) { rFlattenicity.fill(HIST("hAmpT0AvsVtxBeforeCalibration"), vtxZ, - sumAmpFT0A); + sumAmpFT0ABeforeVtx); rFlattenicity.fill(HIST("hAmpT0CvsVtxBeforeCalibration"), vtxZ, - sumAmpFT0C); - } - if (flatSel.applyCalibVtx) { - sumAmpFT0A *= gVtx[1].Eval(vtxZ); - sumAmpFT0C *= gVtx[2].Eval(vtxZ); - } - if (flattenicityQAhere) { + sumAmpFT0CBeforeVtx); rFlattenicity.fill(HIST("hAmpT0AvsVtx"), vtxZ, sumAmpFT0A); rFlattenicity.fill(HIST("hAmpT0CvsVtx"), vtxZ, sumAmpFT0C); } } - float flatenicityT0a = 9999; - if (flatSel.isflattenicitywithFT0) { + const int nLitFV0 = countActiveCells(rhoLattice); + const int nLitFT0A = countActiveCells(rhoLatticeT0A); + const int nLitFT0C = countActiveCells(rhoLatticeT0C); + if (flattenicityQAhere) { + if (fv0Read) { + rFlattenicity.fill(HIST("hNActiveCellsFV0"), nLitFV0); + } + if (ft0Read) { + rFlattenicity.fill(HIST("hNActiveFT0Channels"), nActiveFT0Ch); + rFlattenicity.fill(HIST("hNActiveCellsFT0A"), nLitFT0A); + rFlattenicity.fill(HIST("hNActiveCellsFT0C"), nLitFT0C); + } + } + + float flatenicityT0a = kFlatUndefined; + float flatenicityT0c = kFlatUndefined; + if (ft0Read) { flatenicityT0a = getFlatenicity({rhoLatticeT0A.data(), rhoLatticeT0A.size()}); - } - float flatenicityT0c = 9999; - if (flatSel.isflattenicitywithFT0 || flatSel.isflattenicitywithFV0FT0C) { flatenicityT0c = getFlatenicity({rhoLatticeT0C.data(), rhoLatticeT0C.size()}); } @@ -1166,10 +1673,30 @@ struct Lambdak0sflattenicity { estimator[iEe] = 0; } - if (!collision.has_foundFV0() || !collision.has_foundFT0()) { - // no FV0/FT0, flattenicity undefined + // FV0 and FT0 are missing on different collisions, so require only the + // detector the selected estimator reads + const bool detectorsOk = + (flatSel.flattenicityforanalysis == kFlatFromFT0) ? hasFT0 : hasFV0; + if (!detectorsOk) { + return kInvalidFlattenicity; + } + flatStage = kFlatStageLowOccupancy; + + // Reject a lattice too sparse for sigma/ to be continuous. Only the one + // the analysis estimator reads is tested; the other still fills QA. + const bool occupancyOk = + (flatSel.flattenicityforanalysis == kFlatFromFT0) + ? (nLitFT0A >= flatSel.minLitCellsFT0A && nLitFT0C >= flatSel.minLitCellsFT0C) + : (nLitFV0 >= flatSel.minLitCellsFV0); + if (!occupancyOk) { return kInvalidFlattenicity; } + flatStage = kFlatStageNoSignal; + + // an estimator with an unread detector holds a sentinel, keep it out of the QA + const bool estFV0Ok = fv0Read; + const bool estFT0Ok = ft0Read; + const bool estFV0FT0COk = fv0Read && ft0Read; float allWeights = 0; // option 5 @@ -1215,9 +1742,13 @@ struct Lambdak0sflattenicity { } } if (flattenicityQAhere) { - rFlattenicity.fill(HIST("hFT0Aampl"), sumAmpFT0A); - rFlattenicity.fill(HIST("hFT0Campl"), sumAmpFT0C); - rFlattenicity.fill(HIST("hFV0amplRing1to4"), sumAmpFV01to4Ch); + if (ft0Read) { + rFlattenicity.fill(HIST("hFT0Aampl"), sumAmpFT0A); + rFlattenicity.fill(HIST("hFT0Campl"), sumAmpFT0C); + } + if (fv0Read) { + rFlattenicity.fill(HIST("hFV0amplRing1to4"), sumAmpFV01to4Ch); + } rFlattenicity.fill(HIST("hEv"), 4); } estimator[0] = multGlob; @@ -1227,18 +1758,21 @@ struct Lambdak0sflattenicity { float flatenicityFT0 = (flatenicityT0a + flatenicityT0c) / 2.0; estimator[4] = 1.0 - flatenicityFT0; estimator[5] = combinedEstimator6; - float flatenicityFT0v0 = 0.5 * flattenicityfv0 + 0.5 * flatenicityT0c; - estimator[6] = 1.0 - flatenicityFT0v0; - estimator[7] = ptT; + estimator[6] = ptT; if (flattenicityQAhere) { rFlattenicity.fill(HIST(kHEst[0]), estimator[0], estimator[0]); - rFlattenicity.fill(HIST(kHEst[1]), estimator[1], estimator[0]); - rFlattenicity.fill(HIST(kHEst[2]), estimator[2], estimator[0]); - rFlattenicity.fill(HIST(kHEst[3]), estimator[3], estimator[0]); - rFlattenicity.fill(HIST(kHEst[4]), estimator[4], estimator[0]); - rFlattenicity.fill(HIST(kHEst[5]), estimator[5], estimator[0]); rFlattenicity.fill(HIST(kHEst[6]), estimator[6], estimator[0]); - rFlattenicity.fill(HIST(kHEst[7]), estimator[7], estimator[0]); + if (estFV0Ok) { + rFlattenicity.fill(HIST(kHEst[1]), estimator[1], estimator[0]); + rFlattenicity.fill(HIST(kHEst[2]), estimator[2], estimator[0]); + } + if (estFT0Ok) { + rFlattenicity.fill(HIST(kHEst[3]), estimator[3], estimator[0]); + rFlattenicity.fill(HIST(kHEst[4]), estimator[4], estimator[0]); + } + if (estFV0FT0COk) { + rFlattenicity.fill(HIST(kHEst[5]), estimator[5], estimator[0]); + } // plot pt vs estimators for (const auto& track : tracks) { @@ -1247,37 +1781,44 @@ struct Lambdak0sflattenicity { } float pt = track.pt(); rFlattenicity.fill(HIST(kHPtEst[0]), estimator[0], pt); - rFlattenicity.fill(HIST(kHPtEst[1]), estimator[1], pt); - rFlattenicity.fill(HIST(kHPtEst[2]), estimator[2], pt); - rFlattenicity.fill(HIST(kHPtEst[3]), estimator[3], pt); - rFlattenicity.fill(HIST(kHPtEst[4]), estimator[4], pt); - rFlattenicity.fill(HIST(kHPtEst[5]), estimator[5], pt); rFlattenicity.fill(HIST(kHPtEst[6]), estimator[6], pt); - rFlattenicity.fill(HIST(kHPtEst[7]), estimator[7], pt); + if (estFV0Ok) { + rFlattenicity.fill(HIST(kHPtEst[1]), estimator[1], pt); + rFlattenicity.fill(HIST(kHPtEst[2]), estimator[2], pt); + } + if (estFT0Ok) { + rFlattenicity.fill(HIST(kHPtEst[3]), estimator[3], pt); + rFlattenicity.fill(HIST(kHPtEst[4]), estimator[4], pt); + } + if (estFV0FT0COk) { + rFlattenicity.fill(HIST(kHPtEst[5]), estimator[5], pt); + } } - if (flatSel.isflattenicitywithFV0) { + if (estFV0Ok) { for (int iCh = 0; iCh < kNCells; ++iCh) { rFlattenicity.fill(HIST("hAmpV0VsCh"), iCh, ampchannel[iCh]); rFlattenicity.fill(HIST("hAmpV0VsChBeforeCalibration"), iCh, ampchannelBefore[iCh]); } + rFlattenicity.fill(HIST("fMultFv0"), sumAmpFV0); + } + if (estFT0Ok) { + rFlattenicity.fill(HIST("hFlatFT0CvsFlatFT0A"), flatenicityT0c, + flatenicityT0a); } - - rFlattenicity.fill(HIST("fMultFv0"), sumAmpFV0); - rFlattenicity.fill(HIST("hFlatFT0CvsFlatFT0A"), flatenicityT0c, - flatenicityT0a); } float finalflattenicity = estimator[2]; - if (flattenicityQAhere) { + if (flattenicityQAhere && estFV0Ok) { rFlattenicity.fill(HIST("hFV0amplvsFlat"), sumAmpFV0, estimator[2]); } if (flatSel.flattenicityforanalysis == kFlatFromFT0) { finalflattenicity = estimator[4]; } - if (flatSel.flattenicityforanalysis == kFlatFromFV0FT0C) { - finalflattenicity = estimator[6]; + // a lattice with no signal leaves a sentinel, which the callers reject as negative + if (finalflattenicity >= 0.f) { + flatStage = kFlatStageOk; } return finalflattenicity; } @@ -1289,6 +1830,21 @@ struct Lambdak0sflattenicity { static constexpr int kFdOther = 3; static constexpr int kNFeedDownMothers = 4; + // -1 for a species that does not feed the measured hadrons + static int feedDownSpecies(int pdgCode) + { + switch (std::abs(pdgCode)) { + case PDG_t::kXiMinus: + return kFdXiMinus; + case o2::constants::physics::Pdg::kXi0: + return kFdXiZero; + case PDG_t::kOmegaMinus: + return kFdOmegaMinus; + default: + return -1; + } + } + template int getFeedDownMother(TMcParticle const& mcParticle, float& motherPt) { @@ -1298,29 +1854,26 @@ struct Lambdak0sflattenicity { } for (const auto& mother : mcParticle.template mothers_as()) { motherPt = mother.pt(); - const int motherPdg = std::abs(mother.pdgCode()); - if (motherPdg == PDG_t::kXiMinus) { - return kFdXiMinus; - } - if (motherPdg == o2::constants::physics::Pdg::kXi0) { - return kFdXiZero; - } - if (motherPdg == PDG_t::kOmegaMinus) { - return kFdOmegaMinus; - } - return kFdOther; + const int species = feedDownSpecies(mother.pdgCode()); + return (species >= 0) ? species : kFdOther; } return kFdOther; } + // fillQA=false skips hTrueFV0amplvsFlat, for callers that would fill it twice template - float estimateFlattenicityFV0MC(McParticles const& mcParticles) + float estimateFlattenicityFV0MC(McParticles const& mcParticles, bool fillQA = true) { rhoLatticeFV0AMC.fill(0); int multFV0 = 0; for (const auto& mcParticle : mcParticles) { - if (!(mcParticle.isPhysicalPrimary() && mcParticle.pt() > 0)) { + // the measured 1-rho also sees secondaries; dropping the primary + // requirement is the handle on the leading MC non-closure source + if (eventClass.genFlatPrimariesOnly && !mcParticle.isPhysicalPrimary()) { + continue; + } + if (!(mcParticle.pt() > 0)) { continue; } @@ -1345,7 +1898,12 @@ struct Lambdak0sflattenicity { const float maxphi = (iphi + 1) * constants::math::TwoPI / nsectors; const float dphi = std::abs(maxphi - minphi); if (etap >= etamin && etap < etamax && phip >= minphi && phip < maxphi) { - rhoLatticeFV0AMC[isegment] += 1.0 / std::abs(dphi * kDetaFV0); + // yield per cell with the outer ring halved, as the amplitude is in + // estimateFlattenicity; the alternative normalises to the cell area + rhoLatticeFV0AMC[isegment] += + flatSel.genFlatDetectorLikeNorm + ? ((ieta == kOuterFV0RingIndex) ? 0.5f : 1.0f) + : 1.0 / std::abs(dphi * kDetaFV0); multFV0++; } isegment++; @@ -1353,11 +1911,94 @@ struct Lambdak0sflattenicity { } } - const float flattenicity = - 1.0 - getFlatenicity({rhoLatticeFV0AMC.data(), rhoLatticeFV0AMC.size()}); - rEventSelection.fill(HIST("hTrueFV0amplvsFlat"), multFV0, flattenicity); + const float flatFV0 = + getFlatenicity({rhoLatticeFV0AMC.data(), rhoLatticeFV0AMC.size()}); + if (flatFV0 >= kFlatUndefined) { + return kInvalidFlattenicity; + } + const float flattenicity = 1.0 - flatFV0; + if (fillQA) { + rEventSelection.fill(HIST("hTrueFV0amplvsFlat"), multFV0, flattenicity); + } return flattenicity; } + + // Generated counterpart of the FT0 branch of estimateFlattenicity(): same cell + // counts, same average of the two rho. Weights are uniform and a per-side + // constant cancels in sigma/, so genFlatDetectorLikeNorm does not apply. + template + float estimateFlattenicityFT0MC(McParticles const& mcParticles, bool fillQA = true) + { + rhoLatticeFT0AMC.fill(0); + rhoLatticeFT0CMC.fill(0); + int multFT0 = 0; + + const float detaFT0A = (kMaxEtaFT0A - kMinEtaFT0A) / kNEtaBinsFT0MC; + const float detaFT0C = (kMaxEtaFT0C - kMinEtaFT0C) / kNEtaBinsFT0MC; + + for (const auto& mcParticle : mcParticles) { + if (eventClass.genFlatPrimariesOnly && !mcParticle.isPhysicalPrimary()) { + continue; + } + if (!(mcParticle.pt() > 0)) { + continue; + } + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!(pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge)) { + continue; + } + + const float etap = mcParticle.eta(); + const float phip = mcParticle.phi(); + const bool inA = (etap >= kMinEtaFT0A && etap < kMaxEtaFT0A); + const bool inC = (etap >= kMinEtaFT0C && etap < kMaxEtaFT0C); + if (!inA && !inC) { + continue; + } + + const int nphi = inA ? kNPhiBinsFT0AMC : kNPhiBinsFT0CMC; + const float eta0 = inA ? kMinEtaFT0A : kMinEtaFT0C; + const float deta = inA ? detaFT0A : detaFT0C; + int ieta = static_cast((etap - eta0) / deta); + int iphi = static_cast(phip * nphi / constants::math::TwoPI); + ieta = std::clamp(ieta, 0, kNEtaBinsFT0MC - 1); + iphi = std::clamp(iphi, 0, nphi - 1); + const int icell = ieta * nphi + iphi; + + if (inA) { + rhoLatticeFT0AMC[icell] += 1.f; + } else { + rhoLatticeFT0CMC[icell] += 1.f; + } + multFT0++; + } + + const float flatA = + getFlatenicity({rhoLatticeFT0AMC.data(), rhoLatticeFT0AMC.size()}); + const float flatC = + getFlatenicity({rhoLatticeFT0CMC.data(), rhoLatticeFT0CMC.size()}); + // in pp one side can be left completely empty, and the average is then undefined + if (flatA >= kFlatUndefined || flatC >= kFlatUndefined) { + return kInvalidFlattenicity; + } + const float flattenicity = 1.0 - (flatA + flatC) / 2.0; + if (fillQA) { + rEventSelection.fill(HIST("hTrueFT0amplvsFlat"), multFT0, flattenicity); + rEventSelection.fill(HIST("hNActiveCellsFT0AMCGen"), countActiveCells(rhoLatticeFT0AMC)); + rEventSelection.fill(HIST("hNActiveCellsFT0CMCGen"), countActiveCells(rhoLatticeFT0CMC)); + } + return flattenicity; + } + + // the generator-level counterpart of whichever estimator the analysis uses + template + float estimateFlattenicityGen(McParticles const& mcParticles, bool fillQA = true) + { + if (flatSel.flattenicityforanalysis == kFlatFromFT0) { + return estimateFlattenicityFT0MC(mcParticles, fillQA); + } + return estimateFlattenicityFV0MC(mcParticles, fillQA); + } // ====================== Flattenicity estimation ends ===================== // Filters on V0s @@ -1371,7 +2012,7 @@ struct Lambdak0sflattenicity { (nabs(aod::track::eta) < trkPid.cfgTrkEtaCut && aod::track::pt > trkPid.cfgTrkLowPtCut); using TrackCandidates = soa::Filtered< - soa::Join>; void processDataRun3LambdaK0s( @@ -1381,9 +2022,10 @@ struct Lambdak0sflattenicity { soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/) { + const bool own = (eventHistOwner == kOwnerDataV0); if (evSel.applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria return; } @@ -1392,29 +2034,28 @@ struct Lambdak0sflattenicity { auto vtxX = collision.posX(); float flattenicity = estimateFlattenicity(collision, tracks); + if (own) { + fillFlattenicityStages(); + } if (flattenicity < 0.f) { return; } - rEventSelection.fill(HIST("hEventsSelected"), nbinFlattenicity - 0.5); + if (own) { - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); - rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); - rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracks, flattenicity); + } for (const auto& v0 : V0s) { const auto& posDaughterTrack = v0.posTrack_as(); const auto& negDaughterTrack = v0.negTrack_as(); - if (std::abs(posDaughterTrack.eta()) > trkPid.cfgTrkEtaCut || - std::abs(negDaughterTrack.eta()) > trkPid.cfgTrkEtaCut || - negDaughterTrack.pt() < trkPid.cfgTrkLowPtCut || - posDaughterTrack.pt() < trkPid.cfgTrkLowPtCut) { - continue; - } - - if (posDaughterTrack.tpcNClsCrossedRows() < v0Sel.v0settingNTPCcrossedRows || - negDaughterTrack.tpcNClsCrossedRows() < v0Sel.v0settingNTPCcrossedRows) { + if (!isSelectedDaughterTrack(posDaughterTrack, v0Sel.v0settingNTPCcrossedRows) || + !isSelectedDaughterTrack(negDaughterTrack, v0Sel.v0settingNTPCcrossedRows)) { continue; } float massK0s = v0.mK0Short(); @@ -1493,6 +2134,7 @@ struct Lambdak0sflattenicity { rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); + rLambda.fill(HIST("hDcaV0ToPVLambda"), v0.dcav0topv(), v0.pt(), flattenicity); // Filling the PID of the V0 daughters in the region of the Lambda peak if (std::abs(massLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { @@ -1524,6 +2166,7 @@ struct Lambdak0sflattenicity { rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambda"), v0.dcav0topv(), v0.pt(), flattenicity); // Filling the PID of the V0 daughters in the region of the AntiLambda // peak if (std::abs(massAntiLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { @@ -1539,7 +2182,7 @@ struct Lambdak0sflattenicity { } using TrackCandidatesMC = - soa::Filtered>; @@ -1556,10 +2199,11 @@ struct Lambdak0sflattenicity { soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, aod::McParticles const& mcParticles) { + const bool own = (eventHistOwner == kOwnerRecMCV0); for (const auto& collision : collisions) { if (evSel.applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria continue; } @@ -1573,33 +2217,41 @@ struct Lambdak0sflattenicity { auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); float flattenicity = estimateFlattenicity(collision, tracksThisCollision); + if (own) { + fillFlattenicityStages(); + } if (flattenicity < 0.f) { continue; } - rEventSelection.fill(HIST("hEventsSelected"), nbinFlattenicity - 0.5); + if (own) { - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); - rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); - rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracksThisCollision, flattenicity); + } auto v0sThisCollision = V0s.sliceBy(perCol, collision.globalIndex()); const auto& mcCollision = collision.mcCollision_as(); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); + const float flattenicityMCGen = estimateFlattenicityGen(particlesInCollision, own); + if (own) { + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + rEventSelection.fill(HIST("hFlatGenVsRecFine"), flattenicityMCGen, flattenicity); + fillFlatDistGenInRec(flattenicityMCGen, collision.centFT0M(), collision.isInelGt0()); + } + for (const auto& v0 : v0sThisCollision) { const auto& posDaughterTrack = v0.posTrack_as(); const auto& negDaughterTrack = v0.negTrack_as(); - if (std::abs(posDaughterTrack.eta()) > trkPid.cfgTrkEtaCut || - std::abs(negDaughterTrack.eta()) > trkPid.cfgTrkEtaCut || - negDaughterTrack.pt() < trkPid.cfgTrkLowPtCut || - posDaughterTrack.pt() < trkPid.cfgTrkLowPtCut) { - continue; - } - - if (posDaughterTrack.tpcNClsCrossedRows() < v0Sel.v0settingNTPCcrossedRows || - negDaughterTrack.tpcNClsCrossedRows() < v0Sel.v0settingNTPCcrossedRows) { + if (!isSelectedDaughterTrack(posDaughterTrack, v0Sel.v0settingNTPCcrossedRows) || + !isSelectedDaughterTrack(negDaughterTrack, v0Sel.v0settingNTPCcrossedRows)) { continue; } @@ -1658,6 +2310,9 @@ struct Lambdak0sflattenicity { rKzeroShort.fill(HIST("h2DdecayRadiusK0s"), v0.v0radius()); rKzeroShort.fill(HIST("hMassK0spT"), massK0s, v0.pt()); rKzeroShort.fill(HIST("hMassK0spTFlat"), massK0s, v0.pt(), flattenicity); + rKzeroShort.fill(HIST("hMassK0spTTrueFlat"), massK0s, v0.pt(), flattenicityMCGen); + rKzeroShort.fill(HIST("hPtResK0s"), v0mcParticle.pt(), + (v0.pt() - v0mcParticle.pt()) / v0mcParticle.pt()); rKzeroShort.fill(HIST("hArmPodoAlphavsQTK0sAfterCut"), alpha, qtarm); // Filling the PID of the V0 daughters in the region of the K0s peak @@ -1686,7 +2341,11 @@ struct Lambdak0sflattenicity { const int motherIndex = getFeedDownMother(v0mcParticle, motherPt); rLambda.fill(HIST("hMassFeedDownLambdapTFlat"), massLambda, v0.pt(), flattenicity); rLambda.fill(HIST("hFeedDownLambdaPtVsMotherPt"), v0.pt(), motherPt); + rLambda.fill(HIST("hFeedDownLambdaMatrix"), v0.pt(), motherPt, flattenicity, motherIndex); rLambda.fill(HIST("hFeedDownLambdaMotherPdg"), motherIndex); + rLambda.fill(HIST("hDcaV0ToPVLambdaSec"), v0.dcav0topv(), v0.pt(), flattenicity); + } else { + rLambda.fill(HIST("hDcaV0ToPVLambdaPrim"), v0.dcav0topv(), v0.pt(), flattenicity); } if (keepForEfficiency) { @@ -1698,6 +2357,10 @@ struct Lambdak0sflattenicity { rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); + rLambda.fill(HIST("hMassLambdapTTrueFlat"), massLambda, v0.pt(), flattenicityMCGen); + rLambda.fill(HIST("hDcaV0ToPVLambda"), v0.dcav0topv(), v0.pt(), flattenicity); + rLambda.fill(HIST("hPtResLambda"), v0mcParticle.pt(), + (v0.pt() - v0mcParticle.pt()) / v0mcParticle.pt()); // Filling the PID of the V0 daughters in the region of the Lambda peak if (std::abs(massLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { @@ -1726,7 +2389,11 @@ struct Lambdak0sflattenicity { const int motherIndex = getFeedDownMother(v0mcParticle, motherPt); rAntiLambda.fill(HIST("hMassFeedDownAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); rAntiLambda.fill(HIST("hFeedDownAntiLambdaPtVsMotherPt"), v0.pt(), motherPt); + rAntiLambda.fill(HIST("hFeedDownAntiLambdaMatrix"), v0.pt(), motherPt, flattenicity, motherIndex); rAntiLambda.fill(HIST("hFeedDownAntiLambdaMotherPdg"), motherIndex); + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambdaSec"), v0.dcav0topv(), v0.pt(), flattenicity); + } else { + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambdaPrim"), v0.dcav0topv(), v0.pt(), flattenicity); } if (keepForEfficiency) { @@ -1739,6 +2406,10 @@ struct Lambdak0sflattenicity { rAntiLambda.fill(HIST("h2DdecayRadiusAntiLambda"), v0.v0radius()); rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hMassAntiLambdapTTrueFlat"), massAntiLambda, v0.pt(), flattenicityMCGen); + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambda"), v0.dcav0topv(), v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hPtResAntiLambda"), v0mcParticle.pt(), + (v0.pt() - v0mcParticle.pt()) / v0mcParticle.pt()); // Filling the PID of the V0 daughters in the region of the AntiLambda // peak @@ -1754,69 +2425,92 @@ struct Lambdak0sflattenicity { } } - const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); - float flattenicityMCGen = estimateFlattenicityFV0MC(particlesInCollision); - rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); - rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); - const bool isInelGt0Rec = collision.isInelGt0(); + int nchGenInRec = 0; for (const auto& mcParticle : particlesInCollision) { if (!mcParticle.isPhysicalPrimary()) { continue; } - if (std::abs(mcParticle.y()) > kMcRapidityWindow) { + if (eventClass.fillChargedQA && std::abs(mcParticle.eta()) <= eventClass.cfgEtaChargedCut) { + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge) { + nchGenInRec++; + rCharged.fill(HIST("hPtChVsFlatGenInRec"), mcParticle.pt(), flattenicity); + } + } + + // normalisation of hFeedDownLambdaMatrix, before the Lambda rapidity cut + if (std::abs(mcParticle.y()) <= eventClass.cfgFeedDownMotherRapidity) { + const int motherSpecies = feedDownSpecies(mcParticle.pdgCode()); + if (motherSpecies >= 0) { + rLambda.fill(HIST("hGenFeedDownMotherPtFlat"), mcParticle.pt(), flattenicity, motherSpecies); + } + } + + if (std::abs(mcParticle.y()) > v0Sel.v0settingRapidity) { continue; } if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INEL_K0Short"), mcParticle.pt(), flattenicity); if (isInelGt0Rec) { - rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityMCGen); } } if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_Lambda"), mcParticle.pt(), flattenicity); if (isInelGt0Rec) { - rLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityMCGen); } } if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (isInelGt0Rec) { - rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityMCGen); } } } + if (eventClass.fillChargedQA) { + rCharged.fill(HIST("hNchVsFlatGenInRec"), nchGenInRec, flattenicity); + } } } // Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < evSel.cutzvertex); void processGenMC( - o2::aod::McCollision const& mcCollision, const soa::SmallGroups>& collisions, TrackCandidatesMC const& tracks, aod::FT0s const& /*ft0s*/, + o2::aod::McCollision const& mcCollision, const soa::SmallGroups>& collisions, TrackCandidatesMC const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, o2::aod::McParticles const& mcParticles) { - // without a reconstructed counterpart the sentinel is kept, it falls in the - // underflow so the loss counters stay complete - float flattenicity = kInvalidFlattenicity; - if (flatSel.flattenicityforLossCorrRec) { - for (const auto& collision : collisions) { - if (evSel.applyEvSel && !isEventSelected(collision, false)) { - continue; - } - auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); - flattenicity = estimateFlattenicity(collision, tracksThisCollision, fillFlattenicityQAInGenMC); - if (flattenicity >= 0.f) { - break; - } + // Both estimates are always computed: the reconstructed one classifies the + // numerator of the closure, the true one its denominator. Without a + // reconstructed counterpart the sentinel is kept, it falls in the underflow + // so the loss counters stay complete. + float flattenicityRec = kInvalidFlattenicity; + float centFT0M = -1.f; + for (const auto& collision : collisions) { + if (evSel.applyEvSel && !isEventSelected(collision, false)) { + continue; + } + auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); + flattenicityRec = estimateFlattenicity(collision, tracksThisCollision, fillFlattenicityQAInGenMC); + if (flattenicityRec >= 0.f) { + centFT0M = collision.centFT0M(); + break; } - rEventSelection.fill(HIST("hFlattenicityDistributionRecMCGen"), flattenicity); - } else { - flattenicity = estimateFlattenicityFV0MC(mcParticles); - rEventSelection.fill(HIST("hFlattenicityDistributionMCGen"), flattenicity); } + const float flattenicityTrue = estimateFlattenicityGen(mcParticles, fillFlattenicityQAInGenMC); + rEventSelection.fill(HIST("hFlattenicityDistributionRecMCGen"), flattenicityRec); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen"), flattenicityTrue); + + // which of the two drives the loss corrections written without a suffix + const float flattenicity = flatSel.flattenicityforLossCorrRec ? flattenicityRec : flattenicityTrue; //==================================== //===== Event Loss Denominator ======= @@ -1828,16 +2522,29 @@ struct Lambdak0sflattenicity { return; } rEventSelection.fill(HIST("hNEventsMCGen"), 1.5); + + // The FT0M class has no generator-level counterpart, so with a window + // requested the collision only belongs to it through an accepted + // reconstructed one, which is what leaves centFT0M non-negative above. + // Otherwise the generated denominators stay MB while the numerator is HM. + if (eventClass.applyCentSel && centFT0M < 0.f) { + return; + } + rEventSelection.fill(HIST("hFlat_GenColl_MC"), flattenicity); - bool isINELgt0true = false; + const bool isINELgt0true = pwglf::isINELgtNmc(mcParticles, 0, pdg); - if (pwglf::isINELgtNmc(mcParticles, 0, pdg)) { - isINELgt0true = true; + if (isINELgt0true) { rEventSelection.fill(HIST("hNEventsMCGen"), 2.5); rEventSelection.fill(HIST("hFlat_GenColl_MC_INELgt0"), flattenicity); + rEventSelection.fill(HIST("hFlat_GenColl_MC_INELgt0_TrueFlat"), flattenicityTrue); } + fillFlatDistGen(flattenicityTrue, centFT0M, isINELgt0true); + fillChargedGen(mcParticles, flattenicity, false); + fillChargedGen(mcParticles, flattenicityTrue, true); + //===================================== //===== Signal Loss Denominator ======= //===================================== @@ -1847,32 +2554,35 @@ struct Lambdak0sflattenicity { if (!mcParticle.isPhysicalPrimary()) { continue; } - if (std::abs(mcParticle.y()) > kMcRapidityWindow) { - continue; - } + const bool inV0Rapidity = std::abs(mcParticle.y()) <= v0Sel.v0settingRapidity; + const bool inCascRapidity = std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity; - if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("pGen_MCGenColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("pGen_MCGenColl_INEL_K0Short"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("pGen_MCGenColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("pGen_MCGenColl_INEL_Lambda"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("pGen_MCGenColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("pGen_MCGenColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { - rXi.fill(HIST("pGen_MCGenColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (inCascRapidity && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("pGen_MCGenColl_INEL_Xi"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } } @@ -1902,6 +2612,7 @@ struct Lambdak0sflattenicity { if (collision.isInelGt0() && isINELgt0true) { rEventSelection.fill(HIST("hNEventsMCReco"), 2.5); rEventSelection.fill(HIST("hFlat_RecoColl_MC_INELgt0"), flattenicity); + rEventSelection.fill(HIST("hFlat_RecoColl_MC_INELgt0_TrueFlat"), flattenicityTrue); recoCollIndexINELgt0++; } @@ -1915,33 +2626,35 @@ struct Lambdak0sflattenicity { if (!mcParticle.isPhysicalPrimary()) { continue; } + const bool inV0Rapidity = std::abs(mcParticle.y()) <= v0Sel.v0settingRapidity; + const bool inCascRapidity = std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity; - if (std::abs(mcParticle.y()) > kMcRapidityWindow) { - continue; - } - - if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { - rXi.fill(HIST("Generated_MCRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (inCascRapidity && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("Generated_MCRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } } @@ -1962,6 +2675,7 @@ struct Lambdak0sflattenicity { if (recoCollIndexINELgt0 > 0) { rEventSelection.fill(HIST("hNEventsMCGenReco"), 1.5); rEventSelection.fill(HIST("hFlat_GenRecoColl_MC_INELgt0"), flattenicity); + rEventSelection.fill(HIST("hFlat_GenRecoColl_MC_INELgt0_TrueFlat"), flattenicityTrue); } //===================================== @@ -1973,39 +2687,41 @@ struct Lambdak0sflattenicity { if (!mcParticle.isPhysicalPrimary()) { continue; } + const bool inV0Rapidity = std::abs(mcParticle.y()) <= v0Sel.v0settingRapidity; + const bool inCascRapidity = std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity; - if (std::abs(mcParticle.y()) > kMcRapidityWindow) { - continue; - } - - if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("pGen_MCGenRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("pGen_MCGenRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { - rXi.fill(HIST("pGen_MCGenRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (inCascRapidity && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("pGen_MCGenRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } } } // Cascade Analysis Starts here - using DauTracks = soa::Join; + using DauTracks = soa::Join; using LabeledDauTracks = soa::Join; using LabeledCascades = soa::Join; @@ -2029,14 +2745,9 @@ struct Lambdak0sflattenicity { } // track quality - if (posDaughterTrack.tpcNClsCrossedRows() < cascSel.nTPCcrossedRows || - negDaughterTrack.tpcNClsCrossedRows() < cascSel.nTPCcrossedRows || - bacDaughterTrack.tpcNClsCrossedRows() < cascSel.nTPCcrossedRows) { - return false; - } - if (std::abs(posDaughterTrack.eta()) > trkPid.cfgTrkEtaCut || - std::abs(negDaughterTrack.eta()) > trkPid.cfgTrkEtaCut || - std::abs(bacDaughterTrack.eta()) > trkPid.cfgTrkEtaCut) { + if (!isSelectedDaughterTrack(posDaughterTrack, cascSel.nTPCcrossedRows) || + !isSelectedDaughterTrack(negDaughterTrack, cascSel.nTPCcrossedRows) || + !isSelectedDaughterTrack(bacDaughterTrack, cascSel.nTPCcrossedRows)) { return false; } @@ -2083,9 +2794,10 @@ struct Lambdak0sflattenicity { soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/) { + const bool own = (eventHistOwner == kOwnerDataCasc); if (evSel.applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria return; } @@ -2094,15 +2806,21 @@ struct Lambdak0sflattenicity { auto vtxX = collision.posX(); float flattenicity = estimateFlattenicity(collision, tracks); + if (own) { + fillFlattenicityStages(); + } if (flattenicity < 0.f) { return; } - rEventSelection.fill(HIST("hEventsSelected"), nbinFlattenicity - 0.5); + if (own) { - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); - rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); - rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracks, flattenicity); + } for (const auto& casc : Cascades) { @@ -2148,10 +2866,11 @@ struct Lambdak0sflattenicity { soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, aod::McCollisions const&, aod::McParticles const& mcParticles) { + const bool own = (eventHistOwner == kOwnerRecMCCasc); for (const auto& collision : collisions) { if (evSel.applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria continue; } @@ -2165,19 +2884,34 @@ struct Lambdak0sflattenicity { auto tracksThisCollision = tracks.sliceBy(perColDauTracksMC, collision.globalIndex()); float flattenicity = estimateFlattenicity(collision, tracksThisCollision); + if (own) { + fillFlattenicityStages(); + } if (flattenicity < 0.f) { continue; } - rEventSelection.fill(HIST("hEventsSelected"), nbinFlattenicity - 0.5); + if (own) { - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); - rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); - rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracksThisCollision, flattenicity); + } auto cascsThisCollision = Cascades.sliceBy(perColCasc, collision.globalIndex()); const auto& mcCollision = collision.mcCollision_as(); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cacheCasc); + const float flattenicityMCGen = estimateFlattenicityGen(particlesInCollision, own); + if (own) { + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + rEventSelection.fill(HIST("hFlatGenVsRecFine"), flattenicityMCGen, flattenicity); + fillFlatDistGenInRec(flattenicityMCGen, collision.centFT0M(), collision.isInelGt0()); + } + for (const auto& casc : cascsThisCollision) { // MC truth matching, else the spectra keep the combinatorial background @@ -2206,6 +2940,7 @@ struct Lambdak0sflattenicity { const int motherIndex = getFeedDownMother(cascMcParticle, motherPt); rXi.fill(HIST("hMassFeedDownXipTFlat"), massXi, casc.pt(), flattenicity); rXi.fill(HIST("hFeedDownXiPtVsMotherPt"), casc.pt(), motherPt); + rXi.fill(HIST("hFeedDownXiMatrix"), casc.pt(), motherPt, flattenicity, motherIndex); rXi.fill(HIST("hFeedDownXiMotherPdg"), motherIndex); } if (!isPrimaryCasc && eventClass.requirePrimaryMC) { @@ -2224,33 +2959,112 @@ struct Lambdak0sflattenicity { rXi.fill(HIST("h2DdecayRadiusXi"), casc.cascradius()); rXi.fill(HIST("hMassXipT"), massXi, casc.pt()); rXi.fill(HIST("hMassXipTFlat"), massXi, casc.pt(), flattenicity); + rXi.fill(HIST("hMassXipTTrueFlat"), massXi, casc.pt(), flattenicityMCGen); + rXi.fill(HIST("hPtResXi"), cascMcParticle.pt(), + (casc.pt() - cascMcParticle.pt()) / cascMcParticle.pt()); rXi.fill(HIST("hNSigmaProtonFromXi"), protonDaughter.tpcNSigmaPr(), protonDaughter.tpcInnerParam()); rXi.fill(HIST("hNSigmaPionFromXi"), pionDaughter.tpcNSigmaPi(), pionDaughter.tpcInnerParam()); rXi.fill(HIST("hNSigmaBachPionFromXi"), bacDaughterTrack.tpcNSigmaPi(), bacDaughterTrack.tpcInnerParam()); } } - const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cacheCasc); - float flattenicityMCGen = estimateFlattenicityFV0MC(particlesInCollision); - rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); - rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); - const bool isInelGt0Rec = collision.isInelGt0(); for (const auto& mcParticle : particlesInCollision) { - if (mcParticle.isPhysicalPrimary() && std::abs(mcParticle.y()) < kMcRapidityWindow && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { - rXi.fill(HIST("Generated_MCRecoCollCheck_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (mcParticle.isPhysicalPrimary() && std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity && + std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("Generated_MCRecoCollCheck_INEL_Xi"), mcParticle.pt(), flattenicity); if (isInelGt0Rec) { - rXi.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityMCGen); } } } } } + // ================== Percentile determination pass ====================== // + // + // Event selection and flattenicity only, so a short run gives the 1-rho + // distribution the percentile boundaries are read off. The boundaries then go + // back into binning.axisFlat for the spectra pass, where one class is exactly + // one bin. + + void processFlatDistData( + soa::Join::iterator const& collision, + TrackCandidates const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/) + { + const bool own = (eventHistOwner == kOwnerFlatDistData); + if (evSel.applyEvSel && !isEventSelected(collision, own)) { + return; + } + const float flattenicity = estimateFlattenicity(collision, tracks); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + return; + } + if (own) { + rEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracks, flattenicity); + } + } + + void processFlatDistMC( + soa::Join const& collisions, + aod::McCollisions const&, TrackCandidatesMC const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/, aod::McParticles const& mcParticles) + { + const bool own = (eventHistOwner == kOwnerFlatDistMC); + for (const auto& collision : collisions) { + if (evSel.applyEvSel && !isEventSelected(collision, own)) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); + const float flattenicity = estimateFlattenicity(collision, tracksThisCollision); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + continue; + } + if (!own) { + continue; + } + rEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracksThisCollision, flattenicity); + + const auto& mcCollision = collision.mcCollision_as(); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); + const float flattenicityMCGen = estimateFlattenicityGen(particlesInCollision); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + rEventSelection.fill(HIST("hFlatGenVsRecFine"), flattenicityMCGen, flattenicity); + fillFlatDistGenInRec(flattenicityMCGen, collision.centFT0M(), collision.isInelGt0()); + } + } + + PROCESS_SWITCH(Lambdak0sflattenicity, processFlatDistData, "Flattenicity distribution only, data", false); + PROCESS_SWITCH(Lambdak0sflattenicity, processFlatDistMC, "Flattenicity distribution only, MC", false); PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3LambdaK0s, "Process Run 3 Data LambdaK0s", false); PROCESS_SWITCH(Lambdak0sflattenicity, processRecMCLambdaK0s, "Process Run 3 MC reconstructed LambdaK0s", false); PROCESS_SWITCH(Lambdak0sflattenicity, processGenMC, "Process Run 3 MC generated", false); - PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3Cascade, "Process Run 3 Data Cascade", true); + PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3Cascade, "Process Run 3 Data Cascade", false); PROCESS_SWITCH(Lambdak0sflattenicity, processRecMCRun3Cascade, "Process Run 3 mc Rec Cascade", false); }; diff --git a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx index d16e113b0b5..77aec351dc9 100644 --- a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx @@ -351,6 +351,19 @@ struct sigmaanalysis { histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min IR"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + // + if (doprocessAnalysedCollisions) { + histos.add("hEventPreSelection", "hEventPreSelection", kTH1D, {{8, -0.5f, +7.5f}}); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(2, "kIsTriggerTVX"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(3, "kNoITSROFrameBorder"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(4, "kNoTimeFrameBorder"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(5, "posZ cut"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(6, "kNoSameBunchPileup"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(7, "RCT flags"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(8, "Preselected collisions"); + } + if (fGetIR) { histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1D, {axisIRBinning}); @@ -1873,6 +1886,23 @@ struct sigmaanalysis { } } + // ______________________________________________________ + // Simulated processing in Run 2 (subscribes to MC information too) + void processAnalysedCollisions(aod::StraSelections const& straSelections) + { + for (auto const& straSelection : straSelections) { + // Event selection criteria + histos.get(HIST("hEventPreSelection"))->AddBinContent(1, straSelection.totalNbrOfCollisions() /* all collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(2, straSelection.totalIsTriggerTVXCollisions() /* preselected IsTriggerTVX collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(3, straSelection.totalNoITSROFBorderCollisions() /* + preselected NoITSROF collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(4, straSelection.totalNoTFBorderCollisions() /* + preselected NoTF collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(5, straSelection.totalIsGoodZvtxCollisions() /* + preselected |Zvtx| < X cm collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(6, straSelection.totalNoSBPileupCollisions() /* + preselected NoSameBunchPileup collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(7, straSelection.totalIsGoodRCTCollisions() /* + preselected Good RCT collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(8, straSelection.totalNbrOfSelCollisions() /* total number of preselected collisions */); + } + } + void processRealData(soa::Join const& collisions, Sigma0s const& fullSigma0s) { analyzeRecoeSigma0s(collisions, fullSigma0s); @@ -1925,6 +1955,7 @@ struct sigmaanalysis { PROCESS_SWITCH(sigmaanalysis, processPi0RealData, "Do real data analysis for pi0 QA", false); PROCESS_SWITCH(sigmaanalysis, processPi0MonteCarlo, "Do Monte-Carlo-based analysis for pi0 QA", false); PROCESS_SWITCH(sigmaanalysis, processPi0GeneratedRun3, "process MC generated Run 3 for pi0 QA", false); + PROCESS_SWITCH(sigmaanalysis, processAnalysedCollisions, "process filtered events for bookkeeping", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Utils/CMakeLists.txt b/PWGLF/Utils/CMakeLists.txt index 8971e4a1597..b81a6eb7198 100644 --- a/PWGLF/Utils/CMakeLists.txt +++ b/PWGLF/Utils/CMakeLists.txt @@ -36,3 +36,7 @@ o2physics_add_library(LfStrangenessBuilderHelper o2physics_add_library(LfStrangenessBuilderModule SOURCES strangenessBuilderModule.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle) + +o2physics_add_library(LfCascadeMlResponse + SOURCES cascadeMlResponse.cxx + PUBLIC_LINK_LIBRARIES O2Physics::MLCore) diff --git a/PWGLF/Utils/cascadeMlResponse.cxx b/PWGLF/Utils/cascadeMlResponse.cxx new file mode 100644 index 00000000000..43cb3236f9b --- /dev/null +++ b/PWGLF/Utils/cascadeMlResponse.cxx @@ -0,0 +1,18 @@ +// Copyright 2019-2020 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 cascadeMlResponse.cxx +/// \brief Helper file providing the compilation command for the CascadeMlResponse header. +/// +/// \author ALICE Collaboration + +// o2-linter: disable=name/workflow-file (not a workflow file) +#include "CascadeMlResponse.h" // IWYU pragma: keep diff --git a/PWGLF/Utils/rsnOutput.h b/PWGLF/Utils/rsnOutput.h index 214d6aa8118..c24db42375e 100644 --- a/PWGLF/Utils/rsnOutput.h +++ b/PWGLF/Utils/rsnOutput.h @@ -28,9 +28,7 @@ #include #include -namespace o2::analysis -{ -namespace rsn +namespace o2::analysis::rsn { enum class EventType { zvertex, @@ -49,12 +47,14 @@ enum class PairType { unlikemp, likepp, likemm, - unliketrue, + unliketruerec, + unliketruegen, unlikegen, - unlikegenold, mixingpm, mixingmp, - rotationpm, + rotationz, + rotation, + rotationlike, all }; @@ -80,13 +80,14 @@ enum class MixingType { none }; -MixingType mixingTypeName(std::string name) +MixingType mixingTypeName(const std::string& name) { - if (name == "ce") + if (name == "ce") { return MixingType::ce; - else if (name == "mu") + } + if (name == "mu") { return MixingType::mu; - + } return MixingType::none; } @@ -94,14 +95,15 @@ enum class SystematicsAxisType { ncl, unknown }; + namespace pair_axis { -std::vector names{"im", "pt", "mu", "ce", "ns1", "ns2", "eta", "y", "vz", "mum", "cem", "vzm"}; +const std::vector names{"im", "pt", "mu", "ce", "ns1", "ns2", "eta", "y", "vz", "mum", "cem", "vzm"}; } namespace systematic_axis { -std::vector names{"ncl"}; +const std::vector names{"ncl"}; } class Output @@ -109,22 +111,23 @@ class Output public: virtual ~Output() = default; - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool /*produceTrue*/ = false, MixingType /*eventMixing*/ = MixingType::none, bool /*produceLikesign*/ = false, bool /*produceRotational*/ = false, o2::framework::HistogramRegistry* registry = nullptr) + virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool /*produceTrue*/, MixingType /*eventMixing*/, bool /*produceLikesign*/, bool /*produceRotational*/, o2::framework::HistogramRegistry* registry) { mHistogramRegistry = registry; - if (mHistogramRegistry == nullptr) + if (mHistogramRegistry == nullptr) { mHistogramRegistry = new o2::framework::HistogramRegistry("registry"); + } // check if all axes are added in correct order for (int i = 0; i < static_cast(PairAxisType::unknown); i++) { auto aname = *std::move(allAxes[i].name); LOGF(debug, "Check axis '%s' %d", aname.c_str(), i); - if (aname.compare(pair_axis::names[static_cast(i)])) { + if (aname != pair_axis::names[i]) { LOGF(fatal, "rsn::Output::Error: Order in allAxes is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), pair_axis::names[static_cast(i)]); } } - PairAxisType currentType; + PairAxisType currentType = PairAxisType::unknown; for (const auto& c : sparseAxes) { currentType = type(c); if (currentType >= PairAxisType::unknown) { @@ -136,8 +139,8 @@ class Output mCurrentAxisTypes.push_back(currentType); } - if (mFillPoint != nullptr) - delete mFillPoint; + delete mFillPoint; + mFillPoint = new double[mCurrentAxisTypes.size()]; LOGF(info, "Number of axis added: %d", mCurrentAxes.size()); @@ -147,12 +150,12 @@ class Output for (int i = 0; i < static_cast(SystematicsAxisType::unknown); i++) { auto aname = *std::move(allAxes_sys[i].name); LOGF(debug, "Check axis '%s' %d", aname.c_str(), i); - if (aname.compare(systematic_axis::names[static_cast(i)])) { + if (aname != systematic_axis::names[i]) { LOGF(fatal, "rsn::Output::Error: Order in allAxes_sys is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), systematic_axis::names[static_cast(i)]); } } - SystematicsAxisType currentTypeSys; + SystematicsAxisType currentTypeSys = SystematicsAxisType::unknown; for (const auto& c : sysAxes) { currentTypeSys = typeSys(c); if (currentTypeSys >= SystematicsAxisType::unknown) { @@ -164,8 +167,8 @@ class Output mCurrentAxisTypesSys.push_back(currentTypeSys); } - if (mFillPointSys != nullptr) - delete mFillPointSys; + delete mFillPointSys; + mFillPointSys = new double[mCurrentAxisTypesSys.size()]; LOGF(info, "Number of systematic axis added: %d", mCurrentAxesSys.size()); @@ -173,7 +176,7 @@ class Output } template - void fillSparse(const T& h, double* point) + void fillSparse(const T& h, const double* point) { int i = 0; for (const auto& at : mCurrentAxisTypes) { @@ -183,7 +186,7 @@ class Output } template - void fillSparseSys(const T& h, double* point) + void fillSparseSys(const T& h, const double* point) { int i = 0; for (const auto& at : mCurrentAxisTypesSys) { @@ -209,15 +212,17 @@ class Output virtual void fillUnlikemp(double* point) = 0; virtual void fillLikepp(double* point) = 0; virtual void fillLikemm(double* point) = 0; - virtual void fillUnliketrue(double* point) = 0; - virtual void fillUnlikegen(double* point) = 0; - virtual void fillUnlikegenOld(double* point) = 0; + virtual void fillUnlikeTrueRec(double* point) = 0; + virtual void fillUnlikeTrueGen(double* point) = 0; + virtual void fillUnlikeGen(double* point) = 0; virtual void fillMixingpm(double* point) = 0; virtual void fillMixingmp(double* point) = 0; - virtual void fillRotationpm(double* point) = 0; + virtual void fillRotationZ(double* point) = 0; + virtual void fillRotation(double* point) = 0; + virtual void fillRotationLike(double* point) = 0; virtual void fillSystematics(double* point) = 0; - PairAxisType type(std::string name) + PairAxisType type(const std::string& name) { auto it = std::find(pair_axis::names.begin(), pair_axis::names.end(), name); if (it == pair_axis::names.end()) { @@ -226,7 +231,7 @@ class Output return static_cast(std::distance(pair_axis::names.begin(), it)); } - SystematicsAxisType typeSys(std::string name) + SystematicsAxisType typeSys(const std::string& name) { auto it = std::find(systematic_axis::names.begin(), systematic_axis::names.end(), name); if (it == systematic_axis::names.end()) { @@ -235,22 +240,22 @@ class Output return static_cast(std::distance(systematic_axis::names.begin(), it)); } - std::string name(PairAxisType type) + std::string name(PairAxisType axisType) { - return pair_axis::names[(static_cast(type))]; + return pair_axis::names[(static_cast(axisType))]; } - std::string nameSys(SystematicsAxisType type) + std::string nameSys(SystematicsAxisType axisType) { - return systematic_axis::names[(static_cast(type))]; + return systematic_axis::names[(static_cast(axisType))]; } - o2::framework::AxisSpec axis(std::vector const& allAxes, PairAxisType type) + o2::framework::AxisSpec axis(std::vector const& allAxes, PairAxisType axisType) { - const o2::framework::AxisSpec unknownAxis = {1, 0., 1., "unknown axis", "unknown"}; - if (type == PairAxisType::unknown) - return unknownAxis; - return allAxes[static_cast(type)]; + if (axisType == PairAxisType::unknown) { + return {1, 0., 1., "unknown axis", "unknown"}; + } + return allAxes[static_cast(axisType)]; } protected: @@ -268,7 +273,7 @@ class Output class OutputSparse : public Output { public: - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool produceTrue = false, MixingType eventMixing = MixingType::none, bool produceLikesign = false, bool produceRotational = false, o2::framework::HistogramRegistry* registry = nullptr) + void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool produceTrue, MixingType eventMixing, bool produceLikesign, bool produceRotational, o2::framework::HistogramRegistry* registry) override { Output::init(sparseAxes, allAxes, sysAxes, allAxes_sys, produceTrue, eventMixing, produceLikesign, produceRotational, registry); @@ -278,22 +283,23 @@ class OutputSparse : public Output mHistogramRegistry->add("likemm", "Like MM", *mPairHisto); } if (produceTrue) { - mHistogramRegistry->add("unliketrue", "Unlike True", *mPairHisto); + mHistogramRegistry->add("unliketruerec", "Unlike True (Rec)", *mPairHisto); + mHistogramRegistry->add("unliketruegen", "Unlike True (Gen)", *mPairHisto); mHistogramRegistry->add("unlikegen", "Unlike Gen", *mPairHisto); - mHistogramRegistry->add("unlikegenold", "Unlike Gen Old", *mPairHisto); } if (eventMixing != MixingType::none) { mHistogramRegistry->add("mixingpm", "Event Mixing pm", *mPairHisto); mHistogramRegistry->add("mixingmp", "Event Mixing mp", *mPairHisto); } if (produceRotational) { - mHistogramRegistry->add("rotationpm", "Rotational pm", *mPairHisto); + mHistogramRegistry->add("rotationz", "Rotation around z axis", *mPairHisto); + mHistogramRegistry->add("rotation", "Momentum-axis rotation, unlike-sign", *mPairHisto); + mHistogramRegistry->add("rotationlike", "Momentum-axis rotation, like-sign", *mPairHisto); } mHistogramRegistry->add("Mapping/systematics", "Systematics mapping", *mPairHistoSys); } - virtual void - fill(EventType t, double* point) + void fill(EventType t, double* point) override { switch (t) { case EventType::zvertex: @@ -304,7 +310,7 @@ class OutputSparse : public Output } } - virtual void fill(PairType t, double* point) + void fill(PairType t, double* point) override { switch (t) { case PairType::unlikepm: @@ -319,14 +325,14 @@ class OutputSparse : public Output case PairType::likemm: fillLikemm(point); break; - case PairType::unliketrue: - fillUnliketrue(point); + case PairType::unliketruerec: + fillUnlikeTrueRec(point); break; case PairType::unlikegen: - fillUnlikegen(point); + fillUnlikeGen(point); break; - case PairType::unlikegenold: - fillUnlikegenOld(point); + case PairType::unliketruegen: + fillUnlikeTrueGen(point); break; case PairType::mixingpm: fillMixingpm(point); @@ -334,60 +340,73 @@ class OutputSparse : public Output case PairType::mixingmp: fillMixingmp(point); break; - case PairType::rotationpm: - fillRotationpm(point); + case PairType::rotationz: + fillRotationZ(point); + break; + case PairType::rotation: + fillRotation(point); + break; + case PairType::rotationlike: + fillRotationLike(point); break; default: break; } } - virtual void fillUnlikepm(double* point) + void fillUnlikepm(double* point) override { fillSparse(HIST("unlikepm"), point); } - virtual void fillUnlikemp(double* point) + void fillUnlikemp(double* point) override { fillSparse(HIST("unlikemp"), point); } - virtual void fillLikepp(double* point) + void fillLikepp(double* point) override { fillSparse(HIST("likepp"), point); } - virtual void fillLikemm(double* point) + void fillLikemm(double* point) override { fillSparse(HIST("likemm"), point); } - virtual void fillUnliketrue(double* point) + void fillUnlikeTrueRec(double* point) override { - fillSparse(HIST("unliketrue"), point); + fillSparse(HIST("unliketruerec"), point); } - virtual void fillUnlikegen(double* point) + void fillUnlikeTrueGen(double* point) override { - fillSparse(HIST("unlikegen"), point); + fillSparse(HIST("unliketruegen"), point); } - virtual void fillUnlikegenOld(double* point) + void fillUnlikeGen(double* point) override { - fillSparse(HIST("unlikegenold"), point); + fillSparse(HIST("unlikegen"), point); } - virtual void fillMixingpm(double* point) + void fillMixingpm(double* point) override { fillSparse(HIST("mixingpm"), point); } - virtual void fillMixingmp(double* point) + void fillMixingmp(double* point) override { fillSparse(HIST("mixingmp"), point); } - virtual void fillRotationpm(double* point) + void fillRotationZ(double* point) override + { + fillSparse(HIST("rotationz"), point); + } + void fillRotation(double* point) override + { + fillSparse(HIST("rotation"), point); + } + void fillRotationLike(double* point) override { - fillSparse(HIST("rotationpm"), point); + fillSparse(HIST("rotationlike"), point); } - virtual void fillSystematics(double* point) + void fillSystematics(double* point) override { fillSparse(HIST("Mapping/systematics"), point); } }; -} // namespace rsn -} // namespace o2::analysis +} // namespace o2::analysis::rsn #endif // PWGLF_UTILS_RSNOUTPUT_H_ diff --git a/PWGUD/Tasks/CMakeLists.txt b/PWGUD/Tasks/CMakeLists.txt index 7244f33fb0e..bfe050bbe04 100644 --- a/PWGUD/Tasks/CMakeLists.txt +++ b/PWGUD/Tasks/CMakeLists.txt @@ -110,7 +110,7 @@ o2physics_add_dpl_workflow(upc-cand-analyzer COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(upc-cand-producer-qa - SOURCES upcCandidateProducerQa.cpp + SOURCES upcCandidateProducerQa.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx index faeb7de083f..d708c17e5ae 100644 --- a/PWGUD/Tasks/flowCorrelationsUpc.cxx +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -281,11 +281,15 @@ struct FlowCorrelationsUpc { return false; } // if A or C gap is requested, keep corresponding neutron class - if (cfgGapSide == 0 || cfgGapSide == 1) { - if ((cfgGapSide == 0 && neutronClass == 1) || (cfgGapSide == 1 && neutronClass == 2)) { // o2-linter: disable=magic-number (ZDC time cut) - // accepted - } else { - return false; + if (cfgGapSideMerge) { + // accepted + } else { + if (cfgGapSide == 0 || cfgGapSide == 1) { + if ((cfgGapSide == 0 && neutronClass == 1) || (cfgGapSide == 1 && neutronClass == 2)) { // o2-linter: disable=magic-number (ZDC time cut) + // accepted + } else { + return false; + } } } } diff --git a/PWGUD/Tasks/upcCandidateProducerQa.cpp b/PWGUD/Tasks/upcCandidateProducerQa.cxx similarity index 95% rename from PWGUD/Tasks/upcCandidateProducerQa.cpp rename to PWGUD/Tasks/upcCandidateProducerQa.cxx index 29accce2fe4..19e1deb1244 100644 --- a/PWGUD/Tasks/upcCandidateProducerQa.cpp +++ b/PWGUD/Tasks/upcCandidateProducerQa.cxx @@ -9,15 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/DataModel/EventSelection.h" -#include "CommonConstants/LHCConstants.h" -#include "PWGUD/Core/UPCCutparHolder.h" -#include "PWGUD/Core/UPCHelpers.h" -#include "PWGUD/DataModel/UDTables.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/Tools/KFparticle/KFUtilities.h b/Tools/KFparticle/KFUtilities.h index b6c6e607a9b..1a9a093a588 100644 --- a/Tools/KFparticle/KFUtilities.h +++ b/Tools/KFparticle/KFUtilities.h @@ -192,7 +192,7 @@ o2::track::TrackParCov getTrackParCovFromKFP(const KFParticle& kfParticle, const /// @param kfp KFParticle /// @param PV KFParticle primary vertex /// @return cpa -float cpaFromKF(KFParticle kfp, KFParticle PV) +float cpaFromKF(const KFParticle& kfp, const KFParticle& PV) { float xVtxP{}, yVtxP{}, zVtxP{}, xVtxS{}, yVtxS{}, zVtxS{}, px{}, py{}, pz{}; @@ -216,7 +216,7 @@ float cpaFromKF(KFParticle kfp, KFParticle PV) /// @param kfp KFParticle /// @param PV KFParticle primary vertex /// @return cpa in xy -float cpaXYFromKF(KFParticle kfp, KFParticle PV) +float cpaXYFromKF(const KFParticle& kfp, const KFParticle& PV) { float xVtxP{}, yVtxP{}, xVtxS{}, yVtxS{}, px{}, py{}; @@ -243,7 +243,7 @@ float cpaXYFromKF(KFParticle kfp, KFParticle PV) /// @param kfpprong1 KFParticele Prong 1 /// @param pdgdb Service PDG data base /// @return cos theta star -float cosThetaStarFromKF(int iProng, int pdgvtx, int pdgprong0, int pdgprong1, KFParticle kfpprong0, KFParticle kfpprong1, const o2::framework::Service& pdgdb) +float cosThetaStarFromKF(int iProng, int pdgvtx, int pdgprong0, int pdgprong1, const KFParticle& kfpprong0, const KFParticle& kfpprong1, const o2::framework::Service& pdgdb) { float px0{}, py0{}, pz0{}, px1{}, py1{}, pz1{}; @@ -269,7 +269,7 @@ float cosThetaStarFromKF(int iProng, int pdgvtx, int pdgprong0, int pdgprong1, K /// @param kfpParticle KFParticle /// @param Vertex KFParticle vertex /// @return impact parameter -float impParXYFromKF(KFParticle kfpParticle, KFParticle Vertex) +float impParXYFromKF(const KFParticle& kfpParticle, const KFParticle& Vertex) { float xVtxP{}, yVtxP{}, zVtxP{}, xVtxS{}, yVtxS{}, zVtxS{}, px{}, py{}, pz{}; @@ -293,7 +293,7 @@ float impParXYFromKF(KFParticle kfpParticle, KFParticle Vertex) /// @param kfpParticle KFParticle /// @param PV KFParticle primary vertex /// @return l/delta l -float ldlFromKF(KFParticle kfpParticle, KFParticle PV) +float ldlFromKF(const KFParticle& kfpParticle, const KFParticle& PV) { const float dxParticle = PV.GetX() - kfpParticle.GetX(); const float dyParticle = PV.GetY() - kfpParticle.GetY(); @@ -312,7 +312,7 @@ float ldlFromKF(KFParticle kfpParticle, KFParticle PV) /// @param kfpParticle KFParticle /// @param PV KFParticle primary vertex /// @return l/delta l in xy plane -float ldlXYFromKF(KFParticle kfpParticle, KFParticle PV) +float ldlXYFromKF(const KFParticle& kfpParticle, const KFParticle& PV) { const float dxParticle = PV.GetX() - kfpParticle.GetX(); const float dyParticle = PV.GetY() - kfpParticle.GetY(); @@ -354,7 +354,7 @@ std::array kfCalculateProngMomentumInSecondaryVertex(KFParticle track, /// @param track1 KFParticle first track (must be passed as a copy) /// @param track2 KFParticle second track (must be passed as a copy) /// @return DCA [cm] in the PCA -float kfCalculateDistanceBetweenParticles(KFParticle track1, KFParticle track2) +float kfCalculateDistanceBetweenParticles(const KFParticle& track1, const KFParticle& track2) { float dS[2]; float dsdr[4][6]; @@ -373,7 +373,7 @@ float kfCalculateDistanceBetweenParticles(KFParticle track1, KFParticle track2) /// @param track1 KFParticle first track (must be passed as a copy) /// @param track2 KFParticle second track (must be passed as a copy) /// @return chi2 in PCA -float kfCalculateChi2geoBetweenParticles(KFParticle track1, KFParticle track2) +float kfCalculateChi2geoBetweenParticles(const KFParticle& track1, const KFParticle& track2) { KFParticle kfPair; const KFParticle* kfDaughters[2] = {&track1, &track2}; diff --git a/Tools/KFparticle/qaKFEventTrack.cxx b/Tools/KFparticle/qaKFEventTrack.cxx index 2242de51154..7ff14e80c1c 100644 --- a/Tools/KFparticle/qaKFEventTrack.cxx +++ b/Tools/KFparticle/qaKFEventTrack.cxx @@ -116,7 +116,7 @@ struct qaKFEventTrack { int pVContrib = 0; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { @@ -536,7 +536,7 @@ struct qaKFEvent { Produces rowKFCollisions; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { diff --git a/Tools/KFparticle/qaKFParticle.cxx b/Tools/KFparticle/qaKFParticle.cxx index 4066ed0f49e..5dff4cd3b05 100644 --- a/Tools/KFparticle/qaKFParticle.cxx +++ b/Tools/KFparticle/qaKFParticle.cxx @@ -156,7 +156,7 @@ struct qaKFParticle { Produces rowKF; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { diff --git a/Tools/KFparticle/qaKFParticleLc.cxx b/Tools/KFparticle/qaKFParticleLc.cxx index 86902d349cd..eb7c68eeaa8 100644 --- a/Tools/KFparticle/qaKFParticleLc.cxx +++ b/Tools/KFparticle/qaKFParticleLc.cxx @@ -152,7 +152,7 @@ struct qaKFParticleLc { Produces rowKFLc; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) {