diff --git a/PWGDQ/DataModel/ReducedTablesAlice3.h b/ALICE3/DataModel/ReducedTablesAlice3.h similarity index 85% rename from PWGDQ/DataModel/ReducedTablesAlice3.h rename to ALICE3/DataModel/ReducedTablesAlice3.h index 787d7d38793..fdc9275842c 100644 --- a/PWGDQ/DataModel/ReducedTablesAlice3.h +++ b/ALICE3/DataModel/ReducedTablesAlice3.h @@ -15,8 +15,8 @@ /// /// \author Alexander Tiekoetter (atiekoet@cern.ch) University of Muenster -#ifndef PWGDQ_DATAMODEL_REDUCEDTABLESALICE3_H_ -#define PWGDQ_DATAMODEL_REDUCEDTABLESALICE3_H_ +#ifndef ALICE3_DATAMODEL_REDUCEDTABLESALICE3_H_ +#define ALICE3_DATAMODEL_REDUCEDTABLESALICE3_H_ #include "PWGDQ/DataModel/ReducedInfoTables.h" @@ -50,7 +50,7 @@ DECLARE_SOA_COLUMN(MultMCNParticlesEta20, multMCNParticlesEta20, float); DECLARE_SOA_COLUMN(MultMCNParticlesEta40, multMCNParticlesEta40, float); } // namespace reducedeventmcalice3 -DECLARE_SOA_TABLE_STAGED(ReducedA3Events, "REA3EVENTS", //! Main event information table +DECLARE_SOA_TABLE_STAGED(ReA3Events, "REA3EVENT", //! Main event information table o2::soa::Index<>, collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, collision::CollisionTime, collision::CollisionTimeRes, reducedeventalice3::MultDensity); @@ -62,19 +62,19 @@ DECLARE_SOA_TABLE(ReducedA3EventsVtxCov, "AOD", "REA3VTXCOV", //! Event verte DECLARE_SOA_TABLE(ReducedA3EventsInfo, "AOD", "REA3EVENTINFO", //! Main event index table reducedevent::CollisionId); -DECLARE_SOA_TABLE(ReducedA3MCEvents, "AOD", "REA3MCEVTS", //! Event level MC truth information +DECLARE_SOA_TABLE(ReA3MCEvents, "AOD", "REA3MCEVENT", //! Event level MC truth information o2::soa::Index<>, mccollision::GeneratorsID, reducedeventalice3::MCPosX, reducedeventalice3::MCPosY, reducedeventalice3::MCPosZ, mccollision::T, mccollision::Weight, mccollision::ImpactParameter); -using ReducedA3MCEvent = ReducedA3MCEvents::iterator; -using ReducedA3Event = ReducedA3Events::iterator; +using ReducedA3MCEvent = ReA3MCEvents::iterator; +using ReA3Event = ReA3Events::iterator; namespace reducedtrackalice3 { // basic track information -DECLARE_SOA_INDEX_COLUMN(ReducedA3Event, reduceda3event); //! -DECLARE_SOA_INDEX_COLUMN(Track, track); //! +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); //! // ----------------------------------------------------- @@ -111,8 +111,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! } // namespace reducedtrackalice3 // basic track information -DECLARE_SOA_TABLE(ReducedA3Tracks, "AOD", "REA3TRACK", //! - o2::soa::Index<>, reducedtrackalice3::ReducedA3EventId, reducedtrackalice3::FilteringFlags, +DECLARE_SOA_TABLE(ReA3Tracks, "AOD", "REA3TRACK", //! + o2::soa::Index<>, reducedtrackalice3::ReA3EventId, reducedtrackalice3::FilteringFlags, reducedtrackalice3::Pt, reducedtrackalice3::Eta, reducedtrackalice3::Phi, reducedtrackalice3::Sign, reducedtrackalice3::IsAmbiguous, reducedtrackalice3::Px, reducedtrackalice3::Py, @@ -126,19 +126,19 @@ DECLARE_SOA_TABLE(ReducedA3TracksBarrelCov, "AOD", "REA3BARRELCOV", //! namespace reducedA3trackMC { -DECLARE_SOA_INDEX_COLUMN(ReducedA3MCEvent, reducedA3MCEvent); //! -DECLARE_SOA_COLUMN(McReducedFlags, mcReducedFlags, uint16_t); //! Flags to hold compressed MC selection information -DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother0, mother0, int, "ReducedA3MCTracks_Mother0"); //! Track index of the first mother -DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother1, mother1, int, "ReducedA3MCTracks_Mother1"); //! Track index of the last mother -DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter0, daughter0, int, "ReducedA3MCTracks_Daughter0"); //! Track index of the first daughter -DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter1, daughter1, int, "ReducedA3MCTracks_Daughter1"); //! Track index of the last daughter -DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); //! Mother tracks (possible empty) array. Iterate over mcParticle.mothers_as()) -DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); //! Daughter tracks (possibly empty) slice. Check for non-zero with mcParticle.has_daughters(). Iterate over mcParticle.daughters_as()) -DECLARE_SOA_COLUMN(Pt, pt, float); //! -DECLARE_SOA_COLUMN(Eta, eta, float); //! -DECLARE_SOA_COLUMN(Phi, phi, float); //! -DECLARE_SOA_COLUMN(E, e, float); //! -DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! +DECLARE_SOA_INDEX_COLUMN(ReA3MCEvent, reA3MCEvent); //! +DECLARE_SOA_COLUMN(McReducedFlags, mcReducedFlags, uint16_t); //! Flags to hold compressed MC selection information +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother0, mother0, int, "ReA3MCTracks_Mother0"); //! Track index of the first mother +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother1, mother1, int, "ReA3MCTracks_Mother1"); //! Track index of the last mother +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter0, daughter0, int, "ReA3MCTracks_Daughter0"); //! Track index of the first daughter +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter1, daughter1, int, "ReA3MCTracks_Daughter1"); //! Track index of the last daughter +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); //! Mother tracks (possible empty) array. Iterate over mcParticle.mothers_as()) +DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); //! Daughter tracks (possibly empty) slice. Check for non-zero with mcParticle.has_daughters(). Iterate over mcParticle.daughters_as()) +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(E, e, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! [](float pt, float phi) -> float { return pt * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! [](float pt, float phi) -> float { return pt * std::sin(phi); }); @@ -159,8 +159,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity // 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(ReducedA3MCTracks, "AOD", "REA3MCTRACK", //! MC track information (on disk) - o2::soa::Index<>, reducedA3trackMC::ReducedA3MCEventId, +DECLARE_SOA_TABLE(ReA3MCTracks, "AOD", "REA3MCTRACK", //! MC track information (on disk) + o2::soa::Index<>, reducedA3trackMC::ReA3MCEventId, mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, reducedA3trackMC::MothersIds, reducedA3trackMC::DaughtersIdSlice, mcparticle::Weight, @@ -179,18 +179,18 @@ DECLARE_SOA_TABLE(ReducedA3MCTracks, "AOD", "REA3MCTRACK", //! MC track informa mcparticle::GetHepMCStatusCode, mcparticle::IsPhysicalPrimary); -using ReducedA3MCTrack = ReducedA3MCTracks::iterator; +using ReA3MCTrack = ReA3MCTracks::iterator; namespace reduceda3barreltracklabel { -DECLARE_SOA_INDEX_COLUMN(ReducedA3MCTrack, reducedA3MCTrack); //! +DECLARE_SOA_INDEX_COLUMN(ReA3MCTrack, reA3MCTrack); //! DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); } // namespace reduceda3barreltracklabel // 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::ReducedA3MCTrackId, reduceda3barreltracklabel::McMask, reducedA3trackMC::McReducedFlags); + reduceda3barreltracklabel::ReA3MCTrackId, reduceda3barreltracklabel::McMask, reducedA3trackMC::McReducedFlags); using ReducedA3TrackBarrelLabel = ReducedA3TracksBarrelLabels::iterator; @@ -206,31 +206,31 @@ DECLARE_SOA_TABLE(ReducedA3TracksBarrel, "AOD", "REA3BARREL", DECLARE_SOA_TABLE(ReducedA3TracksBarrelInfo, "AOD", "REA3BARRELINFO", reducedtrackalice3::CollisionId, collision::PosX, collision::PosY, collision::PosZ, reducedtrackalice3::TrackId); -using ReducedA3Track = ReducedA3Tracks::iterator; +using ReducedA3Track = ReA3Tracks::iterator; using ReducedA3TrackBarrel = ReducedA3TracksBarrel::iterator; using ReducedA3TrackBarrelCov = ReducedA3TracksBarrelCov::iterator; using ReducedA3TrackBarrelInfo = ReducedA3TracksBarrelInfo::iterator; namespace reducedeventlabela3 { -DECLARE_SOA_INDEX_COLUMN(ReducedA3MCEvent, reducedA3MCEvent); //! MC collision -DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate collision mismatches (bit ON means mismatch). Bit 15: indicates negative label +DECLARE_SOA_INDEX_COLUMN(ReA3MCEvent, reA3MCEvent); //! MC collision +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate collision mismatches (bit ON means mismatch). Bit 15: indicates negative label } // namespace reducedeventlabela3 DECLARE_SOA_TABLE(ReducedA3MCEventLabels, "AOD", "REA3MCCOLLBL", //! Table joined to the ReducedEvents table containing the MC index - reducedeventlabela3::ReducedA3MCEventId, reducedeventlabela3::McMask); + reducedeventlabela3::ReA3MCEventId, reducedeventlabela3::McMask); using ReducedA3MCEventLabel = ReducedA3MCEventLabels::iterator; namespace reducedA3track_association { -DECLARE_SOA_INDEX_COLUMN(ReducedA3Event, reducedA3event); //! ReducedEvent index -DECLARE_SOA_INDEX_COLUMN(ReducedA3Track, reducedA3track); //! ReducedTrack index +DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3event); //! ReducedEvent index +DECLARE_SOA_INDEX_COLUMN(ReA3Track, reA3track); //! ReducedTrack index } // namespace reducedA3track_association DECLARE_SOA_TABLE(ReducedA3TracksAssoc, "AOD", "REA3ASSOC", //! Table for reducedtrack-to-reducedcollision association - reducedA3track_association::ReducedA3EventId, - reducedA3track_association::ReducedA3TrackId); + reducedA3track_association::ReA3EventId, + reducedA3track_association::ReA3TrackId); DECLARE_SOA_TABLE(ReducedA3PIDTOF, "AOD", "REA3PIDTOF", upgrade_tof::TOFEventTime, @@ -332,4 +332,4 @@ DECLARE_SOA_TABLE(ReducedA3PIDOT, "AOD", "REA3PIDOT", } // namespace o2::aod -#endif // PWGDQ_DATAMODEL_REDUCEDTABLESALICE3_H_ +#endif // ALICE3_DATAMODEL_REDUCEDTABLESALICE3_H_ diff --git a/ALICE3/TableProducer/CMakeLists.txt b/ALICE3/TableProducer/CMakeLists.txt index b183080d3ab..7011fe5a38f 100644 --- a/ALICE3/TableProducer/CMakeLists.txt +++ b/ALICE3/TableProducer/CMakeLists.txt @@ -62,7 +62,7 @@ o2physics_add_dpl_workflow(alice3-tracking-translator COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(alice3-dq-table-maker - SOURCES alice3-dq-table-maker.cxx + SOURCES alice3DqTableMaker.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::PWGDQCore COMPONENT_NAME Analysis) diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index 4340bf9bc33..1b0a1a4fb6f 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -20,6 +20,7 @@ #include "ALICE3/Core/TrackUtilities.h" #include "ALICE3/DataModel/tracksAlice3.h" +#include #include #include #include @@ -47,13 +48,19 @@ using namespace o2; using namespace o2::framework; -static constexpr int NumDecays = 7; +static constexpr int NumDecays = 13; static constexpr int NumParameters = 1; -static constexpr int DefaultParameters[NumDecays][NumParameters]{{1}, {1}, {1}, {1}, {1}, {1}, {1}}; +static constexpr std::array, NumDecays> DefaultParameters{{{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}}; static const std::vector parameterNames{"enable"}; static const std::vector particleNames{"K0s", "Lambda", "Anti-Lambda", + "SigmaPlus", + "Anti-SigmaPlus", + "SigmaMinus", + "Anti-SigmaMinus", + "Xi0", + "Anti-Xi0", "Xi", "Anti-Xi", "Omega", @@ -62,6 +69,12 @@ static const std::vector particleNames{"K0s", static const std::vector pdgCodes{PDG_t::kK0Short, PDG_t::kLambda0, PDG_t::kLambda0Bar, + PDG_t::kSigmaPlus, + PDG_t::kSigmaBarMinus, + PDG_t::kSigmaMinus, + PDG_t::kSigmaBarPlus, + o2::constants::physics::kXi0, + -o2::constants::physics::kXi0, PDG_t::kXiMinus, PDG_t::kXiPlusBar, PDG_t::kOmegaMinus, @@ -78,13 +91,13 @@ struct OnTheFlyDecayer { Produces tableOTFDecayerBits; o2::upgrade::Decayer decayer; - Service pdgDB; + Service pdgDB{}; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; Configurable seed{"seed", 0, "Set seed for particle decayer"}; Configurable magneticField{"magneticField", 20., "Magnetic field (kG)"}; Configurable> enabledDecays{"enabledDecays", - {DefaultParameters[0], NumDecays, NumParameters, particleNames, parameterNames}, + {DefaultParameters[0].data(), NumDecays, NumParameters, particleNames, parameterNames}, "Enable option for particle to be decayed: 0 - no, 1 - yes"}; std::size_t indexOffset = 0; @@ -99,7 +112,7 @@ struct OnTheFlyDecayer { decayer.setSeed(seed); decayer.setBField(magneticField); for (int i = 0; i < NumDecays; ++i) { - if (enabledDecays->get(particleNames[i].c_str(), "enable")) { + if (enabledDecays->get(particleNames[i].c_str(), "enable") != 0) { LOG(info) << " --- Decay enabled: " << pdgCodes[i]; mEnabledDecays.push_back(pdgCodes[i]); } @@ -146,9 +159,9 @@ struct OnTheFlyDecayer { const float decayRadius = decayer.getDecayRadius(); const float trackVelocity = o2::upgrade::computeParticleVelocity(particle.p(), pdgDB->GetParticle(particle.pdgCode())->Mass()); - const int charge = pdgDB->GetParticle(particle.pdgCode())->Charge() / 3; + const int charge = static_cast(pdgDB->GetParticle(particle.pdgCode())->Charge() / 3); float trackLength{-1.f}; - if (!charge) { + if (charge == 0) { const float dx = particle.vx() - decayer.getSecondaryVertexX(); const float dy = particle.vy() - decayer.getSecondaryVertexY(); const float dz = particle.vz() - decayer.getSecondaryVertexZ(); diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 385226d19fc..45dee932571 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -211,6 +211,7 @@ struct OnTheFlyTracker { struct : ConfigurableGroup { std::string prefix = "fastPrimaryTrackerSettings"; + Configurable fastTrackShortLivedParticles{"fastTrackShortLivedParticles", false, "Use fasttracker for short lived tracks"}; Configurable fastTrackPrimaries{"fastTrackPrimaries", false, "Use fasttracker for primary tracks. Enable with care"}; Configurable minSiliconHits{"minSiliconHits", 4, "minimum number of silicon hits to accept track"}; Configurable applyZacceptance{"applyZacceptance", false, "apply z limits to detector layers or not"}; @@ -348,15 +349,20 @@ struct OnTheFlyTracker { v0candidate thisV0; // Constants static constexpr int kv0Prongs = 2; - static constexpr std::array v0PDGs = {kK0Short, - kLambda0, - kLambda0Bar}; + static constexpr std::array v0PDGs = {PDG_t::kK0Short, + PDG_t::kLambda0, + PDG_t::kLambda0Bar}; - static constexpr std::array longLivedHandledPDGs = {kElectron, - kMuonMinus, - kPiPlus, - kKPlus, - kProton}; + static constexpr std::array longLivedHandledPDGs = {PDG_t::kElectron, + PDG_t::kMuonMinus, + PDG_t::kPiPlus, + PDG_t::kKPlus, + PDG_t::kProton}; + + static constexpr std::array shortLivedHandledPDGs = {PDG_t::kSigmaPlus, + PDG_t::kSigmaMinus, + PDG_t::kXiMinus, + PDG_t::kOmegaMinus}; static constexpr std::array nucleiPDGs = {o2::constants::physics::kDeuteron, o2::constants::physics::kTriton, @@ -760,6 +766,10 @@ struct OnTheFlyTracker { return o2::track::PID::Proton; } else if (std::abs(pdgCode) == PDG_t::kLambda0) { return o2::track::PID::Lambda; + } else if (std::abs(pdgCode) == PDG_t::kSigmaPlus) { + return o2::track::PID::XiMinus; // Close enough + } else if (std::abs(pdgCode) == PDG_t::kSigmaMinus) { + return o2::track::PID::XiMinus; // Close enough } else if (std::abs(pdgCode) == PDG_t::kXiMinus) { return o2::track::PID::XiMinus; } else if (std::abs(pdgCode) == PDG_t::kOmegaMinus) { @@ -1875,12 +1885,14 @@ struct OnTheFlyTracker { const bool isCascadeToDecay = (mcParticle.pdgCode() == kXiMinus) && cascadeDecaySettings.decayXi; const bool isV0ToDecay = std::find(v0PDGs.begin(), v0PDGs.end(), mcParticle.pdgCode()) != v0PDGs.end() && v0DecaySettings.decayV0; - const bool longLivedToBeHandled = std::find(longLivedHandledPDGs.begin(), longLivedHandledPDGs.end(), std::abs(mcParticle.pdgCode())) != longLivedHandledPDGs.end(); + const bool shortLivedToBeHandled = std::find(shortLivedHandledPDGs.begin(), shortLivedHandledPDGs.end(), std::abs(mcParticle.pdgCode())) != shortLivedHandledPDGs.end(); const bool nucleiToBeHandled = std::find(nucleiPDGs.begin(), nucleiPDGs.end(), std::abs(mcParticle.pdgCode())) != nucleiPDGs.end(); const bool pdgsToBeHandled = longLivedToBeHandled || (enableNucleiSmearing && nucleiToBeHandled) || - (isCascadeToDecay) || (isV0ToDecay); + (isCascadeToDecay) || (isV0ToDecay) || + (shortLivedToBeHandled && fastPrimaryTrackerSettings.fastTrackShortLivedParticles); + if (!pdgsToBeHandled) { continue; } @@ -1902,7 +1914,7 @@ struct OnTheFlyTracker { bool reconstructed = true; int nTrkHits = 0; if (enablePrimarySmearing) { - if (fastPrimaryTrackerSettings.fastTrackPrimaries) { + if (fastPrimaryTrackerSettings.fastTrackPrimaries || fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { o2::track::TrackParCov perfectTrackParCov; o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); @@ -2052,8 +2064,10 @@ struct OnTheFlyTracker { // Now that the multiplicity is known, we can process the particles to smear them for (const auto& mcParticle : mcParticles) { const bool longLivedToBeHandled = std::find(longLivedHandledPDGs.begin(), longLivedHandledPDGs.end(), std::abs(mcParticle.pdgCode())) != longLivedHandledPDGs.end(); + const bool shortLivedToBeHandled = std::find(shortLivedHandledPDGs.begin(), shortLivedHandledPDGs.end(), std::abs(mcParticle.pdgCode())) != shortLivedHandledPDGs.end(); const bool nucleiToBeHandled = std::find(nucleiPDGs.begin(), nucleiPDGs.end(), std::abs(mcParticle.pdgCode())) != nucleiPDGs.end(); - const bool pdgsToBeHandled = longLivedToBeHandled || (enableNucleiSmearing && nucleiToBeHandled); + const bool pdgsToBeHandled = longLivedToBeHandled || (enableNucleiSmearing && nucleiToBeHandled) || + (shortLivedToBeHandled && fastPrimaryTrackerSettings.fastTrackShortLivedParticles); o2::upgrade::OTFParticle otfParticle(mcParticle); otfParticle.setBits(mcParticle.decayerBits_raw()); @@ -2099,10 +2113,21 @@ struct OnTheFlyTracker { bool reconstructed = false; int nTrkHits = 0; const bool isSecondary = !otfParticle.isPrimary() && otfParticle.checkBit(o2::upgrade::DecayerBits::ProducedByDecayer) && otfParticle.isAlive(); - if (enablePrimarySmearing && otfParticle.isPrimary()) { + if (enablePrimarySmearing && longLivedToBeHandled && otfParticle.isPrimary()) { o2::upgrade::convertMCParticleToO2Track(mcParticle, trackParCov, pdgDB); 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); + perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); + computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); + nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); + if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { + reconstructed = false; + } else { + reconstructed = true; + } } else if (enableSecondarySmearing && isSecondary) { o2::track::TrackParCov perfectTrackParCov; o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); diff --git a/ALICE3/TableProducer/alice3-dq-table-maker.cxx b/ALICE3/TableProducer/alice3DqTableMaker.cxx similarity index 81% rename from ALICE3/TableProducer/alice3-dq-table-maker.cxx rename to ALICE3/TableProducer/alice3DqTableMaker.cxx index a6f36151732..abb2556e583 100644 --- a/ALICE3/TableProducer/alice3-dq-table-maker.cxx +++ b/ALICE3/TableProducer/alice3DqTableMaker.cxx @@ -8,11 +8,10 @@ // 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. -// -// Contact: Ionut Cristian Arsene iarsene@cern.ch, i.c.arsene@fys.uio.no -// Alexander Tiekoetter (alexander.tiekoetter@cern.ch) -/// \file alice3-dq-table-maker.cxx -/// \brief DQ table maker for ALICE 3 +/// \author Ionut Cristian Arsene , Oslo +/// \author Alexander Tiekoetter , Muenster +/// \brief Skimming Task for DQ Table Maker +/// \file alice3DqTableMaker.cxx #include "PWGDQ/Core/AnalysisCompositeCut.h" #include "PWGDQ/Core/AnalysisCut.h" @@ -22,10 +21,10 @@ #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" #include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/DataModel/ReducedTablesAlice3.h" #include "ALICE3/DataModel/OTFRICH.h" #include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/ReducedTablesAlice3.h" #include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/CCDB/EventSelectionParams.h" @@ -67,23 +66,21 @@ using MyBarrelTracks = soa::Join; using MyEventsMC = aod::McCollisions; -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::Collision; -constexpr static uint32_t gkEventMcFillMap = VarManager::ObjTypes::CollisionMC; +constexpr static uint32_t GkEventFillMap = VarManager::ObjTypes::Collision; +constexpr static uint32_t GkEventMcFillMap = VarManager::ObjTypes::CollisionMC; -constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; +constexpr static uint32_t GkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; -struct Alice3DQTableMaker { +struct Alice3DqTableMaker { - Produces eventMC; - Produces trackMC; + Produces eventMC; + Produces trackMC; - Produces event; + Produces event; Produces eventVtxCov; - Produces eventInfo; Produces eventMClabels; - Produces trackBarrelInfo; - Produces trackBasic; + Produces trackBasic; Produces trackBarrel; Produces trackBarrelCov; Produces trackBarrelAssoc; @@ -96,33 +93,32 @@ struct Alice3DQTableMaker { OutputObj fOutputList{"output"}; OutputObj fStatsList{"Statistics"}; //! skimming statistics - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; // Event and track AnalysisCut configurables struct : ConfigurableGroup { - Configurable fConfigEventCuts{"cfgEventCuts", "", "Event selection"}; - Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "", "barrel track cut"}; - Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event selection in JSON format"}; - Configurable fConfigTrackCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + Configurable cfgEventCuts{"cfgEventCuts", "", "Event selection"}; + Configurable cfgBarrelTrackCuts{"cfgBarrelTrackCuts", "", "barrel track cut"}; + Configurable cfgEventCutsJSON{"cfgEventCutsJSON", "", "Additional event selection in JSON format"}; + Configurable cfgBarrelTrackCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; } fConfigCuts; // MC signals to be skimmed - Configurable fConfigMCSignals{"cfgMCsignals", "", "Comma separated list of MC signals"}; - Configurable fConfigMCSignalsJSON{"cfgMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + Configurable cfgMCsignals{"cfgMCsignals", "", "Comma separated list of MC signals"}; + Configurable cfgMCsignalsJSON{"cfgMCsignalsJSON", "", "Additional list of MC signals via JSON"}; // Steer QA output struct : ConfigurableGroup { - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigDetailedQA{"cfgDetailedQA", false, "If true, include more QA histograms (BeforeCuts classes)"}; - Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddMCTruthHistogram{"cfgAddMCTruthHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable cfgQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable cfgDetailedQA{"cfgDetailedQA", false, "If true, include more QA histograms (BeforeCuts classes)"}; + Configurable cfgAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable cfgAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable cfgAddMCTruthHistogram{"cfgAddMCTruthHistogram", "", "Comma separated list of histograms"}; + Configurable cfgAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; } fConfigHistOutput; - AnalysisCompositeCut* fEventCut; //! Event selection cut + AnalysisCompositeCut* fEventCut = nullptr; //! Event selection cut std::vector fTrackCuts; //! Barrel track cuts - std::vector fMuonCuts; //! Muon track cuts bool fDoDetailedQA = false; @@ -140,15 +136,15 @@ struct Alice3DQTableMaker { if (!isProcessSkimmingEnabled) LOG(fatal) << "No process function was enabled ALICE 3 TableMaker"; - VarManager::SetDefaultVarNames(); // Important that this is called before DefineCuts() !!! + VarManager::SetDefaultVarNames(); // Important that this is called before defineCuts() !!! - DefineCuts(); + defineCuts(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - if (fConfigHistOutput.fConfigQA && fConfigHistOutput.fConfigDetailedQA) { + if (fConfigHistOutput.cfgQA && fConfigHistOutput.cfgDetailedQA) { fDoDetailedQA = true; } @@ -158,7 +154,7 @@ struct Alice3DQTableMaker { histClasses += "Event_BeforeCuts;"; } - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { histClasses += "Event_AfterCuts;"; histClasses += "Event_MCTruth;"; } @@ -168,14 +164,14 @@ struct Alice3DQTableMaker { histClasses += "TrackBarrel_BeforeCuts;"; } - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { for (const auto& cut : fTrackCuts) { histClasses += Form("TrackBarrel_%s;", cut->GetName()); } } } - TString configNamesStr = fConfigMCSignals.value; + TString configNamesStr = cfgMCsignals.value; std::unique_ptr objArray(configNamesStr.Tokenize(",")); if (objArray->GetEntries() > 0) { @@ -187,7 +183,7 @@ struct Alice3DQTableMaker { } } - TString addMCSignalsStr = fConfigMCSignalsJSON.value; + TString addMCSignalsStr = cfgMCsignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); @@ -200,7 +196,7 @@ struct Alice3DQTableMaker { } for (const auto& mcIt : fMCSignals) { - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { histClasses += Form("MCTruth_%s;", mcIt->GetName()); } if (fDoDetailedQA) { @@ -212,10 +208,10 @@ struct Alice3DQTableMaker { } } - DefineHistograms(histClasses); + defineHistograms(histClasses); - TString addHistsStr = fConfigHistOutput.fConfigAddJSONHistograms.value; - if (fConfigHistOutput.fConfigQA && addHistsStr != "") { + TString addHistsStr = fConfigHistOutput.cfgAddJSONHistograms.value; + if (fConfigHistOutput.cfgQA && addHistsStr != "") { dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); } @@ -223,13 +219,13 @@ struct Alice3DQTableMaker { fOutputList.setObject(fHistMan->GetMainHistogramList()); } - void DefineCuts() + void defineCuts() { fEventCut = new AnalysisCompositeCut(true); - TString eventCutStr = fConfigCuts.fConfigEventCuts.value; + TString eventCutStr = fConfigCuts.cfgEventCuts.value; fEventCut->AddCut(dqcuts::GetAnalysisCut(eventCutStr.Data())); - TString addEvCutsStr = fConfigCuts.fConfigEventCutsJSON.value; + TString addEvCutsStr = fConfigCuts.cfgEventCutsJSON.value; if (addEvCutsStr != "") { std::vector addEvCuts = dqcuts::GetCutsFromJSON(addEvCutsStr.Data()); for (const auto& cutIt : addEvCuts) { @@ -238,7 +234,7 @@ struct Alice3DQTableMaker { } // Barrel track cuts - TString cutNamesStr = fConfigCuts.fConfigTrackCuts.value; + TString cutNamesStr = fConfigCuts.cfgBarrelTrackCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -246,7 +242,7 @@ struct Alice3DQTableMaker { } } // Additional Barrel track cuts via JSON - TString addTrackCutsStr = fConfigCuts.fConfigTrackCutsJSON.value; + TString addTrackCutsStr = fConfigCuts.cfgBarrelTrackCutsJSON.value; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (const auto& t : addTrackCuts) { @@ -257,71 +253,71 @@ struct Alice3DQTableMaker { VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill } - void DefineHistograms(TString histClasses) + void defineHistograms(TString histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (int iclass = 0; iclass < objArray->GetEntries(); ++iclass) { TString classStr = objArray->At(iclass)->GetName(); - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { fHistMan->AddHistClass(classStr.Data()); } - TString histEventName = fConfigHistOutput.fConfigAddEventHistogram.value; + TString histEventName = fConfigHistOutput.cfgAddEventHistogram.value; if (classStr.Contains("Event")) { - if (fConfigHistOutput.fConfigQA && !classStr.Contains("MCTruth")) { + if (fConfigHistOutput.cfgQA && !classStr.Contains("MCTruth")) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", histEventName); } else { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", "generator"); } } - TString histTrackName = fConfigHistOutput.fConfigAddTrackHistogram.value; + TString histTrackName = fConfigHistOutput.cfgAddTrackHistogram.value; if (classStr.Contains("Track")) { - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); } } - TString histMCTruthName = fConfigHistOutput.fConfigAddMCTruthHistogram.value; + TString histMCTruthName = fConfigHistOutput.cfgAddMCTruthHistogram.value; if (classStr.Contains("MCTruth") && !classStr.Contains("Event")) { - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "mctruth_track", histMCTruthName); } } } - // create statistics histograms (event, tracks, muons, MCsignals) + // create statistics histograms (event, tracks, MCsignals) fStatsList.setObject(new TList()); fStatsList->SetOwner(true); std::vector eventLabels{"Collisions before filtering", "Before cuts", "After cuts"}; TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, o2::aod::evsel::kNsel + 1, -0.5, (float)o2::aod::evsel::kNsel + 0.5); - int ib = 1; - for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { - histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); + int ibX = 1; + for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ibX++) { + histEvents->GetXaxis()->SetBinLabel(ibX, (*label).Data()); } - for (int ib = 1; ib <= o2::aod::evsel::kNsel; ib++) { - histEvents->GetYaxis()->SetBinLabel(ib, o2::aod::evsel::selectionLabels[ib - 1]); + for (int ibY = 1; ibY <= o2::aod::evsel::kNsel; ibY++) { + histEvents->GetYaxis()->SetBinLabel(ibY, o2::aod::evsel::selectionLabels[ibY - 1]); } histEvents->GetYaxis()->SetBinLabel(o2::aod::evsel::kNsel + 1, "Total"); 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); - ib = 1; - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { - histTracks->GetXaxis()->SetBinLabel(ib, (*cut)->GetName()); + ibX = 1; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ibX++) { + histTracks->GetXaxis()->SetBinLabel(ibX, (*cut)->GetName()); } - constexpr int nV0Tags = 5; - const char* v0TagNames[nV0Tags] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; - for (int ib = 0; ib < nV0Tags; ib++) { - histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); + constexpr int NV0Tags = 5; + const char* v0TagNames[NV0Tags] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; + for (int ibY = 0; ibY < NV0Tags; ibY++) { + histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ibY, v0TagNames[ibY]); } fStatsList->Add(histTracks); TH1I* histMCsignals = new TH1I("MCsignals", "MC signals", fMCSignals.size() + 1, -0.5, fMCSignals.size() - 0.5 + 1.0); - ib = 1; - for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ib++) { - histMCsignals->GetXaxis()->SetBinLabel(ib, (*signal)->GetName()); + ibX = 1; + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ibX++) { + histMCsignals->GetXaxis()->SetBinLabel(ibX, (*signal)->GetName()); } histMCsignals->GetXaxis()->SetBinLabel(fMCSignals.size() + 1, "Others (matched to reco tracks)"); fStatsList->Add(histMCsignals); @@ -337,7 +333,7 @@ struct Alice3DQTableMaker { VarManager::ResetValues(0, VarManager::kNVars); for (const auto& mcCollision : mcCollisions) { - VarManager::FillEventAlice3(mcCollision); + VarManager::FillEventAlice3(mcCollision); fHistMan->FillHistClass("Event_MCTruth", VarManager::fgValues); @@ -367,8 +363,8 @@ struct Alice3DQTableMaker { for (const auto& sig : fMCSignals) { bool checked = false; if constexpr (soa::is_soa_filtered_v) { - auto mctrack_raw = mcTracks.rawIteratorAt(mctrack.globalIndex()); - checked = sig->CheckSignal(true, mctrack_raw); + auto mcTrackRaw = mcTracks.rawIteratorAt(mctrack.globalIndex()); + checked = sig->CheckSignal(true, mcTrackRaw); } else { checked = sig->CheckSignal(true, mctrack); } @@ -384,19 +380,22 @@ struct Alice3DQTableMaker { } // If this MC track was not already added to the map, add it now - if (fLabelsMap.find(mctrack.globalIndex()) == fLabelsMap.end()) { - fLabelsMap[mctrack.globalIndex()] = trackCounter; - fLabelsMapReversed[trackCounter] = mctrack.globalIndex(); - fMCFlags[mctrack.globalIndex()] = mcflags; - trackCounter++; + const auto mcTrackIndex = mctrack.globalIndex(); + const bool inserted = fLabelsMap.try_emplace(mcTrackIndex, trackCounter).second; + + if (inserted) { + fLabelsMapReversed.try_emplace(trackCounter, mcTrackIndex); + fMCFlags.try_emplace(mcTrackIndex, mcflags); + ++trackCounter; // fill histograms for each of the signals, if found - if (fConfigHistOutput.fConfigQA) { + if (fConfigHistOutput.cfgQA) { VarManager::FillTrackMC(mcTracks, mctrack); auto mcCollision = mctrack.template mcCollision_as(); - VarManager::FillEvent(mcCollision); + VarManager::FillEvent(mcCollision); + int j = 0; - for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, j++) { + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); ++signal, ++j) { if (mcflags & (static_cast(1) << j)) { fHistMan->FillHistClass(Form("MCTruth_%s", (*signal)->GetName()), VarManager::fgValues); } @@ -418,11 +417,11 @@ struct Alice3DQTableMaker { (reinterpret_cast(fStatsList->At(0)))->Fill(1.0, static_cast(o2::aod::evsel::kNsel)); VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - VarManager::FillEventAlice3(collision); // extract event information and place it in the fValues array + VarManager::FillEventAlice3(collision); // extract event information and place it in the fValues array if (collision.has_mcCollision()) { auto mcCollision = collision.template mcCollision_as(); - VarManager::FillEventAlice3(mcCollision); + VarManager::FillEventAlice3(mcCollision); } if (fDoDetailedQA) { @@ -444,7 +443,6 @@ struct Alice3DQTableMaker { eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); eventMClabels(collision.mcCollisionId(), collision.mcMask()); - eventInfo(collision.globalIndex()); // add an element for this collision into the map fCollIndexMap[collision.globalIndex()] = event.lastIndex(); @@ -478,20 +476,20 @@ struct Alice3DQTableMaker { trackTempFilterMap = static_cast(0); // Compute track quantities and fill histograms - VarManager::FillTrackAlice3(track); + VarManager::FillTrackAlice3(track); if (fDoDetailedQA) { fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); } - int i = 0; - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { + int n = 0; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, n++) { if ((*cut)->IsSelected(VarManager::fgValues)) { - trackTempFilterMap |= (static_cast(1) << i); - if (fConfigHistOutput.fConfigQA) { + trackTempFilterMap |= (static_cast(1) << n); + if (fConfigHistOutput.cfgQA) { fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut)->GetName()), VarManager::fgValues); } - (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(n)); } } if (!trackTempFilterMap) { @@ -512,9 +510,6 @@ struct Alice3DQTableMaker { // In the case of Run2-like analysis, there will be no associations, so this ID will be the one originally assigned in the AO2Ds (updated for the skims) uint32_t reducedEventIdx = fCollIndexMap[track.collisionId()]; - // NOTE: trackBarrelInfo stores the index of the collision as in AO2D (for use in some cases where the analysis on skims is done - // in workflows where the original AO2Ds are also present) - // trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); trackBasic(reducedEventIdx, trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), 0); trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), @@ -522,13 +517,13 @@ struct Alice3DQTableMaker { track.isReconstructed(), track.nSiliconHits(), track.nTPCHits(), track.length(), track.dcaXY(), track.dcaZ()); - if constexpr (static_cast(gkTrackFillMapWithCov & VarManager::ObjTypes::TrackCov)) { + if constexpr (static_cast(GkTrackFillMapWithCov & VarManager::ObjTypes::TrackCov)) { trackBarrelCov(track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); } - if constexpr (static_cast(gkTrackFillMapWithCov & VarManager::ObjTypes::TrackPID)) { + if constexpr (static_cast(GkTrackFillMapWithCov & VarManager::ObjTypes::TrackPID)) { trackPIDTOF(track.tofEventTime(), track.tofEventTimeErr(), track.nSigmaElectronInnerTOF(), track.nSigmaMuonInnerTOF(), track.nSigmaPionInnerTOF(), @@ -612,7 +607,6 @@ struct Alice3DQTableMaker { event.reserve(collisions.size()); eventVtxCov.reserve(collisions.size()); eventMClabels.reserve(collisions.size()); - eventInfo.reserve(collisions.size()); skimCollisions(collisions); @@ -621,7 +615,7 @@ struct Alice3DQTableMaker { skimMCParticles(mcParticles, mcCollisions); - if constexpr (static_cast(gkTrackFillMapWithCov)) { + if constexpr (static_cast(GkTrackFillMapWithCov)) { fTrackIndexMap.clear(); trackBasic.reserve(tracksBarrel.size()); trackBarrel.reserve(tracksBarrel.size()); @@ -638,7 +632,7 @@ struct Alice3DQTableMaker { for (auto const& [origIdx, skimIdx] : fCollIndexMap) { auto collision = collisions.rawIteratorAt(origIdx); - if constexpr (static_cast(gkTrackFillMapWithCov)) { + if constexpr (static_cast(GkTrackFillMapWithCov)) { auto groupedTrackIndices = trackAssocs.sliceBy(trackIndicesPerCollision, origIdx); skimTracks(collision, tracksBarrel, groupedTrackIndices, mcParticles); @@ -712,11 +706,11 @@ struct Alice3DQTableMaker { fullSkimming(collisions, tracksBarrel, trackAssocs, mcCollisions, mcParticles); } - PROCESS_SWITCH(Alice3DQTableMaker, processSkimming, "Build DQ skimmed data model for ALICE3", true); + PROCESS_SWITCH(Alice3DqTableMaker, processSkimming, "Build DQ skimmed data model for ALICE3", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/ALICE3/TableProducer/alice3MulticharmFinder.cxx b/ALICE3/TableProducer/alice3MulticharmFinder.cxx index 65f4393dcf2..ff589f85a15 100644 --- a/ALICE3/TableProducer/alice3MulticharmFinder.cxx +++ b/ALICE3/TableProducer/alice3MulticharmFinder.cxx @@ -13,9 +13,9 @@ /// \brief produces table of xicc candidates /// \author Jesper Karlsson Gumprecht -// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+* // Decay finder task for ALICE 3 -// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+* // // Uses specific ALICE 3 PID and performance for studying // HF decays. Work in progress: use at your own risk! @@ -69,13 +69,6 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -// simple checkers -// #define biton(var, nbit) ((var) |= (static_cast(1) << (nbit))) -// #define bitoff(var, nbit) ((var) &= ~(static_cast(1) << (nbit))) //((a) &= ~(1ULL<<(b))) -#define BIT_CHECK(var, nbit) ((var) & (static_cast(1) << (nbit))) -#define GET_HIST(type, name) std::get>(histPointers[name]) -#define INSERT_HIST(name, ...) histPointers[name] = histos.add((name).c_str(), __VA_ARGS__); - using Alice3Tracks = soa::Join; using Alice3Collision = soa::Join::iterator; using FullCascadeCandidates = soa::Join; @@ -108,12 +101,24 @@ struct Alice3MulticharmFinder { Configurable doDCAplots{"doDCAplots", true, "do daughter prong DCA plots for D mesons"}; Configurable mcSameMotherCheck{"mcSameMotherCheck", true, "check if tracks come from the same MC mother"}; + Configurable posMinDCAxy{"posMinDCAxy", 0.005, "min dcaxy for positive"}; + Configurable negMinDCAxy{"negMinDCAxy", 0.005, "min dcaxy for negative"}; + Configurable bachMinDCAxy{"bachMinDCAxy", 0.005, "min dcaxy for bachelor"}; + + Configurable laMinCosPA{"laMinCosPA", 0.998, "Minimum cos(PA)"}; + Configurable laMinDecayRadius{"laMinDecayRadius", 0.5, "Minimum R2D for la decay (cm)"}; + Configurable laMassWindow{"laMassWindow", 0.012, "Mass window around La peak (GeV/c^2)"}; + Configurable laMaxDauDCA{"laMaxDauDCA", 1, "DCA between Xi daughters (cm)"}; + Configurable xiMinConstDCAxy{"xiMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable xiMinConstDCAz{"xiMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable xiMinPtDepDCAxy{"xiMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; Configurable xiMinPtDepDCAz{"xiMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; Configurable xiMinDecayRadius{"xiMinDecayRadius", 0.5, "Minimum R2D for XiC decay (cm)"}; - Configurable xiMassWindow{"xiMassWindow", 0.005, "Mass window around Xi peak (GeV/c)"}; + Configurable xiMassWindow{"xiMassWindow", 0.005, "Mass window around Xi peak (GeV/c^2)"}; + Configurable xiMaxDauDCA{"xiMaxDauDCA", 1, "DCA between Xi daughters (cm)"}; + Configurable xiMaxNormalizedDecayLength{"xiMaxNormalizedDecayLength", 5, "Max cascade nomralized decay length (ctau/)"}; + Configurable xiMinCosPA{"xiMinCosPA", 0.980000019, "Minimum cos(PA)"}; Configurable picMinConstDCAxy{"picMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable picMinConstDCAz{"picMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; @@ -128,7 +133,7 @@ struct Alice3MulticharmFinder { Configurable xicMinDecayDistanceFromPV{"xicMinDecayDistanceFromPV", -1, "Minimum distance for XiC decay from PV (cm)"}; Configurable xicMinProperLength{"xicMinProperLength", 0.002, "Minimum proper length for XiC decay (cm)"}; Configurable xicMaxProperLength{"xicMaxProperLength", 0.1, "Minimum proper length for XiC decay (cm)"}; - Configurable xicMassWindow{"xicMassWindow", 0.012, "Mass window around XiC peak (GeV/c)"}; + Configurable xicMassWindow{"xicMassWindow", 0.012, "Mass window around XiC peak (GeV/c^2)"}; Configurable piccMinConstDCAxy{"piccMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable piccMinConstDCAz{"piccMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; @@ -220,6 +225,24 @@ struct Alice3MulticharmFinder { std::array parentTrackCovMatrix{}; } thisXiccCandidate; + template + std::shared_ptr& hist(const std::string& name) + { + return std::get>(histPointers[histPath + name]); + } + + template + void insertHist(const std::string& name, const std::string& title, HistType type, const std::vector& axes) + { + auto fullName = histPath + name; + histPointers[fullName] = histos.add(fullName.c_str(), title.c_str(), type, axes); + } + + bool bitCheck(uint32_t var, uint32_t nbit) + { + return (var & (static_cast(1) << nbit)) != 0; + } + template bool buildDecayCandidateTwoBody(TTrackType const& t0, TTrackType const& t1, float mass0, float mass1) { @@ -487,9 +510,9 @@ struct Alice3MulticharmFinder { hFitter3StatusCode->GetXaxis()->SetBinLabel(14, "FailCloserAlt"); // alternative PCA is closer hFitter3StatusCode->GetXaxis()->SetBinLabel(15, "NStatusesDefined"); - INSERT_HIST(std::string("h2dGenXi"), "h2dGenXi", {kTH2D, {{axisPt, axisEta}}}); - INSERT_HIST(std::string("h2dGenXiC"), "h2dGenXiC", {kTH2D, {{axisPt, axisEta}}}); - INSERT_HIST(std::string("h2dGenXiCC"), "h2dGenXiCC", {kTH2D, {{axisPt, axisEta}}}); + histos.add("h2dGenXi", "h2dGenXi", kTH2D, {{axisPt, axisEta}}); + histos.add("h2dGenXiC", "h2dGenXiC", kTH2D, {{axisPt, axisEta}}); + histos.add("h2dGenXiCC", "h2dGenXiCC", kTH2D, {{axisPt, axisEta}}); } void initDetectorConfiguration(const int icfg) @@ -499,80 +522,72 @@ struct Alice3MulticharmFinder { } savedConfigs.push_back(icfg); + insertHist("hCharmBuilding", "hCharmBuilding", kTH1D, {{10, -0.5, 9.5f}}); + insertHist("hMultiCharmBuilding", "hMultiCharmBuilding", kTH1D, {{10, -0.5, 9.5f}}); - // This histogram bookkeeps the attempts at DCA minimization and their eventual - // failure rates. - // --- 0: attempt XiC, 1: success XiC - // --- 2: attempt XiCC, 3: success XiCC - INSERT_HIST(histPath + "hCharmBuilding", "hCharmBuilding", {kTH1D, {{10, -0.5, 9.5f}}}); - INSERT_HIST(histPath + "hMultiCharmBuilding", "hMultiCharmBuilding", {kTH1D, {{10, -0.5, 9.5f}}}); - - INSERT_HIST(histPath + "hMassXi", "hMassXi", {kTH1D, {{axisXiMass}}}); - INSERT_HIST(histPath + "hMassXiC", "hMassXiC", {kTH1D, {{axisXiCMass}}}); + insertHist("hMassXi", "hMassXi", kTH1D, {{axisXiMass}}); + insertHist("hMassXiC", "hMassXiC", kTH1D, {{axisXiCMass}}); - INSERT_HIST(histPath + "hEtaXiCC", "hEtaXiCC", {kTH1D, {{axisEta}}}); - INSERT_HIST(histPath + "hPtXiCC", "hPtXiCC", {kTH1D, {{axisPt}}}); - INSERT_HIST(histPath + "h3dMassXiCC", "h3dMassXiCC", {kTH3D, {{axisPt, axisEta, axisXiCCMass}}}); + insertHist("hEtaXiCC", "hEtaXiCC", kTH1D, {{axisEta}}); + insertHist("hPtXiCC", "hPtXiCC", kTH1D, {{axisPt}}); + insertHist("h3dMassXiCC", "h3dMassXiCC", kTH3D, {{axisPt, axisEta, axisXiCCMass}}); - INSERT_HIST(histPath + "hDCAXiCDaughters", "hDCAXiCDaughters", {kTH1D, {{axisDCAXiCDaughters}}}); - INSERT_HIST(histPath + "hDCAXiCCDaughters", "hDCAXiCCDaughters", {kTH1D, {{axisDCAXiCCDaughters}}}); - INSERT_HIST(histPath + "hDCAxyXi", "hDCAxyXi", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hDCAzXi", "hDCAzXi", {kTH1D, {{axisDCA}}}); + insertHist("hDCAXiCDaughters", "hDCAXiCDaughters", kTH1D, {{axisDCAXiCDaughters}}); + insertHist("hDCAXiCCDaughters", "hDCAXiCCDaughters", kTH1D, {{axisDCAXiCCDaughters}}); + insertHist("hDCAxyXi", "hDCAxyXi", kTH1D, {{axisDCA}}); + insertHist("hDCAzXi", "hDCAzXi", kTH1D, {{axisDCA}}); - INSERT_HIST(histPath + "hDCAxyXiC", "hDCAxyXiC", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hDCAzXiC", "hDCAzXiC", {kTH1D, {{axisDCA}}}); + insertHist("hDCAxyXiC", "hDCAxyXiC", kTH1D, {{axisDCA}}); + insertHist("hDCAzXiC", "hDCAzXiC", kTH1D, {{axisDCA}}); - INSERT_HIST(histPath + "hDCAxyXiCC", "hDCAxyXiCC", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hDCAzXiCC", "hDCAzXiCC", {kTH1D, {{axisDCA}}}); + insertHist("hDCAxyXiCC", "hDCAxyXiCC", kTH1D, {{axisDCA}}); + insertHist("hDCAzXiCC", "hDCAzXiCC", kTH1D, {{axisDCA}}); - INSERT_HIST(histPath + "hPi1cPt", "hPi1cPt", {kTH1D, {{axisPt}}}); - INSERT_HIST(histPath + "hPi2cPt", "hPi2cPt", {kTH1D, {{axisPt}}}); - INSERT_HIST(histPath + "hPiccPt", "hPiccPt", {kTH1D, {{axisPt}}}); + insertHist("hPi1cPt", "hPi1cPt", kTH1D, {{axisPt}}); + insertHist("hPi2cPt", "hPi2cPt", kTH1D, {{axisPt}}); + insertHist("hPiccPt", "hPiccPt", kTH1D, {{axisPt}}); - INSERT_HIST(histPath + "hPi1cDCAxy", "hPi1cDCAxy", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hPi1cDCAz", "hPi1cDCAz", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hPi2cDCAxy", "hPi2cDCAxy", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hPi2cDCAz", "hPi2cDCAz", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hPiccDCAxy", "hPiccDCAxy", {kTH1D, {{axisDCA}}}); - INSERT_HIST(histPath + "hPiccDCAz", "hPiccDCAz", {kTH1D, {{axisDCA}}}); + insertHist("hPi1cDCAxy", "hPi1cDCAxy", kTH1D, {{axisDCA}}); + insertHist("hPi1cDCAz", "hPi1cDCAz", kTH1D, {{axisDCA}}); + insertHist("hPi2cDCAxy", "hPi2cDCAxy", kTH1D, {{axisDCA}}); + insertHist("hPi2cDCAz", "hPi2cDCAz", kTH1D, {{axisDCA}}); + insertHist("hPiccDCAxy", "hPiccDCAxy", kTH1D, {{axisDCA}}); + insertHist("hPiccDCAz", "hPiccDCAz", kTH1D, {{axisDCA}}); - INSERT_HIST(histPath + "hMinXiDecayRadius", "hMinXiDecayRadius", {kTH1D, {{axisRadius2DXi}}}); - INSERT_HIST(histPath + "hMinXiCDecayRadius", "hMinXiCDecayRadius", {kTH1D, {{axisRadius}}}); - INSERT_HIST(histPath + "hMinXiCCDecayRadius", "hMinXiCCDecayRadius", {kTH1D, {{axisRadius}}}); + insertHist("hMinXiDecayRadius", "hMinXiDecayRadius", kTH1D, {{axisRadius2DXi}}); + insertHist("hMinXiCDecayRadius", "hMinXiCDecayRadius", kTH1D, {{axisRadius}}); + insertHist("hMinXiCCDecayRadius", "hMinXiCCDecayRadius", kTH1D, {{axisRadius}}); - INSERT_HIST(histPath + "hMinXicDecayDistanceFromPV", "hMinXicDecayDistanceFromPV", {kTH1D, {{axisDecayLength}}}); - INSERT_HIST(histPath + "hProperLengthXiC", "hProperLengthXiC", {kTH1D, {{axisDecayLength}}}); - INSERT_HIST(histPath + "hProperLengthXiCC", "hProperLengthXiCC", {kTH1D, {{axisDecayLength}}}); + insertHist("hMinXicDecayDistanceFromPV", "hMinXicDecayDistanceFromPV", kTH1D, {{axisDecayLength}}); + insertHist("hProperLengthXiC", "hProperLengthXiC", kTH1D, {{axisDecayLength}}); + insertHist("hProperLengthXiCC", "hProperLengthXiCC", kTH1D, {{axisDecayLength}}); - INSERT_HIST(histPath + "hInnerTOFTrackTimeRecoPi1c", "hInnerTOFTrackTimeRecoPi1c", {kTH1D, {{axisTOFTrack}}}); - INSERT_HIST(histPath + "hInnerTOFTrackTimeRecoPi2c", "hInnerTOFTrackTimeRecoPi2c", {kTH1D, {{axisTOFTrack}}}); - INSERT_HIST(histPath + "hInnerTOFTrackTimeRecoPicc", "hInnerTOFTrackTimeRecoPicc", {kTH1D, {{axisTOFTrack}}}); + insertHist("hInnerTOFTrackTimeRecoPi1c", "hInnerTOFTrackTimeRecoPi1c", kTH1D, {{axisTOFTrack}}); + insertHist("hInnerTOFTrackTimeRecoPi2c", "hInnerTOFTrackTimeRecoPi2c", kTH1D, {{axisTOFTrack}}); + insertHist("hInnerTOFTrackTimeRecoPicc", "hInnerTOFTrackTimeRecoPicc", kTH1D, {{axisTOFTrack}}); - INSERT_HIST(histPath + "hOuterTOFTrackTimeRecoPi1c", "hOuterTOFTrackTimeRecoPi1c", {kTH1D, {{axisTOFTrack}}}); - INSERT_HIST(histPath + "hOuterTOFTrackTimeRecoPi2c", "hOuterTOFTrackTimeRecoPi2c", {kTH1D, {{axisTOFTrack}}}); - INSERT_HIST(histPath + "hOuterTOFTrackTimeRecoPicc", "hOuterTOFTrackTimeRecoPicc", {kTH1D, {{axisTOFTrack}}}); + insertHist("hOuterTOFTrackTimeRecoPi1c", "hOuterTOFTrackTimeRecoPi1c", kTH1D, {{axisTOFTrack}}); + insertHist("hOuterTOFTrackTimeRecoPi2c", "hOuterTOFTrackTimeRecoPi2c", kTH1D, {{axisTOFTrack}}); + insertHist("hOuterTOFTrackTimeRecoPicc", "hOuterTOFTrackTimeRecoPicc", kTH1D, {{axisTOFTrack}}); - INSERT_HIST(histPath + "hXiRadiusVsXicRadius", "hXiRadiusVsXicRadius", {kTH2D, {{axisRadius2D, axisRadius2D}}}); - INSERT_HIST(histPath + "hXicRadiusVsXiccRadius", "hXicRadiusVsXiccRadius", {kTH2D, {{axisRadius2D, axisRadius2D}}}); + insertHist("hXiRadiusVsXicRadius", "hXiRadiusVsXicRadius", kTH2D, {{axisRadius2D, axisRadius2D}}); + insertHist("hXicRadiusVsXiccRadius", "hXicRadiusVsXiccRadius", kTH2D, {{axisRadius2D, axisRadius2D}}); - INSERT_HIST(histPath + "hMassXiCC", "hMassXiCC", {kTH1D, {{axisXiCCMass}}}); - INSERT_HIST(histPath + "hNCollisions", "hNCollisions", {kTH1D, {{2, 0.5, 2.5}}}); - INSERT_HIST(histPath + "hNTracks", "hNTracks", {kTH1D, {{20000, 0, 20000}}}); + insertHist("hMassXiCC", "hMassXiCC", kTH1D, {{axisXiCCMass}}); + insertHist("hNCollisions", "hNCollisions", kTH1D, {{2, 0.5, 2.5}}); + insertHist("hNTracks", "hNTracks", kTH1D, {{20000, 0, 20000}}); - // These histograms bookkeep the exact number of combinations attempted - // CombinationsXiC: triplets Xi-pi-pi considered per Xi - // CombinationsXiCC: doublets XiC-pi considered per XiC - INSERT_HIST(histPath + "hCombinationsXiC", "hCombinationsXiC", {kTH1D, {{axisNConsidered}}}); - INSERT_HIST(histPath + "hCombinationsXiCC", "hCombinationsXiCC", {kTH1D, {{axisNConsidered}}}); + insertHist("hCombinationsXiC", "hCombinationsXiC", kTH1D, {{axisNConsidered}}); + insertHist("hCombinationsXiCC", "hCombinationsXiCC", kTH1D, {{axisNConsidered}}); if (doDCAplots) { - INSERT_HIST(histPath + "h2dDCAxyVsPtXiFromXiC", "h2dDCAxyVsPtXiFromXiC", {kTH2D, {{axisPt, axisDCA2D}}}); - INSERT_HIST(histPath + "h2dDCAxyVsPtPiFromXiC", "h2dDCAxyVsPtPiFromXiC", {kTH2D, {{axisPt, axisDCA2D}}}); - INSERT_HIST(histPath + "h2dDCAxyVsPtPiFromXiCC", "h2dDCAxyVsPtPiFromXiCC", {kTH2D, {{axisPt, axisDCA2D}}}); + insertHist("h2dDCAxyVsPtXiFromXiC", "h2dDCAxyVsPtXiFromXiC", kTH2D, {{axisPt, axisDCA2D}}); + insertHist("h2dDCAxyVsPtPiFromXiC", "h2dDCAxyVsPtPiFromXiC", kTH2D, {{axisPt, axisDCA2D}}); + insertHist("h2dDCAxyVsPtPiFromXiCC", "h2dDCAxyVsPtPiFromXiCC", kTH2D, {{axisPt, axisDCA2D}}); - INSERT_HIST(histPath + "h2dDCAzVsPtXiFromXiC", "h2dDCAzVsPtXiFromXiC", {kTH2D, {{axisPt, axisDCA2D}}}); - INSERT_HIST(histPath + "h2dDCAzVsPtPiFromXiC", "h2dDCAzVsPtPiFromXiC", {kTH2D, {{axisPt, axisDCA2D}}}); - INSERT_HIST(histPath + "h2dDCAzVsPtPiFromXiCC", "h2dDCAzVsPtPiFromXiCC", {kTH2D, {{axisPt, axisDCA2D}}}); + insertHist("h2dDCAzVsPtXiFromXiC", "h2dDCAzVsPtXiFromXiC", kTH2D, {{axisPt, axisDCA2D}}); + insertHist("h2dDCAzVsPtPiFromXiC", "h2dDCAzVsPtPiFromXiC", kTH2D, {{axisPt, axisDCA2D}}); + insertHist("h2dDCAzVsPtPiFromXiCC", "h2dDCAzVsPtPiFromXiCC", kTH2D, {{axisPt, axisDCA2D}}); } } @@ -580,13 +595,13 @@ struct Alice3MulticharmFinder { void processGenerated(aod::McParticles const&) { for (auto const& mcParticle : trueXi) { - GET_HIST(TH2, "h2dGenXi")->Fill(mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("h2dGenXi"), mcParticle.pt(), mcParticle.eta()); } for (auto const& mcParticle : trueXiC) { - GET_HIST(TH2, "h2dGenXiC")->Fill(mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("h2dGenXiC"), mcParticle.pt(), mcParticle.eta()); } for (auto const& mcParticle : trueXiCC) { - GET_HIST(TH2, "h2dGenXiCC")->Fill(mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("h2dGenXiCC"), mcParticle.pt(), mcParticle.eta()); } } @@ -601,50 +616,47 @@ struct Alice3MulticharmFinder { } if (xi.posTrackId() == pi1c.globalIndex() || xi.negTrackId() == pi1c.globalIndex() || xi.bachelorId() == pi1c.globalIndex()) { - continue; // avoid using any track that was already used + continue; } if (pi1c.pt() < picMinPt) { - continue; // too low momentum + continue; } - GET_HIST(TH1, histPath + "hPi1cPt")->Fill(pi1c.pt()); - // second pion from XiC decay for starts here + hist("hPi1cPt")->Fill(pi1c.pt()); for (auto const& pi2c : picTracksGrouped) { if (mcSameMotherCheck && !checkSameMother(xi, pi2c)) { - continue; // keep only if same mother + continue; } if (pi1c.globalIndex() >= pi2c.globalIndex()) { - continue; // avoid same-mother, avoid double-counting + continue; } if (xi.posTrackId() == pi2c.globalIndex() || xi.negTrackId() == pi2c.globalIndex() || xi.bachelorId() == pi2c.globalIndex()) { - continue; // avoid using any track that was already used + continue; } if (pi2c.pt() < picMinPt) { - continue; // too low momentum + continue; } - // if I am here, it means this is a triplet to be considered for XiC vertexing. - // will now attempt to build a three-body decay candidate with these three track rows. nCombinationsC++; - GET_HIST(TH1, histPath + "hCharmBuilding")->Fill(0.0f); - GET_HIST(TH1, histPath + "hPi2cPt")->Fill(pi2c.pt()); + hist("hCharmBuilding")->Fill(0.0f); + hist("hPi2cPt")->Fill(pi2c.pt()); o2::track::TrackParCov pi1cTrack = getTrackParCov(pi1c); o2::track::TrackParCov pi2cTrack = getTrackParCov(pi2c); if (!buildDecayCandidateThreeBody(thisXiCandidate.trackParCov, pi1cTrack, pi2cTrack, o2::constants::physics::MassXiMinus, o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged)) { - continue; // failed at building candidate + continue; } - GET_HIST(TH1, histPath + "hDCAXiCDaughters")->Fill(thisXicCandidate.dca * ToMicrons); + hist("hDCAXiCDaughters")->Fill(thisXicCandidate.dca * ToMicrons); if (std::fabs(thisXicCandidate.mass - o2::constants::physics::MassXiCPlus) > xicMassWindow) { - continue; // out of mass region + continue; } - GET_HIST(TH1, histPath + "hCharmBuilding")->Fill(1.0f); + hist("hCharmBuilding")->Fill(1.0f); const std::array momentumC = {thisXicCandidate.prong0mom[0] + thisXicCandidate.prong1mom[0] + thisXicCandidate.prong2mom[0], thisXicCandidate.prong0mom[1] + thisXicCandidate.prong1mom[1] + thisXicCandidate.prong2mom[1], thisXicCandidate.prong0mom[2] + thisXicCandidate.prong1mom[2] + thisXicCandidate.prong2mom[2]}; @@ -652,20 +664,20 @@ struct Alice3MulticharmFinder { o2::track::TrackParCov xicTrack(thisXicCandidate.xyz, momentumC, thisXicCandidate.parentTrackCovMatrix, +1); float xicDecayRadius2D = std::hypot(thisXicCandidate.xyz[0], thisXicCandidate.xyz[1]); if (xicDecayRadius2D < xicMinDecayRadius) { - continue; // do not take if radius too small, likely a primary combination + continue; } - GET_HIST(TH1, histPath + "hCharmBuilding")->Fill(2.0f); - GET_HIST(TH1, histPath + "hMinXiCDecayRadius")->Fill(xicDecayRadius2D * ToMicrons); + hist("hCharmBuilding")->Fill(2.0f); + hist("hMinXiCDecayRadius")->Fill(xicDecayRadius2D * ToMicrons); if (xicDecayRadius2D > thisXiCandidate.radius) { continue; } - GET_HIST(TH1, histPath + "hCharmBuilding")->Fill(3.0f); - GET_HIST(TH2, histPath + "hXiRadiusVsXicRadius")->Fill(thisXiCandidate.radius * ToMicrons, xicDecayRadius2D * ToMicrons); + hist("hCharmBuilding")->Fill(3.0f); + hist("hXiRadiusVsXicRadius")->Fill(thisXiCandidate.radius * ToMicrons, xicDecayRadius2D * ToMicrons); o2::dataformats::DCA dcaInfo; float xicdcaXY = 1e+10, xicdcaZ = 1e+10; - o2::track::TrackParCov xicTrackCopy(xicTrack); // paranoia + o2::track::TrackParCov xicTrackCopy(xicTrack); o2::vertexing::PVertex primaryVertex; primaryVertex.setXYZ(collision.posX(), collision.posY(), collision.posZ()); @@ -675,15 +687,14 @@ struct Alice3MulticharmFinder { } if (std::fabs(xicdcaXY) < xicMaxDCAxy || std::fabs(xicdcaZ) < xicMaxDCAz) { - continue; // likely a primary xic + continue; } - GET_HIST(TH1, histPath + "hCharmBuilding")->Fill(4.0f); - GET_HIST(TH1, histPath + "hDCAxyXiC")->Fill(std::fabs(xicdcaXY * ToMicrons)); - GET_HIST(TH1, histPath + "hDCAzXiC")->Fill(std::fabs(xicdcaZ * ToMicrons)); - GET_HIST(TH1, histPath + "hMassXiC")->Fill(thisXicCandidate.mass); + hist("hCharmBuilding")->Fill(4.0f); + hist("hDCAxyXiC")->Fill(std::fabs(xicdcaXY * ToMicrons)); + hist("hDCAzXiC")->Fill(std::fabs(xicdcaZ * ToMicrons)); + hist("hMassXiC")->Fill(thisXicCandidate.mass); - // attempt XiCC finding uint32_t nCombinationsCC = 0; for (auto const& picc : piccTracksGrouped) { if (mcSameMotherCheck && !checkSameMotherExtra(xi, picc)) { @@ -691,23 +702,23 @@ struct Alice3MulticharmFinder { } if (xi.posTrackId() == picc.globalIndex() || xi.negTrackId() == picc.globalIndex() || xi.bachelorId() == picc.globalIndex()) { - continue; // avoid using any track that was already used + continue; } if (picc.pt() < piccMinPt) { - continue; // too low momentum + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(0.0f); - GET_HIST(TH1, histPath + "hPiccPt")->Fill(picc.pt()); + hist("hMultiCharmBuilding")->Fill(0.0f); + hist("hPiccPt")->Fill(picc.pt()); o2::track::TrackParCov piccTrack = getTrackParCov(picc); nCombinationsCC++; if (!buildDecayCandidateTwoBody(xicTrack, piccTrack, o2::constants::physics::MassXiCPlus, o2::constants::physics::MassPionCharged)) { - continue; // failed at building candidate + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(1.0f); - GET_HIST(TH1, histPath + "hDCAXiCCDaughters")->Fill(thisXiccCandidate.dca * ToMicrons); + hist("hMultiCharmBuilding")->Fill(1.0f); + hist("hDCAXiCCDaughters")->Fill(thisXiccCandidate.dca * ToMicrons); const std::array momentumCC = { thisXiccCandidate.prong0mom[0] + thisXiccCandidate.prong1mom[0], thisXiccCandidate.prong0mom[1] + thisXiccCandidate.prong1mom[1], @@ -716,10 +727,10 @@ struct Alice3MulticharmFinder { o2::track::TrackParCov xiccTrack(thisXiccCandidate.xyz, momentumCC, thisXiccCandidate.parentTrackCovMatrix, +2); float xiccDecayRadius2D = std::hypot(thisXiccCandidate.xyz[0], thisXiccCandidate.xyz[1]); if (xiccDecayRadius2D < xiccMinDecayRadius) { - continue; // do not take if radius too small, likely a primary combination + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(2.0f); + hist("hMultiCharmBuilding")->Fill(2.0f); float totalMomentumC = std::hypot(momentumC[0], momentumC[1], momentumC[2]); float decayLengthXiC = std::hypot(thisXicCandidate.xyz[0] - thisXiccCandidate.xyz[0], thisXicCandidate.xyz[1] - thisXiccCandidate.xyz[1], @@ -727,38 +738,38 @@ struct Alice3MulticharmFinder { float xicProperLength = decayLengthXiC * thisXicCandidate.mass / totalMomentumC; if (xicProperLength < xicMinProperLength || xicProperLength > xicMaxProperLength) { - continue; // likely background + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(3.0f); - GET_HIST(TH1, histPath + "hProperLengthXiC")->Fill(xicProperLength * ToMicrons); + hist("hMultiCharmBuilding")->Fill(3.0f); + hist("hProperLengthXiC")->Fill(xicProperLength * ToMicrons); float xicDistanceFromPV = std::hypot(thisXicCandidate.xyz[0] - collision.posX(), thisXicCandidate.xyz[1] - collision.posY(), thisXicCandidate.xyz[2] - collision.posZ()); float xicDecayDistanceFromPV = xicDistanceFromPV * thisXicCandidate.mass / totalMomentumC; if (xicDecayDistanceFromPV < xicMinDecayDistanceFromPV) { - continue; // too close to PV + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(4.0f); - GET_HIST(TH1, histPath + "hMinXicDecayDistanceFromPV")->Fill(xicDecayDistanceFromPV * ToMicrons); + hist("hMultiCharmBuilding")->Fill(4.0f); + hist("hMinXicDecayDistanceFromPV")->Fill(xicDecayDistanceFromPV * ToMicrons); float totalMomentumCC = std::hypot(momentumCC[0], momentumCC[1], momentumCC[2]); float decayLengthXiCC = std::hypot(thisXiccCandidate.xyz[0] - collision.posX(), thisXiccCandidate.xyz[1] - collision.posY(), thisXiccCandidate.xyz[2] - collision.posZ()); float xiccProperLength = decayLengthXiCC * thisXiccCandidate.mass / totalMomentumCC; if (xiccProperLength < xiccMinProperLength || xiccProperLength > xiccMaxProperLength) { - continue; // likely background + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(5.0f); - GET_HIST(TH1, histPath + "hProperLengthXiCC")->Fill(xiccProperLength * ToMicrons); + hist("hMultiCharmBuilding")->Fill(5.0f); + hist("hProperLengthXiCC")->Fill(xiccProperLength * ToMicrons); if (xiccDecayRadius2D > xicDecayRadius2D) { - continue; // XiCC should decay before XiC + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(6.0f); - GET_HIST(TH2, histPath + "hXicRadiusVsXiccRadius")->Fill(xicDecayRadius2D * ToMicrons, xiccDecayRadius2D * ToMicrons); + hist("hMultiCharmBuilding")->Fill(6.0f); + hist("hXicRadiusVsXiccRadius")->Fill(xicDecayRadius2D * ToMicrons, xiccDecayRadius2D * ToMicrons); float xiccdcaXY = 1e+10, xiccdcaZ = 1e+10; if (xiccTrack.propagateToDCA(primaryVertex, cfgMagneticField, &dcaInfo)) { xiccdcaXY = dcaInfo.getY(); @@ -766,30 +777,29 @@ struct Alice3MulticharmFinder { } if (std::fabs(xiccdcaXY) > xiccMaxDCAxy || std::fabs(xiccdcaZ) > xiccMaxDCAz) { - continue; // not pointing to PV + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(7.0f); - GET_HIST(TH1, histPath + "hDCAxyXiCC")->Fill(xiccdcaXY * ToMicrons); - GET_HIST(TH1, histPath + "hDCAzXiCC")->Fill(xiccdcaZ * ToMicrons); + hist("hMultiCharmBuilding")->Fill(7.0f); + hist("hDCAxyXiCC")->Fill(xiccdcaXY * ToMicrons); + hist("hDCAzXiCC")->Fill(xiccdcaZ * ToMicrons); if (std::fabs(thisXiccCandidate.eta) > xiccMaxEta) { - continue; // not in central barrel + continue; } - GET_HIST(TH1, histPath + "hMultiCharmBuilding")->Fill(8.0f); - GET_HIST(TH1, histPath + "hMassXiCC")->Fill(thisXiccCandidate.mass); - GET_HIST(TH1, histPath + "hPtXiCC")->Fill(thisXiccCandidate.pt); - GET_HIST(TH1, histPath + "hEtaXiCC")->Fill(thisXiccCandidate.eta); - GET_HIST(TH3, histPath + "h3dMassXiCC")->Fill(thisXiccCandidate.pt, thisXiccCandidate.eta, thisXiccCandidate.mass); + hist("hMultiCharmBuilding")->Fill(8.0f); + hist("hMassXiCC")->Fill(thisXiccCandidate.mass); + hist("hPtXiCC")->Fill(thisXiccCandidate.pt); + hist("hEtaXiCC")->Fill(thisXiccCandidate.eta); + hist("h3dMassXiCC")->Fill(thisXiccCandidate.pt, thisXiccCandidate.eta, thisXiccCandidate.mass); - GET_HIST(TH1, histPath + "hPi1cDCAxy")->Fill(std::abs(pi1c.dcaXY() * ToMicrons)); - GET_HIST(TH1, histPath + "hPi1cDCAz")->Fill(std::abs(pi1c.dcaZ() * ToMicrons)); - GET_HIST(TH1, histPath + "hPi2cDCAxy")->Fill(std::abs(pi2c.dcaXY() * ToMicrons)); - GET_HIST(TH1, histPath + "hPi2cDCAz")->Fill(std::abs(pi2c.dcaZ() * ToMicrons)); - GET_HIST(TH1, histPath + "hPiccDCAxy")->Fill(std::abs(picc.dcaXY() * ToMicrons)); - GET_HIST(TH1, histPath + "hPiccDCAz")->Fill(std::abs(picc.dcaZ() * ToMicrons)); + hist("hPi1cDCAxy")->Fill(std::abs(pi1c.dcaXY() * ToMicrons)); + hist("hPi1cDCAz")->Fill(std::abs(pi1c.dcaZ() * ToMicrons)); + hist("hPi2cDCAxy")->Fill(std::abs(pi2c.dcaXY() * ToMicrons)); + hist("hPi2cDCAz")->Fill(std::abs(pi2c.dcaZ() * ToMicrons)); + hist("hPiccDCAxy")->Fill(std::abs(picc.dcaXY() * ToMicrons)); + hist("hPiccDCAz")->Fill(std::abs(picc.dcaZ() * ToMicrons)); - // produce multi-charm table for posterior analysis if (derivedTable.fillMCharmIdx) { multiCharmIdx(xi.globalIndex(), pi1c.globalIndex(), @@ -816,10 +826,10 @@ struct Alice3MulticharmFinder { collision.lutConfigId()); } } - GET_HIST(TH1, histPath + "hCombinationsXiCC")->Fill(nCombinationsCC); + hist("hCombinationsXiCC")->Fill(nCombinationsCC); } } - GET_HIST(TH1, histPath + "hCombinationsXiC")->Fill(nCombinationsC); + hist("hCombinationsXiC")->Fill(nCombinationsC); } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -829,18 +839,18 @@ struct Alice3MulticharmFinder { histPath = "Configuration_" + std::to_string(collision.lutConfigId()) + "/"; initDetectorConfiguration(collision.lutConfigId()); - GET_HIST(TH1, histPath + "hNCollisions")->Fill(1); - GET_HIST(TH1, histPath + "hNCollisions")->Fill(2); - GET_HIST(TH1, histPath + "hNTracks")->Fill(tracks.size()); + hist("hNCollisions")->Fill(1); + hist("hNCollisions")->Fill(2); + hist("hNTracks")->Fill(tracks.size()); for (auto const& track : tracks) { - if (BIT_CHECK(track.decayMap(), kTruePiFromXiC)) { - GET_HIST(TH2, histPath + "h2dDCAxyVsPtPiFromXiC")->Fill(track.pt(), track.dcaXY() * ToMicrons); - GET_HIST(TH2, histPath + "h2dDCAzVsPtPiFromXiC")->Fill(track.pt(), track.dcaZ() * ToMicrons); + if (bitCheck(track.decayMap(), kTruePiFromXiC)) { + hist("h2dDCAxyVsPtPiFromXiC")->Fill(track.pt(), track.dcaXY() * ToMicrons); + hist("h2dDCAzVsPtPiFromXiC")->Fill(track.pt(), track.dcaZ() * ToMicrons); } - if (BIT_CHECK(track.decayMap(), kTruePiFromXiCC)) { - GET_HIST(TH2, histPath + "h2dDCAxyVsPtPiFromXiCC")->Fill(track.pt(), track.dcaXY() * ToMicrons); - GET_HIST(TH2, histPath + "h2dDCAzVsPtPiFromXiCC")->Fill(track.pt(), track.dcaZ() * ToMicrons); + if (bitCheck(track.decayMap(), kTruePiFromXiCC)) { + hist("h2dDCAxyVsPtPiFromXiCC")->Fill(track.pt(), track.dcaXY() * ToMicrons); + hist("h2dDCAzVsPtPiFromXiCC")->Fill(track.pt(), track.dcaZ() * ToMicrons); } } } @@ -848,33 +858,33 @@ struct Alice3MulticharmFinder { void processPerfectBuilder(Alice3Collision const& collision, soa::Join const& cascades, Alice3Tracks const& tracks, aod::McParticles const&) { configureCollision(collision, tracks); - auto picTracksGrouped = picTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto piccTracksGrouped = piccTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const auto picTracksGrouped = picTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const auto piccTracksGrouped = piccTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (const auto& xiCand : cascades) { - auto xi = xiCand.cascadeTrack_as(); // de-reference cascade track + auto xi = xiCand.cascadeTrack_as(); if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > xiMassWindow) { - continue; // out of mass region + continue; } - if (!BIT_CHECK(xi.decayMap(), kTrueXiFromXiC)) { + if (!bitCheck(xi.decayMap(), kTrueXiFromXiC)) { continue; } if (std::fabs(xi.dcaXY()) < xiMinConstDCAxy || std::fabs(xi.dcaZ()) < xiMinConstDCAz) { - continue; // likely a primary xi + continue; } if (xiCand.cascRadius() < xiMinDecayRadius) { continue; } - GET_HIST(TH1, histPath + "hMassXi")->Fill(xiCand.mXi()); - GET_HIST(TH2, histPath + "h2dDCAxyVsPtXiFromXiC")->Fill(xi.pt(), xi.dcaXY() * ToMicrons); - GET_HIST(TH2, histPath + "h2dDCAzVsPtXiFromXiC")->Fill(xi.pt(), xi.dcaZ() * ToMicrons); - GET_HIST(TH1, histPath + "hDCAxyXi")->Fill(xi.dcaXY() * ToMicrons); - GET_HIST(TH1, histPath + "hDCAzXi")->Fill(xi.dcaZ() * ToMicrons); - GET_HIST(TH1, histPath + "hMinXiDecayRadius")->Fill(xiCand.cascRadius()); + hist("hMassXi")->Fill(xiCand.mXi()); + hist("h2dDCAxyVsPtXiFromXiC")->Fill(xi.pt(), xi.dcaXY() * ToMicrons); + hist("h2dDCAzVsPtXiFromXiC")->Fill(xi.pt(), xi.dcaZ() * ToMicrons); + hist("hDCAxyXi")->Fill(xi.dcaXY() * ToMicrons); + hist("hDCAzXi")->Fill(xi.dcaZ() * ToMicrons); + hist("hMinXiDecayRadius")->Fill(xiCand.cascRadius()); thisXiCandidate.radius = xiCand.cascRadius(); thisXiCandidate.trackParCov = getTrackParCov(xi); processFindXicc(collision, xiCand, picTracksGrouped, piccTracksGrouped); @@ -884,28 +894,75 @@ struct Alice3MulticharmFinder { void processStraBuilder(Alice3Collision const& collision, FullCascadeCandidates const& cascadeCandidates, Alice3Tracks const& tracks, aod::McParticles const&) { configureCollision(collision, tracks); - auto picTracksGrouped = picTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto piccTracksGrouped = piccTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const auto picTracksGrouped = picTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const auto piccTracksGrouped = piccTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (const auto& xiCand : cascadeCandidates) { + const auto positive = xiCand.template posTrack_as(); + const auto negative = xiCand.template negTrack_as(); + const auto bachelor = xiCand.template bachelor_as(); + static constexpr float CtauXi = 4.91f; + const float distanceFromPV = std::hypot(xiCand.x() - collision.posX(), xiCand.y() - collision.posY(), xiCand.z() - collision.posZ()); + const float normalizedDecayLength = o2::constants::physics::MassXiMinus * distanceFromPV / (xiCand.p() * CtauXi); + + if (std::abs(positive.dcaXY()) < posMinDCAxy) { + continue; + } + + if (std::abs(negative.dcaXY()) < negMinDCAxy) { + continue; + } + + if (std::abs(bachelor.dcaXY()) < bachMinDCAxy) { + continue; + } + + if (xiCand.dcaV0daughters() > laMaxDauDCA) { + continue; + } + + if (xiCand.v0radius() < laMinDecayRadius) { + continue; + } + + if (xiCand.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < laMinCosPA) { + continue; + } + + if (std::abs(xiCand.mLambda() - o2::constants::physics::MassLambda0) > laMassWindow) { + continue; + } + + if (xiCand.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < xiMinCosPA) { + continue; // FIXME: Probably not ok + } + + if (xiCand.dcacascdaughters() > xiMaxDauDCA) { + continue; + } + + if (normalizedDecayLength > xiMaxNormalizedDecayLength) { + continue; + } + if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > xiMassWindow) { - continue; // out of mass region + continue; } if (std::fabs(xiCand.dcaXYCascToPV()) < xiMinConstDCAxy || std::fabs(xiCand.dcaZCascToPV()) < xiMinConstDCAz) { - continue; // likely a primary xi + continue; } if (xiCand.cascradius() < xiMinDecayRadius) { continue; } - GET_HIST(TH1, histPath + "hMassXi")->Fill(xiCand.mXi()); - GET_HIST(TH2, histPath + "h2dDCAxyVsPtXiFromXiC")->Fill(xiCand.pt(), xiCand.dcaXYCascToPV() * ToMicrons); - GET_HIST(TH2, histPath + "h2dDCAzVsPtXiFromXiC")->Fill(xiCand.pt(), xiCand.dcaZCascToPV() * ToMicrons); - GET_HIST(TH1, histPath + "hDCAxyXi")->Fill(xiCand.dcaXYCascToPV() * ToMicrons); - GET_HIST(TH1, histPath + "hDCAzXi")->Fill(xiCand.dcaZCascToPV() * ToMicrons); - GET_HIST(TH1, histPath + "hMinXiDecayRadius")->Fill(xiCand.cascradius()); + hist("hMassXi")->Fill(xiCand.mXi()); + hist("h2dDCAxyVsPtXiFromXiC")->Fill(xiCand.pt(), xiCand.dcaXYCascToPV() * ToMicrons); + hist("h2dDCAzVsPtXiFromXiC")->Fill(xiCand.pt(), xiCand.dcaZCascToPV() * ToMicrons); + hist("hDCAxyXi")->Fill(xiCand.dcaXYCascToPV() * ToMicrons); + hist("hDCAzXi")->Fill(xiCand.dcaZCascToPV() * ToMicrons); + hist("hMinXiDecayRadius")->Fill(xiCand.cascradius()); const std::array cascSV = {xiCand.x(), xiCand.y(), xiCand.z()}; const std::array cascP = {xiCand.px(), xiCand.py(), xiCand.pz()}; diff --git a/ALICE3/TableProducer/alice3strangenessFinder.cxx b/ALICE3/TableProducer/alice3strangenessFinder.cxx index 9743faf88b4..50683b8ccec 100644 --- a/ALICE3/TableProducer/alice3strangenessFinder.cxx +++ b/ALICE3/TableProducer/alice3strangenessFinder.cxx @@ -607,11 +607,11 @@ struct Alice3strangenessFinder { } histos.fill(HIST("hCascadeBuilding"), 1.0); - if (inLambdaMassWindow && bachTrack.sign() > 0) { + if (!inLambdaMassWindow && bachTrack.sign() < 0) { continue; // only consider lambda and neg bach track } - if (inAntiLambdaMassWindow && bachTrack.sign() < 0) { + if (!inAntiLambdaMassWindow && bachTrack.sign() > 0) { continue; // only consider anti-lambda and pos bach track } diff --git a/ALICE3/Tasks/CMakeLists.txt b/ALICE3/Tasks/CMakeLists.txt index bd48a5533f9..6e6fbc37ea0 100644 --- a/ALICE3/Tasks/CMakeLists.txt +++ b/ALICE3/Tasks/CMakeLists.txt @@ -80,7 +80,7 @@ o2physics_add_dpl_workflow(alice3strangeness COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(alice3-dq-efficiency - SOURCES alice3-dq-efficiency.cxx + SOURCES alice3DqEfficiency.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore COMPONENT_NAME Analysis) diff --git a/ALICE3/Tasks/alice3-dilepton.cxx b/ALICE3/Tasks/alice3-dilepton.cxx index 9efdb686f46..b258a2cff67 100644 --- a/ALICE3/Tasks/alice3-dilepton.cxx +++ b/ALICE3/Tasks/alice3-dilepton.cxx @@ -25,15 +25,18 @@ #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 diff --git a/ALICE3/Tasks/alice3-prefilterdilepton.cxx b/ALICE3/Tasks/alice3-prefilterdilepton.cxx index 7f800eeaf8f..4f45007107e 100644 --- a/ALICE3/Tasks/alice3-prefilterdilepton.cxx +++ b/ALICE3/Tasks/alice3-prefilterdilepton.cxx @@ -14,29 +14,37 @@ /// \author s.scheid@cern.ch, daiki.sekihata@cern.ch /// -#include "ALICE3/DataModel/OTFCollision.h" #include "ALICE3/DataModel/OTFRICH.h" #include "ALICE3/DataModel/OTFTOF.h" #include "ALICE3/DataModel/prefilterDilepton.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/TrackSelectionTables.h" #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 + using namespace o2; using namespace o2::aod; using namespace o2::soa; diff --git a/ALICE3/Tasks/alice3-dq-efficiency.cxx b/ALICE3/Tasks/alice3DqEfficiency.cxx similarity index 66% rename from ALICE3/Tasks/alice3-dq-efficiency.cxx rename to ALICE3/Tasks/alice3DqEfficiency.cxx index 99dcd281727..78d7af23f06 100644 --- a/ALICE3/Tasks/alice3-dq-efficiency.cxx +++ b/ALICE3/Tasks/alice3DqEfficiency.cxx @@ -8,10 +8,10 @@ // 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. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// alexander.tiekoetter@cern.ch -// Configurable workflow for running several DQ or other PWG analyses +/// \author Ionut Cristian Arsene , Oslo +/// \author Alexander Tiekoetter , Muenster +/// \brief Skimming Task for DQ Table Maker +/// \file alice3DqEfficiency.cxx #include "PWGDQ/Core/AnalysisCompositeCut.h" #include "PWGDQ/Core/AnalysisCut.h" @@ -24,8 +24,8 @@ #include "PWGDQ/Core/MixingLibrary.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/DataModel/ReducedTablesAlice3.h" +#include "ALICE3/DataModel/ReducedTablesAlice3.h" #include "Common/Core/TableHelper.h" #include @@ -41,8 +41,12 @@ #include #include +#include #include +#include #include +#include +#include #include #include #include @@ -75,14 +79,14 @@ DECLARE_SOA_COLUMN(Rapee, rapee, float); DECLARE_SOA_COLUMN(Phiee, phiee, float); DECLARE_SOA_COLUMN(Ptee, ptee, float); DECLARE_SOA_COLUMN(Lxyee, lxyee, float); -DECLARE_SOA_COLUMN(LxyeePoleMass, lxyeepolemass, float); +DECLARE_SOA_COLUMN(LxyeePoleMass, lxyeePoleMass, float); DECLARE_SOA_COLUMN(Lzee, lzee, float); -DECLARE_SOA_COLUMN(MultiplicityFT0A, multiplicityFT0AJPsi2ee, float); -DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0CJPsi2ee, float); -DECLARE_SOA_COLUMN(PercentileFT0M, percentileFT0MJPsi2ee, float); -DECLARE_SOA_COLUMN(MultiplicityNContrib, multiplicityNContribJPsi2ee, float); -DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, AmbiguousJpsiPairsInBunch, bool); -DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, AmbiguousJpsiPairsOutOfBunch, bool); +DECLARE_SOA_COLUMN(MultiplicityFT0A, multiplicityFT0A, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0C, float); +DECLARE_SOA_COLUMN(PercentileFT0M, percentileFT0M, float); +DECLARE_SOA_COLUMN(MultiplicityNContrib, multiplicityNContrib, float); +DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, ambiguousInBunchPairs, bool); +DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, ambiguousOutOfBunchPairs, bool); DECLARE_SOA_COLUMN(Corrassoc, corrassoc, bool); DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); @@ -107,55 +111,62 @@ DECLARE_SOA_TABLE(OniaMCTruth, "AOD", "MCTRUTHONIA", dqanalysisflags::OniaPt, dq // TODO: USE PROPER TABLES -using MyEvents = soa::Join; -using MyEventsSelected = soa::Join; -using MyEventsVtxCov = soa::Join; -using MyEventsVtxCovSelected = soa::Join; +using MyEvents = soa::Join; +using MyEventsSelected = soa::Join; +using MyEventsVtxCov = soa::Join; +using MyEventsVtxCovSelected = soa::Join; using MyBarrelAssocs = soa::Join; using MyBarrelAssocsPrefilter = soa::Join; -using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithCov = soa::Join; -using MyBarrelTracksWithCovWithAmbiguities = soa::Join; -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent; -constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventVtxCov; +constexpr static uint32_t GkEventFillMap = VarManager::ObjTypes::ReducedEvent; +constexpr static uint32_t GkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventVtxCov; + +constexpr static uint32_t GkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t GkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; -constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; -constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; +namespace dqefficiency_helpers +{ +inline float* varValues() { return static_cast(VarManager::fgValues); } +inline TString* varNames() { return static_cast(VarManager::fgVariableNames); } +inline TString* varUnits() { return static_cast(VarManager::fgVariableUnits); } +} // namespace dqefficiency_helpers // 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 -constexpr int TWO_PRONG = 2; -constexpr int THREE_PRONG = 3; +constexpr int TwoProng = 2; +constexpr int ThreeProng = 3; // Analysis task that produces event decisions and the Hash table used in event mixing -struct AnalysisEventSelection { +struct Alice3DqEfficiencyAnalysisEventSelection { Produces eventSel; Produces hash; OutputObj fOutputList{"output"}; - Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddEventMCHistogram{"cfgAddEventMCHistogram", "generator", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; + Configurable cfgMixingVars{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable cfgEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable cfgEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; + Configurable cfgQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable cfgAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable cfgAddEventMCHistogram{"cfgAddEventMCHistogram", "generator", "Comma separated list of histograms"}; + Configurable cfgAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; HistogramManager* fHistMan = nullptr; MixingHandler* fMixHandler = nullptr; - AnalysisCompositeCut* fEventCut; + AnalysisCompositeCut* fEventCut = nullptr; std::map fSelMap; // key: reduced event global index, value: event selection decision @@ -167,7 +178,7 @@ struct AnalysisEventSelection { VarManager::SetDefaultVarNames(); fEventCut = new AnalysisCompositeCut(true); - TString eventCutStr = fConfigEventCuts.value; + TString eventCutStr = cfgEventCuts.value; if (eventCutStr != "") { AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); if (cut != nullptr) { @@ -175,7 +186,7 @@ struct AnalysisEventSelection { } } // Additional cuts via JSON - TString eventCutJSONStr = fConfigEventCutsJSON.value; + TString eventCutJSONStr = cfgEventCutsJSON.value; if (eventCutJSONStr != "") { std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); for (const auto& cutIt : jsonCuts) { @@ -185,18 +196,18 @@ struct AnalysisEventSelection { VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - if (fConfigQA) { + if (cfgQA) { fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram.value.data()); - DefineHistograms(fHistMan, "EventsMC", fConfigAddEventMCHistogram.value.data()); - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // aditional histograms via JSON + fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits()); + defineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", cfgAddEventHistogram.value.data()); + defineHistograms(fHistMan, "EventsMC", cfgAddEventMCHistogram.value.data()); + dqhistograms::AddHistogramsFromJSON(fHistMan, cfgAddJSONHistograms.value.c_str()); // aditional histograms via JSON VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); } - TString mixVarsString = fConfigMixingVariables.value; + TString mixVarsString = cfgMixingVars.value; std::unique_ptr objArray(mixVarsString.Tokenize(",")); if (objArray->GetEntries() > 0) { fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); @@ -207,32 +218,32 @@ struct AnalysisEventSelection { } } - void runEventSelection(MyEventsVtxCov const& events, ReducedA3MCEvents const& mcEvents) + void runEventSelection(MyEventsVtxCov const& events, ReA3MCEvents const& mcEvents) { fSelMap.clear(); for (const auto& event : events) { // Reset the fValues array and fill event observables VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - VarManager::FillEventAlice3(event); - if (event.has_reducedA3MCEvent()) { - VarManager::FillEventAlice3(event.reducedA3MCEvent()); + VarManager::FillEventAlice3(event); + if (event.has_reA3MCEvent()) { + VarManager::FillEventAlice3(event.reA3MCEvent()); } bool decision = false; // if QA is requested fill histograms before event selections - if (fConfigQA) { - fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + if (cfgQA) { + fHistMan->FillHistClass("Event_BeforeCuts", dqefficiency_helpers::varValues()); // automatically fill all the histograms in the class Event } - if (fEventCut->IsSelected(VarManager::fgValues)) { - if (fConfigQA) { - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + if (fEventCut->IsSelected(dqefficiency_helpers::varValues())) { + if (cfgQA) { + fHistMan->FillHistClass("Event_AfterCuts", dqefficiency_helpers::varValues()); } decision = true; } fSelMap[event.globalIndex()] = decision; if (fMixHandler != nullptr) { - int hh = fMixHandler->FindEventCategory(VarManager::fgValues); + int hh = fMixHandler->FindEventCategory(dqefficiency_helpers::varValues()); hash(hh); } } @@ -241,8 +252,8 @@ struct AnalysisEventSelection { // Reset the fValues array and fill event observables VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillEventAlice3(event); - if (fConfigQA) { - fHistMan->FillHistClass("EventsMC", VarManager::fgValues); + if (cfgQA) { + fHistMan->FillHistClass("EventsMC", dqefficiency_helpers::varValues()); } } } @@ -250,7 +261,7 @@ struct AnalysisEventSelection { void publishSelections(MyEventsVtxCov const& events) { // publish the table - uint32_t evSel = static_cast(0); + auto evSel = static_cast(0); for (const auto& event : events) { evSel = 0; if (fSelMap[event.globalIndex()]) { // event passed the user cuts @@ -260,7 +271,7 @@ struct AnalysisEventSelection { } } - void processSkimmed(MyEventsVtxCov const& events, aod::ReducedA3MCEvents const& mcEvents) + void processSkimmed(MyEventsVtxCov const& events, aod::ReA3MCEvents const& mcEvents) { runEventSelection(events, mcEvents); publishSelections(events); @@ -271,28 +282,28 @@ struct AnalysisEventSelection { // do nothing } - PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); - PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", true); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisEventSelection, processDummy, "Dummy function", true); }; // Produces a table with barrel track decisions (joinable to the ReducedA3TracksAssociations) // Here one should add all the track cuts needed through the workflow (e.g. cuts for same-even pairing, electron prefiltering, track for dilepton-track correlations) -struct AnalysisTrackSelection { +struct Alice3DqEfficiencyAnalysisTrackSelection { Produces trackSel; Produces trackAmbiguities; OutputObj fOutputList{"output"}; - Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable cfgTrackCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable cfgBarrelTrackCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + Configurable cfgQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable cfgAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable cfgAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable cfgPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; - Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; - Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + Configurable cfgTrackMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; + Configurable cfgTrackMCsignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; std::vector fTrackCuts; std::vector fMCSignals; // list of signals to be checked std::vector fHistNamesReco; @@ -308,7 +319,7 @@ struct AnalysisTrackSelection { } VarManager::SetDefaultVarNames(); - TString cutNamesStr = fConfigCuts.value; + TString cutNamesStr = cfgTrackCuts.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -316,16 +327,16 @@ struct AnalysisTrackSelection { } } // add extra cuts from JSON - TString addTrackCutsStr = fConfigCutsJSON.value; + TString addTrackCutsStr = cfgBarrelTrackCutsJSON.value; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (const auto& t : addTrackCuts) { - fTrackCuts.push_back(reinterpret_cast(t)); + fTrackCuts.push_back(static_cast(t)); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - TString configSigNamesStr = fConfigMCSignals.value; + TString configSigNamesStr = cfgTrackMCSignals.value; std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); // Setting the MC signals for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { @@ -338,7 +349,7 @@ struct AnalysisTrackSelection { } } // Add the MCSignals from the JSON config - TString addMCSignalsStr = fConfigMCSignalsJSON.value; + TString addMCSignalsStr = cfgTrackMCsignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); for (const auto& mcIt : addMCSignals) { @@ -349,10 +360,10 @@ struct AnalysisTrackSelection { } } - if (fConfigQA) { + if (cfgQA) { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits()); // Configure histogram classes for each track cut; // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) @@ -371,17 +382,17 @@ struct AnalysisTrackSelection { } } - DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data()); - if (fConfigPublishAmbiguity) { - DefineHistograms(fHistMan, "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;", "ambiguity"); + defineHistograms(fHistMan, histClasses.Data(), cfgAddTrackHistogram.value.data()); + if (cfgPublishAmbiguity) { + defineHistograms(fHistMan, "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;", "ambiguity"); } - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + dqhistograms::AddHistogramsFromJSON(fHistMan, cfgAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } } - void runTrackSelection(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& /*events*/, MyBarrelTracksWithCov const& tracks, ReducedA3MCEvents const& /*eventsMC*/, ReducedA3MCTracks const& tracksMC) + void runTrackSelection(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& /*events*/, MyBarrelTracksWithCov const& tracks, ReA3MCEvents const& /*eventsMC*/, ReA3MCTracks const& tracksMC) { fNAssocsInBunch.clear(); fNAssocsOutOfBunch.clear(); @@ -391,7 +402,7 @@ struct AnalysisTrackSelection { // Loop over associations for (const auto& assoc : assocs) { - auto event = assoc.template reducedA3event_as(); + auto event = assoc.template reA3event_as(); if (!event.isEventSelected_bit(0)) { trackSel(0); continue; @@ -399,38 +410,38 @@ struct AnalysisTrackSelection { VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); // fill event information which might be needed in histograms/cuts that combine track and event properties - VarManager::FillEventAlice3(event); - if (event.has_reducedA3MCEvent()) { - VarManager::FillEventAlice3(event.reducedA3MCEvent()); + VarManager::FillEventAlice3(event); + if (event.has_reA3MCEvent()) { + VarManager::FillEventAlice3(event.reA3MCEvent()); } - auto track = assoc.template reducedA3track_as(); - VarManager::FillTrackAlice3(track); + auto track = assoc.template reA3track_as(); + VarManager::FillTrackAlice3(track); // compute quantities which depend on the associated collision, such as DCA - VarManager::FillTrackCollision(track, event); + VarManager::FillTrackCollision(track, event); bool isCorrectAssoc = false; - if (track.has_reducedA3MCTrack()) { - auto trackMC = track.reducedA3MCTrack(); - auto eventMCfromTrack = trackMC.reducedA3MCEvent(); - if (event.has_reducedA3MCEvent()) { - isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedA3MCEvent().globalIndex()); + if (track.has_reA3MCTrack()) { + auto trackMC = track.reA3MCTrack(); + auto eventMCfromTrack = trackMC.reA3MCEvent(); + if (event.has_reA3MCEvent()) { + isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reA3MCEvent().globalIndex()); } VarManager::FillTrackMC(tracksMC, trackMC); VarManager::FillResolutions(trackMC, track); } - if (fConfigQA) { - fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", VarManager::fgValues); + if (cfgQA) { + fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", dqefficiency_helpers::varValues()); } int iCut = 0; - uint32_t filterMap = static_cast(0); + auto filterMap = static_cast(0); for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { - if ((*cut)->IsSelected(VarManager::fgValues)) { + if ((*cut)->IsSelected(dqefficiency_helpers::varValues())) { filterMap |= (static_cast(1) << iCut); - if (fConfigQA) { - fHistMan->FillHistClass(fHistNamesReco[iCut], VarManager::fgValues); + if (cfgQA) { + fHistMan->FillHistClass(fHistNamesReco[iCut], dqefficiency_helpers::varValues()); } } } // end loop over cuts @@ -438,19 +449,19 @@ struct AnalysisTrackSelection { // compute MC matching decisions and fill histograms for matched associations int isig = 0; - if (filterMap > 0 && track.has_reducedA3MCTrack()) { + if (filterMap > 0 && track.has_reA3MCTrack()) { // loop over all MC signals for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { // check if this MC signal is matched - if ((*sig)->CheckSignal(true, track.reducedA3MCTrack())) { + if ((*sig)->CheckSignal(true, track.reA3MCTrack())) { // mcDecision |= (static_cast(1) << isig); // loop over cuts and fill histograms for the cuts that are fulfilled for (unsigned int icut = 0; icut < fTrackCuts.size(); icut++) { - if (filterMap & (static_cast(1) << icut)) { + if ((filterMap & (static_cast(1) << icut)) != 0u) { if (isCorrectAssoc) { - fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig].Data(), VarManager::fgValues); + fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig].Data(), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig + 1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig + 1].Data(), dqefficiency_helpers::varValues()); } } } // end loop over cuts @@ -459,10 +470,10 @@ struct AnalysisTrackSelection { } // end if (filterMap > 0) // count the number of associations per track - if (fConfigPublishAmbiguity && filterMap > 0) { + if (cfgPublishAmbiguity && filterMap > 0) { if (event.isEventSelected_bit(1)) { // for this track, count the number of associated collisions with in-bunch pileup and out of bunch associations - if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { + if (!fNAssocsInBunch.contains(track.globalIndex())) { std::vector evVector = {event.globalIndex()}; fNAssocsInBunch[track.globalIndex()] = evVector; } else { @@ -470,7 +481,7 @@ struct AnalysisTrackSelection { evVector.push_back(event.globalIndex()); } } else { - if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { + if (!fNAssocsOutOfBunch.contains(track.globalIndex())) { std::vector evVector = {event.globalIndex()}; fNAssocsOutOfBunch[track.globalIndex()] = evVector; } else { @@ -484,17 +495,17 @@ struct AnalysisTrackSelection { // QA the collision-track associations // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches // So one could QA these tracks separately - if (fConfigPublishAmbiguity) { - if (fConfigQA) { + if (cfgPublishAmbiguity) { + if (cfgQA) { for (const auto& [trackIdx, evIndices] : fNAssocsInBunch) { if (evIndices.size() == 1) { continue; } auto track = tracks.rawIteratorAt(trackIdx); VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - VarManager::FillTrackAlice3(track); + VarManager::FillTrackAlice3(track); VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); + fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", dqefficiency_helpers::varValues()); } // end loop over in-bunch ambiguous tracks for (const auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { @@ -503,20 +514,20 @@ struct AnalysisTrackSelection { } auto track = tracks.rawIteratorAt(trackIdx); VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - VarManager::FillTrackAlice3(track); + VarManager::FillTrackAlice3(track); VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); + fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", dqefficiency_helpers::varValues()); } // end loop over out-of-bunch ambiguous tracks } // publish the ambiguity table for (const auto& track : tracks) { int8_t nInBunch = 0; - if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + if (!fNAssocsInBunch.contains(track.globalIndex())) { nInBunch = fNAssocsInBunch[track.globalIndex()].size(); } int8_t nOutOfBunch = 0; - if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + if (!fNAssocsOutOfBunch.contains(track.globalIndex())) { nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); } trackAmbiguities(nInBunch, nOutOfBunch); @@ -524,7 +535,7 @@ struct AnalysisTrackSelection { } } // end runTrackSelection() - void processSkimmedWithCov(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedA3MCEvents const& eventsMC, ReducedA3MCTracks const& tracksMC) + void processSkimmedWithCov(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReA3MCEvents const& eventsMC, ReA3MCTracks const& tracksMC) { runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); } @@ -534,26 +545,26 @@ struct AnalysisTrackSelection { // do nothing } - PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); - PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisTrackSelection, processDummy, "Dummy function", true); }; -struct AnalysisPrefilterSelection { +struct Alice3DqEfficiencyAnalysisPrefilterSelection { Produces prefilter; // joinable with ReducedA3TracksAssoc // Configurables - Configurable fConfigPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; - Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; - Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; + Configurable cfgPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; + Configurable cfgPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; + Configurable cfgTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; // Track related options - Configurable fPropTrack{"cfgPropTrack", false, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + Configurable cfgPropTrack{"cfgPropTrack", false, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; std::map fPrefilterMap; - AnalysisCompositeCut* fPairCut; - uint32_t fPrefilterMask; - int fPrefilterCutBit; + AnalysisCompositeCut* fPairCut = nullptr; + uint32_t fPrefilterMask = 0; + int fPrefilterCutBit = -1; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; void init(o2::framework::InitContext& context) { @@ -563,7 +574,7 @@ struct AnalysisPrefilterSelection { bool runPrefilter = true; // get the list of track cuts to be prefiltered - TString trackCutsStr = fConfigTrackCuts.value; + TString trackCutsStr = cfgTrackCuts.value; TObjArray* objArrayTrackCuts = nullptr; if (!trackCutsStr.IsNull()) { objArrayTrackCuts = trackCutsStr.Tokenize(","); @@ -575,7 +586,7 @@ struct AnalysisPrefilterSelection { runPrefilter = false; } // get the cut to be used as loose selection - TString prefilterTrackCutStr = fConfigPrefilterTrackCut.value; + TString prefilterTrackCutStr = cfgPrefilterTrackCut.value; if (prefilterTrackCutStr.IsNull()) { LOG(warn) << " No prefilter loose selection specified! Prefilter will not be run"; runPrefilter = false; @@ -611,13 +622,13 @@ struct AnalysisPrefilterSelection { if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { fPrefilterMask |= (static_cast(1) << icut); } - if (tempStr.CompareTo(fConfigPrefilterTrackCut.value) == 0) { + if (tempStr.CompareTo(cfgPrefilterTrackCut.value) == 0) { fPrefilterCutBit = icut; } } // setup the prefilter pair cut fPairCut = new AnalysisCompositeCut(true); - TString pairCutStr = fConfigPrefilterPairCut.value; + TString pairCutStr = cfgPrefilterPairCut.value; if (!pairCutStr.IsNull()) { fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); } @@ -640,8 +651,8 @@ struct AnalysisPrefilterSelection { } for (const auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { - auto track1 = assoc1.template reducedA3track_as(); - auto track2 = assoc2.template reducedA3track_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) @@ -655,21 +666,21 @@ struct AnalysisPrefilterSelection { bool track1Loose = assoc1.isBarrelSelected_bit(fPrefilterCutBit); bool track2Loose = assoc2.isBarrelSelected_bit(fPrefilterCutBit); - if (!((track1Candidate > 0 && track2Loose) || (track2Candidate > 0 && track1Loose))) { + if ((track1Candidate == 0 || !track2Loose) && (track2Candidate == 0 || !track1Loose)) { continue; } // compute pair quantities - VarManager::FillPairAlice3(track1, track2); - if (fPropTrack) { - VarManager::FillPairCollision(event, track1, track2); + VarManager::FillPairAlice3(track1, track2); + if (cfgPropTrack) { + VarManager::FillPairCollision(event, track1, track2); } // if the pair fullfils the criteria, add an entry into the prefilter map for the two tracks - if (fPairCut->IsSelected(VarManager::fgValues)) { - if (fPrefilterMap.find(track1.globalIndex()) == fPrefilterMap.end() && track1Candidate > 0) { + if (fPairCut->IsSelected(dqefficiency_helpers::varValues())) { + if (!fPrefilterMap.contains(track1.globalIndex()) && track1Candidate > 0) { fPrefilterMap[track1.globalIndex()] = track1Candidate; } - if (fPrefilterMap.find(track2.globalIndex()) == fPrefilterMap.end() && track2Candidate > 0) { + if (!fPrefilterMap.contains(track2.globalIndex()) && track2Candidate > 0) { fPrefilterMap[track2.globalIndex()] = track2Candidate; } } @@ -697,9 +708,9 @@ struct AnalysisPrefilterSelection { } 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 reducedA3track_as(); + auto track = assoc.template reA3track_as(); mymap = -1; - if (fPrefilterMap.find(track.globalIndex()) != fPrefilterMap.end()) { + 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 mymap = ~fPrefilterMap[track.globalIndex()]; prefilter(mymap); @@ -715,57 +726,57 @@ struct AnalysisPrefilterSelection { // do nothing } - PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); - PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisPrefilterSelection, processDummy, "Do nothing", true); }; // Run the same-event pairing // This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) // Runs combinatorics for barrel-barrel combinations // The task implements also process functions for running event mixing -struct AnalysisSameEventPairing { +struct Alice3DqEfficiencyAnalysisSameEventPairing { Produces dielectronList; Produces dielectronsExtraList; Produces dielectronAllList; - Produces MCTruthTableEffi; + Produces mcTruthTableEffi; o2::base::MatLayerCylSet* fLUT = nullptr; OutputObj fOutputList{"output"}; struct : ConfigurableGroup { - Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; - Configurable MCgenAcc{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; + Configurable cfgTrackCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable cfgPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; + Configurable cfgMCGenAccCut{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; // TODO: Add pair cuts via JSON - } fConfigCuts; + } cfgTrackCuts; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable cfgQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable cfgAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable cfgAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; struct : ConfigurableGroup { - Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; - Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; - Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; - Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + Configurable cfgFlatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; + Configurable cfgPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable syst{"syst", "pp", "Collision system, pp or PbPb"}; + Configurable energy{"energy", 13600, "Center of mass energy in GeV"}; } fConfigOptions; struct : ConfigurableGroup { - Configurable genSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - Configurable genSignalsJSON{"cfgMCGenSignalsJSON", "", "Additional list of MC signals (generated) via JSON"}; - Configurable recSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; - Configurable skimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; + Configurable cfgBarrelMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable cfgMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Additional list of MC signals (generated) via JSON"}; + Configurable cfgBarrelMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable cfgMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; + Configurable cfgSkimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; } fConfigMC; // Track related options - Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + Configurable cfgPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; // Filter filterEventSelected = aod::dqanalysisflags::isEventSelected & uint32_t(1); Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; // keep histogram class names in maps, so we don't have to buld their names in the pair loops std::map> fTrackHistNames; @@ -777,14 +788,14 @@ struct AnalysisSameEventPairing { AnalysisCompositeCut fMCGenAccCut; bool fUseMCGenAccCut = false; - uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream - int fNCutsBarrel; - int fNPairCuts; + uint32_t fTrackFilterMask = 0; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream + int fNCutsBarrel = 0; + int fNPairCuts = 0; bool fHasTwoProngGenMCsignals = false; - bool fEnableBarrelHistos; + bool fEnableBarrelHistos = false; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; void init(o2::framework::InitContext& context) { @@ -798,9 +809,9 @@ struct AnalysisSameEventPairing { // Keep track of all the histogram class names to avoid composing strings in the pairing loop TString histNames = ""; - TString cutNamesStr = fConfigCuts.pair.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + TString pairCutNamesStr = cfgTrackCuts.cfgPairCuts.value; + if (!pairCutNamesStr.IsNull()) { + std::unique_ptr objArray(pairCutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } @@ -808,19 +819,19 @@ struct AnalysisSameEventPairing { // get the list of cuts for tracks, check that they were played by the barrel selection tasks // and make a mask for active cuts (barrel selection tasks may run more cuts, needed for other analyses) - TString trackCutsStr = fConfigCuts.track.value; + TString trackCutsStr = cfgTrackCuts.cfgTrackCuts.value; TObjArray* objArrayTrackCuts = nullptr; if (!trackCutsStr.IsNull()) { objArrayTrackCuts = trackCutsStr.Tokenize(","); } // Setting the MC rec signal names - TString sigNamesStr = fConfigMC.recSignals.value; + TString sigNamesStr = fConfigMC.cfgBarrelMCRecSignals.value; std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); if (sig) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required continue; } fRecMCSignals.push_back(sig); @@ -828,11 +839,11 @@ struct AnalysisSameEventPairing { } // Add the MCSignals from the JSON config - TString addMCSignalsStr = fConfigMC.recSignalsJSON.value; + TString addMCSignalsStr = fConfigMC.cfgMCRecSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); for (const auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != TWO_PRONG) { // NOTE: only 2 prong signals + if (mcIt->GetNProngs() != TwoProng) { // NOTE: only 2 prong signals continue; } fRecMCSignals.push_back(mcIt); @@ -854,7 +865,7 @@ struct AnalysisSameEventPairing { } // get the mc generated acceptance cut - TString mcGenAccCutStr = fConfigCuts.MCgenAcc.value; + TString mcGenAccCutStr = cfgTrackCuts.cfgMCGenAccCut.value; if (mcGenAccCutStr != "") { AnalysisCut* cut = dqcuts::GetAnalysisCut(mcGenAccCutStr.Data()); if (cut != nullptr) { @@ -881,7 +892,7 @@ struct AnalysisSameEventPairing { Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; - if (fConfigQA) { + if (cfgQA) { // assign separate hist directories for ambiguous tracks names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); names.push_back(Form("PairsBarrelSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); @@ -898,9 +909,9 @@ struct AnalysisSameEventPairing { // if there are pair cuts specified, assign hist directories for each barrel cut - pair cut combination // NOTE: This could possibly lead to large histogram outputs. It is strongly advised to use pair cuts only // if you know what you are doing. - TString cutNamesStr = fConfigCuts.pair.value; - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + TString pairCutHistNamesStr = cfgTrackCuts.cfgPairCuts.value; + if (!pairCutHistNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutHistNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts names = { @@ -921,7 +932,7 @@ struct AnalysisSameEventPairing { Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName())}; - if (fConfigQA) { + if (cfgQA) { names.push_back(Form("PairsBarrelSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); names.push_back(Form("PairsBarrelSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); @@ -944,7 +955,7 @@ struct AnalysisSameEventPairing { // Add histogram classes for each specified MCsignal at the generator level // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function - TString sigGenNamesStr = fConfigMC.genSignals.value; + TString sigGenNamesStr = fConfigMC.cfgBarrelMCGenSignals.value; std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); @@ -954,11 +965,11 @@ struct AnalysisSameEventPairing { } // Add the MCSignals from the JSON config - TString addMCSignalsGenStr = fConfigMC.genSignalsJSON.value; + TString addMCSignalsGenStr = fConfigMC.cfgMCGenSignalsJSON.value; if (addMCSignalsGenStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsGenStr.Data()); for (const auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() > TWO_PRONG) { // NOTE: only 2 prong signals + if (mcIt->GetNProngs() > TwoProng) { // NOTE: only 2 prong signals continue; } fGenMCSignals.push_back(mcIt); @@ -970,7 +981,7 @@ struct AnalysisSameEventPairing { if (sig->GetNProngs() == 1) { histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function histNames += Form("MCTruthGenSel_%s;", sig->GetName()); - } else if (sig->GetNProngs() == TWO_PRONG) { + } else if (sig->GetNProngs() == TwoProng) { histNames += Form("MCTruthGenPair_%s;", sig->GetName()); histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); fHasTwoProngGenMCsignals = true; @@ -980,40 +991,55 @@ struct AnalysisSameEventPairing { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits()); - VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy + VarManager::SetCollisionSystem((TString)fConfigOptions.syst, fConfigOptions.energy); // set collision system and center of mass energy - DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + defineHistograms(fHistMan, histNames.Data(), cfgAddSEPHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, cfgAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } // Template function to run same event pairing (barrel-barrel) - void runSameEventPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocsPrefilter const& assocs, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& /*mcTracks*/) + void runSameEventPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocsPrefilter const& assocs, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/) { if (events.size() == 0) { LOG(warning) << "No events in this TF, going to the next one ..."; return; } - TString cutNames = fConfigCuts.track.value; + TString cutNames = cfgTrackCuts.cfgTrackCuts.value; std::map> histNames = fTrackHistNames; std::map> histNamesMC = fBarrelHistNamesMCmatched; int ncuts = fNCutsBarrel; - uint32_t twoTrackFilter = static_cast(0); + auto twoTrackFilter = static_cast(0); int sign1 = 0; int sign2 = 0; - uint32_t mcDecision = static_cast(0); - bool isCorrectAssoc_leg1 = false; - bool isCorrectAssoc_leg2 = false; - dielectronList.reserve(1); - dielectronsExtraList.reserve(1); + auto mcDecision = static_cast(0); + 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; + } + } - if (fConfigOptions.flatTables.value) { - dielectronAllList.reserve(1); + dielectronList.reserve(reserveSize); + dielectronsExtraList.reserve(reserveSize); + + if (fConfigOptions.cfgFlatTables.value) { + dielectronAllList.reserve(reserveSize); } for (const auto& event : events) { @@ -1022,8 +1048,8 @@ struct AnalysisSameEventPairing { } // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEventAlice3(event, VarManager::fgValues); - VarManager::FillEventAlice3(event.reducedA3MCEvent(), VarManager::fgValues); + VarManager::FillEventAlice3(event, dqefficiency_helpers::varValues()); + VarManager::FillEventAlice3(event.reA3MCEvent(), dqefficiency_helpers::varValues()); auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); if (groupedAssocs.size() == 0) { @@ -1034,12 +1060,12 @@ struct AnalysisSameEventPairing { twoTrackFilter = a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isBarrelSelectedPrefilter_raw() & fTrackFilterMask; - if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + if (twoTrackFilter == 0u) { // the tracks must have at least one filter bit in common to continue continue; } - auto t1 = a1.template reducedA3track_as(); - auto t2 = a2.template reducedA3track_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 @@ -1057,29 +1083,27 @@ struct AnalysisSameEventPairing { } // run MC matching for this pair - int isig = 0; + int iSigMc = 0; mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedA3MCTrack(), t2.reducedA3MCTrack())) { - mcDecision |= (static_cast(1) << isig); + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, iSigMc++) { + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack()) { + if ((*sig)->CheckSignal(true, t1.reA3MCTrack(), t2.reA3MCTrack())) { + mcDecision |= (static_cast(1) << iSigMc); } } } // end loop over MC signals - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack()) { - isCorrectAssoc_leg1 = (t1.reducedA3MCTrack().reducedA3MCEvent() == event.reducedA3MCEvent()); - isCorrectAssoc_leg2 = (t2.reducedA3MCTrack().reducedA3MCEvent() == event.reducedA3MCEvent()); + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack()) { + isCorrectAssocLeg1 = (t1.reA3MCTrack().reA3MCEvent() == event.reA3MCEvent()); + isCorrectAssocLeg2 = (t2.reA3MCTrack().reA3MCEvent() == event.reA3MCEvent()); } - VarManager::FillPairAlice3(t1, t2); - if (fPropTrack) { - VarManager::FillPairCollision(event, t1, t2); + VarManager::FillPairAlice3(t1, t2); + if (cfgPropTrack) { + VarManager::FillPairCollision(event, t1, t2); } - /* TODO: Reimplement Pair vertexing when secondary vertexing is available - if constexpr (TTwoProngFitter) { - // VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); - }*/ - if (!fConfigMC.skimSignalOnly || (fConfigMC.skimSignalOnly && mcDecision > 0)) { + + 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); @@ -1090,91 +1114,92 @@ struct AnalysisSameEventPairing { bool isAmbiOutOfBunch = false; for (int icut = 0; icut < ncuts; icut++) { - if (twoTrackFilter & (static_cast(1) << icut)) { - isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); - isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); - if (sign1 * sign2 < 0) { // +- pairs - fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); // reconstructed, unmatched - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][0].Data(), VarManager::fgValues); // matched signal - if (fConfigQA) { - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { // correct track-collision association - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), VarManager::fgValues); + if ((twoTrackFilter & (static_cast(1) << icut)) != 0u) { + isAmbiInBunch = ((twoTrackFilter & (static_cast(1) << 28)) != 0u) || ((twoTrackFilter & (static_cast(1) << 29)) != 0u); + isAmbiOutOfBunch = ((twoTrackFilter & (static_cast(1) << 30)) != 0u) || ((twoTrackFilter & (static_cast(1) << 31)) != 0u); + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(histNames[icut][0].Data(), dqefficiency_helpers::varValues()); // reconstructed, unmatched + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if ((mcDecision & (static_cast(1) << isig)) != 0u) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][0].Data(), dqefficiency_helpers::varValues()); // matched signal + if (cfgQA) { + if (isCorrectAssocLeg1 && isCorrectAssocLeg2) { // correct track-collision association + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), dqefficiency_helpers::varValues()); } else { // incorrect track-collision association - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), dqefficiency_helpers::varValues()); } if (isAmbiInBunch) { // ambiguous in bunch - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), VarManager::fgValues); - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), dqefficiency_helpers::varValues()); + if (isCorrectAssocLeg1 && isCorrectAssocLeg2) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), dqefficiency_helpers::varValues()); } } if (isAmbiOutOfBunch) { // ambiguous out of bunch - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), VarManager::fgValues); - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), dqefficiency_helpers::varValues()); + if (isCorrectAssocLeg1 && isCorrectAssocLeg2) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), dqefficiency_helpers::varValues()); } } } } - if (fConfigQA) { + if (cfgQA) { if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][3].Data(), dqefficiency_helpers::varValues()); } if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), dqefficiency_helpers::varValues()); } } } } else { if (sign1 > 0) { // ++ pairs - fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][1].Data(), dqefficiency_helpers::varValues()); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), VarManager::fgValues); + if ((mcDecision & (static_cast(1) << isig)) != 0u) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), dqefficiency_helpers::varValues()); } } - if (fConfigQA) { + if (cfgQA) { if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][4].Data(), dqefficiency_helpers::varValues()); } if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), dqefficiency_helpers::varValues()); } } } else { // -- pairs - fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][2].Data(), dqefficiency_helpers::varValues()); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), VarManager::fgValues); + if ((mcDecision & (static_cast(1) << isig)) != 0u) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), dqefficiency_helpers::varValues()); } } - if (fConfigQA) { + if (cfgQA) { if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][5].Data(), dqefficiency_helpers::varValues()); } if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), dqefficiency_helpers::varValues()); } } } } for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { AnalysisCompositeCut cut = fPairCuts.at(iPairCut); - if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts + if (!(cut.IsSelected(dqefficiency_helpers::varValues()))) { // apply pair cuts continue; + } if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][0].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][0].Data(), dqefficiency_helpers::varValues()); } else { if (sign1 > 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][1].Data(), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][2].Data(), dqefficiency_helpers::varValues()); } } } // end loop (pair cuts) @@ -1184,18 +1209,15 @@ struct AnalysisSameEventPairing { } // end loop over events } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reducedA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; - void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { - [[maybe_unused]] uint32_t mcDecision = 0; - int isig = 0; - for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); // if we have a mc generated acceptance cut, apply it here if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + if (!fMCGenAccCut.IsSelected(dqefficiency_helpers::varValues())) { continue; } } @@ -1204,7 +1226,7 @@ struct AnalysisSameEventPairing { // TODO: Use the mcReducedFlags to select signals for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -1213,52 +1235,48 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } for (const auto& track : mcTracks) { - if (track.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (track.reA3MCEventId() != event.reA3MCEventId()) { continue; } VarManager::FillTrackMC(mcTracks, track); // if we have a mc generated acceptance cut, apply it here if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + if (!fMCGenAccCut.IsSelected(dqefficiency_helpers::varValues())) { continue; } } - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; + auto trackRaw = mcTracks.rawIteratorAt(track.globalIndex()); for (const auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - 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]); + 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]); } - isig++; } } } // end loop over reconstructed events if (fHasTwoProngGenMCsignals) { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + auto t1Raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2Raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1Raw.reA3MCEventId() == t2Raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required here continue; } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { + if (sig->CheckSignal(true, t1Raw, t2Raw)) { VarManager::FillPairMC(t1, t2); if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + if (!fMCGenAccCut.IsSelected(dqefficiency_helpers::varValues())) { continue; } } - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -1268,34 +1286,30 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedA3MCEventId()); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reA3MCEventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (const auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { - mcDecision = 0; - isig = 0; + auto t1Raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2Raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1Raw.reA3MCEventId() == t2Raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required here continue; } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); + if (sig->CheckSignal(true, t1Raw, t2Raw)) { VarManager::FillPairMC(t1, t2); if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + if (!fMCGenAccCut.IsSelected(dqefficiency_helpers::varValues())) { continue; } } - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); } - isig++; } } } @@ -1305,20 +1319,16 @@ struct AnalysisSameEventPairing { void processBarrelOnlySkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocsPrefilter const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); runMCGenWithGrouping(events, mcEvents, mcTracks); } - PresliceUnsorted perReducedMcGenEvent = aod::reducedA3trackMC::reducedA3MCEventId; + PresliceUnsorted perReducedMcGenEvent = aod::reducedA3trackMC::reA3MCEventId; - void processMCGen(soa::Filtered const& events, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + void processMCGen(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { - // Fill Generated histograms taking into account all generated tracks - [[maybe_unused]] uint32_t mcDecision = 0; - int isig = 0; - for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. @@ -1326,7 +1336,7 @@ struct AnalysisSameEventPairing { // TODO: Use the mcReducedFlags to select signals for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -1336,44 +1346,37 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } - VarManager::FillEventAlice3(event, VarManager::fgValues); - VarManager::FillEventAlice3(event.reducedA3MCEvent(), VarManager::fgValues); - // auto groupedMCTracks = mcTracks.sliceBy(perReducedMcGenEvent, event.reducedA3MCEventId()); - // groupedMCTracks.bindInternalIndicesTo(&mcTracks); - // for (const auto& track : groupedMCTracks) { + VarManager::FillEventAlice3(event, dqefficiency_helpers::varValues()); + VarManager::FillEventAlice3(event.reA3MCEvent(), dqefficiency_helpers::varValues()); + for (const auto& track : mcTracks) { - if (track.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (track.reA3MCEventId() != event.reA3MCEventId()) { continue; } VarManager::FillTrackMC(mcTracks, track); - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - // auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; + auto trackRaw = mcTracks.rawIteratorAt(track.globalIndex()); for (const auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - 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]); + 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]); } - isig++; } } } // end loop over reconstructed events if (fHasTwoProngGenMCsignals) { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + auto t1Raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2Raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1Raw.reA3MCEventId() == t2Raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required here continue; } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + if (sig->CheckSignal(true, t1Raw, t2Raw)) { + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -1384,32 +1387,28 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } if (fHasTwoProngGenMCsignals) { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - if (t1.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (t1.reA3MCEventId() != event.reA3MCEventId()) { continue; } - if (t2.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (t2.reA3MCEventId() != event.reA3MCEventId()) { continue; } - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { - mcDecision = 0; - isig = 0; + auto t1Raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2Raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1Raw.reA3MCEventId() == t2Raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required here continue; } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (sig->CheckSignal(true, t1Raw, t2Raw)) { + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); } - isig++; } } } @@ -1417,11 +1416,8 @@ struct AnalysisSameEventPairing { } // end loop over reconstructed events } - void processMCGenWithGrouping(soa::Filtered const& events, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + void processMCGenWithGrouping(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { - [[maybe_unused]] uint32_t mcDecision = 0; - int isig = 0; - for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. @@ -1429,7 +1425,7 @@ struct AnalysisSameEventPairing { // TODO: Use the mcReducedFlags to select signals for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -1438,39 +1434,35 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } for (const auto& track : mcTracks) { - if (track.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (track.reA3MCEventId() != event.reA3MCEventId()) { continue; } VarManager::FillTrackMC(mcTracks, track); - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; + auto trackRaw = mcTracks.rawIteratorAt(track.globalIndex()); for (const auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - 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]); + 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]); } - isig++; } } } // end loop over reconstructed events if (fHasTwoProngGenMCsignals) { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + auto t1Raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2Raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1Raw.reA3MCEventId() == t2Raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required here continue; } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + if (sig->CheckSignal(true, t1Raw, t2Raw)) { + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -1480,28 +1472,24 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedA3MCEventId()); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reA3MCEventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (const auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { - auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { - mcDecision = 0; - isig = 0; + auto t1Raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); + auto t2Raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + if (t1Raw.reA3MCEventId() == t2Raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != TwoProng) { // NOTE: 2-prong signals required here continue; } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (sig->CheckSignal(true, t1Raw, t2Raw)) { + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); } - isig++; } } } @@ -1514,13 +1502,13 @@ struct AnalysisSameEventPairing { // do nothing } - PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmed, "Run barrel only pairing, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processMCGenWithGrouping, "Loop over MC particle stack (grouped MCTracks) and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisSameEventPairing, processBarrelOnlySkimmed, "Run barrel only pairing, with skimmed tracks", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisSameEventPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisSameEventPairing, processMCGenWithGrouping, "Loop over MC particle stack (grouped MCTracks) and fill generator level histograms", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); }; -struct AnalysisAsymmetricPairing { +struct Alice3DqEfficiencyAnalysisAsymmetricPairing { Produces ditrackList; Produces ditrackExtraList; @@ -1529,50 +1517,50 @@ struct AnalysisAsymmetricPairing { OutputObj fOutputList{"output"}; // Configurables - Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; - Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; - Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; - Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; - Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; - Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; - Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; - Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; - - Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; - Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; - Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - - Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; - Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; - - HistogramManager* fHistMan; + Configurable cfgLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; + Configurable cfgLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable cfgLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable cfgLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable cfgCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; + Configurable cfgPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + Configurable cfgPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; + Configurable cfgSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; + + Configurable cfgAsymmetricPairingHistogramsSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; + Configurable cfgSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; + Configurable cfgReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; + Configurable cfgQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable cfgAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Configurable cfgBarrelMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable cfgBarrelMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable cfgMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; + Configurable cfgMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; + + HistogramManager* fHistMan = nullptr; std::vector fPairCuts; - int fNPairHistPrefixes; + int fNPairHistPrefixes = 0; std::vector fRecMCSignals; std::vector fGenMCSignals; // Filter masks to find legs in BarrelTrackCuts table - uint32_t fLegAFilterMask; - uint32_t fLegBFilterMask; - uint32_t fLegCFilterMask; + uint32_t fLegAFilterMask = 0; + uint32_t fLegBFilterMask = 0; + uint32_t fLegCFilterMask = 0; // Maps tracking which combination of leg cuts the track cuts participate in std::map fConstructedLegAFilterMasksMap; std::map fConstructedLegBFilterMasksMap; std::map fConstructedLegCFilterMasksMap; // Filter map for common track cuts - uint32_t fCommonTrackCutMask; + uint32_t fCommonTrackCutMask = 0; // Map tracking which common track cut the track cuts correspond to std::map fCommonTrackCutFilterMasks; - int fNLegCuts; + int fNLegCuts = 0; int fNPairCuts = 0; - int fNCommonTrackCuts; + int fNCommonTrackCuts = 0; // vectors for cut names and signal names, for easy access when calling FillHistogramList() std::vector fLegCutNames; std::vector fPairCutNames; @@ -1581,13 +1569,13 @@ struct AnalysisAsymmetricPairing { Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; - // PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + // PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; // Partitions for triplets and asymmetric pairs - Partition legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); - Partition legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); - Partition legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); + Partition legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & cfgLegAFilterMask) > static_cast(0); + Partition legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & cfgLegBFilterMask) > static_cast(0); + Partition legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & cfgLegCFilterMask) > static_cast(0); // Map to track how many times a pair of tracks has been encountered std::map, int8_t> fPairCount; @@ -1602,38 +1590,38 @@ struct AnalysisAsymmetricPairing { VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits()); // Get the leg cut filter masks - fLegAFilterMask = fConfigLegAFilterMask.value; - fLegBFilterMask = fConfigLegBFilterMask.value; - fLegCFilterMask = fConfigLegCFilterMask.value; + fLegAFilterMask = cfgLegAFilterMask.value; + fLegBFilterMask = cfgLegBFilterMask.value; + fLegCFilterMask = cfgLegCFilterMask.value; // Get the pair cuts - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + TString pairCutNamesStr = cfgPairCuts.value; + if (!pairCutNamesStr.IsNull()) { + std::unique_ptr objArray(pairCutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } } // Extra pair cuts via JSON - TString addPairCutsStr = fConfigPairCutsJSON.value; + TString addPairCutsStr = cfgPairCutsJSON.value; if (addPairCutsStr != "") { std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (const auto& t : addPairCuts) { - fPairCuts.push_back(reinterpret_cast(t)); - cutNamesStr += Form(",%s", t->GetName()); + fPairCuts.push_back(static_cast(t)); + pairCutNamesStr += Form(",%s", t->GetName()); } } - std::unique_ptr objArrayPairCuts(cutNamesStr.Tokenize(",")); + std::unique_ptr objArrayPairCuts(pairCutNamesStr.Tokenize(",")); fNPairCuts = objArrayPairCuts->GetEntries(); for (int j = 0; j < fNPairCuts; j++) { fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); } // Setting the MC rec signal names - TString sigNamesStr = fConfigMCRecSignals.value; + TString sigNamesStr = cfgBarrelMCRecSignals.value; std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); @@ -1642,11 +1630,11 @@ struct AnalysisAsymmetricPairing { } } // Add the reco MCSignals from the JSON config - TString addMCSignalsStr = fConfigMCRecSignalsJSON.value; + TString addMCSignalsStr = cfgMCRecSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); for (const auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != TWO_PRONG && mcIt->GetNProngs() != THREE_PRONG) { + if (mcIt->GetNProngs() != TwoProng && mcIt->GetNProngs() != ThreeProng) { LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 2 or 3 prongs! Fix it"; } fRecMCSignals.push_back(mcIt); @@ -1674,8 +1662,8 @@ struct AnalysisAsymmetricPairing { } std::unique_ptr objArray(tempCutsStr.Tokenize(",")); // Get the common leg cuts - int commonCutIdx; - TString commonNamesStr = fConfigCommonTrackCuts.value; + int commonCutIdx = -1; + TString commonNamesStr = cfgCommonTrackCuts.value; if (!commonNamesStr.IsNull()) { // if common track cuts std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); fNCommonTrackCuts = objArrayCommon->GetEntries(); @@ -1692,36 +1680,36 @@ struct AnalysisAsymmetricPairing { } // Check that the leg cut masks make sense if (static_cast(std::floor(std::log2(fLegAFilterMask))) + 1 > objArray->GetEntries()) { - LOGF(fatal, "fConfigLegAFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(std::log2(fLegAFilterMask))) + 1, objArray->GetEntries()); + LOGF(fatal, "cfgLegAFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(std::log2(fLegAFilterMask))) + 1, objArray->GetEntries()); } if (static_cast(std::floor(std::log2(fLegBFilterMask))) + 1 > objArray->GetEntries()) { - LOGF(fatal, "fConfigLegBFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(std::log2(fLegBFilterMask))) + 1, objArray->GetEntries()); + LOGF(fatal, "cfgLegBFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(std::log2(fLegBFilterMask))) + 1, objArray->GetEntries()); } if (static_cast(std::floor(std::log2(fLegCFilterMask))) + 1 > objArray->GetEntries()) { - LOGF(fatal, "fConfigLegCFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(std::log2(fLegCFilterMask))) + 1, objArray->GetEntries()); + LOGF(fatal, "cfgLegCFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(std::log2(fLegCFilterMask))) + 1, objArray->GetEntries()); } // Get the cuts defining the legs uint32_t fConstructedLegAFilterMask = 0; uint32_t fConstructedLegBFilterMask = 0; uint32_t fConstructedLegCFilterMask = 0; - TString legCutsStr = fConfigLegCuts.value; + TString legCutsStr = cfgLegCuts.value; std::unique_ptr objArrayLegs(legCutsStr.Tokenize(",")); if (objArrayLegs->GetEntries() == 0 && !isMCGen) { LOG(fatal) << "No cuts defining legs. Check the config!"; } fNLegCuts = objArrayLegs->GetEntries(); std::vector isThreeProng; - int legAIdx; - int legBIdx; - int legCIdx; + int legAIdx = -1; + int legBIdx = -1; + int legCIdx = -1; // Loop over leg defining cuts for (int icut = 0; icut < fNLegCuts; ++icut) { TString legsStr = objArrayLegs->At(icut)->GetName(); std::unique_ptr legs(legsStr.Tokenize(":")); - if (legs->GetEntries() == THREE_PRONG) { + if (legs->GetEntries() == ThreeProng) { isThreeProng.push_back(true); - } else if (legs->GetEntries() == TWO_PRONG) { + } else if (legs->GetEntries() == TwoProng) { isThreeProng.push_back(false); } else { LOGF(fatal, "Leg cuts %s has the wrong format and could not be parsed!", legsStr.Data()); @@ -1759,24 +1747,24 @@ struct AnalysisAsymmetricPairing { // Define histogram and histogram directory names if (isThreeProng[icut]) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); - if (fConfigQA) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s", legsStr.Data()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); + if (cfgQA) { + defineHistograms(fHistMan, Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + TString pairCutHistNamesStr = cfgPairCuts.value; + if (!pairCutHistNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutHistNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } // end loop (common cuts) } // end loop (pair cuts) } // end if (pair cuts) @@ -1785,18 +1773,18 @@ struct AnalysisAsymmetricPairing { if (!sigNamesStr.IsNull()) { for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { auto sig = fRecMCSignals.at(isig); - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + if (!pairCutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } // end loop (common cuts) } // end loop (pair cuts) } // end if (pair cuts) @@ -1804,43 +1792,43 @@ struct AnalysisAsymmetricPairing { } // end if (MC signals) } else { std::vector pairHistPrefixes = {"PairsBarrelSEPM"}; - if (fConfigSameSignHistograms.value) { + if (cfgSameSignHistograms.value) { pairHistPrefixes.push_back("PairsBarrelSEPP"); pairHistPrefixes.push_back("PairsBarrelSEMM"); } fNPairHistPrefixes = pairHistPrefixes.size(); for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } - if (fConfigQA) { + if (cfgQA) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } - if (fConfigReflectedHistograms.value) { + if (cfgReflectedHistograms.value) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + if (!pairCutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } // end loop (common cuts) } // end loop (pair cuts) @@ -1851,29 +1839,29 @@ struct AnalysisAsymmetricPairing { for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { auto sig = fRecMCSignals.at(isig); for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } - if (fConfigReflectedHistograms.value) { + if (cfgReflectedHistograms.value) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_reflected_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_reflected_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + if (!pairCutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + defineHistograms(fHistMan, Form("%s_%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); } } // end loop (common cuts) } // end loop (pair cuts) @@ -1885,28 +1873,28 @@ struct AnalysisAsymmetricPairing { // Add histogram classes for each specified MCsignal at the generator level // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function - TString sigGenNamesStr = fConfigMCGenSignals.value; + TString sigGenNamesStr = cfgBarrelMCGenSignals.value; std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); if (sig) { if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required fGenMCSignals.push_back(sig); - DefineHistograms(fHistMan, Form("MCTruthGen_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function - DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + defineHistograms(fHistMan, Form("MCTruthGen_%s;", sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + defineHistograms(fHistMan, Form("MCTruthGenSel_%s;", sig->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function } } } // Add the gen MCSignals from the JSON config - addMCSignalsStr = fConfigMCGenSignalsJSON.value; + addMCSignalsStr = cfgMCGenSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); for (const auto& mcIt : addMCSignals) { if (mcIt->GetNProngs() == 1) { fGenMCSignals.push_back(mcIt); - DefineHistograms(fHistMan, Form("MCTruthGen_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function - DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + defineHistograms(fHistMan, Form("MCTruthGen_%s;", mcIt->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + defineHistograms(fHistMan, Form("MCTruthGenSel_%s;", mcIt->GetName()), cfgAsymmetricPairingHistogramsSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function } } } @@ -1927,13 +1915,13 @@ struct AnalysisAsymmetricPairing { LOGF(fatal, "A mix of pairs and triplets was given as leg cuts. Check your config!"); } - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + dqhistograms::AddHistogramsFromJSON(fHistMan, cfgAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } // 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*/, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& /*mcTracks*/) + void runAsymmetricPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocs const& /*assocs*/, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/) { fPairCount.clear(); @@ -1949,7 +1937,7 @@ struct AnalysisAsymmetricPairing { } // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEventAlice3(event, VarManager::fgValues); + VarManager::FillEventAlice3(event, dqefficiency_helpers::varValues()); auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); if (groupedLegAAssocs.size() == 0) { @@ -1961,33 +1949,32 @@ struct AnalysisAsymmetricPairing { } 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]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut])) { + if (((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) != 0u) && ((a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) != 0u)) { twoTrackFilter |= static_cast(1) << icut; // If the supposed pion passes a kaon cut, this is a K+K-. Skip it. - if (fConfigSkipAmbiguousIdCombinations.value) { - if (a2.isBarrelSelected_raw() & fLegAFilterMask) { + if (cfgSkipAmbiguousIdCombinations.value) { + if ((a2.isBarrelSelected_raw() & fLegAFilterMask) != 0u) { isPairIdWrong = true; } } } } - if (!twoTrackFilter || isPairIdWrong) { + if (twoTrackFilter == 0u || isPairIdWrong) { continue; } // Find common track cuts both candidates pass twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reducedA3track_as(); - auto t2 = a2.template reducedA3track_as(); + auto t1 = a1.template reA3track_as(); + auto t2 = a2.template reA3track_as(); // Avoid self-pairs if (t1.globalIndex() == t2.globalIndex()) { @@ -1996,12 +1983,12 @@ struct AnalysisAsymmetricPairing { bool isReflected = false; std::pair trackIds(t1.globalIndex(), t2.globalIndex()); - if (fPairCount.find(trackIds) != fPairCount.end()) { + if (fPairCount.contains(trackIds)) { // Double counting is possible due to track-collision ambiguity. Skip pairs which were counted before fPairCount[trackIds] += 1; continue; } - if (fPairCount.find(std::pair(trackIds.second, trackIds.first)) != fPairCount.end()) { + if (fPairCount.contains(std::pair(trackIds.second, trackIds.first))) { isReflected = true; } fPairCount[trackIds] += 1; @@ -2017,97 +2004,94 @@ struct AnalysisAsymmetricPairing { } // run MC matching for this pair - int isig = 0; + int iSigMc = 0; mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack()) { - VarManager::FillPairMC(t1.reducedA3MCTrack(), t2.reducedA3MCTrack()); - if ((*sig)->CheckSignal(true, t1.reducedA3MCTrack(), t2.reducedA3MCTrack())) { - mcDecision |= static_cast(1) << isig; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, iSigMc++) { + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack()) { + VarManager::FillPairMC(t1.reA3MCTrack(), t2.reA3MCTrack()); + if ((*sig)->CheckSignal(true, t1.reA3MCTrack(), t2.reA3MCTrack())) { + mcDecision |= static_cast(1) << iSigMc; } } } // end loop over MC signals - VarManager::FillPairAlice3(t1, t2); - /*TODO: Reimplement when secondary vertexing is available - if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); - }*/ + VarManager::FillPairAlice3(t1, t2); + VarManager::FillPairVertexingAlice3(event, t1, t2, true); // Fill histograms bool isAmbi = false; for (int icut = 0; icut < fNLegCuts; icut++) { - if (twoTrackFilter & (static_cast(1) << icut)) { - isAmbi = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); - if (sign1 * sign2 < 0) { // +- pairs - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); // reconstructed, unmatched - if (isAmbi && fConfigQA) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if ((twoTrackFilter & (static_cast(1) << icut)) != 0u) { + isAmbi = ((twoTrackFilter & (static_cast(1) << 30)) != 0u) || ((twoTrackFilter & (static_cast(1) << 31)) != 0u); + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); // reconstructed, unmatched + if (isAmbi && cfgQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isReflected && cfgReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } - } else if (fConfigSameSignHistograms.value) { + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { // ++ pairs - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - if (isAmbi && fConfigQA) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); + if (isAmbi && cfgQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguous_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isReflected && cfgReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } } else { // -- pairs - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - if (isAmbi && fConfigQA) { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); + if (isAmbi && cfgQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguous_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } - if (isReflected && fConfigReflectedHistograms) { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isReflected && cfgReflectedHistograms) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } } } for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { + if ((mcDecision & (static_cast(1) << isig)) != 0u) { if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); + if (isReflected && cfgReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } - } else if (fConfigSameSignHistograms.value) { + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); + if (isReflected && cfgReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); + if (isReflected && cfgReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } } } } } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if ((twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) != 0u) { if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), dqefficiency_helpers::varValues()); + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), dqefficiency_helpers::varValues()); } } for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { + if ((mcDecision & (static_cast(1) << isig)) != 0u) { if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } } } @@ -2116,53 +2100,54 @@ struct AnalysisAsymmetricPairing { } // end loop (common cuts) int iPairCut = 0; for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { - if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + 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()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); } } for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { + if ((mcDecision & (static_cast(1) << isig)) != 0u) { if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } } } } // Histograms with pair cuts and common track cuts for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if ((twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) != 0u) { if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); } } for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { + if ((mcDecision & (static_cast(1) << isig)) != 0u) { if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); + } else if (cfgSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); } } } @@ -2180,7 +2165,8 @@ struct AnalysisAsymmetricPairing { } // Function to run same event triplets (e.g. D+->K-pi+pi+) - void runThreeProng(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocs const& /*assocs*/, MyBarrelTracksWithCovWithAmbiguities const& tracks, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) + template + void runThreeProng(TEvents const& events, PresliceUnsorted& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) { for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { @@ -2188,7 +2174,7 @@ struct AnalysisAsymmetricPairing { } // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEventAlice3(event, VarManager::fgValues); + VarManager::FillEventAlice3(event, dqefficiency_helpers::varValues()); auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); if (groupedLegAAssocs.size() == 0) { @@ -2206,12 +2192,12 @@ struct AnalysisAsymmetricPairing { // Based on triplet type, make suitable combinations of the partitions if (tripletType == VarManager::kTripleCandidateToPKPi) { for (const auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { - readTriplet(a1, a2, a3, tracks, event, tripletType); + readTriplet(a1, a2, a3, tracks, event, tripletType); } } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { for (const auto& a1 : groupedLegAAssocs) { for (const auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { - readTriplet(a1, a2, a3, tracks, event, tripletType); + readTriplet(a1, a2, a3, tracks, event, tripletType); } } } else { @@ -2220,8 +2206,8 @@ struct AnalysisAsymmetricPairing { } // end event loop } - // Helper function to process triplet - void readTriplet(MyBarrelAssocs::iterator const& a1, MyBarrelAssocs::iterator const& a2, MyBarrelAssocs::iterator const& a3, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, MyEventsVtxCovSelected::iterator const& /*event*/, VarManager::PairCandidateType tripletType) + template + void readTriplet(TTrackAssoc const& a1, TTrackAssoc const& a2, TTrackAssoc const& a3, TTracks const& /*tracks*/, TEvent const& event, VarManager::PairCandidateType tripletType) { uint32_t mcDecision = 0; @@ -2231,7 +2217,7 @@ struct AnalysisAsymmetricPairing { // Find out which leg cut combinations the triplet passes if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) && (a3.isBarrelSelected_raw() & fConstructedLegCFilterMasksMap[icut])) { threeTrackFilter |= (static_cast(1) << icut); - if (tripletType == VarManager::kTripleCandidateToPKPi && fConfigSkipAmbiguousIdCombinations.value) { + if (tripletType == VarManager::kTripleCandidateToPKPi && cfgSkipAmbiguousIdCombinations.value) { // Check if the supposed pion passes as a proton or kaon, if so, skip this triplet. It is pKp or pKK. if ((a3.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegBFilterMask)) { return; @@ -2241,7 +2227,7 @@ struct AnalysisAsymmetricPairing { return; } } - if (tripletType == VarManager::kTripleCandidateToKPiPi && fConfigSkipAmbiguousIdCombinations.value) { + if (tripletType == VarManager::kTripleCandidateToKPiPi && cfgSkipAmbiguousIdCombinations.value) { // Check if one of the supposed pions pass as a kaon, if so, skip this triplet. It is KKPi. if ((a2.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegAFilterMask)) { return; @@ -2256,9 +2242,9 @@ struct AnalysisAsymmetricPairing { // Find common track cuts all candidates pass threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reducedA3track_as(); - auto t2 = a2.template reducedA3track_as(); - auto t3 = a3.template reducedA3track_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) { @@ -2288,64 +2274,64 @@ struct AnalysisAsymmetricPairing { } // run MC matching for this triplet - int isig = 0; + int iSigMc = 0; mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack() && t3.has_reducedA3MCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedA3MCTrack(), t2.reducedA3MCTrack(), t3.reducedA3MCTrack())) { - mcDecision |= (static_cast(1) << isig); + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, iSigMc++) { + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack() && t3.has_reA3MCTrack()) { + if ((*sig)->CheckSignal(true, t1.reA3MCTrack(), t2.reA3MCTrack(), t3.reA3MCTrack())) { + mcDecision |= (static_cast(1) << iSigMc); } } } // end loop over MC signals - VarManager::FillTriple(t1, t2, t3, VarManager::fgValues, tripletType); - /* TODO: Reimplement when secondary vertexing is available + VarManager::FillTriple(t1, t2, t3, dqefficiency_helpers::varValues(), tripletType); if constexpr (TThreeProngFitter) { - VarManager::FillTripletVertexing(event, t1, t2, t3, tripletType); - }*/ + VarManager::FillTripletVertexingALICE3(event, t1, t2, t3, tripletType); + } // Fill histograms bool isAmbi = false; for (int icut = 0; icut < fNLegCuts; icut++) { isAmbi = (threeTrackFilter & (static_cast(1) << 29)) || (threeTrackFilter & (static_cast(1) << 30)) || (threeTrackFilter & (static_cast(1) << 31)); if (threeTrackFilter & (static_cast(1) << icut)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); // matched signal } } // end loop (MC signals) - if (fConfigQA && isAmbi) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (cfgQA && isAmbi) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_ambiguous_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), dqefficiency_helpers::varValues()); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); // matched signal } } // end loop (MC signals) } } // end loop (common cuts) int iPairCut = 0; for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { - if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + if (!((*cut)->IsSelected(dqefficiency_helpers::varValues()))) { // apply pair cuts continue; + } // Histograms with pair cuts - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); // matched signal } } // end loop (MC signals) // Histograms with pair cuts and common track cuts for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), dqefficiency_helpers::varValues()); // matched signal } } // end loop (MC signals) } @@ -2358,7 +2344,7 @@ struct AnalysisAsymmetricPairing { void processKaonPionSkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocs const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); } @@ -2366,16 +2352,24 @@ struct AnalysisAsymmetricPairing { void processKaonPionPionSkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocs const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) + { + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToKPiPi); + } + + void processProtonKaonPionSkimmed(MyEventsVtxCovSelected const& events, + MyBarrelAssocs const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { - runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToKPiPi); + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToPKPi); } - void processMCGen(ReducedA3MCTracks const& mcTracks) + void processMCGen(ReA3MCTracks const& mcTracks) { // 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::reducedA3MCEventId, event.reducedMCevent().globalIndex()); + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedA3trackMC::reA3MCEventId, event.reducedMCevent().globalIndex()); for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -2384,35 +2378,35 @@ struct AnalysisAsymmetricPairing { // TODO: Use the mcReducedFlags to select signals for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reducedA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; void processMCGenWithEventSelection(soa::Filtered const& events, - ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedA3MCEventId()); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reA3MCEventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (const auto& track : groupedMCTracks) { VarManager::FillTrackMC(mcTracks, track); - auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + auto trackRaw = groupedMCTracks.rawIteratorAt(track.globalIndex()); for (const auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + if (sig->CheckSignal(true, trackRaw)) { + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); } } } @@ -2424,24 +2418,25 @@ struct AnalysisAsymmetricPairing { // do nothing } - PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisAsymmetricPairing, processProtonKaonPionSkimmed, "Run proton kaon pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisAsymmetricPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisAsymmetricPairing, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(Alice3DqEfficiencyAnalysisAsymmetricPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(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/ALICE3/Tasks/alice3Multicharm.cxx b/ALICE3/Tasks/alice3Multicharm.cxx index fc4cd76c769..cbdbc95e691 100644 --- a/ALICE3/Tasks/alice3Multicharm.cxx +++ b/ALICE3/Tasks/alice3Multicharm.cxx @@ -23,10 +23,8 @@ #include "ALICE3/DataModel/OTFMulticharm.h" #include "Tools/ML/model.h" -#include #include #include -#include #include #include #include diff --git a/ALICE3/Utils/a3StrangenessTofPidHelper.h b/ALICE3/Utils/a3StrangenessTofPidHelper.h index b39a3fe011e..64620419f43 100644 --- a/ALICE3/Utils/a3StrangenessTofPidHelper.h +++ b/ALICE3/Utils/a3StrangenessTofPidHelper.h @@ -20,7 +20,7 @@ #include "ALICE3/Core/TrackUtilities.h" #include -#include +#include #include diff --git a/CODEOWNERS b/CODEOWNERS index 6695663ebf4..b1639500d45 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -31,23 +31,23 @@ /EventFiltering/PWGJE @alibuild @fkrizek @nzardosh @jaimenorman @mpuccio @lietava @fgrosa @ariedel-cern /EventFiltering/PWGEM @alibuild @dsekihat @nstrangm @mpuccio @lietava @fgrosa @ariedel-cern -/PWGCF @alibuild @victor-gonzalez @shouqiye @lauraser -/PWGCF/Core @alibuild @jgrosseo @lauraser -/PWGCF/DataModel @alibuild @jgrosseo @jaelpark @victor-gonzalez @shouqiye @lauraser -/PWGCF/TableProducer @alibuild @jgrosseo @jaelpark @victor-gonzalez @shouqiye @lauraser -/PWGCF/Tasks @alibuild @jgrosseo @jaelpark @victor-gonzalez @shouqiye @lauraser -/PWGCF/EbyEFluctuations @alibuild @SwatiSaha-1997 @isputows @victor-gonzalez @shouqiye @lauraser -/PWGCF/Femto @alibuild @lauraser @ariedel-cern @dimihayl @victor-gonzalez @shouqiye @wrzesaCERN -/PWGCF/FemtoDream @alibuild @lauraser @ariedel-cern @dimihayl @victor-gonzalez @shouqiye @wrzesaCERN -/PWGCF/Femto3D @alibuild @glromane @sofiatomassini @lauraser @dimihayl @victor-gonzalez @shouqiye @wrzesaCERN -/PWGCF/FemtoUniverse @alibuild @prchakra @lgraczykCern @majanik @lauraser @dimihayl @victor-gonzalez @shouqiye @wrzesaCERN -/PWGCF/FemtoWorld @alibuild @prchakra @lgraczykCern @majanik @lauraser @dimihayl @victor-gonzalez @shouqiye @wrzesaCERN -/PWGCF/Flow @alibuild @majanik @EmilGorm @jaelpark @wenyaCern @victor-gonzalez @shouqiye @lauraser -/PWGCF/GenericFramework @alibuild @EmilGorm @jaelpark @wenyaCern @victor-gonzalez @shouqiye @lauraser -/PWGCF/MultiparticleCorrelations @alibuild @abilandz @jaelpark @wenyaCern @victor-gonzalez @shouqiye @lauraser -/PWGCF/JCorran @alibuild @jaelpark @wenyaCern @victor-gonzalez @shouqiye @lauraser -/PWGCF/TwoParticleCorrelations @alibuild @jaelpark @wenyaCern @victor-gonzalez @shouqiye @lauraser -/PWGCF/Tutorial @alibuild @ariedel-cern @victor-gonzalez @shouqiye @lauraser +/PWGCF @alibuild @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/Core @alibuild @jgrosseo @lauraser @dsarkaralice +/PWGCF/DataModel @alibuild @jgrosseo @jaelpark @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/TableProducer @alibuild @jgrosseo @jaelpark @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/Tasks @alibuild @jgrosseo @jaelpark @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/EbyEFluctuations @alibuild @SwatiSaha-1997 @isputows @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/Femto @alibuild @lauraser @ariedel-cern @dimihayl @victor-gonzalez @dsarkaralice @wrzesaCERN +/PWGCF/FemtoDream @alibuild @lauraser @ariedel-cern @dimihayl @victor-gonzalez @dsarkaralice @wrzesaCERN +/PWGCF/Femto3D @alibuild @glromane @sofiatomassini @lauraser @dimihayl @victor-gonzalez @dsarkaralice @wrzesaCERN +/PWGCF/FemtoUniverse @alibuild @prchakra @lgraczykCern @majanik @lauraser @dimihayl @victor-gonzalez @dsarkaralice @wrzesaCERN +/PWGCF/FemtoWorld @alibuild @prchakra @lgraczykCern @majanik @lauraser @dimihayl @victor-gonzalez @dsarkaralice @wrzesaCERN +/PWGCF/Flow @alibuild @majanik @EmilGorm @jaelpark @wenyaCern @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/GenericFramework @alibuild @EmilGorm @jaelpark @wenyaCern @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/MultiparticleCorrelations @alibuild @abilandz @jaelpark @wenyaCern @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/JCorran @alibuild @jaelpark @wenyaCern @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/TwoParticleCorrelations @alibuild @jaelpark @wenyaCern @victor-gonzalez @dsarkaralice @lauraser +/PWGCF/Tutorial @alibuild @ariedel-cern @victor-gonzalez @dsarkaralice @lauraser /PWGDQ @alibuild @iarsene @mcoquet642 @XiaozhiBai @mguilbau /PWGEM @alibuild @feisenhu @dsekihat @jokonig @hscheid @@ -56,18 +56,18 @@ /PWGHF @alibuild @vkucera @fcolamar @fgrosa @fcatalan92 @mfaggin @mmazzilli @deepathoms @NicoleBastid @hahassan7 @jpxrk @apalasciano @zhangbiao-phy @gluparel @stefanopolitano @xinyepeng @singhra1994 # PWG-LF /PWGLF @alibuild @omvazque @skundu692 @mpuccio -/PWGLF/DataModel @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova +/PWGLF/DataModel @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @mario-krueger @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova /PWGLF/Tasks/GlobalEventProperties @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @omvazque /PWGLF/TableProducer/GlobalEventProperties @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @omvazque -/PWGLF/Tasks/Nuspex @alibuild @omvazque @skundu692 @mpuccio @fmazzasc @maciacco @HorstMa -/PWGLF/TableProducer/Nuspex @alibuild @omvazque @skundu692 @mpuccio @fmazzasc @maciacco @HorstMa +/PWGLF/Tasks/Nuspex @alibuild @omvazque @skundu692 @mpuccio @mario-krueger @maciacco @HorstMa +/PWGLF/TableProducer/Nuspex @alibuild @omvazque @skundu692 @mpuccio @mario-krueger @maciacco @HorstMa /PWGLF/Tasks/Resonances @alibuild @omvazque @skundu692 @mpuccio @dmallick2 @smaff92 @prottayCMT /PWGLF/TableProducer/Resonances @alibuild @omvazque @skundu692 @mpuccio @dmallick2 @smaff92 @prottayCMT /PWGLF/Tasks/Strangeness @alibuild @omvazque @skundu692 @mpuccio @ercolessi @romainschotter @lhusova /PWGLF/TableProducer/Strangeness @alibuild @omvazque @mpuccio @skundu692 @ercolessi @romainschotter @lhusova -/PWGLF/TableProducer/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova -/PWGLF/Tasks/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova -/PWGLF/Utils @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova +/PWGLF/TableProducer/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @mario-krueger @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova +/PWGLF/Tasks/QC @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @mario-krueger @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova +/PWGLF/Utils @alibuild @omvazque @skundu692 @mpuccio @gbencedi @abmodak @mario-krueger @maciacco @HorstMa @dmallick2 @smaff92 @ercolessi @romainschotter @prottayCMT @lhusova # PWG-MM (fused with LF, LF conveners included. Directories to be merged in the future) /PWGMM @alibuild @omvazque @mpuccio @skundu692 @aalkin @jgcn diff --git a/Common/Core/fwdtrackUtilities.h b/Common/Core/fwdtrackUtilities.h index 7265f1fe581..29a9db2c194 100644 --- a/Common/Core/fwdtrackUtilities.h +++ b/Common/Core/fwdtrackUtilities.h @@ -60,9 +60,9 @@ concept is_fwd_cov = requires(T t) { { t.sigmaX() } -> std::same_as; }; -/// Produce TrackParCovFwds for MFT and FwdTracks, w/ or w/o cov, with z shift +/// Produce TrackParCovFwds for MFT and FwdTracks, w/ or w/o cov, with x, y and z shifts template -o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float zshift, TCovariance const&... covOpt) +o2::track::TrackParCovFwd getTrackParCovFwd3DShift(TFwdTrack const& track, float xshift, float yshift, float zshift, TCovariance const&... covOpt) { double chi2 = track.chi2(); if constexpr (sizeof...(covOpt) == 0) { @@ -82,7 +82,7 @@ o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float z } } - SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + SMatrix5 tpars(track.x() + xshift, track.y() + yshift, track.phi(), track.tgl(), track.signed1Pt()); SMatrix55 tcovs; if constexpr (sizeof...(covOpt) == 1) { @@ -101,6 +101,13 @@ o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float z return o2::track::TrackParCovFwd(track.z() + zshift, tpars, tcovs, chi2); } +/// Produce TrackParCovFwds for MFT and FwdTracks, w/ or w/o cov, with z shift +template +o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float zshift, TCovariance const&... covOpt) +{ + return getTrackParCovFwd3DShift(track, 0.f, 0.f, zshift, covOpt...); +} + inline o2::track::TrackParCovFwd getTrackParCovFwdShiftManual( const double x, const double y, const double phi, const double tgl, const double signed1Pt, const double cXX, diff --git a/Common/Tasks/checkDataModelMC.cxx b/Common/Tasks/checkDataModelMC.cxx index 799cf68a8e2..8eb6efc03f2 100644 --- a/Common/Tasks/checkDataModelMC.cxx +++ b/Common/Tasks/checkDataModelMC.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/Common/Tools/PID/pidTPCModule.h b/Common/Tools/PID/pidTPCModule.h index e86ec6ea351..de97ef65eba 100644 --- a/Common/Tools/PID/pidTPCModule.h +++ b/Common/Tools/PID/pidTPCModule.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx index 38348abd7bd..caaf159c47d 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx @@ -12,13 +12,18 @@ #include "tableHMPID.h" #include +#include #include +#include +#include #include #include -#include #include +#include +#include + using namespace o2; using namespace o2::framework; diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx index 06c8f92b139..1074a071b60 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx @@ -34,6 +34,8 @@ #include #include +#include +#include #include @@ -73,6 +75,12 @@ struct HmpidTableProducer { Configurable requireTPC{"requireTPC", true, "Require TPC track"}; Configurable requireTOF{"requireTOF", true, "Require TOF track"}; + Configurable useInAbsorberGeomMethod{"useInAbsorberGeomMethod", false, "Use geometrical method to check if daughters are born in absorber"}; + + // (reference) 473 cm - was the legacy value in run2 simulation + Configurable survivalThresholdRich2{"survivalThresholdRich2", 437.5f, "survivalThresholdRich2"}; + Configurable survivalThresholdRich4{"survivalThresholdRich4", 439.0f, "survivalThresholdRich4"}; + using CollisionCandidates = o2::soa::Join; using TrackCandidates = soa::JoinGLOBAL transform is built as: - // pMatrix->SetTranslation(T); - // pMatrix->RotateZ(theta); - // which yields, for a local point p: p_glob = Rz(theta) * p_loc + T. - // In particular the box CENTER in global coordinates is exactly T (the - // rotation does not affect T, since it is applied to p_loc only, not to - // the already-set translation). Only the box AXES are rotated by theta - // with respect to the global x,y axes. - // - // To test whether a global point lies inside the box we invert the - // transform: p_loc = Rz(-theta) * (p_glob - T), then compare component-wise - // against the box half-widths. - // ----------------------------------------------------------------------- + // (reference) HMPID Detector class in O2 static constexpr double AbsThetaDeg = 33.5; - const double mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad()); - const double mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad()); + double mAbsCosT = 0., mAbsSinT = 0.; // Rich2 absorber: trans2 = {435.5, 0., -155.}, thickness 40mm -> halfX = 2cm static constexpr double AbsRich2CenterX = 435.5, AbsRich2CenterZ = -155.; @@ -132,6 +119,9 @@ struct HmpidTableProducer { void init(o2::framework::InitContext&) { + mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad()); + mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad()); + ccdb->setURL(ccdbConfig.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -159,6 +149,10 @@ struct HmpidTableProducer { kTH1F, {{4, -0.5, 3.5, ""}}); histos.add("hProdVertex", ";X (cm);Y (cm);Z (cm)", HistType::kTH3F, {{500, -500., 500.}, {500, -500., 500.}, {500, -500., 500.}}); + histos.add("hDaughterRCyl_Rich2", "hDaughterRCyl_Rich2", kTH1F, {{600, 0., 600.}}); + histos.add("hDaughterRCyl_Rich4", "hDaughterRCyl_Rich4", kTH1F, {{600, 0., 600.}}); + histos.add("hDaughterRSph_Rich2", "hDaughterRSph_Rich2", kTH1F, {{600, 0., 600.}}); + histos.add("hDaughterRSph_Rich4", "hDaughterRSph_Rich4", kTH1F, {{600, 0., 600.}}); } // ----------------------------------------------------------------------- @@ -274,8 +268,9 @@ struct HmpidTableProducer { (x[1] - planePoint[1]) * planeNormal[1] + (x[2] - planePoint[2]) * planeNormal[2]; - if (std::abs(dist) >= std::abs(distPrev)) + if (std::abs(dist) >= std::abs(distPrev)) { return false; + } distPrev = dist; s -= dist; @@ -318,14 +313,16 @@ struct HmpidTableProducer { // Intersection track - radiator plane std::array xRad{}, pAtRad{}; - if (!intersectHelixPlane(bz, charge, x, p, pRad, nRad, xRad, pAtRad)) + if (!intersectHelixPlane(bz, charge, x, p, pRad, nRad, xRad, pAtRad)) { continue; + } // Intersection track - PC plane std::array xPc{}, pAtPc{}; - if (!intersectHelixPlane(bz, charge, xRad, pAtRad, pPc, nPc, xPc, pAtPc)) + if (!intersectHelixPlane(bz, charge, xRad, pAtRad, pPc, nPc, xPc, pAtPc)) { continue; + } double theta = 0., phi = 0.; param->mars2LorsVec(ch, pAtRad.data(), theta, phi); @@ -334,8 +331,9 @@ struct HmpidTableProducer { param->mars2Lors(ch, xPc.data(), xL, yL); // Use isInside to check Chamber intersected - if (param->isInside(xL, yL, param->distCut())) + if (param->isInside(xL, yL, param->distCut())) { return ch; + } } // No chamber intersected @@ -361,17 +359,32 @@ struct HmpidTableProducer { return false; } - // subtract the box center (translation is not rotated, see geometry block above) - const double rx = vx * mAbsCosT + vy * mAbsSinT; - const double ry = -vx * mAbsSinT + vy * mAbsCosT; - const double rz = vz; + // translate to box center + const double lx = vx - centerX; + const double ly = vy; // centerY = 0 + const double lz = vz - centerZ; // rotate by -theta into the box local frame - const double lx = rx - centerX; - const double ly = ry; // centerY = 0 - const double lz = rz - centerZ; + const double rx = lx * mAbsCosT + ly * mAbsSinT; + const double ry = -lx * mAbsSinT + ly * mAbsCosT; + const double rz = lz; + + return std::abs(rx) <= halfX && std::abs(ry) <= AbsHalfY && std::abs(rz) <= AbsHalfZ; + } + + bool survivedAbsorber(double vx, double vy, int chamber) + { + float thresholdR = 0.; + if (chamber == Rich2) { + thresholdR = survivalThresholdRich2; + } else if (chamber == Rich4) { + thresholdR = survivalThresholdRich4; + } else { + return false; + } - return std::abs(lx) <= halfX && std::abs(ly) <= AbsHalfY && std::abs(lz) <= AbsHalfZ; + const float r = std::hypot(vx, vy); + return r > thresholdR; } void processEvent(CollisionCandidates::iterator const& col, @@ -397,8 +410,9 @@ struct HmpidTableProducer { const auto& globalTrack = t.template track_as(); - if (!globalTrack.has_collision()) + if (!globalTrack.has_collision()) { continue; + } const auto& col = globalTrack.template collision_as(); initCCDB(col.template bc_as()); @@ -406,17 +420,20 @@ struct HmpidTableProducer { if ((requireITS && !globalTrack.hasITS()) || (requireTPC && !globalTrack.hasTPC()) || - (requireTOF && !globalTrack.hasTOF())) + (requireTOF && !globalTrack.hasTOF())) { continue; + } - if (mCollisionsWithHmpid.insert(collId).second) + if (mCollisionsWithHmpid.insert(collId).second) { histos.fill(HIST("eventsHmpid"), 0.5); + } // clusSize diagnostics histos.fill(HIST("hClusSize"), t.hmpidClusSize()); bool isCorrupt = (t.hmpidClusSize() <= 0); - if (isCorrupt) + if (isCorrupt) { histos.fill(HIST("hClusSizeCorrupt"), t.hmpidClusSize()); + } // --- M2: clusSize encoding --- int chamberM2 = t.hmpidClusSize() / 1000000; @@ -464,20 +481,22 @@ struct HmpidTableProducer { // bin 2 = clusSize <= 0, M1 recovery (corrupt, M1 ok) // bin 3 = clusSize <= 0, M1 fails (corrupt, skipped) - if (!isCorrupt && chamberM3 >= 0) + if (!isCorrupt && chamberM3 >= 0) { histos.fill(HIST("hChamberAssignment"), 0.); - else if (!isCorrupt && chamberM3 < 0) + } else if (!isCorrupt && chamberM3 < 0) { histos.fill(HIST("hChamberAssignment"), 1.); - else if (isCorrupt && chamberM3 >= 0) + } else if (isCorrupt && chamberM3 >= 0) { histos.fill(HIST("hChamberAssignment"), 2.); - else + } else { histos.fill(HIST("hChamberAssignment"), 3.); + } histos.fill(HIST("hChamberM3"), chamberM3); histos.fill(HIST("hChamberM3vsM2"), chamberM2, chamberM3); - if (chamberM3 < 0) + if (chamberM3 < 0) { continue; + } std::vector hmpidPhotsCharge2(o2::aod::kDimPhotonsCharge, 0.f); @@ -514,23 +533,78 @@ struct HmpidTableProducer { if ((chamberM3 == Rich2 || chamberM3 == Rich4) && mc.has_daughters()) { auto dIds = mc.daughtersIds(); - - for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) { - auto daughter = mcParticles.rawIteratorAt(idx); - - histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz()); - - if (isInAbsorber(daughter.vx(), daughter.vy(), daughter.vz(), chamberM3)) { - interactionInAbsorber = true; - break; - } - } // end loop daughters + bool foundRelevantDaughter = false; // true if at least one non-delta/photon daughter was examined + + if (useInAbsorberGeomMethod) { + for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) { + auto daughter = mcParticles.rawIteratorAt(idx); + + int absPdg = std::abs(daughter.pdgCode()); + if (absPdg == kElectron || absPdg == kGamma) { + continue; + } + + foundRelevantDaughter = true; + + // diagnostics on daughters distribution + histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz()); + + double rCyl = std::hypot(daughter.vx(), daughter.vy()); + double rSph = std::hypot(daughter.vx(), daughter.vy(), daughter.vz()); + if (chamberM3 == Rich2) { + histos.fill(HIST("hDaughterRCyl_Rich2"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich2"), rSph); + } else { + histos.fill(HIST("hDaughterRCyl_Rich4"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich4"), rSph); + } + + if (isInAbsorber(daughter.vx(), daughter.vy(), daughter.vz(), chamberM3)) { + interactionInAbsorber = true; + } + } // end loop daughters + } else { + bool survived = false; + for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) { + auto daughter = mcParticles.rawIteratorAt(idx); + + // skip delta rays (e-/e+), photons, and HMPID Cherenkov/feedback + int absPdg = std::abs(daughter.pdgCode()); + if (absPdg == kElectron || absPdg == kGamma) { + continue; + } + + foundRelevantDaughter = true; + + histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz()); + + double rCyl = std::hypot(daughter.vx(), daughter.vy()); + double rSph = std::hypot(daughter.vx(), daughter.vy(), daughter.vz()); + if (chamberM3 == Rich2) { + histos.fill(HIST("hDaughterRCyl_Rich2"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich2"), rSph); + } else { + histos.fill(HIST("hDaughterRCyl_Rich4"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich4"), rSph); + } + + if (survivedAbsorber(daughter.vx(), daughter.vy(), chamberM3)) { + survived = true; + } + } // end loop daughters + + // No relevant daughter found (only delta rays/photons, or no + // daughters at all): no evidence of a genuine interaction -> treat + // as primary/survived, consistent with the "no daughters" case. + interactionInAbsorber = foundRelevantDaughter ? !survived : false; + } } // end if has_daughters hmpidAnalysisMC(mc.pdgCode(), mc.vx(), mc.vy(), mc.vz(), mc.isPhysicalPrimary(), mc.getProcess(), interactionInAbsorber); } else { - hmpidAnalysisMC(-1, 0.f, 0.f, 0.f, false, -100, false); + // No MC truth associated to this track + hmpidAnalysisMC(-999, -999.f, -999.f, -999.f, false, -100, false); } } // end if constexpr (isMC) diff --git a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx index 491859bec09..7665f440bdb 100644 --- a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx @@ -24,7 +24,6 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include #include #include #include @@ -40,6 +39,8 @@ #include #include +#include +#include #include #include #include @@ -57,7 +58,6 @@ struct MeanPtFlucId { Configurable cfgCutPtMax{"cfgCutPtMax", 2.0, "maximum pT"}; Configurable cfgCutPtMin{"cfgCutPtMin", 0.2, "minimum pT"}; Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut"}; - Configurable cfgCutRap{"cfgCutRap", 0.5, "Rapidity Cut"}; Configurable cfgCutDcaZ{"cfgCutDcaZ", 0.15, "DCAz cut"}; Configurable cfgCutPosZ{"cfgCutPosZ", 7.0, "cut for vertex Z"}; Configurable cfgPosZ{"cfgPosZ", true, "Position Z"}; @@ -67,51 +67,50 @@ struct MeanPtFlucId { Configurable cfgSelCutNSigPi{"cfgSelCutNSigPi", 2.0, "nSigma cut for pion selection"}; Configurable cfgSelCutNSigKa{"cfgSelCutNSigKa", 3.0, "nSigma cut for kaon selection"}; Configurable cfgSelCutNSigPr{"cfgSelCutNSigPr", 2.0, "nSigma cut for proton selection"}; - Configurable cfgRejCutNSigPi{"cfgRejCutNSigPi", 3.0, "nSigma cut for rejection of other particles while selecting pion"}; Configurable cfgCutPiPtMin{"cfgCutPiPtMin", 0.2, "Minimum pion p_{T} cut"}; Configurable cfgCutKaPtMin{"cfgCutKaPtMin", 0.3, "Minimum kaon p_{T} cut"}; Configurable cfgCutPrPtMin{"cfgCutPrPtMin", 0.5, "Minimum proton p_{T} cut"}; Configurable cfgCutPiThrsldP{"cfgCutPiThrsldP", 0.6, "Threshold p cut pion"}; Configurable cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.6, "Threshold p cut kaon"}; Configurable cfgCutPrThrsldP{"cfgCutPrThrsldP", 1.0, "Threshold p cut proton "}; + Configurable cfgP0U{"cfgP0U", 6.36269, "p_{0} for upper cut for N_{TPC} vs N{sim}"}; + Configurable cfgP1U{"cfgP1U", 2.22108, "p_{1} for upper cut for N_{TPC} vs N{sim}"}; + Configurable cfgP2U{"cfgP2U", -0.0118451, "p_{2} for upper cut for N_{TPC} vs N{sim}"}; + Configurable cfgP0L{"cfgP0L", 23.8213, "p_{0} for lower cut for N_{TPC} vs N{sim}"}; + Configurable cfgP1L{"cfgP1L", -0.402328, "p_{1} for lower cut for N_{TPC} vs N{sim}"}; + Configurable cfgP2L{"cfgP2L", 0.0128423, "p_{2} for lower cut for N_{TPC} vs N{sim}"}; + Configurable cfgP0L1{"cfgP0L1", -10.5149, "p_{0} for lower cut for N_{TPC} vs N{sim}"}; + Configurable cfgP1L1{"cfgP1L1", 0.936596, "p_{1} for lower cut for N_{TPC} vs N{sim}"}; + Configurable cfgP0corr{"cfgP0corr", 0.0001, "p_{0} for corrected N_{TPC} "}; + Configurable cfgP1corr{"cfgP1corr", 0.0001, "p_{1} for corrected N_{TPC} "}; + Configurable cfgP2corr{"cfgP2corr", 0.0001, "p_{2} for corrected N_{TPC} "}; Configurable cfgSel8{"cfgSel8", true, "Sel8 trigger"}; - Configurable cfgMinWeight{"cfgMinWeight", 1e-6, "Minimum weight for efficiency correction"}; Configurable cfgNoSameBunchPileup{"cfgNoSameBunchPileup", true, "kNoSameBunchPileup"}; Configurable cfgIsVertexITSTPC{"cfgIsVertexITSTPC", true, "kIsVertexITSTPC"}; + Configurable cfgLightIonCuts{"cfgLightIonCuts", false, "Light Ion Cuts"}; + Configurable cfgIsGoodITSLayersAll{"cfgIsGoodITSLayersAll", true, "kIsGoodITSLayersAll"}; + Configurable cfgIsGoodZvtxFT0vsPV{"cfgIsGoodZvtxFT0vsPV", true, "kIsGoodZvtxFT0vsPV"}; Configurable cfgRejTrk{"cfgRejTrk", true, "Rejected Tracks"}; - Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency"}; - Configurable cfgCorrection{"cfgCorrection", true, "Correction"}; - Configurable cfgWeightPtCh{"cfgWeightPtCh", true, "Efficiency correction (pT) for charged particles"}; - Configurable cfgWeightPtId{"cfgWeightPtId", false, "Efficiency correction (pT) "}; - Configurable cfgWeightPtEtaId{"cfgWeightPtEtaId", false, "Efficiency correction (pT) "}; - Configurable cfgPurityId{"cfgPurityId", false, "Purity correction"}; + Configurable cfgNtpcEventCut{"cfgNtpcEventCut", true, "N_{TPC} Event Cut for reco"}; ConfigurableAxis multTPCBins{"multTPCBins", {150, 0, 150}, "TPC Multiplicity bins"}; + ConfigurableAxis multMCBins{"multMCBins", {300, 0, 300}, "MC Multiplicity bins"}; + ConfigurableAxis multCorrBins{"multCorrBins", {100, 0., 150.}, "Corrected TPC Multiplicity bins"}; ConfigurableAxis multFT0MBins{"multFT0MBins", {1000, 0, 5000}, "Forward Multiplicity bins"}; - ConfigurableAxis qNBins{"qNBins", {1000, 0., 100.}, "nth moments bins"}; - ConfigurableAxis nPairBins{"nPairBins", {2000, 0, 10000}, "nPair bins"}; ConfigurableAxis dcaXYBins{"dcaXYBins", {100, -0.15, 0.15}, "dcaXY bins"}; ConfigurableAxis dcaZBins{"dcaZBins", {500, -1.2, 1.2}, "dcaZ bins"}; + ConfigurableAxis centBins{"centBins", {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, "Centrality bins"}; - Configurable> ptBins{"ptBins", {0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15, 1.20, 1.25, 1.30, 1.35, 1.40, 1.45, 1.50, 1.55, 1.60, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90, 1.95, 2.00}, "p_{T} bins"}; + Configurable> ptBins{"ptBins", {0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15, 1.20, 1.25, 1.30, 1.35, 1.40, 1.45, 1.50, 1.55, 1.60, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90, 1.95, 2.00}, "p_{T} bins"}; Configurable> etaBins{"etaBins", {-0.8, -0.75, -0.7, -0.65, -0.6, -0.55, -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8}, "#eta bins"}; - Configurable cfgUrlCCDB{"cfgUrlCCDB", "http://ccdb-test.cern.ch:8080", "url of ccdb"}; - Configurable cfgPathCCDB{"cfgPathCCDB", "Users/t/tgahlaut/weightCorr/", "Path for ccdb-object"}; + Configurable> ptBinsPi{"ptBinsPi", {0.20, 0.225, 0.25, 0.275, 0.30, 0.325, 0.35, 0.375, 0.40, 0.425, 0.45, 0.475, 0.50, 0.525, 0.55, 0.575, 0.60, 0.70, 0.90, 1.1, 1.3, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90, 1.95, 2.00}, "p_{T} bins for pions"}; + Configurable> ptBinsKa{"ptBinsKa", {0.30, 0.325, 0.35, 0.375, 0.40, 0.425, 0.45, 0.475, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.8, 0.85, 0.90, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.70, 1.80, 1.90, 2.00}, "p_{T} bins for kaons"}; + Configurable> ptBinsPr{"ptBinsPr", {0.40, 0.425, 0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.60, 0.625, 0.65, 0.675, 0.70, 0.725, 0.75, 0.775, 0.80, 0.825, 0.85, 0.875, 0.90, 0.925, 0.95, 1.0, 1.025, 1.05, 1.075, 1.1, 1.15, 1.2, 1.4, 1.6, 1.8, 2.0}, "p_{T} bins for protons"}; - Service ccdb; - Service pdg; + Service pdg{}; HistogramRegistry hist{"hist", {}, OutputObjHandlingPolicy::AnalysisObject}; - TH1D* hWeightPt = nullptr; - TH1D* hPurePt = nullptr; - TH1D* hWeightPtPi = nullptr; - TH1D* hWeightPtKa = nullptr; - TH1D* hWeightPtPr = nullptr; - TH1D* hPurePtPi = nullptr; - TH1D* hPurePtKa = nullptr; - TH1D* hPurePtPr = nullptr; - enum CollisionLabels { kTotCol = 1, kPassSelCol @@ -129,6 +128,8 @@ struct MeanPtFlucId { kSelColSel8, kSelColNoSameBunchPileup, kSelColIsVertexITSTPC, + kSelColIsGoodITSLayersAll, + kSelColIsGoodZvtxFT0vsPV }; enum class PIDType { @@ -153,7 +154,7 @@ struct MeanPtFlucId { Gen_Proton }; - static constexpr std::string_view Dire[] = { + static constexpr std::array Dire{ "QA/after/", "QA/Pion/", "QA/Kaon/", @@ -167,26 +168,34 @@ struct MeanPtFlucId { "Gen/Kaon/", "Gen/Proton/"}; + struct TrackInfo { + double pt; + double eta; + }; + + std::vector chargedTracks; + std::vector pionTracks; + std::vector kaonTracks; + std::vector protonTracks; + + std::vector chargedTracksGen; + std::vector pionTracksGen; + std::vector kaonTracksGen; + std::vector protonTracksGen; + void init(InitContext const&) { - if (cfgLoadEff) { - // Set CCDB url - ccdb->setURL(cfgUrlCCDB.value); - ccdb->setCaching(true); - - TList* lst = ccdb->getForTimeStamp(cfgPathCCDB.value, 1); - hWeightPt = reinterpret_cast(lst->FindObject("hWeightPt")); - hWeightPtPi = reinterpret_cast(lst->FindObject("hWeightPtPi")); - hWeightPtKa = reinterpret_cast(lst->FindObject("hWeightPtKa")); - hWeightPtPr = reinterpret_cast(lst->FindObject("hWeightPtPr")); - hPurePtPi = reinterpret_cast(lst->FindObject("hPurePtPi")); - hPurePtKa = reinterpret_cast(lst->FindObject("hPurePtKa")); - hPurePtPr = reinterpret_cast(lst->FindObject("hPurePtPr")); - - if (!hWeightPt || !hWeightPtPi || !hWeightPtKa || !hWeightPtPr || !hPurePtPi || !hPurePtKa || !hPurePtPr) { - LOGF(info, "FATAL!! Could not find required histograms in CCDB"); - } - } + + const int nEta = etaBins->size() - 1; + const int nPtCh = ptBins->size() - 1; + const int nPtPi = ptBinsPi->size() - 1; + const int nPtKa = ptBinsKa->size() - 1; + const int nPtPr = ptBinsPr->size() - 1; + + const AxisSpec axisKCh{nEta * nPtCh, 0, static_cast(nEta * nPtCh), "k_{ch}"}; + const AxisSpec axisKPi{nEta * nPtPi, 0, static_cast(nEta * nPtPi), "k_{#pi}"}; + const AxisSpec axisKKa{nEta * nPtKa, 0, static_cast(nEta * nPtKa), "k_{K}"}; + const AxisSpec axisKPr{nEta * nPtPr, 0, static_cast(nEta * nPtPr), "k_{p}"}; const AxisSpec axisCol{3, 1, 4, ""}; const AxisSpec axisTrack{5, 1, 6, ""}; @@ -195,16 +204,19 @@ struct MeanPtFlucId { const AxisSpec axisPhi{nPhiBins, 0., +7., "#phi (rad)"}; const AxisSpec axisY{100, -0.6, 0.6, "y"}; const AxisSpec axisPt{ptBins, "p_{T} (GeV/c)"}; + const AxisSpec axisPtPi{ptBinsPi, "p_{T} (GeV/c)"}; + const AxisSpec axisPtKa{ptBinsKa, "p_{T}(GeV/c)"}; + const AxisSpec axisPtPr{ptBinsPr, "p_{T} (GeV/c)"}; const AxisSpec axisP{nPBins, 0., 3., "p (GeV/c)"}; - const AxisSpec axisInnerParam{nPBins, 0., 3., "p_{InnerParam } (GeV/c)"}; + const AxisSpec axisInnerParam{nPBins, 0., 3., "p_{InnerParam} (GeV/c)"}; const AxisSpec axisPart{nPartBins, 0., 18., " "}; - const AxisSpec axisQn{qNBins, ""}; - const AxisSpec axisNpair{nPairBins, "N_{pairs}"}; - const AxisSpec axisMeanPt{100, 0., 3., "M(p_{T}) (GeV/c)"}; const AxisSpec axisMult{100, 0, 100, "N_{ch}"}; const AxisSpec axisMultTPC{multTPCBins, "N_{TPC} "}; + const AxisSpec axisMultCorr{multCorrBins, "N_{Corr} "}; + const AxisSpec axisMultMC{multMCBins, "N_{Gen} "}; const AxisSpec axisMultFT0M{multFT0MBins, "N_{FT0M}"}; const AxisSpec axisCentFT0M{101, 0, 101, "FT0M (%)"}; + const AxisSpec axisCent{centBins, "FT0M (%)"}; const AxisSpec axisVtxZ{80, -20., 20., "V_{Z} (cm)"}; const AxisSpec axisDCAz{dcaZBins, "DCA_{Z} (cm)"}; const AxisSpec axisDCAxy{dcaXYBins, "DCA_{XY} (cm)"}; @@ -217,9 +229,7 @@ struct MeanPtFlucId { const AxisSpec axisM2{100, 0., 1.4, "#it{m}^{2} (GeV/#it{c}^{2})^{2}"}; const AxisSpec axisPid{300, 0, 3000, "PID"}; - HistogramConfigSpec qNHist({HistType::kTHnSparseD, {axisCentFT0M, axisQn}}); - HistogramConfigSpec partHist({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); - HistogramConfigSpec qNMCHist({HistType::kTHnSparseD, {axisCentFT0M, axisQn}}); + HistogramConfigSpec partHistCent({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); HistogramConfigSpec partMCHist({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); HistogramConfigSpec tofNSigmaHist({HistType::kTH2D, {axisP, axisTOFNsigma}}); HistogramConfigSpec tofSignalHist({HistType::kTH2D, {axisP, axisTOFSignal}}); @@ -251,6 +261,7 @@ struct MeanPtFlucId { hist.add("QA/before/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); hist.add("QA/before/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); + hist.add("QA/after/h_Ncorr", "N_{corr}", kTH1D, {axisMultCorr}); hist.add("QA/after/h_counts_evSelCuts", "Event selection cuts", kTH1D, {axisEvents}); hist.add("QA/after/h_TPCChi2perCluster", "TPC #Chi^{2}/Cluster", kTH1D, {axisChi2}); hist.add("QA/after/h_ITSChi2perCluster", "ITS #Chi^{2}/Cluster", kTH1D, {axisChi2}); @@ -264,32 +275,31 @@ struct MeanPtFlucId { hist.add("QA/after/h_DCAxy_secondary", "DCA_{XY} (Secondary)", kTH1D, {axisDCAxy}); hist.add("QA/after/h_DCAz_secondary", "DCA_{Z} (Secondary)", kTH1D, {axisDCAz}); hist.add("QA/after/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); + hist.add("QA/after/h2_NSim_NTPC", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultMC}, {axisMultTPC}}); + hist.add("QA/after/h2_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultMC}}); + hist.add("QA/after/p_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTProfile, {axisMultTPC}); + hist.add("QA/after/h2_Ncorr_NSim", "Truth vs Corrected Multiplicty TPC", kTH2D, {{axisMultCorr}, {axisMultMC}}); + hist.add("QA/after/h2_Ncorr_CentM", "N_{corr} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {axisMultCorr}}); hist.add("QA/Charged/h_Pt", "p_{T}", kTH1D, {axisPt}); hist.add("QA/Charged/h_Eta", "#eta ", kTH1D, {axisEta}); hist.add("QA/Charged/h_Phi", "#phi ", kTH1D, {axisPhi}); hist.add("QA/Charged/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); hist.add("QA/Charged/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); + hist.add("QA/Charged/h2_Pt_PtMC", "p_{T} vs p_{T} (MC)", kTH2D, {{axisPt}, {axisPt}}); hist.add("QA/Charged/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); hist.add("QA/Charged/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); - hist.add("QA/Charged/h_Pt_weighted", "weighted pT distribution", kTH1D, {axisPt}); - hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPt}}); hist.add("QA/Charged/h2_Pt_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); - hist.add("QA/Charged/h3_PtEtaPhi", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); + hist.add("QA/Charged/h3_Pt_Eta_Phi", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); hist.addClone("QA/Charged/", "QA/Pion/"); hist.add("QA/Pion/before/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/before/h2_TPCNsigma_nottof", "n #sigma_{TPC}", tpcNSigmaHist); hist.add("QA/Pion/before/h2_TPCNsigma_tof", "n #sigma_{TPC}", tpcNSigmaHist); hist.add("QA/Pion/before/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); hist.add("QA/Pion/before/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); - hist.add("QA/Pion/h_Rap", "y ", kTH1D, {axisY}); - hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPt}); - hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPt}); - hist.add("QA/Pion/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPt}); - hist.add("QA/Pion/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPt}); - hist.add("QA/Pion/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPt}); hist.add("QA/Pion/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); hist.add("QA/Pion/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); hist.add("QA/Pion/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); @@ -297,61 +307,151 @@ struct MeanPtFlucId { hist.add("QA/Pion/h2_TOFSignal", "TOF Signal", tofSignalHist); hist.add("QA/Pion/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); hist.add("QA/Pion/h2_pvsm2", "p vs m^{2}", pvsM2Hist); - hist.add("QA/Pion/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPt}); - hist.add("QA/Pion/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPt}); hist.addClone("QA/Pion/", "QA/Kaon/"); hist.addClone("QA/Pion/", "QA/Proton/"); + hist.add("QA/Charged/h_PtMC", "p_{T} (MC)", kTH1D, {axisPt}); + hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPt}}); + hist.add("QA/Charged/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPt}, {axisCent}}); + hist.add("QA/Charged/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPt}, {axisCent}}); + hist.add("QA/Charged/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPt}}); + + hist.add("QA/Pion/h_Pt_e", "p_{T}", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("QA/Pion/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + hist.add("QA/Pion/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + hist.add("QA/Pion/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPi}}); + + hist.add("QA/Kaon/h_Pt_e", "p_{T}", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("QA/Kaon/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + hist.add("QA/Kaon/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + hist.add("QA/Kaon/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("QA/Kaon/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtKa}}); + + hist.add("QA/Proton/h_Pt_e", "p_{T}", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("QA/Proton/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/Proton/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/Proton/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("QA/Proton/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPr}}); + // AnalysisPlots - hist.add("Analysis/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); - hist.add("Analysis/Charged/h_N_CentFT0M", "Multiplicity vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisMult}); - hist.add("Analysis/Charged/h_Npair_CentFT0M", "Npair vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisNpair}); - hist.add("Analysis/Charged/h_Q1_CentFT0M", "Q1 vs CentFT0M", qNHist); - hist.add("Analysis/Charged/h_Q2_CentFT0M", "Q2 vs CentFT0M", qNHist); - hist.add("Analysis/Charged/h_twopart1_CentFT0M", "twopart (neum)", qNMCHist); - hist.add("Analysis/Charged/h_mean_pT_Mult_var", " vs N_{TPC} ", partHist); - hist.add("Analysis/Charged/h_twopart_Mult_var", "Twopart vs N_{TPC} ", partHist); - hist.add("Analysis/Charged/p_twopart_CentFT0M", "Twopart vs cent_{FT0M} ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/p_mean_pT_CentFT0M", " vs cent_{FT0M} ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/h_mult", "Multiplicity", kTH1D, {axisMult}); + hist.add("Analysis/Charged/p_Q1_Mult", " Q1 vs Mult ", kTProfile, {axisMultTPC}); + hist.add("Analysis/Charged/p_Q2_Mult", " Q2 vs Mult ", kTProfile, {axisMultTPC}); + hist.add("Analysis/Charged/p_mean_pT_Mult", " vs Mult ", kTProfile, {axisMultTPC}); + hist.add("Analysis/Charged/p_mean_pT_Cent", " vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/p_mean_pT_Cent_var", " vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/p_twopart_Cent_var", "Twopart vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/h_mean_pT_Cent", " vs CentFT0M ", kTH1D, {axisCentFT0M}); + hist.add("Analysis/Charged/h_mean_pT_Cent_var", " vs CentFT0M ", kTH1D, {axisCentFT0M}); + hist.add("Analysis/Charged/h_twopart_Cent_var", "Twopart vs CentFT0M ", kTH1D, {axisCentFT0M}); + hist.add("Analysis/Charged/p_mean_pT_Num_Cent_var", " Numerator vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/p_mean_pT_Den_Cent_var", " Denominator vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/p_twopart_Num_Cent_var", "Twopart Numerator vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/p_twopart_Den_Cent_var", "Twopart Denominator vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/h_mean_pT_Num_Cent_var", " Numerator vs CentFT0M ", kTH1D, {axisCentFT0M}); + hist.add("Analysis/Charged/h_mean_pT_Den_Cent_var", " Denominator vs CentFT0M ", kTH1D, {axisCentFT0M}); + hist.add("Analysis/Charged/h_twopart_Num_Cent_var", "Twopart Numerator vs CentFT0M ", kTH1D, {axisCentFT0M}); + hist.add("Analysis/Charged/h_twopart_Den_Cent_var", "Twopart Denominator vs CentFT0M ", kTH1D, {axisCentFT0M}); hist.addClone("Analysis/Charged/", "Analysis/Pion/"); hist.addClone("Analysis/Charged/", "Analysis/Kaon/"); hist.addClone("Analysis/Charged/", "Analysis/Proton/"); + hist.add("Analysis/Charged/hN1Matrix", "", kTH2D, {{axisCent}, {axisKCh}}); + hist.add("Analysis/Charged/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKCh}}); + hist.add("Analysis/Charged/hN2Matrix", "", kTH3D, {{axisCent}, {axisKCh}, {axisKCh}}); + hist.add("Analysis/Charged/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKCh}, {axisKCh}}); + + hist.add("Analysis/Pion/hN1Matrix", "", kTH2D, {{axisCent}, {axisKPi}}); + hist.add("Analysis/Pion/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKPi}}); + hist.add("Analysis/Pion/hN2Matrix", "", kTH3D, {{axisCent}, {axisKPi}, {axisKPi}}); + hist.add("Analysis/Pion/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKPi}, {axisKPi}}); + + hist.add("Analysis/Kaon/hN1Matrix", "", kTH2D, {{axisCent}, {axisKKa}}); + hist.add("Analysis/Kaon/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKKa}}); + hist.add("Analysis/Kaon/hN2Matrix", "", kTH3D, {{axisCent}, {axisKKa}, {axisKKa}}); + hist.add("Analysis/Kaon/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKKa}, {axisKKa}}); + + hist.add("Analysis/Proton/hN1Matrix", "", kTH2D, {{axisCent}, {axisKPr}}); + hist.add("Analysis/Proton/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKPr}}); + hist.add("Analysis/Proton/hN2Matrix", "", kTH3D, {{axisCent}, {axisKPr}, {axisKPr}}); + hist.add("Analysis/Proton/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKPr}, {axisKPr}}); + // MC Generated hist.add("Gen/h_Counts", "Counts", kTH1D, {axisEvents}); hist.add("Gen/h_VtxZ", "Vertex Z ", kTH1D, {axisVtxZ}); hist.add("Gen/h_VtxZ_b", "Vertex Z ", kTH1D, {axisVtxZ}); - hist.add("Gen/h_NSim", "Truth Multiplicity TPC", kTH1D, {axisMultTPC}); - hist.add("Gen/h2_NTPC_NSim", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultTPC}}); + hist.add("Gen/h_NSim", "Truth Multiplicity TPC", kTH1D, {axisMultMC}); + hist.add("Gen/h2_NSim_NTPC", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultMC}, {axisMultTPC}}); + hist.add("Gen/h2_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultMC}}); hist.add("Gen/Charged/h_EtaTruth", "#eta ", kTH1D, {axisEta}); hist.add("Gen/Charged/h_PhiTruth", "#phi ", kTH1D, {axisPhi}); - hist.add("Gen/Charged/h_PtTruth", "p_{T} ", kTH1D, {axisPt}); - hist.add("Gen/Charged/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); hist.add("Gen/Charged/h2_PtTruth_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); - hist.add("Gen/Charged/h_PtEtaPhiTruth", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); - - hist.add("Gen/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); - hist.add("Gen/Charged/h_N_CentFT0M", "Multiplicity vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisMult}); - hist.add("Gen/Charged/h_Npair_CentFT0M", "Npair vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisNpair}); - hist.add("Gen/Charged/h_Q1_CentFT0M", "Q1", qNMCHist); - hist.add("Gen/Charged/h_Q2_CentFT0M", "Q2", qNMCHist); - hist.add("Gen/Charged/h_twopart1_CentFT0M", "twopart (neum)", qNMCHist); - hist.add("Gen/Charged/h_mean_pT_Mult_var", " vs N_{TPC} ", partMCHist); - hist.add("Gen/Charged/h_twopart_Mult_var", "Twopart vs N_{TPC} ", partMCHist); - hist.add("Gen/Charged/p_twopart_CentFT0M", "Twopart vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Gen/Charged/p_mean_pT_CentFT0M", " vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Gen/Charged/h3_Pt_Eta_PhiTruth", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); hist.addClone("Gen/Charged/", "Gen/Pion/"); hist.add("Gen/Pion/h_RapTruth", "y", kTH1D, {axisY}); - hist.add("Gen/Pion/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPt}); - hist.add("Gen/Pion/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPt}); hist.addClone("Gen/Pion/", "Gen/Kaon/"); hist.addClone("Gen/Pion/", "Gen/Proton/"); + hist.addClone("Analysis/Charged/", "Gen/Charged/"); + hist.addClone("Analysis/Pion/", "Gen/Pion/"); + hist.addClone("Analysis/Kaon/", "Gen/Kaon/"); + hist.addClone("Analysis/Proton/", "Gen/Proton/"); + + hist.add("Gen/Charged/h_PtTruth", "p_{T} ", kTH1D, {axisPt}); + hist.add("Gen/Charged/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); + hist.add("Gen/Charged/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPt}, {axisCent}}); + + hist.add("Gen/Pion/h_PtTruth", "p_{T} ", kTH1D, {axisPtPi}); + hist.add("Gen/Pion/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtPi}); + hist.add("Gen/Pion/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtPi}); + hist.add("Gen/Pion/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("Gen/Pion/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + + hist.add("Gen/Kaon/h_PtTruth", "p_{T} ", kTH1D, {axisPtKa}); + hist.add("Gen/Kaon/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtKa}); + hist.add("Gen/Kaon/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtKa}); + hist.add("Gen/Kaon/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("Gen/Kaon/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + + hist.add("Gen/Proton/h_PtTruth", "p_{T} ", kTH1D, {axisPtPr}); + hist.add("Gen/Proton/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtPr}); + hist.add("Gen/Proton/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtPr}); + hist.add("Gen/Proton/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("Gen/Proton/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/h_collisions_info", "Collisions info", kTH1D, {axisCol}); hist.add("Gen/h_collisions_info", "Collisions info", kTH1D, {axisCol}); hist.add("Gen/h_collision_recgen", "Number of Collisions ", kTH1D, {axisCol}); @@ -371,15 +471,24 @@ struct MeanPtFlucId { hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColSel8, "kSelColSel8"); hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColNoSameBunchPileup, "kSelColNoSameBunchPileup"); hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColIsVertexITSTPC, "kSelColIsVertexITSTPC"); + if (cfgLightIonCuts) { + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColIsGoodITSLayersAll, "kSelColIsGoodITSLayersAll"); + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColIsGoodZvtxFT0vsPV, "kSelColIsGoodZvtxFT0vsPV"); + } } float centFT0M = 0.; int nTPC = 0, nFT0M = 0; + int nSim = 0; // Event selection cuts: template bool selRun3Col(T const& col) { + + centFT0M = col.centFT0M(); + nTPC = col.multNTracksHasTPC(); + nFT0M = col.multFT0M(); hist.fill(HIST("QA/after/h_counts_evSelCuts"), kBeforeSelCol); if (cfgPosZ) { @@ -389,10 +498,6 @@ struct MeanPtFlucId { hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColPosZ); } - centFT0M = col.centFT0M(); - nTPC = col.multNTracksHasTPC(); - nFT0M = col.multFT0M(); - if (cfgSel8) { if (!col.sel8()) { return false; @@ -412,6 +517,21 @@ struct MeanPtFlucId { } hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColIsVertexITSTPC); } + if (cfgLightIonCuts) { + if (cfgIsGoodITSLayersAll) { + if (!col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColIsGoodITSLayersAll); + } + + if (cfgIsGoodZvtxFT0vsPV) { + if (!col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColIsGoodZvtxFT0vsPV); + } + } return true; } @@ -420,121 +540,111 @@ struct MeanPtFlucId { template bool selTrack(T const& track) { - if (!track.isGlobalTrack()) + if (!track.isGlobalTrack()) { return false; + } - if (track.pt() < cfgCutPtMin) + if (track.pt() < cfgCutPtMin) { return false; + } - if (track.pt() >= cfgCutPtMax) + if (track.pt() >= cfgCutPtMax) { return false; + } - if (track.sign() == 0) + if (track.sign() == 0) { return false; + } - if (std::fabs(track.dcaZ()) > cfgCutDcaZ) + if (std::fabs(track.dcaZ()) > cfgCutDcaZ) { return false; + } - if (std::fabs(track.dcaZ()) > (0.0105 + 0.035 / std::pow(track.p(), 1.1))) + if (std::fabs(track.dcaZ()) > (0.0105 + 0.035 / std::pow(track.p(), 1.1))) { return false; + } - if (std::abs(track.eta()) >= cfgCutEta) + if (std::abs(track.eta()) >= cfgCutEta) { return false; + } return true; } - // Cuts to reject the tracks + // Rejection cuts to reject the tracks template bool rejectTracks(T const& track) { - if (((track.tpcNSigmaEl()) > -cfgCutNSig3 && - (track.tpcNSigmaEl()) < cfgCutNSig5) && - (std::fabs(track.tpcNSigmaPi()) > cfgCutNSig3 && - std::fabs(track.tpcNSigmaKa()) > cfgCutNSig3 && - std::fabs(track.tpcNSigmaPr()) > cfgCutNSig3)) { - return true; - } - - return false; + return ((track.tpcNSigmaEl()) > -cfgCutNSig3 && + (track.tpcNSigmaEl()) < cfgCutNSig5) && + (std::fabs(track.tpcNSigmaPi()) > cfgCutNSig3 && + std::fabs(track.tpcNSigmaKa()) > cfgCutNSig3 && + std::fabs(track.tpcNSigmaPr()) > cfgCutNSig3); } - template - bool identifyParticle(T const& track, float momThreshold) + // PID cuts for identified particles + template + bool identifyParticle(T const& track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold) { + std::vector vTpcNSigma = {-999.f, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::vector vTofNSigma = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + + const int sp = static_cast(species); + const int sq = static_cast(reject1); + const int sr = static_cast(reject2); - const int sp = static_cast(s1); - const int sq = static_cast(s2); - const int sr = static_cast(s3); - std::vector vTpcNSigma = {-999., track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; - std::vector vTofNSigma = {-999., track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; - bool isTofPidFlag = false, isTpcPidFlag = false; - - float nSigmaSelCut = 0.; - float nSigmaTofRejCut = 0.; - float nSigmaTpcRejCut = 0.; - if constexpr (s1 == PIDType::kProtons) { - nSigmaSelCut = cfgSelCutNSigPr; - nSigmaTofRejCut = std::fabs(vTofNSigma[sp]); - nSigmaTpcRejCut = std::fabs(vTpcNSigma[sp]); - } else if constexpr (s1 == PIDType::kKaons) { - nSigmaSelCut = cfgSelCutNSigKa; - nSigmaTofRejCut = std::fabs(vTofNSigma[sp]); - nSigmaTpcRejCut = std::fabs(vTpcNSigma[sp]); - } else if constexpr (s1 == PIDType::kPions) { - nSigmaSelCut = cfgSelCutNSigPi; - nSigmaTofRejCut = cfgRejCutNSigPi; - nSigmaTpcRejCut = cfgRejCutNSigPi; + bool isTofPidFlag = false; + bool isTpcPidFlag = false; + + float nSigmaSelCut = 0.f; + + switch (species) { + case PIDType::kPions: + nSigmaSelCut = cfgSelCutNSigPi; + break; + + case PIDType::kKaons: + nSigmaSelCut = cfgSelCutNSigKa; + break; + + case PIDType::kProtons: + nSigmaSelCut = cfgSelCutNSigPr; + break; + + default: + return false; } if (track.hasTOF()) { - if (std::fabs(vTofNSigma[sp]) < nSigmaSelCut && - std::fabs(vTofNSigma[sq]) > nSigmaTofRejCut && - std::fabs(vTofNSigma[sr]) > nSigmaTofRejCut) { + + if (std::abs(vTofNSigma[sp]) < nSigmaSelCut && + std::abs(vTofNSigma[sq]) > std::abs(vTofNSigma[sp]) && + std::abs(vTofNSigma[sr]) > std::abs(vTofNSigma[sp])) { isTofPidFlag = true; } - if (std::fabs(vTpcNSigma[sp]) < cfgCutNSig2) { + + if (std::abs(vTpcNSigma[sp]) < cfgCutNSig2) { isTpcPidFlag = true; } - } else { // select from TPC Only - if (track.p() >= momThreshold) { + + } else { + + if (p >= momThreshold) { return false; } - if (std::fabs(vTpcNSigma[sp]) < nSigmaSelCut && - std::fabs(vTpcNSigma[sq]) > nSigmaTpcRejCut && - std::fabs(vTpcNSigma[sr]) > nSigmaTpcRejCut) { + + if (std::abs(vTpcNSigma[sp]) < nSigmaSelCut && + std::abs(vTpcNSigma[sq]) > std::abs(vTpcNSigma[sp]) && + std::abs(vTpcNSigma[sr]) > std::abs(vTpcNSigma[sp])) { isTofPidFlag = true; isTpcPidFlag = true; } } - if (isTofPidFlag && isTpcPidFlag) { - return true; // Track is identified as one of the particles - } - - return false; // Track is not identified as any of the particles + return (isTofPidFlag && isTpcPidFlag); } - // Get corrected weight for the track: - template - float getCorrectedWeight(T1 hWeightPt, T1 hPurePt, float pt, bool cfgWeightPt, bool cfgPurity) - { - float weight = 1.0; - float purity = 1.0; - - if (cfgPurity) { - purity = hPurePt->GetBinContent(hPurePt->FindBin(pt)); - } - - if (cfgWeightPt) { - float weightPt = hWeightPt->GetBinContent(hWeightPt->FindBin(pt)); - weight = purity * weightPt; - } - - return weight; - } - - // Fill hist before selection cuts: + // Fill QA histograms before selection cuts: template void fillBeforeQAHistos(T const& col, U const& tracks) { @@ -554,7 +664,7 @@ struct MeanPtFlucId { hist.fill(HIST("QA/before/h_NFT0M"), col.multFT0M()); } - // Fill hist after selection cuts: + // Fill QA histograms after selection cuts: template void fillAfterQAHistos(T const& col) { @@ -567,16 +677,20 @@ struct MeanPtFlucId { hist.fill(HIST("QA/after/h2_NTPC_CentM"), centFT0M, nTPC); hist.fill(HIST("QA/after/p_NTPC_CentM"), centFT0M, nTPC); hist.fill(HIST("QA/after/p_NTPC_NFT0M"), nFT0M, nTPC); + hist.fill(HIST("QA/after/h2_NSim_NTPC"), nSim, nTPC); + hist.fill(HIST("QA/after/h2_NTPC_NSim"), nTPC, nSim); + hist.fill(HIST("QA/after/p_NTPC_NSim"), nTPC, nSim); } - // Fill Charged particles QA: + // Fill Charged particles QA histograms after selection cuts: template - void fillChargedQAHistos(T const& track, float centFT0M) + void fillChargedQAHistos(T const& track) { hist.fill(HIST("QA/Charged/h_Eta"), track.eta()); hist.fill(HIST("QA/Charged/h_Phi"), track.phi()); hist.fill(HIST("QA/Charged/h2_Pt_centFT0M"), centFT0M, track.pt()); - hist.fill(HIST("QA/Charged/h3_PtEtaPhi"), track.pt(), track.eta(), track.phi()); + hist.fill(HIST("QA/Charged/h3_Pt_Eta_Phi"), track.pt(), track.eta(), track.phi()); + hist.fill(HIST("QA/Charged/h3_Pt_Eta_centFT0M"), track.eta(), track.pt(), centFT0M); hist.fill(HIST("QA/Charged/h2_Pt_Eta"), track.eta(), track.pt()); hist.fill(HIST("QA/Charged/h_DcaZ"), track.dcaZ()); hist.fill(HIST("QA/Charged/h_DcaXY"), track.dcaXY()); @@ -588,7 +702,7 @@ struct MeanPtFlucId { hist.fill(HIST("QA/after/h_crossedTPC"), track.tpcNClsCrossedRows()); } - // Fill before PID cut QA hist: + // Fill identified QA histograms before PID cuts: template void fillBeforePIDQAHistos(T const& track) { @@ -596,47 +710,41 @@ struct MeanPtFlucId { hist.fill(HIST("QA/before/h2_TPCSignal"), track.p(), track.tpcSignal()); hist.fill(HIST("QA/before/h2_pvsm2"), track.mass() * track.mass(), track.p()); + hist.fill(HIST("QA/Pion/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); if (!track.hasTOF()) - hist.fill(HIST("QA/Pion/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); + hist.fill(HIST("QA/Pion/before/h2_TPCNsigma_nottof"), track.p(), track.tpcNSigmaPi()); if (track.hasTOF()) hist.fill(HIST("QA/Pion/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaPi()); hist.fill(HIST("QA/Pion/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPi()); hist.fill(HIST("QA/Pion/before/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + + hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); if (!track.hasTOF()) - hist.fill(HIST("QA/Proton/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); - if (track.hasTOF()) - hist.fill(HIST("QA/Proton/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaPr()); - hist.fill(HIST("QA/Proton/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); - hist.fill(HIST("QA/Proton/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - if (!track.hasTOF()) - hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); + hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma_nottof"), track.p(), track.tpcNSigmaKa()); if (track.hasTOF()) hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaKa()); hist.fill(HIST("QA/Kaon/before/h2_TOFNsigma"), track.p(), track.tofNSigmaKa()); hist.fill(HIST("QA/Kaon/before/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); - } - // Moments Calculation: - void moments(float pt, float weight, double& Q1, double& Q2) - { - Q1 += pt * weight; - Q2 += pt * pt * weight * weight; + hist.fill(HIST("QA/Proton/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); + if (!track.hasTOF()) + hist.fill(HIST("QA/Proton/before/h2_TPCNsigma_nottof"), track.p(), track.tpcNSigmaPr()); + if (track.hasTOF()) + hist.fill(HIST("QA/Proton/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaPr()); + hist.fill(HIST("QA/Proton/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Proton/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); } - template - void fillIdParticleQAHistos(T const& track, float rap, float nSigmaTPC, float nSigmaTOF, float centFT0M, T1 hWeightPt, T1 hPurePt, bool cfgWeightPtId, bool cfgPurityId, double& NW, double& NW2, double& Q1, double& Q2) + // Fill identified QA histograms after PID cuts: + template + void fillIdParticleQAHistos(T const& track, float ptMC, float etaMC, float rap, float nSigmaTPC, float nSigmaTOF, std::vector& Tracks) { + float pt = track.pt(); float eta = track.eta(); float phi = track.phi(); - float weight = getCorrectedWeight(hWeightPt, hPurePt, pt, cfgWeightPtId, cfgPurityId); - - if (std::abs(weight) < cfgMinWeight) - return; - NW += weight; - NW2 += weight * weight; - moments(pt, weight, Q1, Q2); + Tracks.push_back({pt, eta}); if (track.sign() > 0) { hist.fill(HIST(Dire[Mode]) + HIST("h_PtPos"), pt); @@ -645,13 +753,15 @@ struct MeanPtFlucId { hist.fill(HIST(Dire[Mode]) + HIST("h_PtNeg"), pt); } - if (cfgWeightPtEtaId) - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Eta_weighted"), eta, pt, weight); - - hist.fill(HIST(Dire[Mode]) + HIST("h_Pt_weighted"), pt, weight); + hist.fill(HIST(Dire[Mode]) + HIST("h_Pt"), pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_PtMC"), ptMC); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_PtMC"), ptMC, pt); hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_centFT0M"), centFT0M, pt); - hist.fill(HIST(Dire[Mode]) + HIST("h3_PtEtaPhi"), pt, eta, phi); + hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_Eta_Phi"), pt, eta, phi); hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Eta"), eta, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_Eta_centFT0M"), eta, pt, centFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_EtaMC"), etaMC, ptMC); + hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_EtaMC_centFT0M"), etaMC, ptMC, centFT0M); hist.fill(HIST(Dire[Mode]) + HIST("h_Eta"), eta); hist.fill(HIST(Dire[Mode]) + HIST("h_Phi"), phi); hist.fill(HIST(Dire[Mode]) + HIST("h_Rap"), rap); @@ -674,18 +784,22 @@ struct MeanPtFlucId { hist.fill(HIST("QA/after/h2_pvsm2"), track.mass() * track.mass(), track.p()); } + // Fill Truth identified particles histograms template - void fillPtMCHist(bool cfgGen, float pt, float eta, float rap, float phi, float centFT0M, int pid, int pdgCodePos, int pdgCodeNeg) + void fillPtMCHist(bool cfgGen, float pt, float eta, float rap, float phi, int pid, int pdgCodePos, int pdgCodeNeg) { if (cfgGen) { + hist.fill(HIST(Dire[Mode]) + HIST("h_PtTruth"), pt); hist.fill(HIST(Dire[Mode]) + HIST("h_EtaTruth"), eta); hist.fill(HIST(Dire[Mode]) + HIST("h_RapTruth"), rap); - hist.fill(HIST(Dire[Mode]) + HIST("h2_PtTruth_centFT0M"), centFT0M, pt); - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_EtaTruth"), eta, pt); hist.fill(HIST(Dire[Mode]) + HIST("h_PhiTruth"), phi); - hist.fill(HIST(Dire[Mode]) + HIST("h_PtEtaPhiTruth"), pt, eta, phi); + hist.fill(HIST(Dire[Mode]) + HIST("h2_PtTruth_centFT0M"), centFT0M, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_EtaTruth_centFT0M"), eta, pt, centFT0M); + hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_Eta_PhiTruth"), pt, eta, phi); } + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_EtaTruth"), eta, pt); + if (pid == pdgCodePos) { hist.fill(HIST(Dire[Mode]) + HIST("h_PtPosTruth"), pt); } @@ -694,53 +808,138 @@ struct MeanPtFlucId { } } + int getPtBin(double pt, const std::vector& ptB) + { + for (size_t i = 0; i < ptB.size() - 1; ++i) { + if (pt >= ptB[i] && pt < ptB[i + 1]) { + return i; + } + } + return -1; + } + + int getEtaBin(double eta) + { + for (size_t i = 0; i < etaBins->size() - 1; ++i) { + if (eta >= etaBins->at(i) && eta < etaBins->at(i + 1)) { + return i; + } + } + return -1; + } + + // fill differential matrices for two-particle analysis template - void fillAnalysisHistos(bool cfgCorrection, float centFT0M, double nW, double nW2, double Q1, double Q2) + void fillDifferentialMatrices(const std::vector& tracks, const std::vector& ptB) { - if (nW == 0) { - return; + const int nPtBins = ptB.size() - 1; + + auto getK = [&](int ipt, int ieta) { + return ieta * nPtBins + ipt; + }; + + for (const auto& trk : tracks) { + int ipt = getPtBin(trk.pt, ptB); + int ieta = getEtaBin(trk.eta); + + if (ipt < 0 || ieta < 0) + continue; + + int k = getK(ipt, ieta); + + hist.fill(HIST(Dire[Mode]) + HIST("hN1Matrix"), centFT0M, k, 1.0); + hist.fill(HIST(Dire[Mode]) + HIST("hPt1Matrix"), centFT0M, k, trk.pt); } - hist.fill(HIST(Dire[Mode]) + HIST("h_Mult"), nW); + for (size_t i = 0; i < tracks.size(); ++i) { + int ipt1 = getPtBin(tracks[i].pt, ptB); + int ieta1 = getEtaBin(tracks[i].eta); - double nPair = 0., meanPt = 0., twopart1 = 0., twopart = 0.; + if (ipt1 < 0 || ieta1 < 0) + continue; - if (cfgCorrection) { - nPair = nW * nW - nW2; - } else { - if (nW > 1) { - nPair = nW * (nW - 1); + int k1 = getK(ipt1, ieta1); + + for (size_t j = i + 1; j < tracks.size(); ++j) { + int ipt2 = getPtBin(tracks[j].pt, ptB); + int ieta2 = getEtaBin(tracks[j].eta); + + if (ipt2 < 0 || ieta2 < 0) + continue; + + int k2 = getK(ipt2, ieta2); + + hist.fill(HIST(Dire[Mode]) + HIST("hN2Matrix"), centFT0M, k1, k2, 1.0); + hist.fill(HIST(Dire[Mode]) + HIST("hN2Matrix"), centFT0M, k2, k1, 1.0); + hist.fill(HIST(Dire[Mode]) + HIST("hPtPtMatrix"), centFT0M, k1, k2, tracks[i].pt * tracks[j].pt); + hist.fill(HIST(Dire[Mode]) + HIST("hPtPtMatrix"), centFT0M, k2, k1, tracks[j].pt * tracks[i].pt); } } + } + + // Calculate moments for two-particle correlations + void moments(double pt, int& n, double& q1, double& q2) + { + n++; + q1 += pt; + q2 += pt * pt; + } + + // Fill terms calculted from moments method for two-particle correlations + template + void fillAnalysis(int n, double q1, double q2) + { + + double npair = n * (n - 1); + + if (n > 0) { + double meanPt = q1 / n; + + hist.fill(HIST(Dire[Mode]) + HIST("h_mult"), n); - if (nPair > 0) { - meanPt = Q1 / nW; - twopart1 = (Q1 * Q1 - Q2); - twopart = twopart1 / nPair; + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Cent"), centFT0M, meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Cent"), centFT0M, meanPt); - hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Mult_var"), centFT0M, meanPt); - hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Mult_var"), centFT0M, twopart); - hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_CentFT0M"), centFT0M, meanPt); - hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_CentFT0M"), centFT0M, twopart); - hist.fill(HIST(Dire[Mode]) + HIST("h_twopart1_CentFT0M"), centFT0M, twopart1); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Num_Cent_var"), centFT0M, q1); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Den_Cent_var"), centFT0M, n); + + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Num_Cent_var"), centFT0M, q1); + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Den_Cent_var"), centFT0M, n); + + hist.fill(HIST(Dire[Mode]) + HIST("p_Q1_Mult"), n, q1); + hist.fill(HIST(Dire[Mode]) + HIST("p_Q2_Mult"), n, q2); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Mult"), n, meanPt); } - hist.fill(HIST(Dire[Mode]) + HIST("h_Mult"), nW); - hist.fill(HIST(Dire[Mode]) + HIST("h_N_CentFT0M"), centFT0M, nW); - hist.fill(HIST(Dire[Mode]) + HIST("h_Npair_CentFT0M"), centFT0M, nPair); - hist.fill(HIST(Dire[Mode]) + HIST("h_Q1_CentFT0M"), centFT0M, Q1); - hist.fill(HIST(Dire[Mode]) + HIST("h_Q2_CentFT0M"), centFT0M, Q2); + if (npair != 0) { + double meanPt = q1 / n; + double twopart = (q1 * q1 - q2); + double varPt = twopart / npair; + hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_Num_Cent_var"), centFT0M, twopart); + hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_Den_Cent_var"), centFT0M, npair); + + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Num_Cent_var"), centFT0M, twopart); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Den_Cent_var"), centFT0M, npair); + + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Cent_var"), centFT0M, meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_Cent_var"), centFT0M, varPt); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Cent_var"), centFT0M, varPt); + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Cent_var"), centFT0M, meanPt); + } } + // Fill reconstructed histograms for charged and identified particles template void fillRecoHistos(C const& col, T const& tracks) { - double nChW = 0., nChW2 = 0., q1Ch = 0., q2Ch = 0.; - float wghtCh = 1.0; - double nPiW = 0., nPiW2 = 0., q1Pi = 0., q2Pi = 0.; - double nKaW = 0., nKaW2 = 0., q1Ka = 0., q2Ka = 0.; - double nPrW = 0., nPrW2 = 0., q1Pr = 0., q2Pr = 0.; - float pt = 0., eta = 0., phi = 0.; + chargedTracks.clear(); + pionTracks.clear(); + kaonTracks.clear(); + protonTracks.clear(); + + int nCh = 0, nPi = 0, nKa = 0, nPr = 0; + float pt = 0., eta = 0., phi = 0., p = 0.; + double q1Ch = 0., q2Ch = 0., q1Pi = 0., q2Pi = 0., q1Ka = 0., q2Ka = 0., q1Pr = 0., q2Pr = 0.; hist.fill(HIST("QA/h_collisions_info"), kTotCol); @@ -750,10 +949,23 @@ struct MeanPtFlucId { } } + if constexpr (RecoFlag) { + float lower = cfgP2L * nSim * nSim + cfgP1L * nSim - cfgP0L; + float upper = cfgP2U * nSim * nSim + cfgP1U * nSim + cfgP0U; + if (cfgNtpcEventCut && (nTPC < lower || nTPC > upper)) { + return; // Reject event + } + } + hist.fill(HIST("QA/h_collisions_info"), kPassSelCol); fillAfterQAHistos(col); + double nCorr = cfgP2corr * nTPC * nTPC + cfgP1corr * nTPC + cfgP0corr; + hist.fill(HIST("QA/after/h_Ncorr"), nCorr); + hist.fill(HIST("QA/after/h2_Ncorr_NSim"), nCorr, nSim); + hist.fill(HIST("QA/after/h2_Ncorr_CentM"), centFT0M, nCorr); + for (auto const& track : tracks) { float nSigmaTPCPi = track.tpcNSigmaPi(); float nSigmaTPCKa = track.tpcNSigmaKa(); @@ -779,13 +991,18 @@ struct MeanPtFlucId { hist.fill(HIST("Tracks/h_tracks_info"), kAllSelPassed); pt = track.pt(); + eta = track.eta(); + phi = track.phi(); + p = track.p(); + float ptMC = pt; + float etaMC = eta; if constexpr (RecoFlag) { hist.fill(HIST("Tracks/h2_tracks_pid_before_sel"), track.mcParticle().pdgCode(), track.pt()); auto mc = track.template mcParticle_as(); - pt = mc.pt(); - eta = mc.eta(); - phi = mc.phi(); + ptMC = mc.pt(); + etaMC = mc.eta(); + p = mc.p(); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/after/h_DCAxy_primary"), track.dcaXY()); @@ -796,155 +1013,174 @@ struct MeanPtFlucId { } } - // Charged particles: - wghtCh = getCorrectedWeight(hWeightPt, hPurePt, pt, cfgWeightPtCh, false); + nCh++; + chargedTracks.push_back({pt, eta}); + moments(pt, nCh, q1Ch, q2Ch); - if (std::abs(wghtCh) < cfgMinWeight) - return; + hist.fill(HIST("QA/Charged/h_Pt"), pt); + hist.fill(HIST("QA/Charged/h_PtMC"), ptMC); + hist.fill(HIST("QA/Charged/h2_Pt_PtMC"), ptMC, pt); + hist.fill(HIST("QA/Charged/h2_Pt_EtaMC"), etaMC, ptMC); + hist.fill(HIST("QA/Charged/h3_Pt_EtaMC_centFT0M"), etaMC, ptMC, centFT0M); - nChW += wghtCh; - nChW2 += wghtCh * wghtCh; - moments(pt, wghtCh, q1Ch, q2Ch); - hist.fill(HIST("QA/Charged/h_Pt"), track.pt()); - fillChargedQAHistos(track, centFT0M); + fillChargedQAHistos(track); fillBeforePIDQAHistos(track); - // identified particles: if (cfgRejTrk && rejectTracks(track)) { continue; } - auto selIDPion = identifyParticle(track, cfgCutPiThrsldP); - auto selIDKaon = identifyParticle(track, cfgCutKaThrsldP); - auto selIDProton = identifyParticle(track, cfgCutPrThrsldP); - if (selIDPion && pt >= cfgCutPiPtMin) { - hist.fill(HIST("QA/Pion/h_Pt"), track.pt()); - fillIdParticleQAHistos(track, rapPi, nSigmaTPCPi, nSigmaTOFPi, centFT0M, hWeightPtPi, hPurePtPi, cfgWeightPtId, cfgPurityId, nPiW, nPiW2, q1Pi, q2Pi); + auto selIDPion = identifyParticle(track, PIDType::kPions, PIDType::kKaons, PIDType::kProtons, p, cfgCutPiThrsldP); + auto selIDKaon = identifyParticle(track, PIDType::kKaons, PIDType::kPions, PIDType::kProtons, p, cfgCutKaThrsldP); + auto selIDProton = identifyParticle(track, PIDType::kProtons, PIDType::kPions, PIDType::kKaons, p, cfgCutPrThrsldP); + + if (selIDPion && track.pt() >= cfgCutPiPtMin) { + moments(pt, nPi, q1Pi, q2Pi); + fillIdParticleQAHistos(track, ptMC, etaMC, rapPi, nSigmaTPCPi, nSigmaTOFPi, pionTracks); } - if (selIDKaon && pt >= cfgCutKaPtMin) { - hist.fill(HIST("QA/Kaon/h_Pt"), track.pt()); - fillIdParticleQAHistos(track, rapKa, nSigmaTPCKa, nSigmaTOFKa, centFT0M, hWeightPtKa, hPurePtKa, cfgWeightPtId, cfgPurityId, nKaW, nKaW2, q1Ka, q2Ka); + if (selIDKaon && track.pt() >= cfgCutKaPtMin) { + moments(pt, nKa, q1Ka, q2Ka); + fillIdParticleQAHistos(track, ptMC, etaMC, rapKa, nSigmaTPCKa, nSigmaTOFKa, kaonTracks); } - if (selIDProton && pt >= cfgCutPrPtMin) { - hist.fill(HIST("QA/Proton/h_Pt"), track.pt()); - fillIdParticleQAHistos(track, rapPr, nSigmaTPCPr, nSigmaTOFPr, centFT0M, hWeightPtPr, hPurePtPr, cfgWeightPtId, cfgPurityId, nPrW, nPrW2, q1Pr, q2Pr); + if (selIDProton && track.pt() >= cfgCutPrPtMin) { + moments(pt, nPr, q1Pr, q2Pr); + fillIdParticleQAHistos(track, ptMC, etaMC, rapPr, nSigmaTPCPr, nSigmaTOFPr, protonTracks); } if constexpr (RecoFlag) { auto mc = track.template mcParticle_as(); int pid = mc.pdgCode(); - if (selIDPion && pt >= cfgCutPiPtMin) { + if (selIDPion && track.pt() >= cfgCutPiPtMin) { if (std::abs(pid) == kPiPlus) { - hist.fill(HIST("QA/Pion/h_PtTruth"), pt); - fillPtMCHist(false, pt, eta, rapPi, phi, centFT0M, pid, kPiPlus, kPiMinus); + hist.fill(HIST("QA/Pion/h_PtTruth"), track.pt()); + fillPtMCHist(false, pt, eta, rapPi, phi, pid, kPiPlus, kPiMinus); if (mc.isPhysicalPrimary()) { - hist.fill(HIST("QA/Pion/h_PtTruth_primary"), pt); + hist.fill(HIST("QA/Pion/h_PtTruth_primary"), track.pt()); } else { - hist.fill(HIST("QA/Pion/h_PtTruth_secondary"), pt); + hist.fill(HIST("QA/Pion/h_PtTruth_secondary"), track.pt()); } } } - if (selIDKaon && pt >= cfgCutKaPtMin) { + if (selIDKaon && track.pt() >= cfgCutKaPtMin) { if (std::abs(pid) == kKPlus) { - hist.fill(HIST("QA/Kaon/h_PtTruth"), pt); - fillPtMCHist(false, pt, eta, rapKa, phi, centFT0M, pid, kKPlus, kKMinus); + hist.fill(HIST("QA/Kaon/h_PtTruth"), track.pt()); + fillPtMCHist(false, pt, eta, rapKa, phi, pid, kKPlus, kKMinus); if (mc.isPhysicalPrimary()) { - hist.fill(HIST("QA/Kaon/h_PtTruth_primary"), pt); + hist.fill(HIST("QA/Kaon/h_PtTruth_primary"), track.pt()); } else { - hist.fill(HIST("QA/Kaon/h_PtTruth_secondary"), pt); + hist.fill(HIST("QA/Kaon/h_PtTruth_secondary"), track.pt()); } } } - if (selIDProton && pt >= cfgCutPrPtMin) { + if (selIDProton && track.pt() >= cfgCutPrPtMin) { if (std::abs(pid) == kProton) { - hist.fill(HIST("QA/Proton/h_PtTruth"), pt); - fillPtMCHist(false, pt, eta, rapPr, phi, centFT0M, pid, kProton, kProtonBar); + hist.fill(HIST("QA/Proton/h_PtTruth"), track.pt()); + fillPtMCHist(false, pt, eta, rapPr, phi, pid, kProton, kProtonBar); if (mc.isPhysicalPrimary()) { - hist.fill(HIST("QA/Proton/h_PtTruth_primary"), pt); + hist.fill(HIST("QA/Proton/h_PtTruth_primary"), track.pt()); } else { - hist.fill(HIST("QA/Proton/h_PtTruth_secondary"), pt); + hist.fill(HIST("QA/Proton/h_PtTruth_secondary"), track.pt()); } } } } } - fillAnalysisHistos(cfgCorrection, centFT0M, nChW, nChW2, q1Ch, q2Ch); - fillAnalysisHistos(cfgCorrection, centFT0M, nPiW, nPiW2, q1Pi, q2Pi); - fillAnalysisHistos(cfgCorrection, centFT0M, nKaW, nKaW2, q1Ka, q2Ka); - fillAnalysisHistos(cfgCorrection, centFT0M, nPrW, nPrW2, q1Pr, q2Pr); + fillDifferentialMatrices(chargedTracks, ptBins.value); + fillDifferentialMatrices(pionTracks, ptBinsPi.value); + fillDifferentialMatrices(kaonTracks, ptBinsKa.value); + fillDifferentialMatrices(protonTracks, ptBinsPr.value); + fillAnalysis(nCh, q1Ch, q2Ch); + fillAnalysis(nPi, q1Pi, q2Pi); + fillAnalysis(nKa, q1Ka, q2Ka); + fillAnalysis(nPr, q1Pr, q2Pr); } template void fillGenHistos(C const& mcCol, M const& mcParticles) { - int nSim = 0; - double nChSim = 0., q1ChSim = 0., q2ChSim = 0.; - double nPiSim = 0., q1PiSim = 0., q2PiSim = 0.; - double nKaSim = 0., q1KaSim = 0., q2KaSim = 0.; - double nPrSim = 0., q1PrSim = 0., q2PrSim = 0.; - float pt = 0, eta = 0, phi = 0, rap = 0; + chargedTracksGen.clear(); + pionTracksGen.clear(); + kaonTracksGen.clear(); + protonTracksGen.clear(); + nSim = 0; + int nChSim = 0, nPiSim = 0, nKaSim = 0, nPrSim = 0; + float pt = 0., eta = 0, phi = 0., rap = 0.; + double q1Ch = 0., q2Ch = 0., q1Pi = 0., q2Pi = 0., q1Ka = 0., q2Ka = 0., q1Pr = 0., q2Pr = 0.; for (auto const& mcPart : mcParticles) { if (!mcPart.isPhysicalPrimary()) { continue; } - auto pid = mcPart.pdgCode(); - if (std::abs(pid) != kElectron && std::abs(pid) != kMuonMinus && std::abs(pid) != kPiPlus && std::abs(pid) != kKPlus && std::abs(pid) != kProton) { + auto* particle = pdg->GetParticle(mcPart.pdgCode()); + + if (!particle) + continue; + + if (particle->Charge() == 0) continue; - } pt = mcPart.pt(); eta = mcPart.eta(); phi = mcPart.phi(); + if (std::abs(eta) < cfgCutEta) { nSim++; } + auto pid = mcPart.pdgCode(); + if (std::abs(pid) != kElectron && std::abs(pid) != kMuonMinus && std::abs(pid) != kPiPlus && std::abs(pid) != kKPlus && std::abs(pid) != kProton) { + continue; + } + if (pt >= cfgCutPtMin && pt < cfgCutPtMax && std::abs(eta) < cfgCutEta) { - nChSim++; - moments(pt, 1.0, q1ChSim, q2ChSim); + moments(pt, nChSim, q1Ch, q2Ch); + chargedTracksGen.push_back({pt, eta}); hist.fill(HIST("Gen/Charged/h_PtTruth"), pt); hist.fill(HIST("Gen/Charged/h_EtaTruth"), eta); hist.fill(HIST("Gen/Charged/h_PhiTruth"), phi); hist.fill(HIST("Gen/Charged/h2_Pt_EtaTruth"), eta, pt); hist.fill(HIST("Gen/Charged/h2_PtTruth_centFT0M"), centFT0M, pt); - hist.fill(HIST("Gen/Charged/h_PtEtaPhiTruth"), pt, eta, phi); + hist.fill(HIST("Gen/Charged/h3_Pt_EtaTruth_centFT0M"), eta, pt, centFT0M); + hist.fill(HIST("Gen/Charged/h3_Pt_Eta_PhiTruth"), pt, eta, phi); rap = mcPart.y(); - if (std::abs(pid) == kPiPlus && mcPart.pt() > cfgCutPiPtMin) { - nPiSim++; - moments(pt, 1.0, q1PiSim, q2PiSim); - hist.fill(HIST("Gen/Pion/h_PtTruth"), pt); - fillPtMCHist(true, pt, eta, rap, phi, centFT0M, pid, kPiMinus, kPiMinus); + if (std::abs(pid) == kPiPlus && pt >= cfgCutPiPtMin) { + moments(pt, nPiSim, q1Pi, q2Pi); + pionTracksGen.push_back({pt, eta}); + fillPtMCHist(true, pt, eta, rap, phi, pid, kPiMinus, kPiMinus); } - if (std::abs(pid) == kKPlus && mcPart.pt() > cfgCutKaPtMin) { - nKaSim++; - moments(pt, 1.0, q1KaSim, q2KaSim); - hist.fill(HIST("Gen/Kaon/h_PtTruth"), pt); - fillPtMCHist(true, pt, eta, rap, phi, centFT0M, pid, kKMinus, kKMinus); + if (std::abs(pid) == kKPlus && pt >= cfgCutKaPtMin) { + moments(pt, nKaSim, q1Ka, q2Ka); + kaonTracksGen.push_back({pt, eta}); + fillPtMCHist(true, pt, eta, rap, phi, pid, kKMinus, kKMinus); } - if (std::abs(pid) == kProton && mcPart.pt() > cfgCutPrPtMin) { - nPrSim++; - moments(pt, 1.0, q1PrSim, q2PrSim); - hist.fill(HIST("Gen/Proton/h_PtTruth"), pt); - fillPtMCHist(true, pt, eta, rap, phi, centFT0M, pid, kProtonBar, kProtonBar); + if (std::abs(pid) == kProton && pt >= cfgCutPrPtMin) { + moments(pt, nPrSim, q1Pr, q2Pr); + protonTracksGen.push_back({pt, eta}); + fillPtMCHist(true, pt, eta, rap, phi, pid, kProtonBar, kProtonBar); } } } - fillAnalysisHistos(false, centFT0M, nChSim, nChSim, q1ChSim, q2ChSim); - fillAnalysisHistos(false, centFT0M, nPiSim, nPiSim, q1PiSim, q2PiSim); - fillAnalysisHistos(false, centFT0M, nKaSim, nKaSim, q1KaSim, q2KaSim); - fillAnalysisHistos(false, centFT0M, nPrSim, nPrSim, q1PrSim, q2PrSim); + + fillDifferentialMatrices(chargedTracksGen, ptBins.value); + fillDifferentialMatrices(pionTracksGen, ptBinsPi.value); + fillDifferentialMatrices(kaonTracksGen, ptBinsKa.value); + fillDifferentialMatrices(protonTracksGen, ptBinsPr.value); + fillAnalysis(nChSim, q1Ch, q2Ch); + fillAnalysis(nPiSim, q1Pi, q2Pi); + fillAnalysis(nKaSim, q1Ka, q2Ka); + fillAnalysis(nPrSim, q1Pr, q2Pr); + hist.fill(HIST("Gen/h_Counts"), 2); hist.fill(HIST("Gen/h_VtxZ"), mcCol.posZ()); hist.fill(HIST("Gen/h_NSim"), nSim); - hist.fill(HIST("Gen/h2_NTPC_NSim"), nSim, nTPC); + hist.fill(HIST("Gen/h2_NSim_NTPC"), nSim, nTPC); + hist.fill(HIST("Gen/h2_NTPC_NSim"), nTPC, nSim); } template void analyzeMC(M const& mcCol, C const& cols, T const& tracks, P const& mcParts) { - // fillBeforeQAHistos(cols.begin(), tracks); hist.fill(HIST("Gen/h_VtxZ_b"), mcCol.posZ()); int nRecCols = cols.size(); if (nRecCols == 0) { @@ -965,8 +1201,8 @@ struct MeanPtFlucId { hist.fill(HIST("Gen/h2_collision_posZ"), mcCol.posZ(), cols.begin().posZ()); auto sTracks = tracks.sliceBy(perCollision, cols.begin().globalIndex()); - fillRecoHistos(cols.begin(), sTracks); fillGenHistos(mcCol, mcParts); + fillRecoHistos(cols.begin(), sTracks); } using MyAllTracks = soa::Join #include #include -#include #include #include @@ -57,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -70,16 +70,16 @@ #include #include -#define C_CS(cs) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ - [](std::index_sequence) { \ - static_assert(std::is_array_v> && \ - std::same_as>, char>); \ - return ConstStr<(cs)[indices]...>{}; \ +#define C_CS(cs) /* NOLINT(cppcoreguidelines-macro-usage) */ \ + [](std::index_sequence) constexpr -> ConstStr<(cs)[indices]...> { \ + static_assert(std::is_array_v> && \ + std::same_as>, char>); \ + return ConstStr<(cs)[indices]...>{}; \ }(std::make_index_sequence{}) -#define C_SV(sv) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ - [](std::index_sequence) { \ - static_assert(std::same_as, std::string_view>); \ - return ConstStr<(sv)[indices]...>{}; \ +#define C_SV(sv) /* NOLINT(cppcoreguidelines-macro-usage) */ \ + [](std::index_sequence) constexpr -> ConstStr<(sv)[indices]...> { \ + static_assert(std::same_as, std::string_view>); \ + return ConstStr<(sv)[indices]...>{}; \ }(std::make_index_sequence<(sv).size()>{}) using namespace o2; @@ -88,7 +88,7 @@ using namespace o2::framework::expressions; namespace o2::aod { -using JoinedCollisions = soa::Join; +using JoinedCollisions = soa::Join; using JoinedTracks = soa::Join; using JoinedCollisionsWithMc = soa::Join; using JoinedTracksWithMc = soa::Join; @@ -139,8 +139,8 @@ namespace fluctuation_calculator_base { inline constexpr std::int8_t MaxOrder{8}; inline constexpr std::int32_t NExponentKeys{MaxOrder * (MaxOrder + 1) / 2}; -inline constexpr std::array, NExponentKeys> ExponentKeys{[] { - std::array, NExponentKeys> result{}; +inline constexpr std::array, NExponentKeys> ExponentKeys{[]() constexpr -> std::array, NExponentKeys> { + std::array, NExponentKeys> result{}; std::int32_t index{}; for (std::int32_t const& iExponent : std::views::iota(1, MaxOrder + 1)) { for (std::int32_t const& jExponent : std::views::iota(1, iExponent + 1)) { @@ -149,25 +149,21 @@ inline constexpr std::array, NExponentKeys> ExponentK } return result; }()}; -inline constexpr std::int32_t NOrderKeys{[] { +inline constexpr std::int32_t NOrderKeys{[]() constexpr -> std::int32_t { std::array counts{1}; - for (std::array const& exponentKey /*o2-linter: disable=const-ref-in-for-loop*/ : ExponentKeys) { - const std::int32_t weight{exponentKey[0]}; + for (std::pair const& exponentKey /* o2-linter: disable=const-ref-in-for-loop */ : ExponentKeys) { + const std::int32_t weight{exponentKey.first}; for (std::int32_t const& sum : std::views::iota(weight, MaxOrder + 1)) { counts[sum] += counts[sum - weight]; } } - std::int32_t result{}; - for (std::int32_t const& count : counts) { - result += count; - } - return result; + return std::accumulate(counts.begin(), counts.end(), 0); }()}; -inline constexpr std::array, NOrderKeys> OrderKeys{[] { +inline constexpr std::array, NOrderKeys> OrderKeys{[]() constexpr -> std::array, NOrderKeys> { std::array, NOrderKeys> result{}; std::array current{}; std::int32_t index{}; - const auto fillOrderKeys{[&](const auto& self, const std::int32_t position, const std::int32_t sum, const std::int32_t target) constexpr -> void { + const auto fillOrderKeys{[¤t, &index, &result](const auto& self, const std::int32_t position, const std::int32_t sum, const std::int32_t target) constexpr -> void { if (position == NExponentKeys) { if (sum == target) { result[index++] = current; @@ -175,9 +171,9 @@ inline constexpr std::array, NOrderKeys> return; } - const std::int32_t weight{ExponentKeys[position][0]}; + const std::int32_t weight{ExponentKeys[position].first}; for (std::int32_t power{}; sum + power * weight <= target; ++power) { - current[position] = power; + current[position] = static_cast(power); self(self, position + 1, sum + power * weight, target); } }}; @@ -192,23 +188,46 @@ class FluctuationCalculatorTrack { public: FluctuationCalculatorTrack() = default; + FluctuationCalculatorTrack(const FluctuationCalculatorTrack&) = default; + FluctuationCalculatorTrack(FluctuationCalculatorTrack&&) noexcept = default; + FluctuationCalculatorTrack& operator=(const FluctuationCalculatorTrack&) = default; + FluctuationCalculatorTrack& operator=(FluctuationCalculatorTrack&&) noexcept = default; virtual ~FluctuationCalculatorTrack() = default; - [[nodiscard]] double getProduct(const std::int32_t orderKeyIndex, const double weight = 1.) const + [[nodiscard]] std::array getProducts(const double weight = 1.) const { - double product{1.}; - for (std::int32_t const& iExponentKey : std::views::iota(0, static_cast(fluctuation_calculator_base::NExponentKeys))) { - if (fluctuation_calculator_base::OrderKeys[orderKeyIndex][iExponentKey] != 0) { - product *= std::pow(mQs[iExponentKey], fluctuation_calculator_base::OrderKeys[orderKeyIndex][iExponentKey]); + std::array, fluctuation_calculator_base::NExponentKeys> powersQ{}; + for (std::int32_t const& iExponentKey : std::views::iota(0, fluctuation_calculator_base::NExponentKeys)) { + powersQ[iExponentKey][1] = mQs[iExponentKey]; + for (std::int32_t const& power : std::views::iota(2, fluctuation_calculator_base::MaxOrder / fluctuation_calculator_base::ExponentKeys[iExponentKey].first + 1)) { + powersQ[iExponentKey][power] = powersQ[iExponentKey][power - 1] * mQs[iExponentKey]; } } - return product * weight; + + std::array products{}; + products.fill(weight); + for (std::int32_t const& iOrderKey : std::views::iota(0, fluctuation_calculator_base::NOrderKeys)) { + for (std::int32_t const& iExponentKey : std::views::iota(0, fluctuation_calculator_base::NExponentKeys)) { + if (const std::int32_t power{fluctuation_calculator_base::OrderKeys[iOrderKey][iExponentKey]}; power > 0) { + products[iOrderKey] *= powersQ[iExponentKey][power]; + } + } + } + return products; } - void init() { mQs.fill(0.); } + void clear() { mQs.fill({}); } void fill(const double charge, const double efficiency, const double weight = 1.) { - for (std::int32_t const& iExponentKey : std::views::iota(0, static_cast(fluctuation_calculator_base::NExponentKeys))) { - mQs[iExponentKey] += std::pow(charge, fluctuation_calculator_base::ExponentKeys[iExponentKey][0]) / std::pow(efficiency, fluctuation_calculator_base::ExponentKeys[iExponentKey][1]) * weight; + const double inverseEfficiency{1. / efficiency}; + std::array powersCharge{1.}; + std::array powersInverseEfficiency{1.}; + for (std::int32_t const& exponent : std::views::iota(1, fluctuation_calculator_base::MaxOrder + 1)) { + powersCharge[exponent] = powersCharge[exponent - 1] * charge; + powersInverseEfficiency[exponent] = powersInverseEfficiency[exponent - 1] * inverseEfficiency; + } + for (std::int32_t const& iExponentKey : std::views::iota(0, fluctuation_calculator_base::NExponentKeys)) { + const auto& [exponentCharge, exponentEfficiency]{fluctuation_calculator_base::ExponentKeys[iExponentKey]}; + mQs[iExponentKey] += weight * powersCharge[exponentCharge] * powersInverseEfficiency[exponentEfficiency]; } } @@ -223,14 +242,14 @@ concept IsValid = IsValidEnum...> && ((EV template requires IsValidEnum -inline constexpr std::int32_t toI(const E e) +constexpr std::int32_t toI(const E e) { return static_cast(e); } template requires IsValidEnum -inline constexpr std::int32_t NEs{toI(E::N)}; +constexpr std::int32_t NEs{toI(E::N)}; template requires IsValidEnum @@ -245,7 +264,7 @@ enum class NameKind { }; template requires IsValidEnum -inline constexpr std::string_view getName(const std::int32_t index) +constexpr std::string_view getName(const std::int32_t index) { if constexpr (NameKindValue == NameKind::Lower) { return EnumInfo>::NamesLower.at(index); @@ -259,15 +278,19 @@ inline constexpr std::string_view getName(const std::int32_t index) } template requires IsValidEnum -inline constexpr std::string_view getName(const E e) +constexpr std::string_view getName(const E e) { return getName(toI(e)); } template requires IsValidEnum -inline std::vector getDisplayNames() +std::vector getDisplayNames() { - return std::vector(EnumInfo>::DisplayNames.begin(), EnumInfo>::DisplayNames.end()); + if constexpr (requires { EnumInfo>::DisplayNames; }) { + return {EnumInfo>::DisplayNames.begin(), EnumInfo>::DisplayNames.end()}; + } else { + return {EnumInfo>::Names.begin(), EnumInfo>::Names.end()}; + } } enum class DataMode { @@ -282,7 +305,7 @@ enum class CentralityDefinition { Ft0m, N }; -enum class DcaKind { +enum class DcaMeasure { Mean = 0, Sigma, N @@ -342,119 +365,164 @@ enum class ChargeNumber { }; template <> -struct EnumInfo { - inline static constexpr std::array> Names{"Mean", "Sigma"}; +struct EnumInfo { + static constexpr std::array> Names{"Mean", "Sigma"}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"Xy", "Z"}; - inline static constexpr std::array> DisplayNames{"Xy", "Z"}; + static constexpr std::array> Names{"Xy", "Z"}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"Tpc", "Tof"}; - inline static constexpr std::array> NamesLower{"tpc", "tof"}; - inline static constexpr std::array> DisplayNames{"TPC", "TOF"}; - inline static constexpr std::array> PidStrategyAllValues{PidStrategyAll::Tpc, PidStrategyAll::Tof}; + static constexpr std::array> Names{"Tpc", "Tof"}; + static constexpr std::array> NamesLower{"tpc", "tof"}; + static constexpr std::array> DisplayNames{"TPC", "TOF"}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"Tpc", "TpcTof"}; - inline static constexpr std::array> NamesLower{"tpc", "tpcTof"}; - inline static constexpr std::array> DisplayNames{"TPC", "TPC+TOF"}; - inline static constexpr std::array> PidStrategyAllValues{PidStrategyAll::Tpc, PidStrategyAll::TpcTofCombined}; + static constexpr std::array> Names{"Tpc", "TpcTof"}; + static constexpr std::array> NamesLower{"tpc", "tpcTof"}; + static constexpr std::array> DisplayNames{"TPC", "TPC+TOF"}; + static constexpr std::array> PidStrategyAllValues{PidStrategyAll::Tpc, PidStrategyAll::TpcTofCombined}; +}; +template <> +struct EnumInfo { + static constexpr std::array> DetectorValues{Detector::Tpc, Detector::Tof, Detector::N, Detector::N}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"Pi", "Ka", "Pr"}; - inline static constexpr std::array> DisplayNames{"Pion", "Kaon", "Proton"}; - inline static constexpr std::array> DisplayNamesLower{"pion", "kaon", "proton"}; - inline static constexpr std::array> ParticleSpeciesAllValues{ParticleSpeciesAll::Pion, ParticleSpeciesAll::Kaon, ParticleSpeciesAll::Proton}; + static constexpr std::array> Names{"Pi", "Ka", "Pr"}; + static constexpr std::array> DisplayNames{"Pion", "Kaon", "Proton"}; + static constexpr std::array> DisplayNamesLower{"pion", "kaon", "proton"}; + static constexpr std::array> ParticleSpeciesAllValues{ParticleSpeciesAll::Pion, ParticleSpeciesAll::Kaon, ParticleSpeciesAll::Proton}; + static constexpr std::array>, NEs> PdgCodes{{{PDG_t::kPiPlus, PDG_t::kPiMinus}, {PDG_t::kKPlus, PDG_t::kKMinus}, {PDG_t::kProton, PDG_t::kProtonBar}}}; + static constexpr std::array> Masses{constants::physics::MassPiPlus, constants::physics::MassKPlus, constants::physics::MassProton}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"", "Pi", "Ka", "Pr"}; - inline static constexpr std::array> DisplayNames{"All", "Pion", "Kaon", "Proton"}; - inline static constexpr std::array> DisplayNamesLower{"all", "pion", "kaon", "proton"}; - inline static constexpr std::array> ParticleSpeciesValues{ParticleSpecies::N, ParticleSpecies::Pion, ParticleSpecies::Kaon, ParticleSpecies::Proton}; - inline static constexpr std::array>, NEs> PdgCodes{{{0, 0}, {PDG_t::kPiPlus, PDG_t::kPiMinus}, {PDG_t::kKPlus, PDG_t::kKMinus}, {PDG_t::kProton, PDG_t::kProtonBar}}}; - inline static constexpr std::array> Masses{0., constants::physics::MassPiPlus, constants::physics::MassKPlus, constants::physics::MassProton}; + static constexpr std::array> Names{"", "Pi", "Ka", "Pr"}; + static constexpr std::array> DisplayNames{"All", "Pion", "Kaon", "Proton"}; + static constexpr std::array> DisplayNamesLower{"all", "pion", "kaon", "proton"}; + static constexpr std::array> Titles{"", "#pi", "K", "p"}; + static constexpr std::array> ParticleSpeciesValues{ParticleSpecies::N, ParticleSpecies::Pion, ParticleSpecies::Kaon, ParticleSpecies::Proton}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"Ch", "Ka", "Pr"}; - inline static constexpr std::array> DisplayNames{"Charge", "Kaon", "Proton"}; - inline static constexpr std::array> DisplayNamesLower{"charge", "kaon", "proton"}; + static constexpr std::array> Names{"Ch", "Ka", "Pr"}; + static constexpr std::array> DisplayNames{"Charge", "Kaon", "Proton"}; + static constexpr std::array> DisplayNamesLower{"charge", "kaon", "proton"}; + static constexpr std::array> Titles{"h", "K", "p"}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"P", "M"}; - inline static constexpr std::array> NamesLower{"p", "m"}; + static constexpr std::array> Names{"P", "M"}; + static constexpr std::array> NamesLower{"p", "m"}; + static constexpr std::array> Titles{"+", "#minus"}; }; template <> struct EnumInfo { - inline static constexpr std::array> Names{"P", "M", "T", "N"}; + static constexpr std::array> Names{"P", "M", "T", "N"}; }; +template + requires IsValidEnum +constexpr std::string_view getTitle(const std::int32_t index) +{ + return EnumInfo>::Titles.at(index); +} template requires IsValidEnum -inline constexpr To getValue(const E e) +constexpr To getValue(const E e) { - if constexpr (std::is_same_v, PidStrategyAll>) { + if constexpr (std::is_same_v, Detector>) { + return EnumInfo::DetectorValues[toI(e)]; + } else if constexpr (std::is_same_v, PidStrategyAll>) { return EnumInfo::PidStrategyAllValues[toI(e)]; } else if constexpr (std::is_same_v, ParticleSpecies>) { return EnumInfo::ParticleSpeciesValues[toI(e)]; } else if constexpr (std::is_same_v, ParticleSpeciesAll>) { return EnumInfo::ParticleSpeciesAllValues[toI(e)]; + } else { + return To::N; } - return To::N; } -inline constexpr std::int32_t getPdgCode(const ParticleSpeciesAll e, const ChargeSpecies chargeSpecies) +constexpr std::int32_t getPdgCode(const ParticleSpecies particleSpecies, const ChargeSpecies chargeSpecies) { - return EnumInfo::PdgCodes[toI(e)][toI(chargeSpecies)]; + return EnumInfo::PdgCodes[toI(particleSpecies)][toI(chargeSpecies)]; } -inline constexpr double getMass(const ParticleSpeciesAll e) +constexpr double getMass(const ParticleSpecies particleSpecies) { - return EnumInfo::Masses[toI(e)]; + return EnumInfo::Masses[toI(particleSpecies)]; } template requires std::is_arithmetic_v -inline constexpr std::int32_t nEnabled(const Configurable>& cfg) +constexpr std::int32_t nEnabled(const Configurable>& cfg) { const LabeledArray& la{cfg.value}; - return std::count_if(la[0], la[0] + la.rows() * la.cols(), [](T x) { return x != T{}; }); + return std::count_if(la[0], la[0] + la.rows() * la.cols(), [](const T x) constexpr -> bool { return x != T{}; }); } template requires std::is_arithmetic_v -inline constexpr bool isEnabled(const Configurable>& cfg) +constexpr bool isEnabled(const Configurable>& cfg) { return nEnabled(cfg) > 0; } + +double interpolate(const TH3* const h, const double x, const double y, const double z) +{ + if (!h) { + return 0.; + } + + static constexpr auto GetBinIndicesWeights{[](const TAxis* const axis, const double position) -> std::array, 2> { + if (!axis) { + return {}; + } + + const std::int32_t n{axis->GetNbins()}; + if (n == 1 || position <= axis->GetBinCenter(1)) { + return {{{1, 1.}, {1, 0.}}}; + } + if (position >= axis->GetBinCenter(n)) { + return {{{n, 1.}, {n, 0.}}}; + } + + const std::int32_t bin{axis->FindFixBin(position)}; + const std::int32_t lower{position < axis->GetBinCenter(bin) ? bin - 1 : bin}; + const std::int32_t upper{lower + 1}; + const double fraction{(position - axis->GetBinCenter(lower)) / (axis->GetBinCenter(upper) - axis->GetBinCenter(lower))}; + + return {{{lower, 1. - fraction}, {upper, fraction}}}; + }}; + + const std::array, 2> xb{GetBinIndicesWeights(h->GetXaxis(), x)}; + const std::array, 2> yb{GetBinIndicesWeights(h->GetYaxis(), y)}; + const std::array, 2> zb{GetBinIndicesWeights(h->GetZaxis(), z)}; + + double result{}; + for (const auto& [ix, wx] : xb) { + for (const auto& [iy, wy] : yb) { + for (const auto& [iz, wz] : zb) { + result += wx * wy * wz * h->GetBinContent(ix, iy, iz); + } + } + } + return result; +} } // namespace struct PartNumFluc { struct HolderCcdb { - [[maybe_unused]] inline static constexpr std::int32_t NDimensionsEfficiency{4}; + [[maybe_unused]] static constexpr std::int32_t NDimensionsEfficiency{4}; std::map> runNumbersIndicesGroupIndices; - std::vector>, NEs>, NEs>> fPtDca; + std::vector, NEs>, NEs>, NEs>> fPtMeasureDca; std::vector>, NEs>, NEs>> hCentralityPtEtaShiftNSigmaPid; std::vector>, NEs>, NEs>> hVzCentralityPtEtaEfficiency; - - void clear() - { - runNumbersIndicesGroupIndices.clear(); - fPtDca.clear(); - hCentralityPtEtaShiftNSigmaPid.clear(); - hVzCentralityPtEtaEfficiency.clear(); - } } holderCcdb{}; struct HolderMcEvent { - std::int32_t runNumber{}; - std::int32_t runIndex{}; - std::int32_t runGroupIndex{}; double vz{}; std::array>, NEs> numbers{}; std::array>, NEs> numbersEff{}; @@ -463,7 +531,8 @@ struct PartNumFluc { } holderMcEvent{}; struct HolderEvent { - inline static constexpr std::pair RangeCentrality{0., 100.}; + static constexpr std::pair RangeCentrality{0., 100.}; + static constexpr bool isValidCentrality(const double value) { return RangeCentrality.first <= value && value <= RangeCentrality.second; } std::int32_t runNumber{}; std::int32_t runIndex{}; @@ -471,8 +540,9 @@ struct PartNumFluc { double vz{}; std::array> nGlobalTracks{}; std::array> nPvContributors{}; - std::array>, NEs>, NEs> dca{}; + std::array>, NEs>, NEs> measureDca{}; std::array> nTofBeta{}; + double centralityCalibration{}; double centrality{}; std::int32_t subgroupIndex{}; std::array>, NEs> numbers{}; @@ -480,9 +550,9 @@ struct PartNumFluc { void clear() { *this = {}; } [[nodiscard]] std::int32_t getNGlobalTracks() const { return std::accumulate(nGlobalTracks.begin(), nGlobalTracks.end(), 0); } [[nodiscard]] std::int32_t getNPvContributors() const { return std::accumulate(nPvContributors.begin(), nPvContributors.end(), 0); } - template - requires IsValid - [[nodiscard]] double getDca() const + template + requires IsValid + [[nodiscard]] double getMeasureDca() const { const std::int32_t sumNGlobalTracks{getNGlobalTracks()}; if (sumNGlobalTracks == 0) { @@ -490,18 +560,18 @@ struct PartNumFluc { } double sumDca{}; - if constexpr (DcaKindValue == DcaKind::Sigma) { - const double meanDca{getDca()}; + if constexpr (DcaMeasureValue == DcaMeasure::Sigma) { + const double meanDca{getMeasureDca()}; for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - sumDca += (std::pow(dca[toI(DcaKind::Sigma)][toI(DcaAxisValue)][iChargeSpecies], 2.) + std::pow(dca[toI(DcaKind::Mean)][toI(DcaAxisValue)][iChargeSpecies] - meanDca, 2.)) * nGlobalTracks[iChargeSpecies]; + sumDca += (std::pow(measureDca[toI(DcaMeasure::Sigma)][toI(DcaAxisValue)][iChargeSpecies], 2.) + std::pow(measureDca[toI(DcaMeasure::Mean)][toI(DcaAxisValue)][iChargeSpecies] - meanDca, 2.)) * nGlobalTracks[iChargeSpecies]; } return std::sqrt(sumDca / sumNGlobalTracks); + } else { + for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { + sumDca += measureDca[toI(DcaMeasure::Mean)][toI(DcaAxisValue)][iChargeSpecies] * nGlobalTracks[iChargeSpecies]; + } + return sumDca / sumNGlobalTracks; } - - for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - sumDca += dca[toI(DcaKind::Mean)][toI(DcaAxisValue)][iChargeSpecies] * nGlobalTracks[iChargeSpecies]; - } - return sumDca / sumNGlobalTracks; } [[nodiscard]] std::int32_t getNTofBeta() const { return std::accumulate(nTofBeta.begin(), nTofBeta.end(), 0); } } holderEvent{}; @@ -516,19 +586,26 @@ struct PartNumFluc { } holderMcParticle{}; struct HolderTrack { - inline static constexpr double TruncationAbsNSigmaPid{999.}; - static constexpr double truncateNSigmaPid(const double value) { return std::abs(value) < TruncationAbsNSigmaPid ? value : -TruncationAbsNSigmaPid; } + static constexpr double TruncationAbsNSigmaPid{999.}; + static constexpr double truncateNSigmaPid(const double value, const double shift = {}) + { + const double valueShifted{value - shift}; + return std::abs(value) < TruncationAbsNSigmaPid && std::abs(valueShifted) < TruncationAbsNSigmaPid ? valueShifted : -TruncationAbsNSigmaPid; + } + + [[nodiscard]] double getNSigmaPidCombined(const std::int32_t particleSpeciesIndex) const + { + return truncateNSigmaPid(std::copysign(std::hypot(nSigmaPid[toI(Detector::Tpc)][particleSpeciesIndex], nSigmaPid[toI(Detector::Tof)][particleSpeciesIndex]), nSigmaPid[toI(Detector::Tpc)][particleSpeciesIndex] + nSigmaPid[toI(Detector::Tof)][particleSpeciesIndex])); + } std::array> dca{}; std::int32_t sign{}; - double p{}; double pt{}; double eta{}; double phi{}; - double phiIu{}; std::array> hasPid{}; - std::array>, NEs> nSigmaPid{[] { - std::array>, NEs> a{}; + std::array>, NEs> nSigmaPid{[]() constexpr -> std::array>, NEs> { + std::array>, NEs> a{}; std::array> b{}; b.fill(-TruncationAbsNSigmaPid); a.fill(b); @@ -552,8 +629,8 @@ struct PartNumFluc { std::array> nMcParticles{}; std::array> nTracks{}; - std::vector signedEfficienciesMcParticle{[] {std::vector v{}; v.reserve(256); return v; }()}; - std::vector signedEfficienciesTrack{[] {std::vector v{}; v.reserve(256); return v; }()}; + std::vector signedEfficienciesMcParticle{[]() constexpr -> std::vector { std::vector v{}; v.reserve(256); return v; }()}; + std::vector signedEfficienciesTrack{[]() constexpr -> std::vector { std::vector v{}; v.reserve(256); return v; }()}; void clear() { @@ -578,14 +655,14 @@ struct PartNumFluc { Configurable cfgFlagQaCentrality{"cfgFlagQaCentrality", false, "Centrality QA flag"}; Configurable cfgFlagQaTrack{"cfgFlagQaTrack", false, "Track QA flag"}; Configurable cfgFlagQaDca{"cfgFlagQaDca", false, "DCA QA flag"}; - Configurable> cfgFlagsQaAcceptance{"cfgFlagsQaAcceptance", {std::array>{0, 0, 0, 0}.data(), NEs, getDisplayNames()}, "Acceptance QA flags"}; - Configurable> cfgFlagsQaPhi{"cfgFlagsQaPhi", {std::array>{0, 0, 0, 0}.data(), NEs, getDisplayNames()}, "Phi QA flags"}; - Configurable> cfgFlagsQaPid{"cfgFlagsQaPid", {std::array>{0, 0, 0, 0}.data(), NEs, getDisplayNames()}, "PID QA flags"}; + Configurable> cfgFlagsQaAcceptance{"cfgFlagsQaAcceptance", {std::array>{}.data(), NEs, getDisplayNames()}, "Acceptance QA flags"}; + Configurable> cfgFlagsQaPhi{"cfgFlagsQaPhi", {std::array>{}.data(), NEs, getDisplayNames()}, "Phi QA flags"}; + Configurable> cfgFlagsQaPid{"cfgFlagsQaPid", {std::array>{}.data(), NEs, getDisplayNames()}, "PID QA flags"}; Configurable cfgFlagQaMc{"cfgFlagQaMc", false, "MC QA flag"}; - Configurable> cfgFlagsCalculationYield{"cfgFlagsCalculationYield", {std::array>{0, 0, 0}.data(), NEs, getDisplayNames()}, "Yield calculation flags"}; - Configurable> cfgFlagsCalculationPurity{"cfgFlagsCalculationPurity", {std::array>{0, 0, 0}.data(), NEs, getDisplayNames()}, "Purity calculation flags"}; - Configurable> cfgFlagsCalculationFractionPrimary{"cfgFlagsCalculationFractionPrimary", {std::array>{0, 0, 0}.data(), NEs, getDisplayNames()}, "Primary fraction calculation flags"}; - Configurable> cfgFlagsCalculationFluctuation{"cfgFlagsCalculationFluctuation", {std::array>{0, 0, 0}.data(), NEs, getDisplayNames()}, "Fluctuation calculation flags"}; + Configurable> cfgFlagsCalculationYield{"cfgFlagsCalculationYield", {std::array>{}.data(), NEs, getDisplayNames()}, "Yield calculation flags"}; + Configurable> cfgFlagsCalculationPurity{"cfgFlagsCalculationPurity", {std::array>{}.data(), NEs, getDisplayNames()}, "Purity calculation flags"}; + Configurable> cfgFlagsCalculationFractionPrimary{"cfgFlagsCalculationFractionPrimary", {std::array>{}.data(), NEs, getDisplayNames()}, "Primary fraction calculation flags"}; + Configurable> cfgFlagsCalculationFluctuation{"cfgFlagsCalculationFluctuation", {std::array>{}.data(), NEs, getDisplayNames()}, "Fluctuation calculation flags"}; } groupAnalysis{}; struct : ConfigurableGroup { @@ -593,28 +670,31 @@ struct PartNumFluc { Configurable cfgFlagRejectionRunBadMc{"cfgFlagRejectionRunBadMc", false, "MC bad run rejection flag"}; Configurable cfgLabelFlagsRct{"cfgLabelFlagsRct", "CBT_hadronPID", "RCT flags label"}; Configurable> cfgFlagsRct{"cfgFlagsRct", {std::array{0, 1, 1}.data(), 3, {"ZDC", "Acceptance", "Table"}}, "RCT flags"}; - Configurable cfgBitsSelectionEvent{"cfgBitsSelectionEvent", std::uint64_t{0b10000000001101000000000000000000000000000000000000}, "Event selection bits"}; + Configurable cfgBitsSelectionEvent{"cfgBitsSelectionEvent", std::uint64_t{0b00000000000001000000000000000000000000000000000000}, "Event selection bits"}; Configurable cfgFlagInelEvent{"cfgFlagInelEvent", true, "Flag of requiring inelastic event"}; Configurable cfgFlagInelEventMc{"cfgFlagInelEventMc", false, "Flag of requiring inelastic MC event"}; - Configurable cfgCutMaxAbsVz{"cfgCutMaxAbsVz", 6., "Maximum absolute z-vertex position (cm)"}; - Configurable cfgFlagCutVzMc{"cfgFlagCutVzMc", false, "Flag of requiring MC z-vertex cut"}; + Configurable cfgCutMaxAbsVz{"cfgCutMaxAbsVz", 8., "Maximum absolute z-vertex position (cm)"}; + Configurable cfgCutMaxAbsVzMc{"cfgCutMaxAbsVzMc", 999., "Maximum absolute MC z-vertex position (cm)"}; Configurable cfgCutMinDeviationNPvContributors{"cfgCutMinDeviationNPvContributors", -4, "Minimum nPvContributors deviation from nGlobalTracks"}; Configurable cfgIndexDefinitionCentrality{"cfgIndexDefinitionCentrality", 2, "Centrality definition index"}; + Configurable cfgFlagDefinitionCentralitySameQa{"cfgFlagDefinitionCentralitySameQa", false, "Flag of using the same centrality definition for QA"}; ConfigurableAxis cfgAxisCentrality{"cfgAxisCentrality", {18, 0., 90.}, "Centrality axis in fluctuation calculation"}; + ConfigurableAxis cfgAxisCentralityCalibration{"cfgAxisCentralityCalibration", {VARIABLE_WIDTH, 0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 100.}, "Centrality axis in calibration"}; Configurable cfgNSubgroups{"cfgNSubgroups", 20, "Number of subgroups in fluctuation calculation"}; Configurable cfgFlagSingleCollisionMc{"cfgFlagSingleCollisionMc", false, "Flag of requiring exactly single collision of MC collision"}; - Configurable cfgFlagBestCollisionMc{"cfgFlagBestCollisionMc", true, "Flag of requiring best collision of MC collision"}; + Configurable cfgFlagBestCollisionMc{"cfgFlagBestCollisionMc", false, "Flag of requiring best collision of MC collision"}; Configurable cfgFlagMcCollisionVz{"cfgFlagMcCollisionVz", false, "Flag of using z-vertex position of MC collision"}; } groupEvent{}; struct : ConfigurableGroup { Configurable cfgFlagPvContributor{"cfgFlagPvContributor", true, "Flag of requiring PV contributor"}; Configurable cfgCutMinItsNCls{"cfgCutMinItsNCls", 5, "Minimum number of clusters ITS"}; - Configurable cfgCutMaxItsChi2NCls{"cfgCutMaxItsChi2NCls", 30., "Maximum chi2 per cluster ITS"}; + Configurable cfgCutMaxItsChi2NCls{"cfgCutMaxItsChi2NCls", 25., "Maximum chi2 per cluster ITS"}; Configurable cfgCutMinTpcNCls{"cfgCutMinTpcNCls", 55, "Minimum number of clusters TPC"}; + Configurable cfgCutMinTpcChi2NCls{"cfgCutMinTpcChi2NCls", 0., "Minimum chi2 per cluster TPC"}; Configurable cfgCutMaxTpcChi2NCls{"cfgCutMaxTpcChi2NCls", 3.5, "Maximum chi2 per cluster TPC"}; - Configurable cfgCutMaxTpcNClsSharedRatio{"cfgCutMaxTpcNClsSharedRatio", 0.25, "Maximum ratio of shared clusters over clusters TPC"}; - Configurable cfgCutMinTpcNCrossedRows{"cfgCutMinTpcNCrossedRows", 75, "Minimum number of crossed rows TPC"}; + Configurable cfgCutMaxTpcNClsSharedRatio{"cfgCutMaxTpcNClsSharedRatio", 0.4, "Maximum ratio of shared clusters over clusters TPC"}; + Configurable cfgCutMinTpcNCrossedRows{"cfgCutMinTpcNCrossedRows", 80, "Minimum number of crossed rows TPC"}; Configurable cfgCutMinTpcNCrossedRowsRatio{"cfgCutMinTpcNCrossedRowsRatio", 0.8, "Minimum ratio of crossed rows over findable clusters TPC"}; Configurable cfgFlagRecalibrationDca{"cfgFlagRecalibrationDca", false, "DCA recalibration flag"}; Configurable> cfgCutsMaxAbsNSigmaDca{"cfgCutsMaxAbsNSigmaDca", {std::array>{2.5, 2.5}.data(), NEs, getDisplayNames()}, "Maximum absolute nSigma values of DCA (cm)"}; @@ -622,13 +702,21 @@ struct PartNumFluc { Configurable cfgCutMaxPt{"cfgCutMaxPt", 2., "Maximum pT (GeV/c)"}; Configurable cfgCutMaxAbsEta{"cfgCutMaxAbsEta", 0.8, "Maximum absolute eta"}; Configurable> cfgThresholdsPtTofPid{"cfgThresholdsPtTofPid", {std::array>{0.5, 0.5, 0.8}.data(), NEs, getDisplayNames()}, "pT (GeV/c) thresholds for TOF PID"}; - Configurable> cfgFlagsRecalibrationNSigmaPid{"cfgFlagsRecalibrationNSigmaPid", {std::array>{0, 0, 0}.data(), NEs, getDisplayNames()}, "nSigma PID recalibration flags"}; + Configurable> cfgFlagsRecalibrationNSigmaPid{"cfgFlagsRecalibrationNSigmaPid", {std::array>{}.data(), NEs, getDisplayNames()}, "nSigma PID recalibration flags"}; Configurable cfgFlagRejectionOthers{"cfgFlagRejectionOthers", false, "Other particle species rejection flag"}; Configurable> cfgCutsMaxAbsNSigmaPid{"cfgCutsMaxAbsNSigmaPid", {std::array>{2., 2., 2.}.data(), NEs, getDisplayNames()}, "Maximum absolute nSigma values for PID"}; Configurable cfgFlagMcParticlePhysicalPrimary{"cfgFlagMcParticlePhysicalPrimary", true, "Flag of requiring physical primary MC particle"}; Configurable cfgFlagMcParticleMomentum{"cfgFlagMcParticleMomentum", true, "Flag of using momentum of MC particle"}; } groupTrack{}; + bool doQaAcceptance{}; + bool doQaPhi{}; + bool doQaPid{}; + bool doCalculationYield{}; + bool doCalculationPurity{}; + bool doCalculationFractionPrimary{}; + bool doCalculationFluctuation{}; + HistogramRegistry hrCalculationFluctuation{"hrCalculationFluctuation", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrCalculationFractionPrimary{"hrCalculationFractionPrimary", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrCalculationPurity{"hrCalculationPurity", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -660,19 +748,27 @@ struct PartNumFluc { Produces miniMcParticle{}; Produces miniTrack{}; - void init(InitContext&) + void init(const InitContext&) { gRandom->SetSeed(0); - if (doprocessRaw.value == doprocessMc.value) { - LOG(fatal) << "Identical doprocessRaw and doprocessMc!"; + if (doProcessRaw.value == doProcessMc.value) { + LOG(fatal) << "Identical values of doProcessRaw and doProcessMc!"; } - if (doprocessRaw.value) { - LOG(info) << "Enabling raw data process."; - } else if (doprocessMc.value) { + if (doProcessMc.value) { LOG(info) << "Enabling MC data process."; + } else { + LOG(info) << "Enabling raw data process."; } + doQaAcceptance = isEnabled(groupAnalysis.cfgFlagsQaAcceptance); + doQaPhi = isEnabled(groupAnalysis.cfgFlagsQaPhi); + doQaPid = isEnabled(groupAnalysis.cfgFlagsQaPid); + doCalculationYield = isEnabled(groupAnalysis.cfgFlagsCalculationYield); + doCalculationPurity = isEnabled(groupAnalysis.cfgFlagsCalculationPurity); + doCalculationFractionPrimary = isEnabled(groupAnalysis.cfgFlagsCalculationFractionPrimary); + doCalculationFluctuation = isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation); + rctFlagsChecker.init(groupEvent.cfgLabelFlagsRct.value, static_cast(groupEvent.cfgFlagsRct.value.get("ZDC")), static_cast(groupEvent.cfgFlagsRct.value.get("Acceptance")), static_cast(groupEvent.cfgFlagsRct.value.get("Table"))); ccdb->setURL(groupCcdb.cfgCcdbUrl.value); @@ -686,7 +782,6 @@ struct PartNumFluc { if (!ccdbObject || ccdbObject->IsA() != TList::Class()) { LOG(fatal) << "Invalid CCDB object!"; } - holderCcdb.clear(); std::int32_t nRunsBad{}; std::int32_t nRunGroups{}; @@ -711,10 +806,11 @@ struct PartNumFluc { } for (std::int32_t const& iRun : std::views::iota(0, gRunNumberGroupIndex->GetN())) { if (std::llrint(gRunNumberGroupIndex->GetY()[iRun]) <= 0) { - auto iter = holderCcdb.runNumbersIndicesGroupIndices.find(std::llrint(gRunNumberGroupIndex->GetX()[iRun])); - if (iter != holderCcdb.runNumbersIndicesGroupIndices.end() && iter->second.second > 0) { + if (const auto iter{holderCcdb.runNumbersIndicesGroupIndices.find(std::llrint(gRunNumberGroupIndex->GetX()[iRun]))}; iter != holderCcdb.runNumbersIndicesGroupIndices.end() && iter->second.second > 0) { iter->second.second = -iter->second.second; - ++nRunsBad; + if (groupEvent.cfgFlagRejectionRunBad.value) { + ++nRunsBad; + } } } } @@ -775,9 +871,9 @@ struct PartNumFluc { break; } - const auto readListRunGroup{[&](const std::int32_t runGroupIndex) -> const TList* { - const char* const name{Form("lRunGroup_%d", runGroupIndex)}; - const TList* const lRunGroup{dynamic_cast(ccdbObject->FindObject(name))}; + static constexpr auto ReadListRunGroup{[](const TList* const ccdbObject, const std::int32_t runGroupIndex) -> const TList* { + const std::string name{std::format("lRunGroup_{}", runGroupIndex)}; + const TList* const lRunGroup{dynamic_cast(ccdbObject->FindObject(name.c_str()))}; if (!lRunGroup) { LOG(fatal) << "Invalid " << name << "!"; } @@ -787,18 +883,27 @@ struct PartNumFluc { if (groupTrack.cfgFlagRecalibrationDca.value) { LOG(info) << "Enabling DCA recalibration."; - holderCcdb.fPtDca.resize(nRunGroups); + holderCcdb.fPtMeasureDca.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup{readListRunGroup(iRunGroup + 1)}; - for (std::int32_t const& iDcaKind : std::views::iota(0, NEs)) { + const TList* const lRunGroup{ReadListRunGroup(ccdbObject, iRunGroup + 1)}; + for (std::int32_t const& iDcaMeasure : std::views::iota(0, NEs)) { for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - const char* const name{Form("fPt%sDca%s%s%s_runGroup%d", getName(iDcaKind).data(), getName(iDcaAxis).data(), getName(iChargeSpecies).data(), doprocessMc.value ? "_mc" : "", iRunGroup + 1)}; - holderCcdb.fPtDca[iRunGroup][iDcaKind][iDcaAxis][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name)); - if (!holderCcdb.fPtDca[iRunGroup][iDcaKind][iDcaAxis][iChargeSpecies]) { - LOG(fatal) << "Invalid " << name << "!"; + std::pair& calibration{holderCcdb.fPtMeasureDca[iRunGroup][iDcaMeasure][iDcaAxis][iChargeSpecies]}; + const std::string nameFormula{std::format("fPt{}Dca{}{}{}_runGroup{}", getName(iDcaMeasure), getName(iDcaAxis), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", iRunGroup + 1)}; + calibration.first = dynamic_cast(lRunGroup->FindObject(nameFormula.c_str())); + if (!calibration.first || calibration.first->GetNdim() != 1 || calibration.first->GetNpar() <= 0) { + LOG(fatal) << "Invalid " << nameFormula << "!"; + } + LOG(info) << "Reading from CCDB: " << nameFormula << " \"" << calibration.first->GetExpFormula() << "\""; + const std::int32_t nParameters{calibration.first->GetNpar()}; + + const std::string nameHistogram{std::format("hCentralityEtaParameterPt{}Dca{}{}{}_runGroup{}", getName(iDcaMeasure), getName(iDcaAxis), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", iRunGroup + 1)}; + calibration.second = dynamic_cast(lRunGroup->FindObject(nameHistogram.c_str())); + if (calibration.second == nullptr || calibration.second->GetNbinsZ() != nParameters || std::ranges::any_of(std::views::iota(0, nParameters), [zAxis = calibration.second->GetZaxis()](const std::int32_t binIndex) -> bool { return zAxis->GetBinCenter(binIndex + 1) != binIndex; })) { + LOG(fatal) << "Invalid " << nameHistogram << "!"; } - LOG(info) << "Reading from CCDB: " << name << " \"" << holderCcdb.fPtDca[iRunGroup][iDcaKind][iDcaAxis][iChargeSpecies]->GetExpFormula("clingp") << "\""; + LOG(info) << "Reading from CCDB: " << nameHistogram; } } } @@ -814,11 +919,11 @@ struct PartNumFluc { holderCcdb.hCentralityPtEtaShiftNSigmaPid.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup{readListRunGroup(iRunGroup + 1)}; + const TList* const lRunGroup{ReadListRunGroup(ccdbObject, iRunGroup + 1)}; for (std::int32_t const& iDetector : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - const char* const name{Form("hCentralityPtEtaShift%sNSigma%s%s%s_runGroup%d", getName(iDetector).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data(), doprocessMc.value ? "_mc" : "", iRunGroup + 1)}; - holderCcdb.hCentralityPtEtaShiftNSigmaPid[iRunGroup][iDetector][iParticleSpecies][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name)); + const std::string name{std::format("hCentralityPtEtaShift{}NSigma{}{}{}_runGroup{}", getName(iDetector), getName(iParticleSpecies), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", iRunGroup + 1)}; + holderCcdb.hCentralityPtEtaShiftNSigmaPid[iRunGroup][iDetector][iParticleSpecies][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name.c_str())); if (!holderCcdb.hCentralityPtEtaShiftNSigmaPid[iRunGroup][iDetector][iParticleSpecies][iChargeSpecies]) { LOG(fatal) << "Invalid " << name << "!"; } @@ -829,14 +934,14 @@ struct PartNumFluc { } hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{10 + aod::evsel::EventSelectionFlags::kNsel, -0.5, 9.5 + static_cast(aod::evsel::EventSelectionFlags::kNsel), "Selection"}}}); - if (doprocessMc.value) { + if (doProcessMc.value) { hrCounter.add("hNMcEvents", ";;No. of MC Events", {HistType::kTH1D, {{10, -0.5, 9.5, "Selection"}}}); } if (groupAnalysis.cfgFlagQaRun.value) { LOG(info) << "Enabling run QA."; - const HistogramConfigSpec hcsQaRun(HistType::kTProfile, {{static_cast(holderCcdb.runNumbersIndicesGroupIndices.size()), -0.5, holderCcdb.runNumbersIndicesGroupIndices.size() - 0.5, "Run Index"}}); + const HistogramConfigSpec hcsQaRun{HistType::kTProfile, {{static_cast(holderCcdb.runNumbersIndicesGroupIndices.size()), -0.5, holderCcdb.runNumbersIndicesGroupIndices.size() - 0.5, "Run Index"}}}; for (const auto& [name, title, isChargeSpeciesSeparated] : std::to_array>( {{"Vx", "#LT#it{V}_{#it{x}}#GT (cm)", false}, @@ -844,15 +949,16 @@ struct PartNumFluc { {"Vz", "#LT#it{V}_{#it{z}}#GT (cm)", false}, {"MultiplicityFt0a", "FT0A #LTMultiplicity#GT", false}, {"MultiplicityFt0c", "FT0C #LTMultiplicity#GT", false}, + {"CentralityNtpv", "NTPV #LTCentrality#GT", false}, {"CentralityFt0a", "FT0A #LTCentrality#GT", false}, {"CentralityFt0c", "FT0C #LTCentrality#GT", false}, {"CentralityFt0m", "FT0M #LTCentrality#GT", false}, {"NGlobalTracks", "#LTnGlobalTracks#GT", true}, {"NPvContributors", "#LTnPvContributors#GT", true}, - {Form("%sDca%s", getName(DcaKind::Mean).data(), getName(DcaAxis::Xy).data()), "#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm)", true}, - {Form("%sDca%s", getName(DcaKind::Sigma).data(), getName(DcaAxis::Xy).data()), "#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm)", true}, - {Form("%sDca%s", getName(DcaKind::Mean).data(), getName(DcaAxis::Z).data()), "#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm)", true}, - {Form("%sDca%s", getName(DcaKind::Sigma).data(), getName(DcaAxis::Z).data()), "#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm)", true}, + {std::format("{}Dca{}", getName(DcaMeasure::Mean), getName(DcaAxis::Xy)), "#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm)", true}, + {std::format("{}Dca{}", getName(DcaMeasure::Sigma), getName(DcaAxis::Xy)), "#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm)", true}, + {std::format("{}Dca{}", getName(DcaMeasure::Mean), getName(DcaAxis::Z)), "#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm)", true}, + {std::format("{}Dca{}", getName(DcaMeasure::Sigma), getName(DcaAxis::Z)), "#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm)", true}, {"NTofBeta", "#LTnTofBeta#GT", true}, {"ItsNCls", "ITS #LTnClusters#GT", true}, {"ItsChi2NCls", "ITS #LT#it{#chi}^{2}/nClusters#GT", true}, @@ -861,24 +967,22 @@ struct PartNumFluc { {"TpcNClsSharedRatio", "TPC #LTnSharedClusters/nClusters#GT", true}, {"TpcNCrossedRows", "TPC #LTnCrossedRows#GT", true}, {"TpcNCrossedRowsRatio", "TPC #LTnCrossedRows/nFindableClusters#GT", true}, - {"DcaXy", "#LTDCA_{#it{xy}}#GT (cm)", true}, - {"DcaZ", "#LTDCA_{#it{z}}#GT (cm)", true}, {"Pt", "#LT#it{p}_{T}#GT (GeV/#it{c})", true}, {"Eta", "#LT#it{#eta}#GT", true}, {"Phi", "#LT#it{#varphi}#GT", true}, {"TpcDeDx", "TPC #LTd#it{E}/d#it{x}#GT (a.u.)", true}, - {Form("%sNSigma%s", getName(Detector::Tpc).data(), getName(ParticleSpecies::Pion).data()), Form("%s #LT#it{n}#it{#sigma}_{#pi}#GT", getName(Detector::Tpc).data()), true}, - {Form("%sNSigma%s", getName(Detector::Tpc).data(), getName(ParticleSpecies::Kaon).data()), Form("%s #LT#it{n}#it{#sigma}_{K}#GT", getName(Detector::Tpc).data()), true}, - {Form("%sNSigma%s", getName(Detector::Tpc).data(), getName(ParticleSpecies::Proton).data()), Form("%s #LT#it{n}#it{#sigma}_{p}#GT", getName(Detector::Tpc).data()), true}, + {std::format("{}NSigma{}", getName(Detector::Tpc), getName(ParticleSpecies::Pion)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{#pi}}#GT", getName(Detector::Tpc)), true}, + {std::format("{}NSigma{}", getName(Detector::Tpc), getName(ParticleSpecies::Kaon)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{K}}#GT", getName(Detector::Tpc)), true}, + {std::format("{}NSigma{}", getName(Detector::Tpc), getName(ParticleSpecies::Proton)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{p}}#GT", getName(Detector::Tpc)), true}, {"TofInverseBeta", "TOF #LT1/#it{#beta}#GT", true}, - {Form("%sNSigma%s", getName(Detector::Tof).data(), getName(ParticleSpecies::Pion).data()), Form("%s #LT#it{n}#it{#sigma}_{#pi}#GT", getName(Detector::Tof).data()), true}, - {Form("%sNSigma%s", getName(Detector::Tof).data(), getName(ParticleSpecies::Kaon).data()), Form("%s #LT#it{n}#it{#sigma}_{K}#GT", getName(Detector::Tof).data()), true}, - {Form("%sNSigma%s", getName(Detector::Tof).data(), getName(ParticleSpecies::Proton).data()), Form("%s #LT#it{n}#it{#sigma}_{p}#GT", getName(Detector::Tof).data()), true}})) { + {std::format("{}NSigma{}", getName(Detector::Tof), getName(ParticleSpecies::Pion)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{#pi}}#GT", getName(Detector::Tof)), true}, + {std::format("{}NSigma{}", getName(Detector::Tof), getName(ParticleSpecies::Kaon)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{K}}#GT", getName(Detector::Tof)), true}, + {std::format("{}NSigma{}", getName(Detector::Tof), getName(ParticleSpecies::Proton)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{p}}#GT", getName(Detector::Tof)), true}})) { if (!isChargeSpeciesSeparated) { - hrQaRun.add(Form("QaRun/pRunIndex%s", name.data()), Form(";;%s", title.data()), hcsQaRun); + hrQaRun.add(std::format("QaRun/pRunIndex{}", name).c_str(), std::format(";;{}", title).c_str(), hcsQaRun); } else { - hrQaRun.add(Form("QaRun/pRunIndex%s_%s", name.data(), getName(ChargeSpecies::Plus).data()), Form(";;%s (#it{q}>0)", title.data()), hcsQaRun); - hrQaRun.add(Form("QaRun/pRunIndex%s_%s", name.data(), getName(ChargeSpecies::Minus).data()), Form(";;%s (#it{q}<0)", title.data()), hcsQaRun); + hrQaRun.add(std::format("QaRun/pRunIndex{}_{}", name, getName(ChargeSpecies::Plus)).c_str(), std::format(";;{} (#it{{q}}>0)", title).c_str(), hcsQaRun); + hrQaRun.add(std::format("QaRun/pRunIndex{}_{}", name, getName(ChargeSpecies::Minus)).c_str(), std::format(";;{} (#it{{q}}<0)", title).c_str(), hcsQaRun); } } } @@ -886,8 +990,8 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaEvent.value) { LOG(info) << "Enabling event QA."; - const AxisSpec asNTracks(200, -0.5, 199.5); - const HistogramConfigSpec hcsQaEvent(HistType::kTHnSparseD, {asNTracks, asNTracks}); + const AxisSpec asNTracks{200, -0.5, 199.5}; + const HistogramConfigSpec hcsQaEvent{HistType::kTHnSparseD, {asNTracks, asNTracks}}; hrQaEvent.add("QaEvent/hVxVy", "", {HistType::kTHnSparseD, {{150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); hrQaEvent.add("QaEvent/hVz", "", {HistType::kTH1D, {{300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); @@ -917,7 +1021,7 @@ struct PartNumFluc { {"TpcChi2NCls", {HistType::kTH1D, {{100, 0., 5., "TPC #it{#chi}^{2}/nClusters"}}}}, {"TpcNClsFindableNCrossedRows", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}}})) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaTrack.add(Form("QaTrack/h%s_%s", name.data(), getName(iChargeSpecies).data()), "", configSpec); + hrQaTrack.add(std::format("QaTrack/h{}_{}", name, getName(iChargeSpecies)).c_str(), "", configSpec); } } } @@ -925,16 +1029,16 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaDca.value) { LOG(info) << "Enabling DCA QA."; - const AxisSpec asPt(40, 0., 2., "#it{p}_{T} (GeV/#it{c})"); - const HistogramConfigSpec hcsQaDcaProfile(HistType::kTProfile3D, {asPt, {24, -1.2, 1.2, "#it{#eta}"}, {constants::math::NSectors, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}); + const AxisSpec asPt{40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}; + const HistogramConfigSpec hcsQaDcaProfile{HistType::kTProfile3D, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, asPt, {24, -1.2, 1.2, "#it{#eta}"}}}; for (const auto& [name, title, configSpec] : std::to_array>( {{"hPtDcaXy", "", {HistType::kTHnSparseD, {asPt, {250, -0.25, 0.25, "DCA_{#it{xy}} (cm)"}}}}, - {"pPtEtaPhiIuDcaXy", ";;#LTDCA_{#it{xy}}#GT (cm)", hcsQaDcaProfile}, + {"pCentralityPtEtaDcaXy", ";;#LTDCA_{#it{xy}}#GT (cm)", hcsQaDcaProfile}, {"hPtDcaZ", "", {HistType::kTHnSparseD, {asPt, {250, -0.5, 0.5, "DCA_{#it{z}} (cm)"}}}}, - {"pPtEtaPhiIuDcaZ", ";;#LTDCA_{#it{z}}#GT (cm)", hcsQaDcaProfile}})) { + {"pCentralityPtEtaDcaZ", ";;#LTDCA_{#it{z}}#GT (cm)", hcsQaDcaProfile}})) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaDca.add(Form("QaDca/%s_%s", name.data(), getName(iChargeSpecies).data()), title.data(), configSpec); + hrQaDca.add(std::format("QaDca/{}_{}", name, getName(iChargeSpecies)).c_str(), title.data(), configSpec); } } } @@ -948,7 +1052,7 @@ struct PartNumFluc { for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaAcceptance.add(Form("QaAcceptance/h%sPt_%sEdge%s%s", iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "Eta" : "Rapidity", getName(iPidStrategy).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), "", {HistType::kTHnSparseD, {{300, -1.5, 1.5, iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "#it{#eta}" : "#it{y}"}, {250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"}}}); + hrQaAcceptance.add(std::format("QaAcceptance/h{}Pt_{}Edge{}{}", iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "Eta" : "Rapidity", getName(iPidStrategy), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), "", {HistType::kTHnSparseD, {{300, -1.5, 1.5, iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "#it{#eta}" : "#it{y}"}, {250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"}}}); } } } @@ -960,12 +1064,11 @@ struct PartNumFluc { LOG(info) << "Enabling " << getName(iParticleSpeciesAll) << " phi QA."; - const HistogramConfigSpec hcsQaPhi(HistType::kTHnSparseF, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}, {360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}); + const HistogramConfigSpec hcsQaPhi{HistType::kTHnSparseF, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}, {360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPhi.add(Form("QaPhi/hCentralityPtEtaPhi_%s%s%s", doprocessMc.value ? Form("mc%s", getName(iPidStrategy).data()) : getName(iPidStrategy).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), "", hcsQaPhi); - hrQaPhi.add(Form("QaPhi/hCentralityPtEtaPhiIu_%s%s%s", doprocessMc.value ? Form("mc%s", getName(iPidStrategy).data()) : getName(iPidStrategy).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), "", hcsQaPhi); + hrQaPhi.add(std::format("QaPhi/hCentralityPtEtaPhi_{}{}{}{}", doProcessMc.value ? "mc" : "", doProcessMc.value ? getName(iPidStrategy) : getName(iPidStrategy), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), "", hcsQaPhi); } } } @@ -977,48 +1080,48 @@ struct PartNumFluc { LOG(info) << "Enabling " << getName(iParticleSpeciesAll) << " PID QA."; - const AxisSpec asCentrality({0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"); + const AxisSpec asCentrality{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}; if (iParticleSpeciesAll == toI(ParticleSpeciesAll::All)) { - const AxisSpec asPOverQ(350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"); - const AxisSpec asEta(48, -1.2, 1.2, "#it{#eta}"); + const AxisSpec asPOverQ{350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"}; + const AxisSpec asEta{48, -1.2, 1.2, "#it{#eta}"}; hrQaPid.add("QaPid/hCentralityPOverQEtaTpcLnDeDx", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); hrQaPid.add("QaPid/hCentralityPOverQEtaTofInverseBeta", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); } else { - const HistogramConfigSpec hcsQaPid(HistType::kTHnSparseF, {asCentrality, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}, {300, -30., 30.}}); + const HistogramConfigSpec hcsQaPid{HistType::kTHnSparseF, {asCentrality, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}, {300, -30., 30.}}}; - constexpr std::array> ParticleSpeciesAllTitles{"", "#pi", "K", "p"}; - if (doprocessMc.value) { + if (doProcessMc.value) { for (std::int32_t const& iDetector : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(Form("QaPid/hCentralityPtEta%sNSigma%s_mc%s%s", getName(iDetector).data(), getName(iParticleSpeciesAll).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), Form(";;;;%s #it{n}#it{#sigma}_{%s};", getName(iDetector).data(), ParticleSpeciesAllTitles[iParticleSpeciesAll].data()), hcsQaPid); + hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_mc{}{}", getName(iDetector), getName(iParticleSpeciesAll), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(iDetector), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } } } else { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(Form("QaPid/hCentralityPtEta%sNSigma%s_%s", getName(Detector::Tpc).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), Form(";;;;%s #it{n}#it{#sigma}_{%s};", getName(Detector::Tpc).data(), ParticleSpeciesAllTitles[iParticleSpeciesAll].data()), hcsQaPid); + hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}", getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tpc), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(Form("QaPid/hCentralityPtEta%sNSigma%s_%s%s%s", getName(Detector::Tpc).data(), getName(iParticleSpeciesAll).data(), getName(Detector::Tof).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), Form(";;;;%s #it{n}#it{#sigma}_{%s};", getName(Detector::Tpc).data(), ParticleSpeciesAllTitles[iParticleSpeciesAll].data()), hcsQaPid); + hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}{}{}", getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(Detector::Tof), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tpc), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(Form("QaPid/hCentralityPtEta%sNSigma%s_%s%s%s", getName(Detector::Tof).data(), getName(iParticleSpeciesAll).data(), getName(Detector::Tpc).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), Form(";;;;%s #it{n}#it{#sigma}_{%s};", getName(Detector::Tof).data(), ParticleSpeciesAllTitles[iParticleSpeciesAll].data()), hcsQaPid); + hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}{}{}", getName(Detector::Tof), getName(iParticleSpeciesAll), getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tof), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(Form("QaPid/hCentralityPtEta%sNSigma%s_%s", getName(PidStrategy::TpcTof).data(), getName(iParticleSpeciesAll).data(), getName(iChargeSpecies).data()), Form(";;;;%s #it{n}#it{#sigma}_{%s};", getName(PidStrategy::TpcTof).data(), ParticleSpeciesAllTitles[iParticleSpeciesAll].data()), hcsQaPid); + hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}", getName(PidStrategy::TpcTof), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(PidStrategy::TpcTof), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } } } } - if (doprocessMc.value) { + if (doProcessMc.value) { if (groupAnalysis.cfgFlagQaMc.value) { LOG(info) << "Enabling MC QA."; - const AxisSpec asCentrality(20, 0., 100., "Centrality (%)"); + const double maxAbsVz{std::ceil(groupEvent.cfgFlagMcCollisionVz.value ? groupEvent.cfgCutMaxAbsVzMc.value : groupEvent.cfgCutMaxAbsVz.value)}; + const AxisSpec asCentrality{20, 0., 100., "Centrality (%)"}; - hrQaMc.add("QaMc/hCentralityVzMcDeltaVz", "", {HistType::kTHnSparseF, {asCentrality, {static_cast(std::llrint(std::ceil(groupEvent.cfgCutMaxAbsVz.value))) * 20, -std::ceil(groupEvent.cfgCutMaxAbsVz.value), std::ceil(groupEvent.cfgCutMaxAbsVz.value), "#it{V}_{#it{z}}^{Gen} (cm)"}, {200, -0.2, 0.2, "#it{V}_{#it{z}}^{Rec}#minus#it{V}_{#it{z}}^{Gen} (cm)"}}}); + hrQaMc.add("QaMc/hCentralityVzMcDeltaVz", "", {HistType::kTHnSparseF, {asCentrality, {static_cast(maxAbsVz) * 20, -maxAbsVz, maxAbsVz, "#it{V}_{#it{z}}^{Gen} (cm)"}, {200, -0.2, 0.2, "#it{V}_{#it{z}}^{Rec}#minus#it{V}_{#it{z}}^{Gen} (cm)"}}}); hrQaMc.add("QaMc/hCentralityPtMcEtaMcDeltaPt", "", {HistType::kTHnSparseF, {asCentrality, {200, 0., 2., "#it{p}_{T}^{Gen} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}_{Gen}"}, {320, -0.8, 0.8, "#it{p}_{T}^{Rec}#minus#it{p}_{T}^{Gen} (GeV/#it{c})"}}}); hrQaMc.add("QaMc/hCentralityPtMcEtaMcDeltaEta", "", {HistType::kTHnSparseF, {asCentrality, {20, 0., 2., "#it{p}_{T}^{Gen} (GeV/#it{c})"}, {240, -1.2, 1.2, "#it{#eta}_{Gen}"}, {160, -0.4, 0.4, "#it{#eta}_{Rec}#minus#it{#eta}_{Gen}"}}}); } @@ -1030,31 +1133,32 @@ struct PartNumFluc { } LOG(info) << "Enabling " << getName(iParticleSpecies) << " yield calculation."; - const HistogramConfigSpec hcsCalculationYield(HistType::kTHnSparseF, {{static_cast(std::llrint(std::ceil(groupEvent.cfgCutMaxAbsVz.value))) * 2, -std::ceil(groupEvent.cfgCutMaxAbsVz.value), std::ceil(groupEvent.cfgCutMaxAbsVz.value), "#it{V}_{#it{z}} (cm)"}, {{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}}); + const double maxAbsVz{std::ceil(doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? groupEvent.cfgCutMaxAbsVzMc.value : groupEvent.cfgCutMaxAbsVz.value)}; + const HistogramConfigSpec hcsCalculationYield{HistType::kTHnSparseF, {{static_cast(maxAbsVz) * 2, -maxAbsVz, maxAbsVz, "#it{V}_{#it{z}} (cm)"}, {groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}}}; - if (doprocessMc.value) { + if (doProcessMc.value) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationYield.add(Form("CalculationYield/hVzCentralityPtMcEtaMc_mc%s%s", getName(iParticleSpecies).data(), getName(iChargeSpecies).data()), "", hcsCalculationYield); + hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtMcEtaMc_mc{}{}", getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { if (groupTrack.cfgFlagMcParticleMomentum.value) { - hrCalculationYield.add(Form("CalculationYield/hVzCentralityPtMcEtaMc_mc%s%s%s", getName(iPidStrategy).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data()), "", hcsCalculationYield); + hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtMcEtaMc_mc{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } else { - hrCalculationYield.add(Form("CalculationYield/hVzCentralityPtEta_mc%s%s%s", getName(iPidStrategy).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data()), "", hcsCalculationYield); + hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtEta_mc{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } } } } else { for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationYield.add(Form("CalculationYield/hVzCentralityPtEta_%s%s%s", getName(iPidStrategy).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data()), "", hcsCalculationYield); + hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtEta_{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } } } } - if (doprocessMc.value) { + if (doProcessMc.value) { for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { if (!static_cast(groupAnalysis.cfgFlagsCalculationPurity.value.get(iParticleSpecies))) { continue; @@ -1062,17 +1166,17 @@ struct PartNumFluc { LOG(info) << "Enabling " << getName(iParticleSpecies) << " purity calculation."; - const HistogramConfigSpec hcsCalculationPurity(HistType::kTProfile3D, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}); + const HistogramConfigSpec hcsCalculationPurity{HistType::kTProfile3D, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationPurity.add(Form("CalculationPurity/pCentralityPtEtaPurity%s%s%s", getName(iPidStrategy).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data()), "", hcsCalculationPurity); + hrCalculationPurity.add(std::format("CalculationPurity/pCentralityPtEtaPurity{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationPurity); } } } } - if (doprocessMc.value) { + if (doProcessMc.value) { for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { if (!static_cast(groupAnalysis.cfgFlagsCalculationFractionPrimary.value.get(iParticleSpecies))) { continue; @@ -1080,11 +1184,11 @@ struct PartNumFluc { LOG(info) << "Enabling " << getName(iParticleSpecies) << " primary fraction calculation."; - const HistogramConfigSpec hcsCalculationFractionPrimary(HistType::kTProfile3D, {{{0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}); + const HistogramConfigSpec hcsCalculationFractionPrimary{HistType::kTProfile3D, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationFractionPrimary.add(Form("CalculationFractionPrimary/pCentralityPtEtaFractionPrimary%s%s%s", getName(iPidStrategy).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data()), "", hcsCalculationFractionPrimary); + hrCalculationFractionPrimary.add(std::format("CalculationFractionPrimary/pCentralityPtEtaFractionPrimary{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationFractionPrimary); } } } @@ -1093,7 +1197,7 @@ struct PartNumFluc { if (nEnabled(groupAnalysis.cfgFlagsCalculationFluctuation) > 1) { LOG(fatal) << "Invalid " << groupAnalysis.cfgFlagsCalculationFluctuation.name << "!"; } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation) && groupEvent.cfgNSubgroups.value <= 0) { + if (doCalculationFluctuation && groupEvent.cfgNSubgroups.value <= 0) { LOG(fatal) << "Invalid " << groupEvent.cfgNSubgroups.name << "!"; } for (std::int32_t const& iParticleNumber : std::views::iota(0, NEs)) { @@ -1103,26 +1207,24 @@ struct PartNumFluc { LOG(info) << "Enabling " << getName(iParticleNumber) << " number fluctuation calculation."; - const AxisSpec asCentrality(groupEvent.cfgAxisCentrality, "Centrality (%)"); - const HistogramConfigSpec hcsDistribution(HistType::kTHnSparseD, {asCentrality, {200, -0.5, 199.5}, {200, -0.5, 199.5}}); - const HistogramConfigSpec hcsFluctuationCalculator(HistType::kTH3D, {asCentrality, {groupEvent.cfgNSubgroups.value, -0.5, groupEvent.cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderKeys, -0.5, fluctuation_calculator_base::NOrderKeys - 0.5, "Order Key Index"}}); + const AxisSpec asCentrality{groupEvent.cfgAxisCentrality, "Centrality (%)"}; + const HistogramConfigSpec hcsDistribution{HistType::kTHnSparseD, {asCentrality, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}; + const HistogramConfigSpec hcsFluctuationCalculator{HistType::kTH3D, {asCentrality, {groupEvent.cfgNSubgroups.value, -0.5, groupEvent.cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderKeys, -0.5, fluctuation_calculator_base::NOrderKeys - 0.5, "Order Key Index"}}}; for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { fluctuationCalculatorTrack[iParticleNumber][iChargeNumber] = std::make_unique(); } - constexpr std::array> ParticleNumberTitles{"h", "K", "p"}; - constexpr std::array> ChargeSpeciesTitles{"+", "#minus"}; - if (doprocessMc.value) { - hrCalculationFluctuation.add(Form("CalculationFluctuation/hCentralityN%s%sN%s%s_mc", getName(iParticleNumber).data(), getName(ChargeSpecies::Plus).data(), getName(iParticleNumber).data(), getName(ChargeSpecies::Minus).data()), Form(";;#it{N}(%s^{%s});#it{N}(%s^{%s});", ParticleNumberTitles[iParticleNumber].data(), ChargeSpeciesTitles[toI(ChargeSpecies::Plus)].data(), ParticleNumberTitles[iParticleNumber].data(), ChargeSpeciesTitles[toI(ChargeSpecies::Minus)].data()), hcsDistribution); - hrCalculationFluctuation.add(Form("CalculationFluctuation/hCentralityN%s%sN%s%s_mcEff", getName(iParticleNumber).data(), getName(ChargeSpecies::Plus).data(), getName(iParticleNumber).data(), getName(ChargeSpecies::Minus).data()), Form(";;#it{N}(%s^{%s});#it{N}(%s^{%s});", ParticleNumberTitles[iParticleNumber].data(), ChargeSpeciesTitles[toI(ChargeSpecies::Plus)].data(), ParticleNumberTitles[iParticleNumber].data(), ChargeSpeciesTitles[toI(ChargeSpecies::Minus)].data()), hcsDistribution); + if (doProcessMc.value) { + hrCalculationFluctuation.add(std::format("CalculationFluctuation/hCentralityN{}{}N{}{}_mc", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); + hrCalculationFluctuation.add(std::format("CalculationFluctuation/hCentralityN{}{}N{}{}_mcEff", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - hrCalculationFluctuation.add(Form("CalculationFluctuation/hFluctuationCalculator%s%s_mc", getName(iParticleNumber).data(), getName(iChargeNumber).data()), "", hcsFluctuationCalculator); + hrCalculationFluctuation.add(std::format("CalculationFluctuation/hFluctuationCalculator{}{}_mc", getName(iParticleNumber), getName(iChargeNumber)).c_str(), "", hcsFluctuationCalculator); } } - hrCalculationFluctuation.add(Form("CalculationFluctuation/hCentralityN%s%sN%s%s", getName(iParticleNumber).data(), getName(ChargeSpecies::Plus).data(), getName(iParticleNumber).data(), getName(ChargeSpecies::Minus).data()), Form(";;#it{N}(%s^{%s});#it{N}(%s^{%s});", ParticleNumberTitles[iParticleNumber].data(), ChargeSpeciesTitles[toI(ChargeSpecies::Plus)].data(), ParticleNumberTitles[iParticleNumber].data(), ChargeSpeciesTitles[toI(ChargeSpecies::Minus)].data()), hcsDistribution); + hrCalculationFluctuation.add(std::format("CalculationFluctuation/hCentralityN{}{}N{}{}", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - hrCalculationFluctuation.add(Form("CalculationFluctuation/hFluctuationCalculator%s%s", getName(iParticleNumber).data(), getName(iChargeNumber).data()), "", hcsFluctuationCalculator); + hrCalculationFluctuation.add(std::format("CalculationFluctuation/hFluctuationCalculator{}{}", getName(iParticleNumber), getName(iChargeNumber)).c_str(), "", hcsFluctuationCalculator); } } @@ -1133,11 +1235,11 @@ struct PartNumFluc { holderCcdb.hVzCentralityPtEtaEfficiency.resize(nRunGroups); for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup{readListRunGroup(iRunGroup + 1)}; + const TList* const lRunGroup{ReadListRunGroup(ccdbObject, iRunGroup + 1)}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - const char* const name{Form("hVzCentralityPtEtaEfficiency%s%s%s_runGroup%d", getName(iPidStrategy).data(), getName(iParticleSpecies).data(), getName(iChargeSpecies).data(), iRunGroup + 1)}; - holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name)); + const std::string name{std::format("hVzCentralityPtEtaEfficiency{}{}{}_runGroup{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies), iRunGroup + 1)}; + holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name.c_str())); if (!holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies] || holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies]->GetNdimensions() != HolderCcdb::NDimensionsEfficiency) { LOG(fatal) << "Invalid " << name << "!"; } @@ -1150,36 +1252,60 @@ struct PartNumFluc { template requires IsValid - double getEfficiency(const bool doUsingMcParticleMomentum) + double getEfficiency(const bool doUseMcParticleMomentum) const { - const THnBase* const hVzCentralityPtEtaEfficiency{holderCcdb.hVzCentralityPtEtaEfficiency.at(std::abs(holderEvent.runGroupIndex) - 1)[toI(PidStrategyValue)][toI(ParticleSpeciesValue)][toI(ChargeSpeciesValue)]}; - return hVzCentralityPtEtaEfficiency ? hVzCentralityPtEtaEfficiency->GetBinContent(hVzCentralityPtEtaEfficiency->GetBin(std::array{doprocessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, doUsingMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt, doUsingMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta}.data())) : 0.; + const THnBase* const hVzCentralityPtEtaEfficiency{holderCcdb.hVzCentralityPtEtaEfficiency[std::abs(holderEvent.runGroupIndex) - 1][toI(PidStrategyValue)][toI(ParticleSpeciesValue)][toI(ChargeSpeciesValue)]}; + return hVzCentralityPtEtaEfficiency ? hVzCentralityPtEtaEfficiency->GetBinContent(hVzCentralityPtEtaEfficiency->GetBin(std::array{doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, doUseMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt, doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta}.data())) : 0.; } - template + template requires IsValid - double getShiftNSigmaPid() + double getShiftNSigmaPid() const { - if (!groupTrack.cfgFlagsRecalibrationNSigmaPid.value.get(toI(ParticleSpeciesValue))) { - return 0.; + if constexpr (DoRecalibration) { + if (groupTrack.cfgFlagsRecalibrationNSigmaPid.value.get(toI(ParticleSpeciesValue))) { + return interpolate(holderCcdb.hCentralityPtEtaShiftNSigmaPid[std::abs(holderEvent.runGroupIndex) - 1][toI(DetectorValue)][toI(ParticleSpeciesValue)][holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)], holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta); + } } + return 0.; + } - static const auto clampInAxis{[](const double value, const TAxis* const axis) { - const std::int32_t first{std::clamp(axis->GetFirst(), 1, axis->GetNbins())}; - const std::int32_t last{std::clamp(axis->GetLast(), 1, axis->GetNbins())}; - return first == last ? axis->GetBinCenter(first) : std::clamp(value, std::nextafter(axis->GetBinCenter(first), std::numeric_limits::infinity()), std::nextafter(axis->GetBinCenter(last), -std::numeric_limits::infinity())); - }}; + template + void setNSigmaPid(const T& track) + { + if (holderTrack.hasPid[toI(Detector::Tpc)]) { + holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Pion)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPi(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Kaon)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaKa(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Proton)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPr(), getShiftNSigmaPid()); + } + if (holderTrack.hasPid[toI(Detector::Tof)]) { + holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Pion)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaPi(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Kaon)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaKa(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Proton)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaPr(), getShiftNSigmaPid()); + } + } - if (holderTrack.sign == 0) { - return 0.; + double getMeasureDca(const std::pair& calibration) const + { + static thread_local std::vector parametersPtMeasureDcaScratch{}; + + const TFormula* const fPtMeasureDca{calibration.first}; + const TH3* const hCentralityEtaParameterPtMeasureDca{calibration.second}; + const std::int32_t nParameters{fPtMeasureDca->GetNpar()}; + if (static_cast(parametersPtMeasureDcaScratch.size()) < nParameters) { + parametersPtMeasureDcaScratch.resize(nParameters); + } + const std::int32_t centralityBinIndex{std::clamp(hCentralityEtaParameterPtMeasureDca->GetXaxis()->FindFixBin(holderEvent.centralityCalibration), 1, hCentralityEtaParameterPtMeasureDca->GetNbinsX())}; + const std::int32_t etaBinIndex{std::clamp(hCentralityEtaParameterPtMeasureDca->GetYaxis()->FindFixBin(holderTrack.eta), 1, hCentralityEtaParameterPtMeasureDca->GetNbinsY())}; + for (std::int32_t const& iParameter : std::views::iota(0, nParameters)) { + parametersPtMeasureDcaScratch[iParameter] = hCentralityEtaParameterPtMeasureDca->GetBinContent(centralityBinIndex, etaBinIndex, iParameter + 1); } - const TH3* const hCentralityPtEtaShiftNSigmaPid{holderCcdb.hCentralityPtEtaShiftNSigmaPid.at(std::abs(holderEvent.runGroupIndex) - 1)[toI(DetectorValue)][toI(ParticleSpeciesValue)][holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)]}; - return hCentralityPtEtaShiftNSigmaPid ? hCentralityPtEtaShiftNSigmaPid->Interpolate(clampInAxis(holderEvent.centrality, hCentralityPtEtaShiftNSigmaPid->GetXaxis()), clampInAxis(holderTrack.pt, hCentralityPtEtaShiftNSigmaPid->GetYaxis()), clampInAxis(holderTrack.eta, hCentralityPtEtaShiftNSigmaPid->GetZaxis())) : 0.; + return fPtMeasureDca->EvalPar(&holderTrack.pt, parametersPtMeasureDcaScratch.data()); } template requires IsValid - bool isPid(const bool doRejectingOthers) + bool isPid(const bool doRejectOthers) const { if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { if constexpr (PidStrategyAllValue == PidStrategyAll::Tpc) { @@ -1198,20 +1324,29 @@ struct PartNumFluc { } else { constexpr std::int32_t ParticleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; if constexpr (PidStrategyAllValue == PidStrategyAll::TpcTofSeparated) { - if (!(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + if (!(std::abs(holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { return false; } - if (!(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + if (!(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { return false; } - if (doRejectingOthers && !(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][ParticleSpeciesIndex]) < std::min(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][(ParticleSpeciesIndex + 1) % NEs]), std::abs(holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][(ParticleSpeciesIndex + 2) % NEs])))) { + if (doRejectOthers && !(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]) < std::min(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][(ParticleSpeciesIndex + 1) % NEs]), std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][(ParticleSpeciesIndex + 2) % NEs])))) { + return false; + } + } else if constexpr (PidStrategyAllValue == PidStrategyAll::TpcTofCombined) { + const double absNSigmaPidCombined{std::abs(holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex))}; + if (!(absNSigmaPidCombined < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + return false; + } + if (doRejectOthers && !(absNSigmaPidCombined < std::min(std::abs(holderTrack.getNSigmaPidCombined((ParticleSpeciesIndex + 1) % NEs)), std::abs(holderTrack.getNSigmaPidCombined((ParticleSpeciesIndex + 2) % NEs))))) { return false; } } else { - if (!(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAllValue)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + constexpr std::int32_t DetectorIndex{toI(getValue(PidStrategyAllValue))}; + if (!(std::abs(holderTrack.nSigmaPid[DetectorIndex][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { return false; } - if (doRejectingOthers && !(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAllValue)][ParticleSpeciesIndex]) < std::min(std::abs(holderTrack.nSigmaPid[toI(PidStrategyAllValue)][(ParticleSpeciesIndex + 1) % NEs]), std::abs(holderTrack.nSigmaPid[toI(PidStrategyAllValue)][(ParticleSpeciesIndex + 2) % NEs])))) { + if (doRejectOthers && !(std::abs(holderTrack.nSigmaPid[DetectorIndex][ParticleSpeciesIndex]) < std::min(std::abs(holderTrack.nSigmaPid[DetectorIndex][(ParticleSpeciesIndex + 1) % NEs]), std::abs(holderTrack.nSigmaPid[DetectorIndex][(ParticleSpeciesIndex + 2) % NEs])))) { return false; } } @@ -1221,47 +1356,29 @@ struct PartNumFluc { template requires IsValid - bool isPid() + bool isPid() const { if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { - if constexpr (ChargeSpeciesValue == ChargeSpecies::Plus) { - if (holderMcParticle.charge <= 0) { - return false; - } - } else { // ChargeSpeciesValue == ChargeSpecies::Minus - if (holderMcParticle.charge >= 0) { - return false; - } - } + return ChargeSpeciesValue == ChargeSpecies::Plus ? holderMcParticle.charge > 0 : holderMcParticle.charge < 0; } else { - if (holderMcParticle.pdgCode != getPdgCode(ParticleSpeciesAllValue, ChargeSpeciesValue)) { - return false; - } + return holderMcParticle.pdgCode == getPdgCode(getValue(ParticleSpeciesAllValue), ChargeSpeciesValue); } - return true; } - bool isGoodMomentum(const bool doUsingMcParticleMomentum) + bool isGoodMomentum(const bool doUseMcParticleMomentum) const { - if (doUsingMcParticleMomentum) { - if (!(groupTrack.cfgCutMinPt.value < holderMcParticle.pt) || !(holderMcParticle.pt < groupTrack.cfgCutMaxPt.value)) { - return false; - } - if (!(std::abs(holderMcParticle.eta) < groupTrack.cfgCutMaxAbsEta.value)) { - return false; - } - } else { - if (!(groupTrack.cfgCutMinPt.value < holderTrack.pt) || !(holderTrack.pt < groupTrack.cfgCutMaxPt.value)) { - return false; - } - if (!(std::abs(holderTrack.eta) < groupTrack.cfgCutMaxAbsEta.value)) { - return false; - } + const double pt{doUseMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt}; + const double eta{doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta}; + if (!(groupTrack.cfgCutMinPt.value < pt) || !(pt < groupTrack.cfgCutMaxPt.value)) { + return false; + } + if (!(std::abs(eta) < groupTrack.cfgCutMaxAbsEta.value)) { + return false; } return true; } - bool isGoodDca() + bool isGoodDca() const { if (!groupTrack.cfgFlagRecalibrationDca.value) { for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { @@ -1270,13 +1387,12 @@ struct PartNumFluc { } } } else { - if (holderTrack.sign == 0) { - return false; - } const std::int32_t chargeSpeciesIndex{holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)}; - const std::array>, NEs>, NEs>& fPtDcaGroup{holderCcdb.fPtDca.at(std::abs(holderEvent.runGroupIndex) - 1)}; + const std::array, NEs>, NEs>, NEs>& fPtMeasureDcaGroup{holderCcdb.fPtMeasureDca[std::abs(holderEvent.runGroupIndex) - 1]}; for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { - if (!fPtDcaGroup[toI(DcaKind::Mean)][iDcaAxis][chargeSpeciesIndex] || !fPtDcaGroup[toI(DcaKind::Sigma)][iDcaAxis][chargeSpeciesIndex] || !(std::abs(holderTrack.dca[iDcaAxis] - fPtDcaGroup[toI(DcaKind::Mean)][iDcaAxis][chargeSpeciesIndex]->Eval(holderTrack.pt)) < groupTrack.cfgCutsMaxAbsNSigmaDca.value.get(iDcaAxis) * fPtDcaGroup[toI(DcaKind::Sigma)][iDcaAxis][chargeSpeciesIndex]->Eval(holderTrack.pt))) { + const double mean{getMeasureDca(fPtMeasureDcaGroup[toI(DcaMeasure::Mean)][iDcaAxis][chargeSpeciesIndex])}; + const double sigma{getMeasureDca(fPtMeasureDcaGroup[toI(DcaMeasure::Sigma)][iDcaAxis][chargeSpeciesIndex])}; + if (!(std::abs(holderTrack.dca[iDcaAxis] - mean) < groupTrack.cfgCutsMaxAbsNSigmaDca.value.get(iDcaAxis) * sigma)) { return false; } } @@ -1285,7 +1401,7 @@ struct PartNumFluc { } template - bool isGoodTrack(const T& track) + bool isGoodTrack(const T& track) const { if (groupTrack.cfgFlagPvContributor.value && !track.isPVContributor()) { return false; @@ -1299,7 +1415,7 @@ struct PartNumFluc { if (!(track.tpcNClsFound() > groupTrack.cfgCutMinTpcNCls.value)) { return false; } - if (!(track.tpcChi2NCl() < groupTrack.cfgCutMaxTpcChi2NCls.value)) { + if (!(groupTrack.cfgCutMinTpcChi2NCls.value < track.tpcChi2NCl()) || !(track.tpcChi2NCl() < groupTrack.cfgCutMaxTpcChi2NCls.value)) { return false; } if (!(track.tpcFractionSharedCls() < groupTrack.cfgCutMaxTpcNClsSharedRatio.value)) { @@ -1315,7 +1431,7 @@ struct PartNumFluc { } template - bool isGoodMcParticle(const MP& mcParticle) + bool isGoodMcParticle(const MP& mcParticle) const { if constexpr (IsMc) { if (!mcParticle.isPhysicalPrimary()) { @@ -1329,14 +1445,14 @@ struct PartNumFluc { requires IsValid void fillQaRunByTrackByChargeSpecies(const T& track) { - const auto fill{[&](const auto& name, const auto value) { + const auto fill{[this](const auto& name, const auto value) -> void { hrQaRun.fill(C_CS("QaRun/pRunIndex") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.runIndex, value); }}; const auto fillNSigmaPidByDetectorParticleSpecies{ - [&] - requires IsValid(DetectorValue), ParticleSpeciesValue> - () { - const double nSigmaPid{holderTrack.nSigmaPid[toI(getValue(DetectorValue))][toI(ParticleSpeciesValue)]}; + [this, &fill] + requires IsValid + () -> void { + const double nSigmaPid{holderTrack.nSigmaPid[toI(DetectorValue)][toI(ParticleSpeciesValue)]}; if (std::abs(nSigmaPid) < HolderTrack::TruncationAbsNSigmaPid) { fill(C_SV(getName(DetectorValue)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesValue)), nSigmaPid); } @@ -1349,8 +1465,6 @@ struct PartNumFluc { fill(C_CS("TpcNClsSharedRatio"), track.tpcFractionSharedCls()); fill(C_CS("TpcNCrossedRows"), track.tpcNClsCrossedRows()); fill(C_CS("TpcNCrossedRowsRatio"), track.tpcCrossedRowsOverFindableCls()); - fill(C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderTrack.dca[toI(DcaAxis::Xy)]); - fill(C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderTrack.dca[toI(DcaAxis::Z)]); fill(C_CS("Pt"), holderTrack.pt); fill(C_CS("Eta"), holderTrack.eta); fill(C_CS("Phi"), holderTrack.phi); @@ -1372,17 +1486,17 @@ struct PartNumFluc { requires IsValid void fillQaRunByEventByChargeSpecies() { - const auto fill{[&](const auto& name, const auto value) { + const auto fill{[this](const auto& name, const auto value) -> void { hrQaRun.fill(C_CS("QaRun/pRunIndex") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.runIndex, value); }}; fill(C_CS("NGlobalTracks"), holderEvent.nGlobalTracks[toI(ChargeSpeciesValue)]); fill(C_CS("NPvContributors"), holderEvent.nPvContributors[toI(ChargeSpeciesValue)]); if (holderEvent.nGlobalTracks[toI(ChargeSpeciesValue)] > 0) { - fill(C_SV(getName(DcaKind::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.dca[toI(DcaKind::Mean)][toI(DcaAxis::Xy)][toI(ChargeSpeciesValue)]); - fill(C_SV(getName(DcaKind::Sigma)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.dca[toI(DcaKind::Sigma)][toI(DcaAxis::Xy)][toI(ChargeSpeciesValue)]); - fill(C_SV(getName(DcaKind::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.dca[toI(DcaKind::Mean)][toI(DcaAxis::Z)][toI(ChargeSpeciesValue)]); - fill(C_SV(getName(DcaKind::Sigma)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.dca[toI(DcaKind::Sigma)][toI(DcaAxis::Z)][toI(ChargeSpeciesValue)]); + fill(C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.measureDca[toI(DcaMeasure::Mean)][toI(DcaAxis::Xy)][toI(ChargeSpeciesValue)]); + fill(C_SV(getName(DcaMeasure::Sigma)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.measureDca[toI(DcaMeasure::Sigma)][toI(DcaAxis::Xy)][toI(ChargeSpeciesValue)]); + fill(C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.measureDca[toI(DcaMeasure::Mean)][toI(DcaAxis::Z)][toI(ChargeSpeciesValue)]); + fill(C_SV(getName(DcaMeasure::Sigma)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.measureDca[toI(DcaMeasure::Sigma)][toI(DcaAxis::Z)][toI(ChargeSpeciesValue)]); } fill(C_CS("NTofBeta"), holderEvent.nTofBeta[toI(ChargeSpeciesValue)]); } @@ -1391,7 +1505,7 @@ struct PartNumFluc { requires IsValid void fillQaTrackByChargeSpecies(const T& track) { - const auto fill{[&](const auto& name, const auto... positionAndWeight) { + const auto fill{[this](const auto& name, const auto... positionAndWeight) -> void { hrQaTrack.fill(C_CS("QaTrack/h") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), positionAndWeight...); }}; @@ -1407,11 +1521,11 @@ struct PartNumFluc { void fillQaDcaByChargeSpecies() { const auto fillByDcaAxis{ - [&] + [this] requires IsValid - () { + () -> void { hrQaDca.fill(C_CS("QaDca/hPtDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderTrack.pt, holderTrack.dca[toI(DcaAxisValue)]); - hrQaDca.fill(C_CS("QaDca/pPtEtaPhiIuDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderTrack.pt, holderTrack.eta, holderTrack.phiIu, holderTrack.dca[toI(DcaAxisValue)]); + hrQaDca.fill(C_CS("QaDca/pCentralityPtEtaDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.dca[toI(DcaAxisValue)]); }}; fillByDcaAxis.template operator()(); @@ -1422,18 +1536,18 @@ struct PartNumFluc { requires IsValid void fillQaAcceptancebyParticleSpeciesAll(const T& track) { - if (!groupAnalysis.cfgFlagsQaAcceptance.value.get(toI(ParticleSpeciesAllValue)) || holderTrack.sign == 0) { + if (!groupAnalysis.cfgFlagsQaAcceptance.value.get(toI(ParticleSpeciesAllValue))) { return; } const auto fillByChargeSpecies{ - [&] + [this] requires IsValid - (const auto& name, const auto value) { + (const auto& name, const double value) -> void { const auto fillByPidStrategy{ - [&] + [this, &name, value] requires IsValid - () { + () -> void { if (isPid(PidStrategyValue), ParticleSpeciesAllValue>(false)) { hrQaAcceptance.fill(C_CS("QaAcceptance/h") + name + C_CS("Pt_") + C_SV(getName(PidStrategyValue)) + C_CS("Edge") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), value, holderTrack.pt); // NOLINT(clang-analyzer-core.NonNullParamChecker) } @@ -1451,9 +1565,9 @@ struct PartNumFluc { } } else { if (holderTrack.sign > 0) { - fillByChargeSpecies.template operator()(C_CS("Rapidity"), track.rapidity(getMass(ParticleSpeciesAllValue))); + fillByChargeSpecies.template operator()(C_CS("Rapidity"), track.rapidity(getMass(getValue(ParticleSpeciesAllValue)))); } else { - fillByChargeSpecies.template operator()(C_CS("Rapidity"), track.rapidity(getMass(ParticleSpeciesAllValue))); + fillByChargeSpecies.template operator()(C_CS("Rapidity"), track.rapidity(getMass(getValue(ParticleSpeciesAllValue)))); } } } @@ -1466,27 +1580,21 @@ struct PartNumFluc { return; } - if (holderTrack.sign == 0) { // DataModeValue != DataMode::McMcParticle - return; - } - const auto fillByChargeSpecies{ - [&] + [this] requires IsValid - () { + () -> void { const auto fillByPidStrategy{ - [&] + [this] requires IsValid - () { + () -> void { if constexpr (DataModeValue == DataMode::McTrack) { if (isPid() && isPid(PidStrategyValue), ParticleSpeciesAllValue>(false)) { - hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhi_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); - hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhiIu_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phiIu); + hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhi_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.phi); } } else { // DataModeValue == DataMode::RawTrack if (isPid(PidStrategyValue), ParticleSpeciesAllValue>(false)) { - hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhi_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phi); - hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhiIu_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.phiIu); + hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhi_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.phi); } } }}; @@ -1506,36 +1614,37 @@ struct PartNumFluc { requires IsValid && (DataModeValue != DataMode::McMcParticle) void fillQaPidByParticleSpeciesAll(const T& track) { - if (!groupAnalysis.cfgFlagsQaPid.value.get(toI(ParticleSpeciesAllValue)) || holderTrack.sign == 0) { + if (!groupAnalysis.cfgFlagsQaPid.value.get(toI(ParticleSpeciesAllValue))) { return; } if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { if (isPid(PidStrategy::Tpc), ParticleSpeciesAll::All>(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPOverQEtaTpcLnDeDx"), holderEvent.centrality, holderTrack.p / holderTrack.sign, holderTrack.eta, track.tpcSignal()); + hrQaPid.fill(C_CS("QaPid/hCentralityPOverQEtaTpcLnDeDx"), holderEvent.centralityCalibration, track.p() / holderTrack.sign, holderTrack.eta, std::log(track.tpcSignal())); } if (isPid(PidStrategy::TpcTof), ParticleSpeciesAll::All>(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPOverQEtaTofInverseBeta"), holderEvent.centrality, holderTrack.p / holderTrack.sign, holderTrack.eta, 1. / track.beta()); + hrQaPid.fill(C_CS("QaPid/hCentralityPOverQEtaTofInverseBeta"), holderEvent.centralityCalibration, track.p() / holderTrack.sign, holderTrack.eta, 1. / track.beta()); } } else { + constexpr std::int32_t ParticleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; const auto fillByChargeSpecies{ - [&] + [this] requires IsValid - () { + () -> void { if constexpr (DataModeValue == DataMode::McTrack) { if (isPid()) { - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)][toI(ParticleSpeciesAllValue)]); - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][toI(ParticleSpeciesAllValue)]); + hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); + hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]); } } else { // DataModeValue == DataMode::RawTrack - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)][toI(ParticleSpeciesAllValue)]); + hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); if (isPid(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tof)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)][toI(ParticleSpeciesAllValue)]); + hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tof)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); } if (isPid(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tpc)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][toI(ParticleSpeciesAllValue)]); + hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tpc)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]); } - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(PidStrategy::TpcTof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(PidStrategyAll::TpcTofCombined)][toI(ParticleSpeciesAllValue)]); + hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(PidStrategy::TpcTof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex)); } }}; @@ -1555,36 +1664,38 @@ struct PartNumFluc { return; } - const std::int32_t chargeSign{[&] { + const std::int32_t chargeSign{[](const std::int32_t chargeMcParticle, const std::int32_t signTrack) constexpr -> std::int32_t { if constexpr (DataModeValue == DataMode::McMcParticle) { - return holderMcParticle.charge; + return chargeMcParticle; } else { - return holderTrack.sign; + return signTrack; + } + }(holderMcParticle.charge, holderTrack.sign)}; + if constexpr (DataModeValue == DataMode::McMcParticle) { + if (chargeSign == 0) { + return; } - }()}; - if (chargeSign == 0) { - return; } const auto fillByChargeSpecies{ - [&] + [this] requires IsValid - () { + () -> void { if constexpr (DataModeValue == DataMode::McMcParticle) { if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>()) { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtMcEtaMc_mc") + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), doprocessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); + hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtMcEtaMc_mc") + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); } } else { const auto fillByPidStrategy{ - [&] + [this] requires IsValid - () { + () -> void { if constexpr (DataModeValue == DataMode::McTrack) { if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>() && isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { if (groupTrack.cfgFlagMcParticleMomentum.value) { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtMcEtaMc_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), doprocessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); + hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtMcEtaMc_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); } else { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtEta_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), doprocessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderTrack.pt, holderTrack.eta); + hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtEta_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderTrack.pt, holderTrack.eta); } } } else { // DataModeValue == DataMode::RawTrack @@ -1610,18 +1721,18 @@ struct PartNumFluc { requires IsValid void fillCalculationPurityByParticleSpecies() { - if (!groupAnalysis.cfgFlagsCalculationPurity.value.get(toI(ParticleSpeciesValue)) || holderTrack.sign == 0) { + if (!groupAnalysis.cfgFlagsCalculationPurity.value.get(toI(ParticleSpeciesValue))) { return; } const auto fillByChargeSpecies{ - [&] + [this] requires IsValid - () { + () -> void { const auto fillByPidStrategy{ - [&] + [this] requires IsValid - () { + () -> void { if (isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { hrCalculationPurity.fill(C_CS("CalculationPurity/pCentralityPtEtaPurity") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, isPid(ParticleSpeciesValue), ChargeSpeciesValue>() ? 1. : 0.); } @@ -1642,18 +1753,18 @@ struct PartNumFluc { requires IsValid void fillCalculationFractionPrimaryByParticleSpecies(const MP& mcParticle) { - if (!groupAnalysis.cfgFlagsCalculationFractionPrimary.value.get(toI(ParticleSpeciesValue)) || holderTrack.sign == 0) { + if (!groupAnalysis.cfgFlagsCalculationFractionPrimary.value.get(toI(ParticleSpeciesValue))) { return; } const auto fillByChargeSpecies{ - [&] + [this, &mcParticle] requires IsValid - () { + () -> void { const auto fillByPidStrategy{ - [&] + [this, &mcParticle] requires IsValid - () { + () -> void { if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>() && isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { hrCalculationFractionPrimary.fill(C_CS("CalculationFractionPrimary/pCentralityPtEtaFractionPrimary") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, mcParticle.isPhysicalPrimary() ? 1. : 0.); } @@ -1675,7 +1786,7 @@ struct PartNumFluc { for (std::int32_t const& iParticleNumber : std::views::iota(0, NEs)) { if (static_cast(groupAnalysis.cfgFlagsCalculationFluctuation.value.get(iParticleNumber))) { for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - fluctuationCalculatorTrack[iParticleNumber][iChargeNumber]->init(); + fluctuationCalculatorTrack[iParticleNumber][iChargeNumber]->clear(); } } } @@ -1689,27 +1800,29 @@ struct PartNumFluc { return; } - const std::int32_t chargeSign{[&] { + const std::int32_t chargeSign{[](const std::int32_t chargeMcParticle, const std::int32_t signTrack) constexpr -> std::int32_t { if constexpr (DataModeValue == DataMode::McMcParticle) { - return holderMcParticle.charge; + return chargeMcParticle; } else { - return holderTrack.sign; + return signTrack; + } + }(holderMcParticle.charge, holderTrack.sign)}; + if constexpr (DataModeValue == DataMode::McMcParticle) { + if (chargeSign == 0) { + return; } - }()}; - if (chargeSign == 0) { - return; } - const bool doUsingMcParticleMomentum{[&] { + const bool doUseMcParticleMomentum{[](const bool flagMcParticleMomentum) constexpr -> bool { if constexpr (DataModeValue == DataMode::McMcParticle) { return true; } else if constexpr (DataModeValue == DataMode::McTrack) { - return groupTrack.cfgFlagMcParticleMomentum.value; - } else { // DataModeValue == DataMode::RawTrack + return flagMcParticleMomentum; + } else { return false; } - }()}; - if (!isGoodMomentum(doUsingMcParticleMomentum)) { + }(groupTrack.cfgFlagMcParticleMomentum.value)}; + if (!isGoodMomentum(doUseMcParticleMomentum)) { return; } @@ -1720,39 +1833,37 @@ struct PartNumFluc { } const auto calculateByParticleSpecies{ - [&] + [this, chargeSign, doUseMcParticleMomentum] requires IsValid && (ParticleNumberValue == ParticleNumber::Charge || (ParticleNumberValue == ParticleNumber::Kaon && ParticleSpeciesValue == ParticleSpecies::Kaon) || (ParticleNumberValue == ParticleNumber::Proton && ParticleSpeciesValue == ParticleSpecies::Proton)) - () { + () -> void { const auto calculateByChargeSpecies{ - [&] + [this, chargeSign, doUseMcParticleMomentum] requires IsValid - () { + () -> void { if constexpr (DataModeValue != DataMode::RawTrack) { if (!isPid(ParticleSpeciesValue), ChargeSpeciesValue>()) { return; } } - const bool doUsingTofPid{[&] { - return [&] { - if constexpr (DataModeValue == DataMode::McMcParticle) { - return holderMcParticle.pt; - } else if constexpr (DataModeValue == DataMode::McTrack) { - return groupTrack.cfgFlagMcParticleMomentum.value ? holderMcParticle.pt : holderTrack.pt; - } else { // DataModeValue == DataMode::RawTrack - return holderTrack.pt; - } - }() >= groupTrack.cfgThresholdsPtTofPid.value.get(toI(ParticleSpeciesValue)); - }()}; + const bool doUseTofPid{[](const bool doUseMcParticleMomentumValue, const double ptMcParticle, const double ptTrack, const double thresholdPtTofPid) constexpr -> bool { + if constexpr (DataModeValue == DataMode::McMcParticle) { + return ptMcParticle >= thresholdPtTofPid; + } else if constexpr (DataModeValue == DataMode::McTrack) { + return (doUseMcParticleMomentumValue ? ptMcParticle : ptTrack) >= thresholdPtTofPid; + } else { + return ptTrack >= thresholdPtTofPid; + } + }(doUseMcParticleMomentum, holderMcParticle.pt, holderTrack.pt, groupTrack.cfgThresholdsPtTofPid.value.get(toI(ParticleSpeciesValue)))}; if constexpr (DataModeValue != DataMode::McMcParticle) { - if (!(doUsingTofPid ? isPid(PidStrategy::TpcTof), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value) : isPid(PidStrategy::Tpc), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value))) { + if (!(doUseTofPid ? isPid(PidStrategy::TpcTof), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value) : isPid(PidStrategy::Tpc), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value))) { return; } } - const double efficiency{doUsingTofPid ? getEfficiency(doUsingMcParticleMomentum) : getEfficiency(doUsingMcParticleMomentum)}; // NOLINT(clang-analyzer-core.NullDereference) + const double efficiency{doUseTofPid ? getEfficiency(doUseMcParticleMomentum) : getEfficiency(doUseMcParticleMomentum)}; // NOLINT(clang-analyzer-core.NullDereference) const auto fill{ - [&] { + [this, efficiency]() -> void { if constexpr (ChargeSpeciesValue == ChargeSpecies::Plus) { fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Plus)]->fill(1., efficiency); fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Net)]->fill(1., efficiency); @@ -1768,11 +1879,11 @@ struct PartNumFluc { ++holderMcEvent.numbersEff[toI(ParticleNumberValue)][toI(ChargeSpeciesValue)]; fill(); } - holderDerivedData.signedEfficienciesMcParticle.push_back(HolderDerivedData::convertRound(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); + holderDerivedData.signedEfficienciesMcParticle.push_back(HolderDerivedData::convertRound(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); } else { ++holderEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpeciesValue)]; fill(); - holderDerivedData.signedEfficienciesTrack.push_back(HolderDerivedData::convertRound(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); + holderDerivedData.signedEfficienciesTrack.push_back(HolderDerivedData::convertRound(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); } }}; @@ -1810,14 +1921,15 @@ struct PartNumFluc { } const auto fillByChargeNumber{ - [&] + [this] requires IsValid - () { + () -> void { + const std::array products{fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumberValue)]->getProducts()}; for (std::int32_t const& iOrderKey : std::views::iota(0, fluctuation_calculator_base::NOrderKeys)) { if constexpr (DataModeValue == DataMode::McMcParticle) { - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)) + C_CS("_mc"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumberValue)]->getProduct(iOrderKey)); + hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)) + C_CS("_mc"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, products[iOrderKey]); } else { - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumberValue)]->getProduct(iOrderKey)); + hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, products[iOrderKey]); } } }}; @@ -1828,109 +1940,86 @@ struct PartNumFluc { fillByChargeNumber.template operator()(); } - template - bool initTrack(const T& track, const TIs& tracksIu) + template + bool initTrack(const T& track) { + if (std::abs(track.sign()) != 1) { + return false; + } + holderTrack.clear(); holderTrack.dca[toI(DcaAxis::Xy)] = track.dcaXY(); holderTrack.dca[toI(DcaAxis::Z)] = track.dcaZ(); holderTrack.sign = track.sign(); - holderTrack.p = track.p(); holderTrack.pt = track.pt(); holderTrack.eta = track.eta(); holderTrack.phi = track.phi(); - { - const std::int64_t localIndexTrackIu{track.globalIndex() - static_cast(tracksIu.offset())}; - if (0 <= localIndexTrackIu && localIndexTrackIu < tracksIu.size()) { - const auto& trackIu{tracksIu.iteratorAt(localIndexTrackIu)}; - if (track.globalIndex() == trackIu.globalIndex()) { - holderTrack.phiIu = trackIu.phi(); - } else { - LOG(warning) << "Mismatched track " << track.globalIndex() << " and trackIu " << trackIu.globalIndex(); - } - } else { - LOG(warning) << "Invalid trackIu " << track.globalIndex(); - } - } holderTrack.hasPid[toI(Detector::Tpc)] = (track.hasTPC() && track.tpcSignal() > 0.); - if (holderTrack.hasPid[toI(Detector::Tpc)]) { - holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)] = {HolderTrack::truncateNSigmaPid(track.tpcNSigmaPi() - getShiftNSigmaPid()), HolderTrack::truncateNSigmaPid(track.tpcNSigmaKa() - getShiftNSigmaPid()), HolderTrack::truncateNSigmaPid(track.tpcNSigmaPr() - getShiftNSigmaPid())}; - } holderTrack.hasPid[toI(Detector::Tof)] = (track.hasTOF() && track.beta() > 0.); - if (holderTrack.hasPid[toI(Detector::Tof)]) { - holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)] = {HolderTrack::truncateNSigmaPid(track.tofNSigmaPi() - getShiftNSigmaPid()), HolderTrack::truncateNSigmaPid(track.tofNSigmaKa() - getShiftNSigmaPid()), HolderTrack::truncateNSigmaPid(track.tofNSigmaPr() - getShiftNSigmaPid())}; - if (holderTrack.hasPid[toI(Detector::Tpc)]) { - for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { - holderTrack.nSigmaPid[toI(PidStrategyAll::TpcTofCombined)][iParticleSpecies] = HolderTrack::truncateNSigmaPid(std::copysign(std::hypot(holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)][iParticleSpecies], holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][iParticleSpecies]), holderTrack.nSigmaPid[toI(PidStrategyAll::Tpc)][iParticleSpecies] + holderTrack.nSigmaPid[toI(PidStrategyAll::Tof)][iParticleSpecies])); - } - } - } + setNSigmaPid(track); - if constexpr (DoInitingEvent) { - if (track.isPrimaryTrack() && holderTrack.sign != 0) { + if constexpr (DoInitEvent) { + if (track.isPrimaryTrack()) { const std::int32_t chargeSpeciesIndex{toI(holderTrack.sign > 0 ? ChargeSpecies::Plus : ChargeSpecies::Minus)}; ++holderEvent.nGlobalTracks[chargeSpeciesIndex]; if (track.isPVContributor()) { ++holderEvent.nPvContributors[chargeSpeciesIndex]; } for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { - holderEvent.dca[toI(DcaKind::Mean)][iDcaAxis][chargeSpeciesIndex] += holderTrack.dca[iDcaAxis]; - holderEvent.dca[toI(DcaKind::Sigma)][iDcaAxis][chargeSpeciesIndex] += std::pow(holderTrack.dca[iDcaAxis], 2.); + holderEvent.measureDca[toI(DcaMeasure::Mean)][iDcaAxis][chargeSpeciesIndex] += holderTrack.dca[iDcaAxis]; + holderEvent.measureDca[toI(DcaMeasure::Sigma)][iDcaAxis][chargeSpeciesIndex] += std::pow(holderTrack.dca[iDcaAxis], 2.); } if (holderTrack.hasPid[toI(Detector::Tof)]) { ++holderEvent.nTofBeta[chargeSpeciesIndex]; } } - } - if constexpr (DoInitingEvent) { if (groupAnalysis.cfgFlagQaRun.value && track.isPrimaryTrack()) { if (holderTrack.sign > 0) { fillQaRunByTrackByChargeSpecies(track); - } else if (holderTrack.sign < 0) { + } else { fillQaRunByTrackByChargeSpecies(track); } } - } - if constexpr (!DoInitingEvent) { + return true; + } else { if (groupAnalysis.cfgFlagQaTrack.value && track.isPrimaryTrack()) { if (holderTrack.sign > 0) { fillQaTrackByChargeSpecies(track); - } else if (holderTrack.sign < 0) { + } else { fillQaTrackByChargeSpecies(track); } } - } - if (!isGoodTrack(track)) { - return false; - } + if (!isGoodTrack(track)) { + return false; + } - if constexpr (!DoInitingEvent) { if (groupAnalysis.cfgFlagQaDca.value) { if (holderTrack.sign > 0) { fillQaDcaByChargeSpecies(); - } else if (holderTrack.sign < 0) { + } else { fillQaDcaByChargeSpecies(); } } - } - if (!isGoodDca()) { - return false; - } + if (!isGoodDca()) { + return false; + } - if constexpr (!DoInitingEvent) { - if (isEnabled(groupAnalysis.cfgFlagsQaAcceptance) && (holderTrack.eta * holderEvent.vz > 0. && std::abs(holderEvent.vz) > groupEvent.cfgCutMaxAbsVz.value - 1.)) { - fillQaAcceptancebyParticleSpeciesAll(track); - fillQaAcceptancebyParticleSpeciesAll(track); - fillQaAcceptancebyParticleSpeciesAll(track); - fillQaAcceptancebyParticleSpeciesAll(track); + { + const double vz{doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz}; + if (doQaAcceptance && (holderTrack.eta * vz > 0. && std::abs(vz) > (doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? groupEvent.cfgCutMaxAbsVzMc.value : groupEvent.cfgCutMaxAbsVz.value) - 1.)) { + fillQaAcceptancebyParticleSpeciesAll(track); + fillQaAcceptancebyParticleSpeciesAll(track); + fillQaAcceptancebyParticleSpeciesAll(track); + fillQaAcceptancebyParticleSpeciesAll(track); + } } - } - return true; + return true; + } } template @@ -1956,8 +2045,8 @@ struct PartNumFluc { return isGoodMcParticle(mcParticle); } - template - bool initEvent(const C& collision, const Ts& tracks, const TIs& tracksIu) + template + bool initEvent(const C& collision, const Ts& tracks) { holderEvent.clear(); holderEvent.vz = collision.posZ(); @@ -1972,66 +2061,58 @@ struct PartNumFluc { holderEvent.centrality = collision.centFT0M(); break; } + holderEvent.centralityCalibration = (groupEvent.cfgFlagDefinitionCentralitySameQa.value ? holderEvent.centrality : collision.centNTPV()); - hrCounter.fill(C_CS("hNEvents"), 0.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 0.); - } - - if (!collision.has_foundBC()) { - hrCounter.fill(C_CS("hNEvents"), 2.); + const auto fillEventSelection{[this](const auto... selections) -> void { + (hrCounter.fill(C_CS("hNEvents"), selections), ...); if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 2.); + (hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, selections), ...); } + }}; + + fillEventSelection(0.); + + if (!collision.has_foundBC()) { + fillEventSelection(2.); return false; } - const auto& bc{collision.template bc_as()}; - holderEvent.runNumber = bc.runNumber(); + const auto& foundBc{collision.template foundBC_as()}; + holderEvent.runNumber = foundBc.runNumber(); - if (!holderCcdb.runNumbersIndicesGroupIndices.contains(holderEvent.runNumber)) { - hrCounter.fill(C_CS("hNEvents"), 2.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 2.); + { + const auto iter{holderCcdb.runNumbersIndicesGroupIndices.find(holderEvent.runNumber)}; + if (iter == holderCcdb.runNumbersIndicesGroupIndices.end()) { + fillEventSelection(2.); + return false; } - return false; + std::tie(holderEvent.runIndex, holderEvent.runGroupIndex) = iter->second; } - std::tie(holderEvent.runIndex, holderEvent.runGroupIndex) = holderCcdb.runNumbersIndicesGroupIndices.at(holderEvent.runNumber); - if (holderEvent.runGroupIndex == 0 || (groupEvent.cfgFlagRejectionRunBad.value && holderEvent.runGroupIndex < 0)) { - hrCounter.fill(C_CS("hNEvents"), 2.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 2.); - } + fillEventSelection(2.); return false; } - if (!rctFlagsChecker.checkTable(collision)) { - hrCounter.fill(C_CS("hNEvents"), 3.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 3.); - } + if (rctFlagsChecker.any() && !rctFlagsChecker.checkTable(collision)) { + fillEventSelection(3.); + return false; + } + + if (groupEvent.cfgFlagInelEvent.value && !collision.isInelGt0()) { + fillEventSelection(4.); return false; } for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { if (((groupEvent.cfgBitsSelectionEvent.value >> iEvSel) & 1) && !collision.selection_bit(iEvSel)) { - hrCounter.fill(C_CS("hNEvents"), 4.); - hrCounter.fill(C_CS("hNEvents"), 10. + iEvSel); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 4.); - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 10. + iEvSel); - } + fillEventSelection(5., 10. + iEvSel); return false; } } - if (groupEvent.cfgFlagInelEvent.value && !collision.isInelGt0()) { - hrCounter.fill(C_CS("hNEvents"), 5.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 5.); - } + if (!HolderEvent::isValidCentrality(holderEvent.centrality) || !HolderEvent::isValidCentrality(holderEvent.centralityCalibration)) { + fillEventSelection(6.); return false; } @@ -2041,10 +2122,7 @@ struct PartNumFluc { } if (!(std::abs(holderEvent.vz) < groupEvent.cfgCutMaxAbsVz.value)) { - hrCounter.fill(C_CS("hNEvents"), 6.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 6.); - } + fillEventSelection(7.); return false; } @@ -2054,29 +2132,28 @@ struct PartNumFluc { hrQaRun.fill(C_CS("QaRun/pRunIndexVz"), holderEvent.runIndex, holderEvent.vz); hrQaRun.fill(C_CS("QaRun/pRunIndexMultiplicityFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); hrQaRun.fill(C_CS("QaRun/pRunIndexMultiplicityFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); - if (HolderEvent::RangeCentrality.first <= collision.centFT0A() && collision.centFT0A() <= HolderEvent::RangeCentrality.second) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0a"), holderEvent.runIndex, collision.centFT0A()); + if (const double centrality{collision.centNTPV()}; HolderEvent::isValidCentrality(centrality)) { + hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityNtpv"), holderEvent.runIndex, centrality); + } + if (const double centrality{collision.centFT0A()}; HolderEvent::isValidCentrality(centrality)) { + hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0a"), holderEvent.runIndex, centrality); } - if (HolderEvent::RangeCentrality.first <= collision.centFT0C() && collision.centFT0C() <= HolderEvent::RangeCentrality.second) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0c"), holderEvent.runIndex, collision.centFT0C()); + if (const double centrality{collision.centFT0C()}; HolderEvent::isValidCentrality(centrality)) { + hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0c"), holderEvent.runIndex, centrality); } - if (HolderEvent::RangeCentrality.first <= collision.centFT0M() && collision.centFT0M() <= HolderEvent::RangeCentrality.second) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0m"), holderEvent.runIndex, collision.centFT0M()); + if (const double centrality{collision.centFT0M()}; HolderEvent::isValidCentrality(centrality)) { + hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0m"), holderEvent.runIndex, centrality); } } for (const auto& track : tracks) { - if (!track.has_collision() || track.collisionId() != collision.globalIndex()) { - continue; - } - - initTrack(track, tracksIu); + initTrack(track); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { if (holderEvent.nGlobalTracks[iChargeSpecies] > 0) { for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { - holderEvent.dca[toI(DcaKind::Mean)][iDcaAxis][iChargeSpecies] /= holderEvent.nGlobalTracks[iChargeSpecies]; - holderEvent.dca[toI(DcaKind::Sigma)][iDcaAxis][iChargeSpecies] = std::sqrt(std::max(0., holderEvent.dca[toI(DcaKind::Sigma)][iDcaAxis][iChargeSpecies] / holderEvent.nGlobalTracks[iChargeSpecies] - std::pow(holderEvent.dca[toI(DcaKind::Mean)][iDcaAxis][iChargeSpecies], 2.))); + holderEvent.measureDca[toI(DcaMeasure::Mean)][iDcaAxis][iChargeSpecies] /= holderEvent.nGlobalTracks[iChargeSpecies]; + holderEvent.measureDca[toI(DcaMeasure::Sigma)][iDcaAxis][iChargeSpecies] = std::sqrt(std::max(0., holderEvent.measureDca[toI(DcaMeasure::Sigma)][iDcaAxis][iChargeSpecies] / holderEvent.nGlobalTracks[iChargeSpecies] - std::pow(holderEvent.measureDca[toI(DcaMeasure::Mean)][iDcaAxis][iChargeSpecies], 2.))); } } } @@ -2089,29 +2166,23 @@ struct PartNumFluc { if (groupAnalysis.cfgFlagQaEvent.value) { hrQaEvent.fill(C_CS("QaEvent/hNPvContributorsNGlobalTracks"), holderEvent.getNPvContributors(), holderEvent.getNGlobalTracks()); if (holderEvent.getNGlobalTracks() > 0) { - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaKind::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.getNGlobalTracks(), holderEvent.getDca()); - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaKind::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.getNGlobalTracks(), holderEvent.getDca()); + hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); + hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); } hrQaEvent.fill(C_CS("QaEvent/hNTofBetaNGlobalTracks"), holderEvent.getNTofBeta(), holderEvent.getNGlobalTracks()); } if (!(holderEvent.getNPvContributors() - holderEvent.getNGlobalTracks() > groupEvent.cfgCutMinDeviationNPvContributors.value)) { - hrCounter.fill(C_CS("hNEvents"), 7.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 7.); - } + fillEventSelection(8.); return false; } - hrCounter.fill(C_CS("hNEvents"), 1.); - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, 1.); - } + fillEventSelection(1.); if (groupAnalysis.cfgFlagQaEvent.value) { if (holderEvent.getNGlobalTracks() > 0) { - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaKind::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getDca()); - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaKind::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getDca()); + hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); + hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); } hrQaEvent.fill(C_CS("QaEvent/hNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.getNTofBeta(), holderEvent.getNGlobalTracks()); } @@ -2131,38 +2202,18 @@ struct PartNumFluc { hrCounter.fill(C_CS("hNMcEvents"), 0.); - if (!mcCollision.has_bc()) { - hrCounter.fill(C_CS("hNMcEvents"), 2.); - return false; - } - - const auto& bc{mcCollision.template bc_as()}; - holderMcEvent.runNumber = bc.runNumber(); - - if (!holderCcdb.runNumbersIndicesGroupIndices.contains(holderMcEvent.runNumber)) { - hrCounter.fill(C_CS("hNMcEvents"), 2.); - return false; - } - - std::tie(holderMcEvent.runIndex, holderMcEvent.runGroupIndex) = holderCcdb.runNumbersIndicesGroupIndices.at(holderMcEvent.runNumber); - - if (holderMcEvent.runGroupIndex == 0 || (groupEvent.cfgFlagRejectionRunBad.value && holderMcEvent.runGroupIndex < 0)) { + if (groupEvent.cfgFlagInelEventMc.value && !mcCollision.isInelGt0()) { hrCounter.fill(C_CS("hNMcEvents"), 2.); return false; } - if (groupEvent.cfgFlagInelEventMc.value && !mcCollision.isInelGt0()) { + if (!(std::abs(holderMcEvent.vz) < groupEvent.cfgCutMaxAbsVzMc.value)) { hrCounter.fill(C_CS("hNMcEvents"), 3.); return false; } - if (groupEvent.cfgFlagCutVzMc.value && !(std::abs(holderMcEvent.vz) < groupEvent.cfgCutMaxAbsVz.value)) { - hrCounter.fill(C_CS("hNMcEvents"), 4.); - return false; - } - if (groupEvent.cfgFlagSingleCollisionMc.value && mcCollision.numRecoCollision() != 1) { - hrCounter.fill(C_CS("hNMcEvents"), 5.); + hrCounter.fill(C_CS("hNMcEvents"), 4.); return false; } @@ -2171,67 +2222,62 @@ struct PartNumFluc { return true; } - void processRaw(const soa::Filtered::iterator& collision, const soa::Filtered& tracks, const aod::TracksIU& tracksIu, const aod::BCsWithTimestamps&) + void processRaw(const soa::Filtered::iterator& collision, const soa::Filtered& tracks, const aod::BCsWithTimestamps&) { - if (!initEvent(collision, tracks, tracksIu) || (!groupAnalysis.cfgFlagQaTrack.value && !groupAnalysis.cfgFlagQaDca.value && !isEnabled(groupAnalysis.cfgFlagsQaAcceptance) && !isEnabled(groupAnalysis.cfgFlagsQaPhi) && !isEnabled(groupAnalysis.cfgFlagsQaPid) && !isEnabled(groupAnalysis.cfgFlagsCalculationYield) && !isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation))) { + if (!initEvent(collision, tracks) || (!groupAnalysis.cfgFlagQaTrack.value && !groupAnalysis.cfgFlagQaDca.value && !doQaAcceptance && !doQaPhi && !doQaPid && !doCalculationYield && !doCalculationFluctuation)) { return; } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationFluctuation) { holderEvent.subgroupIndex = gRandom->Integer(groupEvent.cfgNSubgroups.value); initCalculationFluctuation(); holderDerivedData.clear(); } for (const auto& track : tracks) { - if (!track.has_collision() || track.collisionId() != collision.globalIndex()) { + if (!initTrack(track)) { continue; } - if (!initTrack(track, tracksIu)) { - continue; - } - - if (isEnabled(groupAnalysis.cfgFlagsQaPhi)) { + if (doQaPhi) { fillQaPhiByParticleSpeciesAll(); fillQaPhiByParticleSpeciesAll(); fillQaPhiByParticleSpeciesAll(); fillQaPhiByParticleSpeciesAll(); } - if (isEnabled(groupAnalysis.cfgFlagsQaPid)) { + if (doQaPid) { fillQaPidByParticleSpeciesAll(track); fillQaPidByParticleSpeciesAll(track); fillQaPidByParticleSpeciesAll(track); fillQaPidByParticleSpeciesAll(track); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationYield)) { + if (doCalculationYield) { fillCalculationYieldByParticleSpecies(); fillCalculationYieldByParticleSpecies(); fillCalculationYieldByParticleSpecies(); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationFluctuation) { calculateFluctuationByParticleNumber(); calculateFluctuationByParticleNumber(); calculateFluctuationByParticleNumber(); } } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationFluctuation) { fillCalculationFluctuationByParticleNumber(); fillCalculationFluctuationByParticleNumber(); fillCalculationFluctuationByParticleNumber(); - miniCollision(HolderDerivedData::convertFloor(holderEvent.vz * 10.), HolderDerivedData::convertFloor(holderEvent.centrality * 500.), holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); - for (auto const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { + miniCollision(HolderDerivedData::convertFloor(holderEvent.vz * 10.), HolderDerivedData::convertFloor(holderEvent.centrality * 500.), holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); + for (std::int16_t const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { miniTrack(miniCollision.lastIndex(), signedEfficiency); } } } - PROCESS_SWITCH(PartNumFluc, processRaw, "Process raw data", true); - void processMc(const soa::Filtered::iterator& mcCollision, const aod::McParticles& mcParticles, const soa::SmallGroups& collisions, const soa::Filtered& tracksUngrouped, const aod::TracksIU& tracksIuUngrouped, const aod::BCsWithTimestamps&) + void processMc(const soa::Filtered::iterator& mcCollision, const aod::McParticles& mcParticles, const soa::SmallGroups& collisions, const soa::Filtered& tracksUngrouped, const aod::BCsWithTimestamps&) { if (!initMcEvent(mcCollision)) { return; @@ -2243,59 +2289,54 @@ struct PartNumFluc { } const auto& tracks{tracksUngrouped.sliceBy(presliceTracksPerCollision, collision.globalIndex())}; - const auto& tracksIu{tracksIuUngrouped.sliceBy(presliceTracksPerCollision, collision.globalIndex())}; - if (!initEvent(collision, tracks, tracksIu)) { + if (!initEvent(collision, tracks)) { continue; } if (groupAnalysis.cfgFlagQaMc.value) { - hrQaMc.fill(C_CS("QaMc/hCentralityVzMcDeltaVz"), holderEvent.centrality, holderMcEvent.vz, holderEvent.vz - holderMcEvent.vz); + hrQaMc.fill(C_CS("QaMc/hCentralityVzMcDeltaVz"), holderEvent.centralityCalibration, holderMcEvent.vz, holderEvent.vz - holderMcEvent.vz); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationYield) || isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationYield || doCalculationFluctuation) { + if (doCalculationFluctuation) { holderEvent.subgroupIndex = gRandom->Integer(groupEvent.cfgNSubgroups.value); initCalculationFluctuation(); holderDerivedData.clear(); } for (const auto& mcParticle : mcParticles) { - if (!mcParticle.has_mcCollision() || mcParticle.mcCollisionId() != mcCollision.globalIndex()) { - continue; - } - if (!initMcParticle(mcParticle)) { continue; } - if (isEnabled(groupAnalysis.cfgFlagsCalculationYield)) { + if (doCalculationYield) { fillCalculationYieldByParticleSpecies(); fillCalculationYieldByParticleSpecies(); fillCalculationYieldByParticleSpecies(); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationFluctuation) { calculateFluctuationByParticleNumber(); calculateFluctuationByParticleNumber(); calculateFluctuationByParticleNumber(); } } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationFluctuation) { fillCalculationFluctuationByParticleNumber(); fillCalculationFluctuationByParticleNumber(); fillCalculationFluctuationByParticleNumber(); } } - if (groupAnalysis.cfgFlagQaTrack.value || groupAnalysis.cfgFlagQaDca.value || isEnabled(groupAnalysis.cfgFlagsQaAcceptance) || isEnabled(groupAnalysis.cfgFlagsQaPhi) || isEnabled(groupAnalysis.cfgFlagsQaPid) || isEnabled(groupAnalysis.cfgFlagsCalculationYield) || isEnabled(groupAnalysis.cfgFlagsCalculationPurity) || isEnabled(groupAnalysis.cfgFlagsCalculationFractionPrimary) || isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (groupAnalysis.cfgFlagQaTrack.value || groupAnalysis.cfgFlagQaDca.value || doQaAcceptance || doQaPhi || doQaPid || groupAnalysis.cfgFlagQaMc.value || doCalculationYield || doCalculationPurity || doCalculationFractionPrimary || doCalculationFluctuation) { + if (doCalculationFluctuation) { initCalculationFluctuation(); } for (const auto& track : tracks) { - if (!track.has_collision() || track.collisionId() != collision.globalIndex() || !track.has_mcParticle()) { + if (!track.has_mcParticle()) { continue; } @@ -2304,18 +2345,18 @@ struct PartNumFluc { continue; } - if (!initTrack(track, tracksIu) || !initMcParticle(mcParticle)) { + if (!initTrack(track) || !initMcParticle(mcParticle)) { continue; } - if (isEnabled(groupAnalysis.cfgFlagsQaPhi)) { + if (doQaPhi) { fillQaPhiByParticleSpeciesAll(); fillQaPhiByParticleSpeciesAll(); fillQaPhiByParticleSpeciesAll(); fillQaPhiByParticleSpeciesAll(); } - if (isEnabled(groupAnalysis.cfgFlagsQaPid)) { + if (doQaPid) { fillQaPidByParticleSpeciesAll(track); fillQaPidByParticleSpeciesAll(track); fillQaPidByParticleSpeciesAll(track); @@ -2323,45 +2364,45 @@ struct PartNumFluc { } if (groupAnalysis.cfgFlagQaMc.value && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { - hrQaMc.fill(C_CS("QaMc/hCentralityPtMcEtaMcDeltaPt"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderTrack.pt - holderMcParticle.pt); - hrQaMc.fill(C_CS("QaMc/hCentralityPtMcEtaMcDeltaEta"), holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, holderTrack.eta - holderMcParticle.eta); + hrQaMc.fill(C_CS("QaMc/hCentralityPtMcEtaMcDeltaPt"), holderEvent.centralityCalibration, holderMcParticle.pt, holderMcParticle.eta, holderTrack.pt - holderMcParticle.pt); + hrQaMc.fill(C_CS("QaMc/hCentralityPtMcEtaMcDeltaEta"), holderEvent.centralityCalibration, holderMcParticle.pt, holderMcParticle.eta, holderTrack.eta - holderMcParticle.eta); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationYield) && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + if (doCalculationYield && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { fillCalculationYieldByParticleSpecies(); fillCalculationYieldByParticleSpecies(); fillCalculationYieldByParticleSpecies(); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationPurity) && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + if (doCalculationPurity && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { fillCalculationPurityByParticleSpecies(); fillCalculationPurityByParticleSpecies(); fillCalculationPurityByParticleSpecies(); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFractionPrimary)) { + if (doCalculationFractionPrimary) { fillCalculationFractionPrimaryByParticleSpecies(mcParticle); fillCalculationFractionPrimaryByParticleSpecies(mcParticle); fillCalculationFractionPrimaryByParticleSpecies(mcParticle); } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation) && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + if (doCalculationFluctuation && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { calculateFluctuationByParticleNumber(); calculateFluctuationByParticleNumber(); calculateFluctuationByParticleNumber(); } } - if (isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation)) { + if (doCalculationFluctuation) { fillCalculationFluctuationByParticleNumber(); fillCalculationFluctuationByParticleNumber(); fillCalculationFluctuationByParticleNumber(); miniMcCollision(holderDerivedData.nMcParticles[toI(ChargeSpecies::Plus)], holderDerivedData.nMcParticles[toI(ChargeSpecies::Minus)]); - miniCollision(HolderDerivedData::convertFloor(holderEvent.vz * 10.), HolderDerivedData::convertFloor(holderEvent.centrality * 500.), holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); - for (auto const& signedEfficiency : holderDerivedData.signedEfficienciesMcParticle) { + miniCollision(HolderDerivedData::convertFloor(holderEvent.vz * 10.), HolderDerivedData::convertFloor(holderEvent.centrality * 500.), holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); + for (std::int16_t const& signedEfficiency : holderDerivedData.signedEfficienciesMcParticle) { miniMcParticle(miniMcCollision.lastIndex(), signedEfficiency); } - for (auto const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { + for (std::int16_t const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { miniTrack(miniCollision.lastIndex(), signedEfficiency); } } @@ -2370,7 +2411,9 @@ struct PartNumFluc { break; } } - PROCESS_SWITCH(PartNumFluc, processMc, "Process MC data", false); + + PROCESS_SWITCH_FULL(PartNumFluc, processRaw, ProcessRaw, "Flag of processing raw data", true); + PROCESS_SWITCH_FULL(PartNumFluc, processMc, ProcessMc, "Flag of processing MC data", false); }; WorkflowSpec defineDataProcessing(const ConfigContext& configContext) diff --git a/PWGCF/Femto/Core/baseSelection.h b/PWGCF/Femto/Core/baseSelection.h index 5c46c4747a3..8ddc97e3da1 100644 --- a/PWGCF/Femto/Core/baseSelection.h +++ b/PWGCF/Femto/Core/baseSelection.h @@ -165,12 +165,12 @@ class BaseSelection std::string const& selectionName, int mode) { + int selectionMode = mode; + if (mPassThrough) { - mSelectionContainers.at(observableIndex) = selectioncontainer::SelectionContainer(selectionName, std::vector{1}, limits::LimitType::kEqual, false, false, false); - return; + selectionMode = 2; } - - switch (mode) { + switch (selectionMode) { case -1: // cut is optional and we store a bit for it mSelectionContainers.at(observableIndex) = selectioncontainer::SelectionContainer(selectionName, std::vector{1}, limits::LimitType::kEqual, false, false, true); break; diff --git a/PWGCF/Femto/Core/cascadeBuilder.h b/PWGCF/Femto/Core/cascadeBuilder.h index 9e3a73ae2c5..84fd8ddbd41 100644 --- a/PWGCF/Femto/Core/cascadeBuilder.h +++ b/PWGCF/Femto/Core/cascadeBuilder.h @@ -63,31 +63,37 @@ struct ConfCascadeFilters : o2::framework::ConfigurableGroup { }; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CASCADE_DEFAULT_BITS \ - o2::framework::Configurable passThrough{"passThrough", false, "If true, all Cascades are passed through. Bits for all selections are stored."}; \ - o2::framework::Configurable> cascadeCpaMin{"cascadeCpaMin", {0.95f}, "Minimum cosine of pointing angle"}; \ - o2::framework::Configurable> cascadeTransRadMin{"cascadeTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ - o2::framework::Configurable> cascadeDcaDauMax{"cascadeDcaDauMax", {0.25f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ - o2::framework::Configurable> lambdaCpaMin{"lambdaCpaMin", {0.78f}, "Minimum cosine of pointing angle"}; \ - o2::framework::Configurable> lambdaTransRadMin{"lambdaTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ - o2::framework::Configurable> lambdaDcaDauMax{"lambdaDcaDauMax", {0.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ - o2::framework::Configurable> lambdaDcaToPvMin{"lambdaDcaToPvMin", {0.3f}, "Minimum DCA between the lambda and primary vertex"}; \ - o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| of all daughters"}; \ - o2::framework::Configurable> dauDcaMin{"dauDcaMin", {0.05f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ - o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; \ - o2::framework::Configurable> posDauTpc{"posDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for positive daughter tracks"}; \ - o2::framework::Configurable> negDauTpc{"negDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for negative daughter tracks"}; +#define CASCADE_DEFAULT_BITS \ + o2::framework::Configurable passThrough{"passThrough", false, "If true, all Cascades are passed through. Bits for all selections are stored."}; \ + o2::framework::Configurable> cascadeCpaMin{"cascadeCpaMin", {0.95f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> cascadeTransRadMin{"cascadeTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> cascadeDcaDauMax{"cascadeDcaDauMax", {0.25f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> lambdaCpaMin{"lambdaCpaMin", {0.78f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> lambdaTransRadMin{"lambdaTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> lambdaDcaDauMax{"lambdaDcaDauMax", {0.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> lambdaDcaToPvMin{"lambdaDcaToPvMin", {0.3f}, "Minimum DCA between the lambda and primary vertex"}; \ + o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| of all daughters"}; \ + o2::framework::Configurable> dauAbsDcaxyMin{"dauAbsDcaxyMin", {0.05f}, "Minimum |DCAxy| of the daughters and bachelor from primary vertex (cm)"}; \ + o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; \ + o2::framework::Configurable> posDauTpc{"posDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for positive daughter tracks"}; \ + o2::framework::Configurable> negDauTpc{"negDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for negative daughter tracks"}; \ + o2::framework::Configurable> posDauTof{"posDauTof", {}, "Maximum |nsimga_Pion/Proton| TOF for positive daughter tracks"}; \ + o2::framework::Configurable> negDauTof{"negDauTof", {}, "Maximum |nsigma_Pion/Proton| TOF for negative daughter tracks"}; \ + o2::framework::Configurable requireTof{"requireTof", false, "If true, TOF PID is a mandatory selection"}; \ + o2::framework::Configurable keepTracksWithoutTof{"keepTracksWithoutTof", true, "If true, candidates whose daughters have no TOF signal are kept"}; struct ConfXiBits : o2::framework::ConfigurableGroup { std::string prefix = std::string("XiBits"); CASCADE_DEFAULT_BITS o2::framework::Configurable> bachelorTpcPion{"bachelorTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for bachelor tracks"}; + o2::framework::Configurable> bachelorTofPion{"bachelorTofPion", {}, "Maximum |nsimga_Pion| TOF for bachelor tracks"}; }; struct ConfOmegaBits : o2::framework::ConfigurableGroup { std::string prefix = std::string("OmegaBits"); CASCADE_DEFAULT_BITS o2::framework::Configurable> bachelorTpcKaon{"bachelorTpcKaon", {5.f}, "Maximum |nsimga_Kaon| TPC for bachelor tracks"}; + o2::framework::Configurable> bachelorTofKaon{"bachelorTofKaon", {}, "Maximum |nsimga_Kaon| TOF for bachelor tracks"}; }; #undef CASCADE_DEFAULT_BITS @@ -126,23 +132,27 @@ enum CascadeSels { kCascadeTransRadMin, ///< max. transverse radius // selection for lambda daughter - kLambdaCpaMin, ///< Min. DCA of the lambda daughers at primary vertex - kLambdaDcaDauMax, ///< TPC PID for daughters (Pion/Proton) - kLambdaTransRadMin, ///< Min. number of TPC clusters of daughter - kLambdaDcaToPvMin, ///< Min. DCA to primary vertex of daughter lambda + kLambdaCpaMin, ///< Min. CPA of the lambda + kLambdaDcaDauMax, ///< Max. DCA between the lambda daughters at lambda decay vertex + kLambdaTransRadMin, ///< Min. tranverse radius of the lambda + kLambdaDcaToPvMin, ///< Min. DCA of the lambda to the primary vertex // selection for bachelor/daugthers - kDauAbsEtaMax, ///< Min. DCA of the daughers/bachelor at primary vertex - kDauTpcClsMin, ///< Min. number of TPC clusters of daughters/bachelor - kDauDcaMin, ///< TPC Pion PID for negative daughter + kDauAbsEtaMax, ///< Max. |eta| of daughter tracks + kDauTpcClsMin, ///< Min. number of TPC clusters of daughters/bachelor + kDauAbsDcaxyMin, ///< Min. |DCAxy| of the daughers and bachelor from primary vertex // PID selection for cascade bachelor kBachelorTpcPion, ///< TPC Pion PID for bachelor kBachelorTpcKaon, ///< TPC Kaon PID for bachelor + kBachelorTofPion, ///< TOF Pion PID for bachelor + kBachelorTofKaon, ///< TOF Kaon PID for bachelor /// // PID selection for lambda daughers kPosDauTpc, ///< TPC PID for positive daughter kNegDauTpc, ///< TPC PID for negative daughter + kPosDauTof, ///< TOF PID for positive daughter + kNegDauTof, ///< TOF PID for negative daughter kCascadeSelsMax }; @@ -162,15 +172,16 @@ const std::unordered_map cascadeSelectionNames = { {kDauAbsEtaMax, "Daughter Abs Eta Max"}, {kDauTpcClsMin, "Daughter TPC Clusters Min"}, - {kDauDcaMin, "Daughter DCA Min"}, + {kDauAbsDcaxyMin, "Daughter |DCAxy| Min"}, {kBachelorTpcPion, "Bachelor TPC Pion PID"}, {kBachelorTpcKaon, "Bachelor TPC Kaon PID"}, - + {kBachelorTofPion, "Bachelor TOF Pion PID"}, + {kBachelorTofKaon, "Bachelor TOF Kaon PID"}, {kPosDauTpc, "Positive Daughter TPC PID"}, {kNegDauTpc, "Negative Daughter TPC PID"}, - - {kCascadeSelsMax, "Cascade Selections Max"}}; + {kPosDauTof, "Positive Daughter TOF PID"}, + {kNegDauTof, "Negative Daughter TOF PID"}}; /// enum for all cascade pre-filters (evaluated in checkFilters, before the selection bitmask) enum CascadeFilters { @@ -224,6 +235,17 @@ class CascadeSelection : public baseselection::BaseSelectioninit(config.passThrough.value); + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + mLambdaMassMin = filter.massLambdaMin.value; + mLambdaMassMax = filter.massLambdaMax.value; + mRequireTof = config.requireTof.value; + mKeepTracksWithoutTof = config.keepTracksWithoutTof.value; + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { mXiMassLowerLimit = filter.massXiMin.value; mXiMassUpperLimit = filter.massXiMax.value; @@ -231,6 +253,7 @@ class CascadeSelection : public baseselection::BaseSelectionaddSelection(kBachelorTpcPion, cascadeSelectionNames.at(kBachelorTpcPion), config.bachelorTpcPion.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kBachelorTofPion, cascadeSelectionNames.at(kBachelorTofPion), config.bachelorTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false); } if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { mOmegaMassLowerLimit = filter.massOmegaMin.value; @@ -239,19 +262,13 @@ class CascadeSelection : public baseselection::BaseSelectionaddSelection(kBachelorTpcKaon, cascadeSelectionNames.at(kBachelorTpcKaon), config.bachelorTpcKaon.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kBachelorTofKaon, cascadeSelectionNames.at(kBachelorTofKaon), config.bachelorTofKaon.value, limits::kAbsUpperLimit, true, mRequireTof, false); } - mPtMin = filter.ptMin.value; - mPtMax = filter.ptMax.value; - mEtaMin = filter.etaMin.value; - mEtaMax = filter.etaMax.value; - mPhiMin = filter.phiMin.value; - mPhiMax = filter.phiMax.value; - mLambdaMassMin = filter.massLambdaMin.value; - mLambdaMassMax = filter.massLambdaMax.value; - this->addSelection(kPosDauTpc, cascadeSelectionNames.at(kPosDauTpc), config.posDauTpc.value, limits::kAbsUpperLimit, true, true, false); this->addSelection(kNegDauTpc, cascadeSelectionNames.at(kNegDauTpc), config.negDauTpc.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kPosDauTof, cascadeSelectionNames.at(kPosDauTof), config.posDauTof.value, limits::kAbsUpperLimit, true, mRequireTof, false); + this->addSelection(kNegDauTof, cascadeSelectionNames.at(kNegDauTof), config.negDauTof.value, limits::kAbsUpperLimit, true, mRequireTof, false); this->addSelection(kCascadeCpaMin, cascadeSelectionNames.at(kCascadeCpaMin), config.cascadeCpaMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kCascadeTransRadMin, cascadeSelectionNames.at(kCascadeTransRadMin), config.cascadeTransRadMin.value, limits::kLowerLimit, true, true, false); @@ -261,7 +278,7 @@ class CascadeSelection : public baseselection::BaseSelectionaddSelection(kLambdaDcaDauMax, cascadeSelectionNames.at(kLambdaDcaDauMax), config.lambdaDcaDauMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kLambdaDcaToPvMin, cascadeSelectionNames.at(kLambdaDcaToPvMin), config.lambdaDcaToPvMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kDauAbsEtaMax, cascadeSelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); - this->addSelection(kDauDcaMin, cascadeSelectionNames.at(kDauDcaMin), config.dauDcaMin.value, limits::kAbsLowerLimit, true, true, false); + this->addSelection(kDauAbsDcaxyMin, cascadeSelectionNames.at(kDauAbsDcaxyMin), config.dauAbsDcaxyMin.value, limits::kAbsLowerLimit, true, true, false); this->addSelection(kDauTpcClsMin, cascadeSelectionNames.at(kDauTpcClsMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); this->setupSelectionHistogram(registry); @@ -305,31 +322,64 @@ class CascadeSelection : public baseselection::BaseSelection(); // daughter selections - std::array etaDaughters = {std::fabs(bachelor.eta()), std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; + std::array etaDaughters = {std::fabs(cascade.bacheloreta()), std::fabs(cascade.positiveeta()), std::fabs(cascade.negativeeta())}; this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); - std::array dcaDaughters = {std::hypot(bachelor.dcaXY(), bachelor.dcaZ()), - std::hypot(posDaughter.dcaXY(), posDaughter.dcaZ()), - std::hypot(negDaughter.dcaXY(), negDaughter.dcaZ())}; - this->evaluateObservable(kDauDcaMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); + std::array dcaDaughters = {std::fabs(cascade.dcabachtopv()), std::fabs(cascade.dcapostopv()), std::fabs(cascade.dcanegtopv())}; + this->evaluateObservable(kDauAbsDcaxyMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); std::array clustersDaughters = {1.f * bachelor.tpcNClsFound(), 1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); - // bachelor pid selection - // check both pion and kaon PID for xi and omega - this->evaluateObservable(kBachelorTpcPion, bachelor.tpcNSigmaPi()); - this->evaluateObservable(kBachelorTpcKaon, bachelor.tpcNSigmaKa()); - - // depending on the charge, we check lambda or antilambda hypothesis - if (cascade.sign() < 0) { - this->evaluateObservable(kPosDauTpc, posDaughter.tpcNSigmaPr()); - this->evaluateObservable(kNegDauTpc, negDaughter.tpcNSigmaPi()); - } else if (cascade.sign() > 0) { - this->evaluateObservable(kPosDauTpc, posDaughter.tpcNSigmaPi()); - this->evaluateObservable(kNegDauTpc, negDaughter.tpcNSigmaPr()); - } else { + // pid selections + // TPC nSigma comes from the daughter track, TOF nSigma and the has-TOF flags from the cascade candidate + // if a daughter has no TOF signal, feed 0 so the bit passes any limit (opt-in via keepTracksWithoutTof) + auto evaluatePid = [this](CascadeSels tpcBit, float tpcNSigma, + CascadeSels tofBit, float tofNSigma, bool hasTof) { + this->evaluateObservable(tpcBit, tpcNSigma); + if (hasTof) { + this->evaluateObservable(tofBit, tofNSigma); + } else if (mKeepTracksWithoutTof) { + this->evaluateObservable(tofBit, 0.f); + } + }; + + const bool bachHasTof = cascade.bachelorHasTOF(); + const bool posHasTof = cascade.positiveHasTOF(); + const bool negHasTof = cascade.negativeHasTOF(); + + // bachelor: pion for Xi, kaon for Omega + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + evaluatePid(kBachelorTpcPion, bachelor.tpcNSigmaPi(), + kBachelorTofPion, cascade.tofNSigmaXiPi(), bachHasTof); + } else if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + evaluatePid(kBachelorTpcKaon, bachelor.tpcNSigmaKa(), + kBachelorTofKaon, cascade.tofNSigmaOmKa(), bachHasTof); + } + + // v0 daughters: charge of the cascade fixes the Lambda vs. AntiLambda hypothesis + if (cascade.sign() == 0) { LOG(warn) << "Encountered Cascade candidate with 0 charge"; + } else { + // sign < 0: Xi-/Omega- -> Lambda -> p pi- (pos = proton, neg = pion) + // sign > 0: Xi+/Omega+ -> AntiLambda (pos = pion, neg = antiproton) + const bool isMatter = cascade.sign() < 0; + + const float tpcPosDau = isMatter ? posDaughter.tpcNSigmaPr() : posDaughter.tpcNSigmaPi(); + const float tpcNegDau = isMatter ? negDaughter.tpcNSigmaPi() : negDaughter.tpcNSigmaPr(); + + float tofPosDau = 0.f; + float tofNegDau = 0.f; + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + tofPosDau = isMatter ? cascade.tofNSigmaXiLaPr() : cascade.tofNSigmaXiLaPi(); + tofNegDau = isMatter ? cascade.tofNSigmaXiLaPi() : cascade.tofNSigmaXiLaPr(); + } else if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + tofPosDau = isMatter ? cascade.tofNSigmaOmLaPr() : cascade.tofNSigmaOmLaPi(); + tofNegDau = isMatter ? cascade.tofNSigmaOmLaPi() : cascade.tofNSigmaOmLaPr(); + } + + evaluatePid(kPosDauTpc, tpcPosDau, kPosDauTof, tofPosDau, posHasTof); + evaluatePid(kNegDauTpc, tpcNegDau, kNegDauTof, tofNegDau, negHasTof); } this->assembleBitmask(); @@ -439,13 +489,17 @@ class CascadeSelection : public baseselection::BaseSelection producedXis; + o2::framework::Produces producedLiteXis; o2::framework::Produces producedXiMasks; o2::framework::Produces producedXiExtras; o2::framework::Produces producedOmegas; + o2::framework::Produces producedLiteOmegas; o2::framework::Produces producedOmegaMasks; o2::framework::Produces producedOmegaExtras; }; @@ -453,9 +507,11 @@ struct CascadeBuilderProducts : o2::framework::ProducesGroup { struct ConfCascadeTables : o2::framework::ConfigurableGroup { std::string prefix = std::string("CascadeTables"); o2::framework::Configurable produceXis{"produceXis", -1, "Produce Xis (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteXis{"produceLiteXis", -1, "Produce LiteXis (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceXiMasks{"produceXiMasks", -1, "Produce XiMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceXiExtras{"produceXiExtras", -1, "Produce XiExtras (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceOmegas{"produceOmegas", -1, "Produce Omegas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteOmegas{"produceLiteOmegas", -1, "Produce LiteOmegas (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceOmegaMasks{"produceOmegaMasks", -1, "Produce OmegaMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceOmegaExtras{"produceOmegaExtras", -1, "Produce OmegaExtras (-1: auto; 0 off; 1 on)"}; }; @@ -467,23 +523,58 @@ class CascadeBuilder CascadeBuilder() = default; ~CascadeBuilder() = default; - template - void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext, T5& trackBuilder) { if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { LOG(info) << "Initialize femto Xi builder..."; + mProduceLiteXis = utils::enableTable("FLiteXis_001", table.produceLiteXis.value, initContext); mProduceXis = utils::enableTable("FXis_001", table.produceXis.value, initContext); - mProduceXiMasks = utils::enableTable("FXiMasks_001", table.produceXiMasks.value, initContext); + mProduceXiMasks = utils::enableTable("FXiMasks_002", table.produceXiMasks.value, initContext); mProduceXiExtras = utils::enableTable("FXiExtras_001", table.produceXiExtras.value, initContext); + + if (mProduceXis && mProduceLiteXis) { + LOG(fatal) << "FXis and FLiteXis are mutually exclusive -- enable only one. " + << "FLiteXis is meant to replace FXis at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FXis from FLiteXis downstream."; + } + if (mProduceXis && !trackBuilder.producingTracks()) { + LOG(fatal) << "FXis is enabled, but the track builder is not producing FTracks (full precision). " + << "FXis stores daughter indices into FTracks -- enable TrackTables.produceTracks, " + << "or switch to FLiteXis if TrackTables.produceLiteTracks is enabled instead."; + } + if (mProduceLiteXis && !trackBuilder.producingLiteTracks()) { + LOG(fatal) << "FLiteXis is enabled, but the track builder is not producing FLiteTracks. " + << "FLiteXis stores daughter indices into FLiteTracks -- enable TrackTables.produceLiteTracks, " + << "or switch to FXis if TrackTables.produceTracks is enabled instead."; + } } if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { LOG(info) << "Initialize femto Omega builder..."; mProduceOmegas = utils::enableTable("FOmegas_001", table.produceOmegas.value, initContext); - mProduceOmegaMasks = utils::enableTable("FOmegaMasks_001", table.produceOmegaMasks.value, initContext); + mProduceLiteOmegas = utils::enableTable("FLiteOmegas_001", table.produceLiteOmegas.value, initContext); + mProduceOmegaMasks = utils::enableTable("FOmegaMasks_002", table.produceOmegaMasks.value, initContext); mProduceOmegaExtras = utils::enableTable("FOmegaExtras_001", table.produceOmegaExtras.value, initContext); + + if (mProduceOmegas && mProduceLiteOmegas) { + LOG(fatal) << "FOmegas and FLiteOmegas are mutually exclusive -- enable only one. " + << "FLiteOmegas is meant to replace FOmegas at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FOmegas from FLiteOmegas downstream."; + } + if (mProduceOmegas && !trackBuilder.producingTracks()) { + LOG(fatal) << "FOmegas is enabled, but the track builder is not producing FTracks (full precision). " + << "FOmegas stores daughter indices into FTracks -- enable TrackTables.produceTracks, " + << "or switch to FLiteOmegas if TrackTables.produceLiteTracks is enabled instead."; + } + if (mProduceLiteOmegas && !trackBuilder.producingLiteTracks()) { + LOG(fatal) << "FLiteOmegas is enabled, but the track builder is not producing FLiteTracks. " + << "FLiteOmegas stores daughter indices into FLiteTracks -- enable TrackTables.produceLiteTracks, " + << "or switch to FOmegas if TrackTables.produceTracks is enabled instead."; + } } - if (mProduceXis || mProduceXiExtras || mProduceXiMasks || mProduceOmegas || mProduceOmegaMasks || mProduceOmegaExtras) { + if (mProduceXis || mProduceLiteXis || mProduceXiExtras || mProduceXiMasks || + mProduceOmegas || mProduceLiteOmegas || mProduceOmegaMasks || mProduceOmegaExtras) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -517,15 +608,15 @@ class CascadeBuilder collisionBuilder.template fillCollision(collisionProducts, col); auto bachelor = cascade.template bachelor_as(); - bachelorIndex = trackBuilder.template getDaughterIndex(bachelor, trackProducts, collisionProducts); + bachelorIndex = trackBuilder.template getDaughterIndex(bachelor, trackProducts, collisionBuilder); auto posDaughter = cascade.template posTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionBuilder); auto negDaughter = cascade.template negTrack_as(); - negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionBuilder); - fillCascade(collisionProducts, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); + fillCascade(collisionBuilder, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); } } @@ -551,30 +642,46 @@ class CascadeBuilder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); auto bachelor = cascade.template bachelor_as(); - bachelorIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, bachelor, trackProducts, mcParticles, mcBuilder, mcProducts); + bachelorIndex = trackBuilder.template getDaughterIndex(bachelor, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); auto posDaughter = cascade.template posTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, posDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); auto negDaughter = cascade.template negTrack_as(); - negDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, negDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); - fillCascade(collisionProducts, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); + fillCascade(collisionBuilder, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { - mcBuilder.template fillMcXiWithLabel(col, mcCols, cascade, mcParticles, mcProducts); + mcBuilder.template fillMcXiWithLabel(cascade, mcParticles, mcCols, mcProducts); } if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { - mcBuilder.template fillMcOmegaWithLabel(col, mcCols, cascade, mcParticles, mcProducts); + mcBuilder.template fillMcOmegaWithLabel(cascade, mcParticles, mcCols, mcProducts); } } } template - void fillCascade(T1& collisionProducts, T2& cascadeProducts, T3 const& cascade, T4 const& col, int bachelorIndex, int posDaughterIndex, int negDaughterIndex) + void fillCascade(T1& collisionBuilder, T2& cascadeProducts, T3 const& cascade, T4 const& col, int bachelorIndex, int posDaughterIndex, int negDaughterIndex) { + float strangeTofBachelor = 0.f; + float strangeTofPosDau = 0.f; + float strangeTofNegDau = 0.f; + const bool isMatter = cascade.sign() < 0; // Xi-/Omega- -> Lambda -> p pi- (pos=proton, neg=pion) + + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + strangeTofBachelor = cascade.tofNSigmaXiPi(); + strangeTofPosDau = isMatter ? cascade.tofNSigmaXiLaPr() : cascade.tofNSigmaXiLaPi(); + strangeTofNegDau = isMatter ? cascade.tofNSigmaXiLaPi() : cascade.tofNSigmaXiLaPr(); + } + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + strangeTofBachelor = cascade.tofNSigmaOmKa(); + strangeTofPosDau = isMatter ? cascade.tofNSigmaOmLaPr() : cascade.tofNSigmaOmLaPi(); + strangeTofNegDau = isMatter ? cascade.tofNSigmaOmLaPi() : cascade.tofNSigmaOmLaPr(); + } + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { if (mProduceXis) { - cascadeProducts.producedXis(collisionProducts.producedCollision.lastIndex(), + cascadeProducts.producedXis(collisionBuilder.collisionIndex(), cascade.sign() * cascade.pt(), cascade.eta(), cascade.phi(), @@ -583,6 +690,16 @@ class CascadeBuilder posDaughterIndex, negDaughterIndex); } + if (mProduceLiteXis) { + cascadeProducts.producedLiteXis(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binSignedPt(cascade.sign() * cascade.pt()), + o2::aod::femtobase::lite::binEta(cascade.eta()), + o2::aod::femtobase::lite::binPhi(cascade.phi()), + o2::aod::femtocascades::lite::binXiMass(cascade.mXi()), + bachelorIndex, + posDaughterIndex, + negDaughterIndex); + } if (mProduceXiMasks) { cascadeProducts.producedXiMasks(mCascadeSelection.getBitmask()); } @@ -596,12 +713,15 @@ class CascadeBuilder cascade.v0cosPA(col.posX(), col.posY(), col.posZ()), cascade.dcaV0daughters(), cascade.v0radius(), - cascade.dcav0topv(col.posX(), col.posY(), col.posZ())); + cascade.dcav0topv(col.posX(), col.posY(), col.posZ()), + strangeTofBachelor, + strangeTofPosDau, + strangeTofNegDau); } } if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { if (mProduceOmegas) { - cascadeProducts.producedOmegas(collisionProducts.producedCollision.lastIndex(), + cascadeProducts.producedOmegas(collisionBuilder.collisionIndex(), cascade.sign() * cascade.pt(), cascade.eta(), cascade.phi(), @@ -610,6 +730,16 @@ class CascadeBuilder posDaughterIndex, negDaughterIndex); } + if (mProduceLiteOmegas) { + cascadeProducts.producedLiteOmegas(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binSignedPt(cascade.sign() * cascade.pt()), + o2::aod::femtobase::lite::binEta(cascade.eta()), + o2::aod::femtobase::lite::binPhi(cascade.phi()), + o2::aod::femtocascades::lite::binOmegaMass(cascade.mOmega()), + bachelorIndex, + posDaughterIndex, + negDaughterIndex); + } if (mProduceOmegaMasks) { cascadeProducts.producedOmegaMasks(mCascadeSelection.getBitmask()); } @@ -623,20 +753,26 @@ class CascadeBuilder cascade.v0cosPA(col.posX(), col.posY(), col.posZ()), cascade.dcaV0daughters(), cascade.v0radius(), - cascade.dcav0topv(col.posX(), col.posY(), col.posZ())); + cascade.dcav0topv(col.posX(), col.posY(), col.posZ()), + strangeTofBachelor, + strangeTofPosDau, + strangeTofNegDau); } } } - bool fillAnyTable() { return mFillAnyTable; } + [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } + [[nodiscard]] bool isPassThrough() const { return mCascadeSelection.isPassThrough(); } private: CascadeSelection mCascadeSelection; bool mFillAnyTable = false; bool mProduceXis = false; + bool mProduceLiteXis = false; bool mProduceXiMasks = false; bool mProduceXiExtras = false; bool mProduceOmegas = false; + bool mProduceLiteOmegas = false; bool mProduceOmegaMasks = false; bool mProduceOmegaExtras = false; }; diff --git a/PWGCF/Femto/Core/cascadeHistManager.h b/PWGCF/Femto/Core/cascadeHistManager.h index 663abe12f98..2f0f88405ac 100644 --- a/PWGCF/Femto/Core/cascadeHistManager.h +++ b/PWGCF/Femto/Core/cascadeHistManager.h @@ -58,6 +58,9 @@ enum CascadeHist { kLambdaDauDca, kLambdaTransRadius, kLambdaDcaToPv, + kStrangeTofBachelor, + kStrangeTofPosDau, + kStrangeTofNegDau, // 2d qa kPtVsEta, kPtVsPhi, @@ -67,6 +70,9 @@ enum CascadeHist { kPtVsMassOmega, kPtVsMassLambda, kMassXiVsMassOmega, + kStrangeTofVsTofBachelor, + kStrangeTofVsTofPosDau, + kStrangeTofVsTofNegDau, // mc kOrigin, kPdg, @@ -122,6 +128,7 @@ struct ConfCascadeQaBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis lambdaDauDca{"lambdaDauDca", {{150, 0, 1.0}}, "DCA of lambda daughters at lambda decay vertex"}; o2::framework::ConfigurableAxis lambdaTransRadius{"lambdaTransRadius", {{100, 0, 100}}, "DCA of lambda daughters at lambda decay vertex"}; o2::framework::ConfigurableAxis lambdaDcaToPv{"lambdaDcaToPv", {{100, 0, 200}}, "DCA of lambda daughter from primary vertex"}; + o2::framework::ConfigurableAxis strangeTof{"strangeTof", {{500, -5, 5}}, "Strangeness TOF vs TOF Nsigma for bachelor/daughters"}; }; constexpr const char PrefixXiQaBinning[] = "XiQaBinning"; @@ -149,6 +156,9 @@ constexpr std::array, kCascadeHistLast> HistT {kLambdaDauDca, o2::framework::HistType::kTH1F, "hLambdaDauDca", "Daughter DCA at #Lambda decay vertex ; DCA_{#Lambda dau decay vertex} (cm); Entries"}, {kLambdaTransRadius, o2::framework::HistType::kTH1F, "hLambdaTransRadius", "Transverse radius of daughter #Lambda ; r_{xy,#Lambda dau} (cm); Entries"}, {kLambdaDcaToPv, o2::framework::HistType::kTH1F, "hLambdaDcaToPv", "DCA to primary vertex of daughter #Lambda ; DCA_{#Lambda} (cm); Entries"}, + {kStrangeTofBachelor, o2::framework::HistType::kTH1F, "hStrangeTofBachelor", "Strange TOF of bachelor ; n#sigma_{TOF, strange}; Entries"}, + {kStrangeTofPosDau, o2::framework::HistType::kTH1F, "hStrangeTofPosDau", "Strange TOF of positive Daughter ; n#sigma_{TOF, strange}; Entries"}, + {kStrangeTofNegDau, o2::framework::HistType::kTH1F, "hStrangeTofNegDau", "Strange TOF of negative Daughter ; n#sigma_{TOF, strange}; Entries"}, {kPtVsEta, o2::framework::HistType::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}) ; #eta"}, {kPtVsPhi, o2::framework::HistType::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}) ; #varphi"}, {kPhiVsEta, o2::framework::HistType::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi ; #eta"}, @@ -157,6 +167,9 @@ constexpr std::array, kCascadeHistLast> HistT {kPtVsMassOmega, o2::framework::HistType::kTH2F, "hPtVsMassOmega", "p_{T} vs mass #Omega; p_{T} (GeV/#it{c}); m_{#LambdaK} (GeV/#it{c}^{2})"}, {kPtVsMassLambda, o2::framework::HistType::kTH2F, "hPtVsMassLambda", "p_{T} vs mass daughter #Lambda; p_{T} (GeV/#it{c}); m_{#Lambda dau} (GeV/#it{c}^{2})"}, {kMassXiVsMassOmega, o2::framework::HistType::kTH2F, "hMassXiVsMassOmega", "mass #Xi vs mass #Omega; m_{#Lambda#pi} (GeV/#it{c}^{2}); m_{#LambdaK} (GeV/#it{c}^{2})"}, + {kStrangeTofVsTofBachelor, o2::framework::HistType::kTH2F, "hStrangeTofVsTofBachelor", "TOF_{Strange} vs TOF_{Tracking} of bachelor; n#sigma_{TOF, strange}; n#sigma_{TOF, tracking}"}, + {kStrangeTofVsTofPosDau, o2::framework::HistType::kTH2F, "hStrangeTofVsTofPosDau", "TOF_{Strange} vs TOF_{Tracking} of positive Daughter; n#sigma_{TOF, strange}; n#sigma_{TOF, tracking}"}, + {kStrangeTofVsTofNegDau, o2::framework::HistType::kTH2F, "hStrangeTofVsTofNegDau", "TOF_{Strange} vs TOF_{Tracking} of negative Daughter; n#sigma_{TOF, strange}; n#sigma_{TOF, tracking}"}, {kOrigin, o2::framework::HistType::kTH1F, "hOrigin", "Status Codes (=Origin); Status Code; Entries"}, {kPdg, o2::framework::HistType::kTH1F, "hPdg", "PDG Codes of reconstructed v0; PDG Code; Entries"}, {kPdgMother, o2::framework::HistType::kTH1F, "hPdgMother", "PDG Codes of mother of reconstructed v0; PDG Code; Entries"}, @@ -194,25 +207,31 @@ constexpr std::array, kCascadeHistLast> HistT {kPdgPartonicMother, {(conf).pdgCodes}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CASCADE_HIST_QA_MAP(confAnalysis, confQa) \ - {kCosPa, {(confQa).cosPa}}, \ - {kDecayDauDca, {(confQa).dauDcaAtDecay}}, \ - {kTransRadius, {(confQa).transRadius}}, \ - {kLambdaMass, {(confQa).lambdaMass}}, \ - {kLambdaCosPa, {(confQa).lambdaCosPa}}, \ - {kLambdaDauDca, {(confQa).lambdaDauDca}}, \ - {kLambdaTransRadius, {(confQa).lambdaTransRadius}}, \ - {kLambdaDcaToPv, {(confQa).lambdaDcaToPv}}, \ - {kPtVsEta, {(confAnalysis).pt, (confAnalysis).eta}}, \ - {kPtVsPhi, {(confAnalysis).pt, (confAnalysis).phi}}, \ - {kPhiVsEta, {(confAnalysis).phi, (confAnalysis).eta}}, \ - {kPtVsCosPa, {(confAnalysis).pt, (confQa).cosPa}}, \ - {kMassXi, {(confQa).massXi}}, \ - {kMassOmega, {(confQa).massOmega}}, \ - {kPtVsMassXi, {(confAnalysis).pt, (confQa).massXi}}, \ - {kPtVsMassOmega, {(confAnalysis).pt, (confQa).massOmega}}, \ - {kPtVsMassLambda, {(confAnalysis).pt, (confQa).lambdaMass}}, \ - {kMassXiVsMassOmega, {(confQa).massXi, (confQa).massOmega}}, +#define CASCADE_HIST_QA_MAP(confAnalysis, confQa) \ + {kCosPa, {(confQa).cosPa}}, \ + {kDecayDauDca, {(confQa).dauDcaAtDecay}}, \ + {kTransRadius, {(confQa).transRadius}}, \ + {kLambdaMass, {(confQa).lambdaMass}}, \ + {kLambdaCosPa, {(confQa).lambdaCosPa}}, \ + {kLambdaDauDca, {(confQa).lambdaDauDca}}, \ + {kLambdaTransRadius, {(confQa).lambdaTransRadius}}, \ + {kLambdaDcaToPv, {(confQa).lambdaDcaToPv}}, \ + {kStrangeTofBachelor, {(confQa).strangeTof}}, \ + {kStrangeTofPosDau, {(confQa).strangeTof}}, \ + {kStrangeTofNegDau, {(confQa).strangeTof}}, \ + {kPtVsEta, {(confAnalysis).pt, (confAnalysis).eta}}, \ + {kPtVsPhi, {(confAnalysis).pt, (confAnalysis).phi}}, \ + {kPhiVsEta, {(confAnalysis).phi, (confAnalysis).eta}}, \ + {kPtVsCosPa, {(confAnalysis).pt, (confQa).cosPa}}, \ + {kMassXi, {(confQa).massXi}}, \ + {kMassOmega, {(confQa).massOmega}}, \ + {kPtVsMassXi, {(confAnalysis).pt, (confQa).massXi}}, \ + {kPtVsMassOmega, {(confAnalysis).pt, (confQa).massOmega}}, \ + {kPtVsMassLambda, {(confAnalysis).pt, (confQa).lambdaMass}}, \ + {kMassXiVsMassOmega, {(confQa).massXi, (confQa).massOmega}}, \ + {kStrangeTofVsTofBachelor, {(confQa).strangeTof, (confQa).strangeTof}}, \ + {kStrangeTofVsTofPosDau, {(confQa).strangeTof, (confQa).strangeTof}}, \ + {kStrangeTofVsTofNegDau, {(confQa).strangeTof, (confQa).strangeTof}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define CASCADE_HIST_MC_QA_MAP(confAnalysis, confQa) \ @@ -431,28 +450,28 @@ class CascadeHistManager fillAnalysis(cascadeCandidate); } if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { - fillQa(cascadeCandidate); + fillQa(cascadeCandidate, bachelor, posDaughter, negDaughter); } } - template - void fill(T1 const& cascadeCandidate, T2 const& tracks, T3 const& mcParticles, T4 const& mcMothers, T5 const& mcPartonicMothers) + template + void fill(T1 const& cascadeCandidate, T2 const& tracks, T3 const& col, T4 const& mcParticles, T5 const& mcMothers, T6 const& mcPartonicMothers) { auto posDaughter = tracks.rawIteratorAt(cascadeCandidate.posDauId() - tracks.offset()); - mPosDauManager.template fill(posDaughter, tracks, mcParticles, mcMothers, mcPartonicMothers); + mPosDauManager.template fill(posDaughter, tracks, col, mcParticles, mcMothers, mcPartonicMothers); auto negDaughter = tracks.rawIteratorAt(cascadeCandidate.negDauId() - tracks.offset()); - mNegDauManager.template fill(negDaughter, tracks, mcParticles, mcMothers, mcPartonicMothers); + mNegDauManager.template fill(negDaughter, tracks, col, mcParticles, mcMothers, mcPartonicMothers); auto bachelor = tracks.rawIteratorAt(cascadeCandidate.bachelorId() - tracks.offset()); - mBachelorManager.template fill(bachelor, tracks, mcParticles, mcMothers, mcPartonicMothers); + mBachelorManager.template fill(bachelor, tracks, col, mcParticles, mcMothers, mcPartonicMothers); if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->fillAnalysis(cascadeCandidate); } if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { - this->fillQa(cascadeCandidate); + this->fillQa(cascadeCandidate, bachelor, negDaughter, posDaughter); } if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { - this->template fillMc(cascadeCandidate, mcParticles, mcMothers, mcPartonicMothers); + this->template fillMc(cascadeCandidate, col, mcParticles, mcMothers, mcPartonicMothers); } } @@ -496,6 +515,9 @@ class CascadeHistManager mHistogramRegistry->add(qaDir + getHistNameV2(kLambdaDcaToPv, HistTable), getHistDesc(kLambdaDcaToPv, HistTable), getHistType(kLambdaDcaToPv, HistTable), {cascadeSpecs.at(kLambdaDcaToPv)}); mHistogramRegistry->add(qaDir + getHistNameV2(kMassXi, HistTable), getHistDesc(kMassXi, HistTable), getHistType(kMassXi, HistTable), {cascadeSpecs.at(kMassXi)}); mHistogramRegistry->add(qaDir + getHistNameV2(kMassOmega, HistTable), getHistDesc(kMassOmega, HistTable), getHistType(kMassOmega, HistTable), {cascadeSpecs.at(kMassOmega)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofBachelor, HistTable), getHistDesc(kStrangeTofBachelor, HistTable), getHistType(kStrangeTofBachelor, HistTable), {cascadeSpecs.at(kStrangeTofBachelor)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofPosDau, HistTable), getHistDesc(kStrangeTofPosDau, HistTable), getHistType(kStrangeTofPosDau, HistTable), {cascadeSpecs.at(kStrangeTofPosDau)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofNegDau, HistTable), getHistDesc(kStrangeTofNegDau, HistTable), getHistType(kStrangeTofNegDau, HistTable), {cascadeSpecs.at(kStrangeTofNegDau)}); if (mPlot2d) { mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {cascadeSpecs.at(kPtVsEta)}); @@ -507,6 +529,9 @@ class CascadeHistManager mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsMassOmega, HistTable), getHistDesc(kPtVsMassOmega, HistTable), getHistType(kPtVsMassOmega, HistTable), {cascadeSpecs.at(kPtVsMassOmega)}); mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsMassLambda, HistTable), getHistDesc(kPtVsMassLambda, HistTable), getHistType(kPtVsMassLambda, HistTable), {cascadeSpecs.at(kPtVsMassLambda)}); mHistogramRegistry->add(qaDir + getHistNameV2(kMassXiVsMassOmega, HistTable), getHistDesc(kMassXiVsMassOmega, HistTable), getHistType(kMassXiVsMassOmega, HistTable), {cascadeSpecs.at(kMassXiVsMassOmega)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofVsTofBachelor, HistTable), getHistDesc(kStrangeTofVsTofBachelor, HistTable), getHistType(kStrangeTofVsTofBachelor, HistTable), {cascadeSpecs.at(kStrangeTofVsTofBachelor)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofVsTofPosDau, HistTable), getHistDesc(kStrangeTofVsTofPosDau, HistTable), getHistType(kStrangeTofVsTofPosDau, HistTable), {cascadeSpecs.at(kStrangeTofVsTofPosDau)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofVsTofNegDau, HistTable), getHistDesc(kStrangeTofVsTofNegDau, HistTable), getHistType(kStrangeTofVsTofNegDau, HistTable), {cascadeSpecs.at(kStrangeTofVsTofNegDau)}); } } @@ -562,19 +587,33 @@ class CascadeHistManager mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsMass, HistTable)), cascadeCandidate.pt(), cascadeCandidate.mass()); } - template - void fillQa(T const& cascadeCandidate) + template + void fillQa(T1 const& cascadeCandidate, T2 const& bachelor, T3 const& posDau, T4 const& negDau) { float massXi = 0.f; float massOmega = 0.f; + float tofBachelor = 0.f; + float tofPosDau = 0.f; + float tofNegDau = 0.f; if constexpr (modes::isEqual(cascade, modes::Cascade::kXi)) { massXi = cascadeCandidate.mass(); massOmega = cascadeCandidate.massOmega(); + tofBachelor = bachelor.tofNSigmaPi(); } if constexpr (modes::isEqual(cascade, modes::Cascade::kOmega)) { massXi = cascadeCandidate.massXi(); massOmega = cascadeCandidate.mass(); + tofBachelor = bachelor.tofNSigmaKa(); + } + + if (cascadeCandidate.sign() > 0) { + tofPosDau = posDau.tofNSigmaPr(); + tofNegDau = negDau.tofNSigmaPi(); + } else { + tofPosDau = posDau.tofNSigmaPi(); + tofNegDau = negDau.tofNSigmaPr(); } + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kCosPa, HistTable)), cascadeCandidate.cascadeCosPa()); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kDecayDauDca, HistTable)), cascadeCandidate.cascadeDauDca()); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kTransRadius, HistTable)), cascadeCandidate.cascadeTransRadius()); @@ -585,6 +624,9 @@ class CascadeHistManager mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kLambdaDcaToPv, HistTable)), cascadeCandidate.lambdaDcaToPv()); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kMassXi, HistTable)), massXi); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kMassOmega, HistTable)), massOmega); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofBachelor, HistTable)), cascadeCandidate.strangeTofBachelor()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofPosDau, HistTable)), cascadeCandidate.strangeTofPosDau()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofNegDau, HistTable)), cascadeCandidate.strangeTofNegDau()); if (mPlot2d) { mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsEta, HistTable)), cascadeCandidate.pt(), cascadeCandidate.eta()); @@ -595,11 +637,14 @@ class CascadeHistManager mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsMassOmega, HistTable)), cascadeCandidate.pt(), massOmega); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsMassLambda, HistTable)), cascadeCandidate.pt(), cascadeCandidate.lambdaMass()); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kMassXiVsMassOmega, HistTable)), massXi, massOmega); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofVsTofBachelor, HistTable)), cascadeCandidate.strangeTofBachelor(), tofBachelor); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofVsTofPosDau, HistTable)), cascadeCandidate.strangeTofPosDau(), tofPosDau); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofVsTofNegDau, HistTable)), cascadeCandidate.strangeTofNegDau(), tofNegDau); } } - template - void fillMc(T1 const& cascadeCandidate, T2 const& /*mcParticles*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/) + template + void fillMc(T1 const& cascadeCandidate, T2 const& col, T3 const& /*mcParticles*/, T4 const& /*mcMothers*/, T5 const& /*mcPartonicMothers*/) { // No MC Particle if (!cascadeCandidate.has_fMcParticle()) { @@ -614,17 +659,21 @@ class CascadeHistManager } // Retrieve MC particle - auto mcParticle = cascadeCandidate.template fMcParticle_as(); + auto mcParticle = cascadeCandidate.template fMcParticle_as(); + + // whether a particle is associated to a wrong collision or not cannot be known by the producer so we check it here + bool fromWrongCollision = mcParticle.fMcColId() != col.fMcColId(); - // missidentifed particles are special case // whether a particle is missidentfied or not cannot be known by the producer so we check it here bool isMissidentified = mcParticle.pdgCode() != mPdgCode; mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kTruePtVsPt, HistTable)), mcParticle.pt(), cascadeCandidate.pt()); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kTrueEtaVsEta, HistTable)), mcParticle.eta(), cascadeCandidate.eta()); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kTruePhiVsPhi, HistTable)), mcParticle.phi(), cascadeCandidate.phi()); - if (isMissidentified) { - mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kFromWrongCollision)); + } else if (isMissidentified) { + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); } else { mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), mcParticle.origin()); } @@ -632,7 +681,7 @@ class CascadeHistManager // get mother if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), mother.pdgCode()); } else { mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), 0); @@ -640,7 +689,7 @@ class CascadeHistManager // get partonic mother if (mcParticle.has_fMcPartMoth()) { - auto partonicMother = mcParticle.template fMcPartMoth_as(); + auto partonicMother = mcParticle.template fMcPartMoth_as(); mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), partonicMother.pdgCode()); } else { mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), 0); @@ -648,8 +697,9 @@ class CascadeHistManager if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { if (mPlotOrigins) { - // check first if particle is missidentified - if (isMissidentified) { + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kFromWrongCollision, HistTable)), cascadeCandidate.pt(), cascadeCandidate.cascadeCosPa()); + } else if (isMissidentified) { // if it is, we fill it as such mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(McDir) + HIST(getHistName(kMissidentified, HistTable)), cascadeCandidate.pt(), cascadeCandidate.cascadeCosPa()); } else { @@ -666,7 +716,7 @@ class CascadeHistManager break; case modes::McOrigin::kFromSecondaryDecay: if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); int motherPdgCode = std::abs(mother.pdgCode()); // Switch on PDG of the mother if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel1 && motherPdgCode == mPdgCodesSecondaryMother[0]) { diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h new file mode 100644 index 00000000000..628f392a380 --- /dev/null +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -0,0 +1,471 @@ +// Copyright 2019-2026 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 charmHadronBuilder.h +/// \brief charm hadron builder +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#ifndef PWGCF_FEMTO_CORE_CHARMHADRONBUILDER_H_ +#define PWGCF_FEMTO_CORE_CHARMHADRONBUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto::charmhadronbuilder +{ +// number of ML probability classes (background, prompt, non-prompt) provided by the HF ML selector +constexpr std::size_t NSizeMLScore{3u}; + +// filter applied in the producer task +struct ConfD0Filters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Filters"); + // kinematic windows + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 24.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.8f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + // rapidity acceptance (HF convention: y, not eta) + o2::framework::Configurable useYCut{"useYCut", true, "cut on y (true) or eta (false)"}; + o2::framework::Configurable yMin{"yMin", -0.8f, "Minimum rapidity"}; + o2::framework::Configurable yMax{"yMax", 0.8f, "Maximum rapidity"}; + // invariant-mass window + o2::framework::Configurable massMin{"massMin", 1.7f, "Minimum invariant mass for D0"}; + o2::framework::Configurable massMax{"massMax", 2.0f, "Maximum invariant mass for D0"}; + o2::framework::Configurable rejectAmbiguousHypothesis{"rejectAmbiguousHypothesis", false, "Reject candidates selected under both D0 and D0bar hypotheses"}; +}; + +// derived selection bits for D0s +struct ConfD0Bits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Bits"); + o2::framework::Configurable passThrough{"passThrough", false, "If true, all D0s are passed through. Bits for all selections are stored."}; + o2::framework::Configurable> cpaMin{"cpaMin", {0.9f}, "Minimum cosine of pointing angle"}; + o2::framework::Configurable> decayLengthMin{"decayLengthMin", {0.02f}, "Minimum decay length (cm)"}; + o2::framework::Configurable> impactParameterProductMax{"impactParameterProductMax", {0.f}, "Maximum product of prong impact parameters d0*d0 (cm^2)"}; + o2::framework::Configurable> cosThetaStarMax{"cosThetaStarMax", {1.f}, "Maximum |cos(theta*)| of the decay"}; +}; + +// base selection for analysis task for D0s +template +struct ConfD0Selection : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable pdgCodeAbs{"pdgCodeAbs", o2::constants::physics::Pdg::kD0, "PDG code (D0)"}; + o2::framework::Configurable sign{"sign", 0, "Particle sign (+1: D0; -1: D0bar; 0: both)"}; + o2::framework::Configurable ptMin{"ptMin", 1.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 3.f, "Maximum pT"}; + // acceptance is applied as a rapidity cut in the builder; the eta/phi windows + // are kept open and exist only to satisfy MAKE_D0_PARTITION + o2::framework::Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.8f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + // signal region; side-bands remain available in the derived data + o2::framework::Configurable massMin{"massMin", 1.81f, "Minimum invariant mass for D0"}; + o2::framework::Configurable massMax{"massMax", 1.922f, "Maximum invariant mass for D0"}; + o2::framework::Configurable mask{"mask", 0, "Bitmask for D0 selection"}; +}; + +constexpr const char PrefixD0Selection1[] = "D0Selection1"; +constexpr const char PrefixD0Selection2[] = "D0Selection2"; +using ConfD0Selection1 = ConfD0Selection; +using ConfD0Selection2 = ConfD0Selection; + +/// The different selections for D0s +enum D0Sels { + // topological selections + kCpaMin, ///< Min. CPA (cosine pointing angle) + kDecayLengthMin, ///< Min. decay length + kImpactParameterProductMax, ///< Max. product of prong impact parameters (d0*d0) + kCosThetaStarMax, ///< Max. |cos(theta*)| of the decay + + kD0SelsMax +}; + +constexpr char D0SelHistName[] = "hD0Selection"; +constexpr char D0barSelHistName[] = "hD0barSelection"; +constexpr char D0SelsName[] = "D0 selection object"; +const std::unordered_map d0SelectionNames = { + {kCpaMin, "Min. CPA (cosine pointing angle)"}, + {kDecayLengthMin, "Min. decay length"}, + {kImpactParameterProductMax, "Max. product of prong impact parameters (d0*d0)"}, + {kCosThetaStarMax, "Max. |cos(theta*)| of the decay"}}; + +/// enum for all D0 filters (loose kinematic pre-selection, applied before the bit selections) +enum D0Filters { + kDecayChannel, + kHypothesis, + kPtMin, + kPtMax, + kEtaMin, + kEtaMax, + kPhiMin, + kPhiMax, + kYMin, + kYMax, + kMassMin, + kMassMax, + kRejectAmbiguous, + kD0FiltersMax +}; + +constexpr char D0FilterHistName[] = "hD0Filters"; +constexpr char D0barFilterHistName[] = "hD0barFilters"; +const std::unordered_map d0FilterNames = { + {kDecayChannel, "D0 -> K pi decay channel"}, + {kHypothesis, "D0/D0bar hypothesis"}, + {kPtMin, "Minimum pT"}, + {kPtMax, "Maximum pT"}, + {kEtaMin, "Minimum eta"}, + {kEtaMax, "Maximum eta"}, + {kPhiMin, "Minimum phi"}, + {kPhiMax, "Maximum phi"}, + {kYMin, "Minimum rapidity"}, + {kYMax, "Maximum rapidity"}, + {kMassMin, "Minimum invariant mass"}, + {kMassMax, "Maximum invariant mass"}, + {kRejectAmbiguous, "Reject ambiguous D0/D0bar hypothesis"}}; + +template +class D0Selection : public baseselection::BaseSelection +{ + public: + D0Selection() = default; + ~D0Selection() override = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) + { + this->init(config.passThrough.value); + + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + mMassMin = filter.massMin.value; + mMassMax = filter.massMax.value; + mUseYCut = filter.useYCut.value; + mYMin = filter.yMin.value; + mYMax = filter.yMax.value; + mRejectAmbiguousHypothesis = filter.rejectAmbiguousHypothesis.value; + + this->addSelection(kCpaMin, d0SelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kDecayLengthMin, d0SelectionNames.at(kDecayLengthMin), config.decayLengthMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kImpactParameterProductMax, d0SelectionNames.at(kImpactParameterProductMax), config.impactParameterProductMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kCosThetaStarMax, d0SelectionNames.at(kCosThetaStarMax), config.cosThetaStarMax.value, limits::kAbsUpperLimit, true, true, false); + + this->template setupSelectionHistogram(registry); + this->template setupFilterHistogram( + registry, + { + {d0FilterNames.at(kDecayChannel), 1}, + {d0FilterNames.at(kHypothesis), 1}, + {d0FilterNames.at(kPtMin), mPtMin}, + {d0FilterNames.at(kPtMax), mPtMax}, + {d0FilterNames.at(kEtaMin), mEtaMin}, + {d0FilterNames.at(kEtaMax), mEtaMax}, + {d0FilterNames.at(kPhiMin), mPhiMin}, + {d0FilterNames.at(kPhiMax), mPhiMax}, + {d0FilterNames.at(kYMin), mYMin}, + {d0FilterNames.at(kYMax), mYMax}, + {d0FilterNames.at(kMassMin), mMassMin}, + {d0FilterNames.at(kMassMax), mMassMax}, + {d0FilterNames.at(kRejectAmbiguous), static_cast(mRejectAmbiguousHypothesis)}, + }); + } + + template + void applySelections(T1 const& d0candidate) + { + this->reset(); + this->evaluateObservable(kCpaMin, d0candidate.cpa()); + this->evaluateObservable(kDecayLengthMin, d0candidate.decayLength()); + this->evaluateObservable(kImpactParameterProductMax, d0candidate.impactParameter0() * d0candidate.impactParameter1()); + this->evaluateObservable(kCosThetaStarMax, mHfHelper.cosThetaStarD0(d0candidate)); + this->template assembleBitmask(); + } + + template + bool checkFilters(const T& d0candidate) const + { + bool pass = true; + bool p = false; + + // decay channel + p = (d0candidate.hfflag() & (1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) != 0; + this->template fillFilter(kDecayChannel, p); + pass &= p; + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + p = d0candidate.isSelD0(); + } else { + p = d0candidate.isSelD0bar(); + } + + this->template fillFilter(kHypothesis, p); + pass &= p; + + bool competing = false; + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + competing = d0candidate.isSelD0bar(); + } else { + competing = d0candidate.isSelD0(); + } + p = !mRejectAmbiguousHypothesis || !competing; + this->template fillFilter(kRejectAmbiguous, p); + pass &= p; + + p = d0candidate.pt() > mPtMin; + this->template fillFilter(kPtMin, p); + pass &= p; + + p = d0candidate.pt() < mPtMax; + this->template fillFilter(kPtMax, p); + pass &= p; + + p = d0candidate.eta() > mEtaMin; + this->template fillFilter(kEtaMin, p); + pass &= p; + + p = d0candidate.eta() < mEtaMax; + this->template fillFilter(kEtaMax, p); + pass &= p; + + p = d0candidate.phi() > mPhiMin; + this->template fillFilter(kPhiMin, p); + pass &= p; + + p = d0candidate.phi() < mPhiMax; + this->template fillFilter(kPhiMax, p); + pass &= p; + + // rapidity + if (mUseYCut) { + const float y = mHfHelper.yD0(d0candidate); + p = y > mYMin; + this->template fillFilter(kYMin, p); + pass &= p; + + p = y < mYMax; + this->template fillFilter(kYMax, p); + pass &= p; + } + + this->template fillFilterSummary(pass); + return this->isPassThrough() || pass; + } + + [[nodiscard]] float getMassMin() const + { + return mMassMin; + } + + [[nodiscard]] float getMassMax() const + { + return mMassMax; + } + + private: + HfHelper mHfHelper; + float mPtMin = 0.f; + float mPtMax = 24.f; + float mEtaMin = -0.8f; + float mEtaMax = 0.8f; + float mPhiMin = 0.f; + float mPhiMax = o2::constants::math::TwoPI; + float mMassMin = 1.7f; + float mMassMax = 2.0f; + bool mUseYCut = true; + float mYMin = -0.8f; + float mYMax = 0.8f; + bool mRejectAmbiguousHypothesis = false; +}; + +// tables produced by the D0 builder: kinematics, bitmask and QA +struct CharmHadronBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedD0s; + o2::framework::Produces producedD0Masks; + o2::framework::Produces producedD0Extras; +}; + +// per-table produce switches (-1: auto = produce only if a downstream device subscribes; 0 off; 1 on) +struct ConfD0Tables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Tables"); + o2::framework::Configurable produceD0s{"produceD0s", -1, "Produce D0s (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceD0Masks{"produceD0Masks", -1, "Produce D0Masks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceD0Extras{"produceD0Extras", -1, "Produce D0Extras (-1: auto; 0 off; 1 on)"}; +}; + +template +class CharmHadronBuilder +{ + public: + CharmHadronBuilder() = default; + ~CharmHadronBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + { + LOG(info) << "Initialize femto D0 builder..."; + mProduceD0s = utils::enableTable("FD0s_001", table.produceD0s.value, initContext); + mProduceD0Masks = utils::enableTable("FD0Masks_001", table.produceD0Masks.value, initContext); + mProduceD0Extras = utils::enableTable("FD0Extras_001", table.produceD0Extras.value, initContext); + + if (mProduceD0s || mProduceD0Masks || mProduceD0Extras) { + mFillAnyTable = true; + } else { + LOG(info) << "No D0 tables configured, selection object will not be configured..."; + return; + } + + mD0Selection.configure(registry, config, filter); + mD0Selection.printSelections(D0SelsName); + } + + template + void fillD0Tables(T1& collisionProducts, T2& d0Products, T3 const& candidate, + float signedPt, float mass, int64_t posDauIndex, int64_t negDauIndex) + { + if (mProduceD0s) { + d0Products.producedD0s(collisionProducts.producedCollision.lastIndex(), + signedPt, + candidate.eta(), + candidate.phi(), + mass, + posDauIndex, + negDauIndex); + } + if (mProduceD0Masks) { + d0Products.producedD0Masks(mD0Selection.getBitmask()); + } + if (mProduceD0Extras) { + d0Products.producedD0Extras( + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.impactParameter0() * candidate.impactParameter1(), + mHfHelper.cosThetaStarD0(candidate), + candidate.mlProbD0().size() < NSizeMLScore ? -1.f : candidate.mlProbD0()[0], + candidate.mlProbD0().size() < NSizeMLScore ? -1.f : candidate.mlProbD0()[1], + candidate.mlProbD0().size() < NSizeMLScore ? -1.f : candidate.mlProbD0()[2], + candidate.mlProbD0bar().size() < NSizeMLScore ? -1.f : candidate.mlProbD0bar()[0], + candidate.mlProbD0bar().size() < NSizeMLScore ? -1.f : candidate.mlProbD0bar()[1], + candidate.mlProbD0bar().size() < NSizeMLScore ? -1.f : candidate.mlProbD0bar()[2], + static_cast(candidate.isSelD0()), + static_cast(candidate.isSelD0bar())); + } + } + + template + void fillD0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, + T5& d0Products, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) + { + if (!mFillAnyTable) { + return; + } + int64_t posDauIndex = 0; + int64_t negDauIndex = 0; + for (const auto& candidate : candidates) { + if (!mD0Selection.checkFilters(candidate)) { + continue; + } + mD0Selection.applySelections(candidate); + if (!mD0Selection.passesAllRequiredSelections()) { + continue; + } + + collisionBuilder.template fillCollision(collisionProducts, col); + + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, collisionBuilder); + negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + this->fillD0Tables(collisionProducts, d0Products, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + } else { + this->fillD0Tables(collisionProducts, d0Products, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + } + } + } + + template + void fillMcD0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& mcCols, T5& trackProducts, + T6& d0Products, T7 const& candidates, T8 const& tracks, T9& trackBuilder, T10 const& mcParticles, T11& mcBuilder, T12& mcProducts) + { + if (!mFillAnyTable) { + return; + } + int64_t posDauIndex = 0; + int64_t negDauIndex = 0; + for (const auto& candidate : candidates) { + if (!mD0Selection.checkFilters(candidate)) { + continue; + } + + mD0Selection.applySelections(candidate); + if (!mD0Selection.passesAllRequiredSelections()) { + continue; + } + + collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); + + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + this->fillD0Tables(collisionProducts, d0Products, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + } else { + this->fillD0Tables(collisionProducts, d0Products, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + } + mcBuilder.template fillMcD0WithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); + } + } + + [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } + [[nodiscard]] bool isPassThrough() const { return mD0Selection.isPassThrough(); } + + private: + D0Selection mD0Selection; + HfHelper mHfHelper; + + bool mProduceD0s = false; + bool mProduceD0Masks = false; + bool mProduceD0Extras = false; + bool mFillAnyTable = false; +}; +} // namespace o2::analysis::femto::charmhadronbuilder + +#endif // PWGCF_FEMTO_CORE_CHARMHADRONBUILDER_H_ diff --git a/PWGCF/Femto/Core/charmHadronHistManager.h b/PWGCF/Femto/Core/charmHadronHistManager.h new file mode 100644 index 00000000000..544a4273d95 --- /dev/null +++ b/PWGCF/Femto/Core/charmHadronHistManager.h @@ -0,0 +1,501 @@ +// Copyright 2019-2026 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 charmHadronHistManager.h +/// \brief histogram manager for charm hadron histograms +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#ifndef PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackHistManager.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto::charmhadronhistmanager +{ +enum CharmHadronHist { + kPt, + kEta, + kPhi, + kMass, + kSign, + kPtVsMass, + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kMassD0, + kMassD0bar, + kMlBkg, + kMlPrompt, + kMlNonPrompt, + kCpa, + kCpaXY, + kDecayLength, + kDecayLengthXY, + kImpactParameterProduct, + kCosThetaStar, + + // mc + kOrigin, + kPdg, + kPdgMother, + kTruePtVsPt, + kTrueEtaVsEta, + kTruePhiVsPhi, + kPtVsOrigin, + + kCharmHadronHistLast +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_DEFAULT_BINNING(defaultMassMin, defaultMassMax) \ + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; \ + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; \ + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; \ + o2::framework::ConfigurableAxis mass{"mass", {{200, (defaultMassMin), (defaultMassMax)}}, "Mass"}; \ + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; \ + o2::framework::ConfigurableAxis charmHadrons{"charmHadrons", {{8001, -4000.5, 4000.5}}, "MC ONLY: CharmHadrons codes of reconstructed D0s"}; \ + o2::framework::ConfigurableAxis pt2d{"pt2d", {{240, 0, 6}}, "Pt for 2D QA"}; \ + o2::framework::ConfigurableAxis eta2d{"eta2d", {{200, -1.5, 1.5}}, "Eta for 2D QA"}; \ + o2::framework::ConfigurableAxis phi2d{"phi2d", {{200, 0, 1.f * o2::constants::math::TwoPI}}, "Phi for 2D QA"}; + +template +struct ConfD0Binning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + CHARMHADRON_DEFAULT_BINNING(1.7, 2.0) +}; + +#undef CHARMHADRON_DEFAULT_BINNING + +constexpr const char PrefixD0Binning1[] = "D0Binning1"; +constexpr const char PrefixD0Binning2[] = "D0Binning2"; +using ConfD0Binning1 = ConfD0Binning; +using ConfD0Binning2 = ConfD0Binning; + +template +struct ConfD0QaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable plotTopology{"plotTopology", true, "Generate topological QA plots (cpa, decayLength, impactParameterProduct, cosThetaStar)"}; + o2::framework::ConfigurableAxis massD0{"massD0", {{200, 1.7, 2.0}}, "Mass of candidates selected as D0"}; + o2::framework::ConfigurableAxis massD0bar{"massD0bar", {{200, 1.7, 2.0}}, "Mass of candidates selected as D0bar"}; + o2::framework::ConfigurableAxis mlScore{"mlScore", {{100, 0.f, 1.f}}, "BDT ML score (bkg/prompt/non-prompt)"}; + o2::framework::ConfigurableAxis cpa{"cpa", {{100, 0.9f, 1.f}}, "Cosine of pointing angle"}; + o2::framework::ConfigurableAxis decayLength{"decayLength", {{200, 0.f, 0.2f}}, "Decay length (cm)"}; + o2::framework::ConfigurableAxis impactParameterProduct{"impactParameterProduct", {{200, -0.001f, 0.001f}}, "Product of daughter impact parameters (cm^2)"}; + o2::framework::ConfigurableAxis cosThetaStar{"cosThetaStar", {{100, -1.f, 1.f}}, "Cosine of decay angle in D0 rest frame"}; +}; + +constexpr const char PrefixD0QaBinning1[] = "D0QaBinning1"; +using ConfD0QaBinning1 = ConfD0QaBinning; + +// must be in sync with enum CharmHadronHist +// the enum gives the correct index in the array +constexpr std::array, kCharmHadronHistLast> HistTable = { + {{kPt, o2::framework::HistType::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::HistType::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"}, + {kPhi, o2::framework::HistType::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kMass, o2::framework::HistType::kTH1F, "hMass", "Invariant Mass; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kSign, o2::framework::HistType::kTH1F, "hSign", "Sign (-1 -> D0bar, +1 -> D0); sign; Entries"}, + {kPtVsMass, o2::framework::HistType::kTH2F, "hPtVsMass", "Transverse momentum vs invariant mass; p_{T} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}, + {kPtVsEta, o2::framework::HistType::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}); #eta"}, + {kPtVsPhi, o2::framework::HistType::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}); #varphi"}, + {kPhiVsEta, o2::framework::HistType::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi; #eta"}, + {kMassD0, o2::framework::HistType::kTH1F, "hMassD0", "Invariant mass of D^{0} candidates; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kMassD0bar, o2::framework::HistType::kTH1F, "hMassD0bar", "Invariant mass of #bar{D}^{0} candidates; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kMlBkg, o2::framework::HistType::kTH1F, "hMlBkg", "BDT background score; ML score (bkg); Entries"}, + {kMlPrompt, o2::framework::HistType::kTH1F, "hMlPrompt", "BDT prompt score; ML score (prompt); Entries"}, + {kMlNonPrompt, o2::framework::HistType::kTH1F, "hMlNonPrompt", "BDT non-prompt score; ML score (non-prompt); Entries"}, + {kCpa, o2::framework::HistType::kTH1F, "hCpa", "Cosine of pointing angle; cos(#alpha); Entries"}, + {kCpaXY, o2::framework::HistType::kTH1F, "hCpaXY", "Cosine of pointing angle (XY); cos(#alpha)_{XY}; Entries"}, + {kDecayLength, o2::framework::HistType::kTH1F, "hDecayLength", "Decay length; L (cm); Entries"}, + {kDecayLengthXY, o2::framework::HistType::kTH1F, "hDecayLengthXY", "Decay length (XY); L_{XY} (cm); Entries"}, + {kImpactParameterProduct, o2::framework::HistType::kTH1F, "hImpactParameterProduct", "Product of daughter impact parameters; d_{0}^{K} #times d_{0}^{#pi} (cm^{2}); Entries"}, + {kCosThetaStar, o2::framework::HistType::kTH1F, "hCosThetaStar", "Cosine of decay angle in D0 rest frame; cos(#theta*); Entries"}, + {kOrigin, o2::framework::HistType::kTH1F, "hOrigin", "MC origin (prompt / non-prompt); origin; Entries"}, + {kPdg, o2::framework::HistType::kTH1F, "hPdg", "PDG code of matched generated particle; PDG code; Entries"}, + {kPdgMother, o2::framework::HistType::kTH1F, "hPdgMother", "PDG code of the mother; PDG code; Entries"}, + {kTruePtVsPt, o2::framework::HistType::kTH2F, "hTruePtVsPt", "True vs reconstructed p_{T}; p_{T,true} (GeV/#it{c}); p_{T} (GeV/#it{c})"}, + {kTrueEtaVsEta, o2::framework::HistType::kTH2F, "hTrueEtaVsEta", "True vs reconstructed #eta; #eta_{true}; #eta"}, + {kTruePhiVsPhi, o2::framework::HistType::kTH2F, "hTruePhiVsPhi", "True vs reconstructed #varphi; #varphi_{true}; #varphi"}, + {kPtVsOrigin, o2::framework::HistType::kTH2F, "hPtVsOrigin", "p_{T} vs MC origin; p_{T} (GeV/#it{c}); origin"}}, +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_HIST_ANALYSIS_MAP(conf) \ + {kPt, {(conf).pt}}, \ + {kEta, {(conf).eta}}, \ + {kPhi, {(conf).phi}}, \ + {kMass, {(conf).mass}}, \ + {kSign, {(conf).sign}}, \ + {kPtVsMass, {(conf).pt, (conf).mass}}, \ + {kPtVsEta, {(conf).pt2d, (conf).eta2d}}, \ + {kPtVsPhi, {(conf).pt2d, (conf).phi2d}}, \ + {kPhiVsEta, {(conf).phi2d, (conf).eta2d}}, + +template +auto makeD0HistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis)}; +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_HIST_MC_MAP(conf) \ + {kPdg, {(conf).charmHadrons}}, \ + {kPdgMother, {(conf).charmHadrons}}, \ + {kTruePtVsPt, {(conf).pt, (conf).pt}}, \ + {kTrueEtaVsEta, {(conf).eta, (conf).eta}}, \ + {kTruePhiVsPhi, {(conf).phi, (conf).phi}}, \ + {kPtVsOrigin, {(conf).pt2d}}, + +template +auto makeD0McHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis) + CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_HIST_QA_MAP(conf) \ + {kMassD0, {(conf).massD0}}, \ + {kMassD0bar, {(conf).massD0bar}}, \ + {kMlBkg, {(conf).mlScore}}, \ + {kMlPrompt, {(conf).mlScore}}, \ + {kMlNonPrompt, {(conf).mlScore}}, \ + {kCpa, {(conf).cpa}}, \ + {kCpaXY, {(conf).cpa}}, \ + {kDecayLength, {(conf).decayLength}}, \ + {kDecayLengthXY, {(conf).decayLength}}, \ + {kImpactParameterProduct, {(conf).impactParameterProduct}}, \ + {kCosThetaStar, {(conf).cosThetaStar}}, + +template +auto makeD0QaHistSpecMap(const T& confBinningQa) +{ + return std::map>{ + CHARMHADRON_HIST_QA_MAP(confBinningQa)}; +} + +template +auto makeD0McQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQa) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis) + CHARMHADRON_HIST_QA_MAP(confBinningQa) + CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; +} + +#undef CHARMHADRON_HIST_ANALYSIS_MAP +#undef CHARMHADRON_HIST_MC_MAP +#undef CHARMHADRON_HIST_QA_MAP + +// prefixes for the output directories in the histogram registry +constexpr char PrefixD01[] = "D01/"; +constexpr char PrefixD02[] = "D02/"; +constexpr char PrefixD0Qa[] = "D0QA/"; +constexpr std::string_view AnalysisDir = "Analysis/"; +constexpr std::string_view McDir = "MC/"; +constexpr std::string_view QaDir = "QA/"; + +/// \class CharmHadronHistManager +/// \brief Class for histogramming charm hadron properties +template +class CharmHadronHistManager +{ + public: + CharmHadronHistManager() = default; + ~CharmHadronHistManager() = default; + + // init for analysis + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& CharmHadronSpecs, + T const& ConfCharmHadronSelection, + std::map> const& Prong0Specs, + std::map> const& Prong1Specs) + { + mHistogramRegistry = registry; + mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value); + + auto [prong0PdgCodeAbs, prong1PdgCodeAbs] = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); + + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prong0PdgCodeAbs); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prong1PdgCodeAbs); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->initAnalysis(CharmHadronSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { + this->initMc(CharmHadronSpecs); + } + } + + // init for analysis and qa + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& CharmHadronSpecs, + std::map> const& CharmHadronQaSpecs, + T1 const& ConfCharmHadronSelection, + T2 const& ConfCharmHadronQaBinning, + std::map> const& Prong0Specs, + T3 const& ConfProng0BinningQa, + std::map> const& Prong1Specs, + T4 const& ConfProng1BinningQa) + { + mHistogramRegistry = registry; + mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value); + this->enableOptionalHistograms(ConfCharmHadronQaBinning); + + auto [prong0PdgCodeAbs, prong1PdgCodeAbs] = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); + + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prong0PdgCodeAbs, ConfProng0BinningQa); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prong1PdgCodeAbs, ConfProng1BinningQa); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->initAnalysis(CharmHadronSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + this->initQa(CharmHadronQaSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { + this->initMc(CharmHadronSpecs); + } + } + + template + void fill(T1 const& charmHadronCandidate, T2 const& tracks) + { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->fillAnalysis(charmHadronCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + this->fillQa(charmHadronCandidate); + } + } + + template + void fill(T1 const& charmHadronCandidate, T2 const& tracks, T3 const& col, T4 const& mcParticles, T5 const& mcMothers, T6 const& mcPartonicMothers) + { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->fillAnalysis(charmHadronCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + this->fillQa(charmHadronCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { + this->fillMc(charmHadronCandidate, mcParticles, mcMothers, mcPartonicMothers); + } + } + + private: + static constexpr int AbsCharge = 1; + static constexpr int SignPlus = 1; + static constexpr int SignMinus = -1; + + // charge of the prongs is fixed by the PWGHF reconstruction: prong0 is the positive + // daughter, prong1 the negative one. The D0/D0bar hypothesis only swaps which prong is + // the pion and which is the kaon, not their charge. + std::pair resolveProngPdgCodes(int sign) + { + if (mPdgCode != o2::constants::physics::Pdg::kD0) { + LOG(fatal) << "PDG code for charm hadron has to be D0"; + } + if (sign > 0) { + // D0 -> pi+ K- + return {std::abs(PDG_t::kPiPlus), std::abs(PDG_t::kKMinus)}; + } + // D0bar -> K+ pi- + mPdgCode = -1 * mPdgCode; // switch sign for D0bar + return {std::abs(PDG_t::kKPlus), std::abs(PDG_t::kPiMinus)}; + } + + template + void enableOptionalHistograms(T const& ConfCharmHadronQaBinning) + { + mPlotTopology = ConfCharmHadronQaBinning.plotTopology.value; + } + + void initAnalysis(std::map> const& CharmHadronSpecs) + { + std::string analysisDir = std::string(charmHadronPrefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {CharmHadronSpecs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {CharmHadronSpecs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {CharmHadronSpecs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {CharmHadronSpecs.at(kMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {CharmHadronSpecs.at(kSign)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsMass, HistTable), getHistDesc(kPtVsMass, HistTable), getHistType(kPtVsMass, HistTable), {CharmHadronSpecs.at(kPtVsMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {CharmHadronSpecs.at(kPtVsEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {CharmHadronSpecs.at(kPtVsPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {CharmHadronSpecs.at(kPhiVsEta)}); + } + + template + void fillAnalysis(T const& charmHadronCandidate) + { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), charmHadronCandidate.pt()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), charmHadronCandidate.eta()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), charmHadronCandidate.phi()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), charmHadronCandidate.mass()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), charmHadronCandidate.sign()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsMass, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.mass()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsEta, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.eta()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsPhi, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.phi()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhiVsEta, HistTable)), charmHadronCandidate.phi(), charmHadronCandidate.eta()); + } + + void initQa(std::map> const& CharmHadronQaSpecs) + { + std::string qaDir = std::string(charmHadronPrefix) + std::string(QaDir); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0, HistTable), getHistDesc(kMassD0, HistTable), getHistType(kMassD0, HistTable), {CharmHadronQaSpecs.at(kMassD0)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0bar, HistTable), getHistDesc(kMassD0bar, HistTable), getHistType(kMassD0bar, HistTable), {CharmHadronQaSpecs.at(kMassD0bar)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMlBkg, HistTable), getHistDesc(kMlBkg, HistTable), getHistType(kMlBkg, HistTable), {CharmHadronQaSpecs.at(kMlBkg)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMlPrompt, HistTable), getHistDesc(kMlPrompt, HistTable), getHistType(kMlPrompt, HistTable), {CharmHadronQaSpecs.at(kMlPrompt)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMlNonPrompt, HistTable), getHistDesc(kMlNonPrompt, HistTable), getHistType(kMlNonPrompt, HistTable), {CharmHadronQaSpecs.at(kMlNonPrompt)}); + + if (mPlotTopology) { + mHistogramRegistry->add(qaDir + getHistNameV2(kCpa, HistTable), getHistDesc(kCpa, HistTable), getHistType(kCpa, HistTable), {CharmHadronQaSpecs.at(kCpa)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCpaXY, HistTable), getHistDesc(kCpaXY, HistTable), getHistType(kCpaXY, HistTable), {CharmHadronQaSpecs.at(kCpaXY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayLength, HistTable), getHistDesc(kDecayLength, HistTable), getHistType(kDecayLength, HistTable), {CharmHadronQaSpecs.at(kDecayLength)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayLengthXY, HistTable), getHistDesc(kDecayLengthXY, HistTable), getHistType(kDecayLengthXY, HistTable), {CharmHadronQaSpecs.at(kDecayLengthXY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kImpactParameterProduct, HistTable), getHistDesc(kImpactParameterProduct, HistTable), getHistType(kImpactParameterProduct, HistTable), {CharmHadronQaSpecs.at(kImpactParameterProduct)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCosThetaStar, HistTable), getHistDesc(kCosThetaStar, HistTable), getHistType(kCosThetaStar, HistTable), {CharmHadronQaSpecs.at(kCosThetaStar)}); + } + } + + void initMc(std::map> const& CharmHadronSpecs) + { + std::string mcDir = std::string(charmHadronPrefix) + std::string(McDir); + + const o2::framework::AxisSpec axisOrigin = {static_cast(modes::McOrigin::kMcOriginLast), -0.5, static_cast(modes::McOrigin::kMcOriginLast) - 0.5}; + mHistogramRegistry->add(mcDir + getHistNameV2(kOrigin, HistTable), getHistDesc(kOrigin, HistTable), getHistType(kOrigin, HistTable), {axisOrigin}); + mHistogramRegistry->get(HIST(charmHadronPrefix) + HIST(McDir) + HIST(histmanager::getHistName(kOrigin, HistTable)))->GetXaxis()->SetBinLabel(1 + static_cast(modes::McOrigin::kPrompt), modes::mcOriginToString(modes::McOrigin::kPrompt)); + mHistogramRegistry->get(HIST(charmHadronPrefix) + HIST(McDir) + HIST(histmanager::getHistName(kOrigin, HistTable)))->GetXaxis()->SetBinLabel(1 + static_cast(modes::McOrigin::kNonPrompt), modes::mcOriginToString(modes::McOrigin::kNonPrompt)); + + mHistogramRegistry->add(mcDir + getHistNameV2(kPdg, HistTable), getHistDesc(kPdg, HistTable), getHistType(kPdg, HistTable), {CharmHadronSpecs.at(kPdg)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kPdgMother, HistTable), getHistDesc(kPdgMother, HistTable), getHistType(kPdgMother, HistTable), {CharmHadronSpecs.at(kPdgMother)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePtVsPt, HistTable), getHistDesc(kTruePtVsPt, HistTable), getHistType(kTruePtVsPt, HistTable), {CharmHadronSpecs.at(kTruePtVsPt)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueEtaVsEta, HistTable), getHistDesc(kTrueEtaVsEta, HistTable), getHistType(kTrueEtaVsEta, HistTable), {CharmHadronSpecs.at(kTrueEtaVsEta)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePhiVsPhi, HistTable), getHistDesc(kTruePhiVsPhi, HistTable), getHistType(kTruePhiVsPhi, HistTable), {CharmHadronSpecs.at(kTruePhiVsPhi)}); + std::vector ptVsOriginAxes = CharmHadronSpecs.at(kPtVsOrigin); + ptVsOriginAxes.push_back(axisOrigin); + mHistogramRegistry->add(mcDir + getHistNameV2(kPtVsOrigin, HistTable), getHistDesc(kPtVsOrigin, HistTable), getHistType(kPtVsOrigin, HistTable), ptVsOriginAxes); + } + + template + void fillQa(T const& charmHadronCandidate) + { + // invariant mass split by hypothesis: D0 (sign > 0) or D0bar (sign < 0) + if (charmHadronCandidate.sign() > 0) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0, HistTable)), charmHadronCandidate.mass()); + } else { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0bar, HistTable)), charmHadronCandidate.mass()); + } + + // BDT scores of the accepted hypothesis: D0 (sign > 0) or D0bar (sign < 0) + float mlBkg = 0.f; + float mlPrompt = 0.f; + float mlNonPrompt = 0.f; + if (charmHadronCandidate.sign() > 0) { + mlBkg = charmHadronCandidate.mlProbD0Bkg(); + mlPrompt = charmHadronCandidate.mlProbD0Prompt(); + mlNonPrompt = charmHadronCandidate.mlProbD0NonPrompt(); + } else { + mlBkg = charmHadronCandidate.mlProbD0barBkg(); + mlPrompt = charmHadronCandidate.mlProbD0barPrompt(); + mlNonPrompt = charmHadronCandidate.mlProbD0barNonPrompt(); + } + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlBkg, HistTable)), mlBkg); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlPrompt, HistTable)), mlPrompt); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlNonPrompt, HistTable)), mlNonPrompt); + + // topological variables PWGHF selects on + if (mPlotTopology) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCpa, HistTable)), charmHadronCandidate.cpa()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCpaXY, HistTable)), charmHadronCandidate.cpaXY()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kDecayLength, HistTable)), charmHadronCandidate.decayLength()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kDecayLengthXY, HistTable)), charmHadronCandidate.decayLengthXY()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kImpactParameterProduct, HistTable)), charmHadronCandidate.impactParameterProduct()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCosThetaStar, HistTable)), charmHadronCandidate.cosThetaStar()); + } + } + + template + void fillMc(T1 const& charmHadronCandidate, T2 const& /*mcParticles*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/) + { + // no matched generated particle: reconstructed, but not a true D0 + if (!charmHadronCandidate.has_fMcParticle()) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdg, HistTable)), 0); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kNoMcParticle)); + return; + } + + auto mcParticle = charmHadronCandidate.template fMcParticle_as(); + + // resolution: generated vs reconstructed kinematics + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kTruePtVsPt, HistTable)), mcParticle.pt(), charmHadronCandidate.pt()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kTrueEtaVsEta, HistTable)), mcParticle.eta(), charmHadronCandidate.eta()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kTruePhiVsPhi, HistTable)), mcParticle.phi(), charmHadronCandidate.phi()); + + // origin is resolved to prompt / non-prompt in the mc builder + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), mcParticle.origin()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPtVsOrigin, HistTable)), charmHadronCandidate.pt(), mcParticle.origin()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdg, HistTable)), mcParticle.pdgCode()); + + // pdg of the mother, i.e. the beauty hadron for non-prompt D0s + if (mcParticle.has_fMcMother()) { + auto mother = mcParticle.template fMcMother_as(); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), mother.pdgCode()); + } else { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), 0); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + int mPdgCode = 0; + bool mPlotTopology = true; + + trackhistmanager::TrackHistManager mProng0Manager; + trackhistmanager::TrackHistManager mProng1Manager; +}; +}; // namespace o2::analysis::femto::charmhadronhistmanager +#endif // PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h index 70b6a547be4..9460fad49dc 100644 --- a/PWGCF/Femto/Core/closePairRejection.h +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -83,6 +83,9 @@ struct ConfCpr : o2::framework::ConfigurableGroup { constexpr const char PrefixCprTrackTrack[] = "CprTrackTrack"; constexpr const char PrefixCprTrackV0Daughter[] = "CprTrackV0Daughter"; +constexpr const char PrefixCprTrackD0Daughter[] = "CprTrackD0Daughter"; +constexpr const char PrefixCprD0DaughterD0DaughterPos[] = "CprD0DaughterD0DaughterPos"; +constexpr const char PrefixCprD0DaughterD0DaughterNeg[] = "CprD0DaughterD0DaughterNeg"; constexpr const char PrefixCprTrackResonanceDaughter[] = "CprTrackResonanceDaughter"; constexpr const char PrefixCprTrackKinkDaughter[] = "CprTrackKinkDaughter"; constexpr const char PrefixCprV0DaughterV0DaughterPos[] = "CprV0DaughterV0DaughterPos"; @@ -94,6 +97,9 @@ constexpr const char PrefixCprTrackCascadeBachelor[] = "CprTrackCascadeBachelor" // pairs using ConfCprTrackTrack = ConfCpr; using ConfCprTrackV0Daughter = ConfCpr; +using ConfCprTrackD0Daughter = ConfCpr; +using ConfCprD0DaugherD0DaughterPos = ConfCpr; +using ConfCprD0DaugherD0DaughterNeg = ConfCpr; using ConfCprTrackResonanceDaughter = ConfCpr; using ConfCprTrackKinkDaughter = ConfCpr; using ConfCprV0DaugherV0DaughterPos = ConfCpr; @@ -111,6 +117,12 @@ constexpr char PrefixTrackTrackSe[] = "CPR_TrackTrack/SE/"; constexpr char PrefixTrackTrackMe[] = "CPR_TrackTrack/ME/"; constexpr char PrefixTrackV0DaughterSe[] = "CPR_TrackV0Dau/SE/"; constexpr char PrefixTrackV0DaughterMe[] = "CPR_TrackV0Dau/ME/"; +constexpr char PrefixTrackD0DaughterSe[] = "CPR_TrackD0Dau/SE/"; +constexpr char PrefixTrackD0DaughterMe[] = "CPR_TrackD0Dau/ME/"; +constexpr char PrefixD0D0PosSe[] = "CPR_D0D0_PosDau/SE/"; +constexpr char PrefixD0D0NegSe[] = "CPR_D0D0_NegDau/SE/"; +constexpr char PrefixD0D0PosMe[] = "CPR_D0D0_PosDau/ME/"; +constexpr char PrefixD0D0NegMe[] = "CPR_D0D0_NegDau/ME/"; constexpr char PrefixV0V0PosSe[] = "CPR_V0V0_PosDau/SE/"; constexpr char PrefixV0V0NegSe[] = "CPR_V0V0_NegDau/SE/"; constexpr char PrefixV0V0PosMe[] = "CPR_V0V0_PosDau/ME/"; diff --git a/PWGCF/Femto/Core/collisionBuilder.h b/PWGCF/Femto/Core/collisionBuilder.h index 7080ed19286..e65714f754a 100644 --- a/PWGCF/Femto/Core/collisionBuilder.h +++ b/PWGCF/Femto/Core/collisionBuilder.h @@ -25,6 +25,7 @@ #include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/Zorro.h" #include @@ -33,6 +34,10 @@ #include #include +#include + +#include + #include #include #include @@ -80,6 +85,8 @@ struct ConfCollisionBits : o2::framework::ConfigurableGroup { o2::framework::Configurable> sphericityMin{"sphericityMin", {}, "Minimum sphericity"}; o2::framework::Configurable> sphericityMax{"sphericityMax", {}, "Maximum sphericity"}; o2::framework::Configurable> triggers{"triggers", {}, "List of all triggers to be used"}; + o2::framework::Configurable qvecDetector{"qvecDetector", 0, "Detector used to estimate the Q-vector: 0 -> FT0C, 1 -> FT0A"}; + o2::framework::Configurable qvecHarmonic{"qvecHarmonic", 2, "Harmonic n of the Q-vector and event plane angle Psi_n: 1 -> direct, 2 -> elliptic, 3 -> triangular"}; }; struct ConfCcdb : o2::framework::ConfigurableGroup { @@ -240,6 +247,10 @@ class CollisionSelection : public baseselection::BaseSelection(config.qvecDetector.value); + mQvecHarmonic = static_cast(config.qvecHarmonic.value); + this->addSelection(kSel8, collisionSelectionNames.at(kSel8), config.sel8.value); this->addSelection(kNoSameBunchPileUp, collisionSelectionNames.at(kNoSameBunchPileUp), config.noSameBunchPileup.value); this->addSelection(kIsVertexItsTpc, collisionSelectionNames.at(kIsVertexItsTpc), config.isVertexItsTpc.value); @@ -345,6 +356,35 @@ class CollisionSelection : public baseselection::BaseSelection + void setQvector(T const& col) + { + switch (mQvecDetector) { + case modes::QvecDetector::kFT0C: + mQvec = std::hypot(col.qvecFT0CReVec()[0], col.qvecFT0CImVec()[0]) * std::sqrt(col.sumAmplFT0C()); + break; + case modes::QvecDetector::kFT0A: + mQvec = std::hypot(col.qvecFT0AReVec()[0], col.qvecFT0AImVec()[0]) * std::sqrt(col.sumAmplFT0A()); + break; + } + } + [[nodiscard]] float getQvector() const { return mQvec; } + + template + void setEventPlane(T const& col) + { + float harmonic = static_cast(mQvecHarmonic); + switch (mQvecDetector) { + case modes::QvecDetector::kFT0C: + mEventPlane = RecoDecay::constrainAngle((std::atan2(col.qvecFT0CImVec()[0], col.qvecFT0CReVec()[0])) / harmonic, 0, harmonic); // constrain between 0 and 2pi/harmonic + break; + case modes::QvecDetector::kFT0A: + mEventPlane = RecoDecay::constrainAngle((std::atan2(col.qvecFT0AImVec()[0], col.qvecFT0AReVec()[0])) / harmonic, 0, harmonic); // constrain between 0 and 2pi/harmonic + break; + } + } + [[nodiscard]] float getEventPlane() const { return mEventPlane; } + /// \brief Evaluate all pre-filters (kinematics, quality, RCT flags) for a collision candidate, /// filling one filter-histogram bin per bound plus the "All analyzed"/"All passed" summary bins. template @@ -415,6 +455,7 @@ class CollisionSelection : public baseselection::BaseSelectionevaluateObservable(kIsGoodZvtxFt0VsPv, static_cast(col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))); this->evaluateObservable(kNoCollInTimeRangeNarrow, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow))); this->evaluateObservable(kNoCollInTimeRangeStrict, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict))); + this->evaluateObservable(kNoCollInTimeRangeStandard, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))); this->evaluateObservable(kNoCollInRofStrict, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInRofStrict))); this->evaluateObservable(kNoCollInRofStandard, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInRofStandard))); this->evaluateObservable(kNoHighMultCollInPrevRof, static_cast(col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof))); @@ -487,6 +528,11 @@ class CollisionSelection : public baseselection::BaseSelection producedCollision; + o2::framework::Produces producedLiteCollision; o2::framework::Produces producedCollisionMask; o2::framework::Produces producedPositions; o2::framework::Produces producedSphericities; o2::framework::Produces producedMultiplicityEstimators; o2::framework::Produces producedCentralityEstimators; - o2::framework::Produces producedQns; + o2::framework::Produces producedShapes; }; struct ConfCollisionTables : o2::framework::ConfigurableGroup { std::string prefix = std::string("CollisionTables"); o2::framework::Configurable produceCollisions{"produceCollisions", -1, "Produce Collisions (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteCollisions{"produceLiteCollisions", -1, "Produce Lite Collisions (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceCollisionMasks{"produceCollisionMasks", -1, "Produce Collision Masks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producePositions{"producePositions", -1, "Produce Positions (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSphericities{"produceSphericities", -1, "Produce Sphericity (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceMults{"produceMults", -1, "Produce Multiplicities (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceCents{"produceCents", -1, "Produce Centralities (-1: auto; 0 off; 1 on)"}; - o2::framework::Configurable produceQns{"produceQns", -1, "Produce Qn (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceShapes{"produceShapes", -1, "Produce Event shape variables (-1: auto; 0 off; 1 on)"}; }; template @@ -536,13 +584,23 @@ class CollisionBuilder mSubGeneratorId = confFilter.subGeneratorId.value; mProducedCollisions = utils::enableTable("FCols_001", confTable.produceCollisions.value, initContext); + mProducedLiteCollisions = utils::enableTable("FLiteCols_001", confTable.produceLiteCollisions.value, initContext); mProducedCollisionMasks = utils::enableTable("FColMasks_001", confTable.produceCollisionMasks.value, initContext); mProducedPositions = utils::enableTable("FColPos_001", confTable.producePositions.value, initContext); mProducedSphericities = utils::enableTable("FColSphericities_001", confTable.produceSphericities.value, initContext); mProducedMultiplicities = utils::enableTable("FColMults_001", confTable.produceMults.value, initContext); mProducedCentralities = utils::enableTable("FColCents_001", confTable.produceCents.value, initContext); - mProduceQns = utils::enableTable("FColQnBins_001", confTable.produceQns.value, initContext); - if (mProducedCollisions || mProducedCollisionMasks || mProducedPositions || mProducedSphericities || mProducedMultiplicities || mProducedCentralities) { + mProducedShapes = utils::enableTable("FColShapes_001", confTable.produceShapes.value, initContext); + + if (mProducedCollisions && mProducedLiteCollisions) { + LOG(fatal) << "FCols and FLiteCols are mutually exclusive -- enable only one. " + << "FLiteCols is meant to only replace FCols at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FCols from FLiteCols downstream."; + } + + if (mProducedCollisions || mProducedLiteCollisions || mProducedCollisionMasks || + mProducedPositions || mProducedSphericities || mProducedMultiplicities || + mProducedCentralities) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -556,7 +614,7 @@ class CollisionBuilder } template - void initCollision(T1& bc, T2& col, T3& tracks, T4& ccdb, T5& histRegistry) + void initCollision(T1 const& bc, T2 const& col, T3 const& tracks, T4& ccdb, T5& histRegistry) { if (mRunNumber != bc.runNumber()) { mRunNumber = bc.runNumber(); @@ -581,6 +639,11 @@ class CollisionBuilder mCollisionSelection.template setMultiplicity(col); mCollisionSelection.template setCentrality(col); + if constexpr (utils::HasQvectors) { + mCollisionSelection.template setQvector(col); + mCollisionSelection.template setEventPlane(col); + } + std::vector triggerDecisions = mCollisionSelection.getTriggerDecisions(bc.globalBC()); mCollisionSelection.applySelections(col, triggerDecisions); @@ -589,6 +652,9 @@ class CollisionBuilder template bool checkCollision(T1 const& col) { + if (!mFillAnyTable) { + return false; // selection object was never configured, nothing to check or fill + } return mCollisionSelection.checkFilters(col) && mCollisionSelection.passesAllRequiredSelections(); } @@ -596,6 +662,9 @@ class CollisionBuilder template bool checkCollision(T1 const& col, T2 const& /*mcCols*/) { + if (!mFillAnyTable) { + return false; // selection object was never configured, nothing to check or fill + } // check sub generator id of associated generated collision if (mSubGeneratorId >= 0) { if (col.has_mcCollision()) { @@ -616,17 +685,25 @@ class CollisionBuilder if (!mFillAnyTable) { return; } - if (mCollisionAlreadyFilled) { return; } - if (mProducedCollisions) { collisionProducts.producedCollision(col.posZ(), col.multNTracksPV(), mCollisionSelection.getCentrality(), static_cast(mCollisionSelection.getMagneticField())); + + mCurrentCollisionIndex = collisionProducts.producedCollision.lastIndex(); } + if (mProducedLiteCollisions) { + collisionProducts.producedLiteCollision(o2::aod::femtocollisions::lite::binPosZ(col.posZ()), + o2::aod::femtocollisions::lite::binMult(col.multNTracksPV()), + o2::aod::femtocollisions::lite::binCent(mCollisionSelection.getCentrality()), + static_cast(mCollisionSelection.getMagneticField())); + mCurrentCollisionIndex = collisionProducts.producedLiteCollision.lastIndex(); + } + if (mProducedCollisionMasks) { collisionProducts.producedCollisionMask(mCollisionSelection.getBitmask()); } @@ -647,18 +724,18 @@ class CollisionBuilder col.ft0cOccupancyInTimeRange()); } - // TODO: enable later for better QA - // if (mProducedCentralities) { - // collisionProducts.producedCentralityEstimators( - // col.centFT0A(), - // col.centFT0C()); - // } - // PbPb specific columns - // if constexpr (modes::isFlagSet(system, modes::System::kPbPb)) { - // if (mProduceQns) { - // collisionProducts.producedQns(utils::qn(col)); - // } - // } + if (mProducedCentralities) { + collisionProducts.producedCentralityEstimators( + col.centFT0A(), + col.centFT0C(), + col.centFT0M()); + } + + if (mProducedShapes) { + collisionProducts.producedShapes( + mCollisionSelection.getQvector(), + mCollisionSelection.getEventPlane()); + } mCollisionAlreadyFilled = true; } @@ -670,14 +747,25 @@ class CollisionBuilder return; } this->template fillCollision(collisionProducts, col); - mcBuilder.template fillMcCollisionWithLabel(mcProducts, col, mcCols); + mcBuilder.template fillMcCollisionWithLabel(col, mcCols, mcProducts); + } + + [[nodiscard]] int64_t collisionIndex() const { return mCurrentCollisionIndex; } + void reset() + { + mCollisionAlreadyFilled = false; + mCurrentCollisionIndex = -1; } - void reset() { mCollisionAlreadyFilled = false; } + [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } + [[nodiscard]] bool isPassThrough() const { return mCollisionSelection.isPassThrough(); } + [[nodiscard]] bool producingCollisions() const { return mProducedCollisions; } + [[nodiscard]] bool producingLiteCollisions() const { return mProducedLiteCollisions; } private: CollisionSelection mCollisionSelection; bool mCollisionAlreadyFilled = false; + int64_t mCurrentCollisionIndex = -1; int mRunNumber = -1; std::string mGrpPath = std::string(""); int mMagFieldForced = 0; @@ -685,12 +773,13 @@ class CollisionBuilder int mSubGeneratorId = -1; bool mFillAnyTable = false; bool mProducedCollisions = false; + bool mProducedLiteCollisions = false; bool mProducedCollisionMasks = false; bool mProducedPositions = false; bool mProducedSphericities = false; bool mProducedMultiplicities = false; bool mProducedCentralities = false; - bool mProduceQns = false; + bool mProducedShapes = false; }; struct CollisionBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { diff --git a/PWGCF/Femto/Core/collisionHistManager.h b/PWGCF/Femto/Core/collisionHistManager.h index 338da0ac63c..87d4507021d 100644 --- a/PWGCF/Femto/Core/collisionHistManager.h +++ b/PWGCF/Femto/Core/collisionHistManager.h @@ -16,14 +16,17 @@ #ifndef PWGCF_FEMTO_CORE_COLLISIONHISTMANAGER_H_ #define PWGCF_FEMTO_CORE_COLLISIONHISTMANAGER_H_ +#include "PWGCF/Femto/Core/femtoUtils.h" #include "PWGCF/Femto/Core/histManager.h" #include "PWGCF/Femto/Core/modes.h" +#include #include #include #include #include +#include #include #include #include @@ -48,6 +51,10 @@ enum ColHist { kCentVsMult, kCentVsSphericity, kMultVsSphericity, + kFT0AvsFT0C, + // event shape + kQvector, + kEventPlaneAngle, // mc kTruePosZ, // pure mc-truth, no reco collision (kMc without kReco) kTrueCent, // pure mc-truth, no reco collision (kMc without kReco) @@ -80,6 +87,10 @@ constexpr std::array, kColHistLast> HistTable = { {kCentVsMult, o2::framework::HistType::kTH2F, "hCentVsMult", "Centrality vs Multiplicity; Centrality (%); Multiplicity"}, {kMultVsSphericity, o2::framework::HistType::kTH2F, "hMultVsSphericity", "Multiplicity vs Sphericity; Multiplicity; Sphericity"}, {kCentVsSphericity, o2::framework::HistType::kTH2F, "hCentVsSphericity", "Centrality vs Sphericity; Centrality (%); Sphericity"}, + {kFT0AvsFT0C, o2::framework::HistType::kTH2F, "hFT0AvsFT0C", "FT0A centrality vs FT0C centrality; Centrality_{FT0A} (%); Centrality_{FT0C}"}, + // event shape + {kQvector, o2::framework::HistType::kTH1F, "hQvector", "Q-vector; Q-vector; Entries"}, + {kEventPlaneAngle, o2::framework::HistType::kTH1F, "hEventPlaneAngle", "Event Plane angle; #Psi_{n}; Entries"}, // mc {kTruePosZ, o2::framework::HistType::kTH1F, "hTruePosZ", "True vertex Z (mc-truth collision); V_{Z,True} (cm); Entries"}, {kTrueCent, o2::framework::HistType::kTH1F, "hTrueCent", "True centrality (mc-truth collision); Centrality_{True} (%); Entries"}, @@ -94,7 +105,9 @@ constexpr std::array, kColHistLast> HistTable = { {kPosZ, {(conf).vtxZ}}, \ {kMult, {(conf).mult}}, \ {kCent, {(conf).cent}}, \ - {kMagField, {(conf).magField}}, + {kMagField, {(conf).magField}}, \ + {kQvector, {(conf).qvector}}, \ + {kEventPlaneAngle, {(conf).eventPlaneAngle}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define COL_HIST_QA_MAP(confAnalysis, confQa) \ @@ -107,7 +120,8 @@ constexpr std::array, kColHistLast> HistTable = { {kPoszVsCent, {(confAnalysis).vtxZ, (confAnalysis).cent}}, \ {kCentVsMult, {(confAnalysis).cent, (confAnalysis).mult}}, \ {kMultVsSphericity, {(confAnalysis).mult, (confQa).sphericity}}, \ - {kCentVsSphericity, {confBinningAnalysis.cent, (confQa).sphericity}}, + {kCentVsSphericity, {(confAnalysis).cent, (confQa).sphericity}}, \ + {kFT0AvsFT0C, {(confAnalysis).cent, (confAnalysis).cent}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define COL_HIST_MC_MAP(conf) \ @@ -164,6 +178,9 @@ struct ConfCollisionBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis mult{"mult", {200, 0, 200}, "Multiplicity binning"}; o2::framework::ConfigurableAxis cent{"cent", {100, 0.0f, 100.0f}, "Centrality (multiplicity percentile) binning"}; o2::framework::ConfigurableAxis magField{"magField", {11, -5.5, 5.5}, "Magnetic field binning"}; + o2::framework::Configurable plotEventShape{"plotEventShape", false, "Activate histograms for event shape (qvector, event plane angle)"}; + o2::framework::ConfigurableAxis qvector{"qvector", {100, 0.0f, 100.0f}, "Q-vector binning"}; + o2::framework::ConfigurableAxis eventPlaneAngle{"eventPlaneAngle", {720, 0, 1.f * o2::constants::math::PI}, "Event plane angle binning"}; }; struct ConfCollisionQaBinning : o2::framework::ConfigurableGroup { @@ -184,9 +201,10 @@ class CollisionHistManager template void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, - T const& /*ConfCollisionBinning*/) + T const& ConfCollisionBinning) { mHistogramRegistry = registry; + mPlotEventShape = ConfCollisionBinning.plotEventShape.value; if constexpr (isFlagSet(mode, modes::Mode::kReco)) { initAnalysis(Specs); } @@ -257,6 +275,11 @@ class CollisionHistManager mHistogramRegistry->add(analysisDir + getHistNameV2(kMult, HistTable), getHistDesc(kMult, HistTable), getHistType(kMult, HistTable), {Specs.at(kMult)}); mHistogramRegistry->add(analysisDir + getHistNameV2(kCent, HistTable), getHistDesc(kCent, HistTable), getHistType(kCent, HistTable), {Specs.at(kCent)}); mHistogramRegistry->add(analysisDir + getHistNameV2(kMagField, HistTable), getHistDesc(kMagField, HistTable), getHistType(kMagField, HistTable), {Specs.at(kMagField)}); + + if (mPlotEventShape) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kQvector, HistTable), getHistDesc(kQvector, HistTable), getHistType(kQvector, HistTable), {Specs.at(kQvector)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEventPlaneAngle, HistTable), getHistDesc(kEventPlaneAngle, HistTable), getHistType(kEventPlaneAngle, HistTable), {Specs.at(kEventPlaneAngle)}); + } } void initQa(std::map> const& Specs) @@ -273,6 +296,7 @@ class CollisionHistManager mHistogramRegistry->add(qaDir + getHistNameV2(kCentVsMult, HistTable), getHistDesc(kCentVsMult, HistTable), getHistType(kCentVsMult, HistTable), {Specs.at(kCentVsMult)}); mHistogramRegistry->add(qaDir + getHistNameV2(kMultVsSphericity, HistTable), getHistDesc(kMultVsSphericity, HistTable), getHistType(kMultVsSphericity, HistTable), {Specs.at(kMultVsSphericity)}); mHistogramRegistry->add(qaDir + getHistNameV2(kCentVsSphericity, HistTable), getHistDesc(kCentVsSphericity, HistTable), getHistType(kCentVsSphericity, HistTable), {Specs.at(kCentVsSphericity)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kFT0AvsFT0C, HistTable), getHistDesc(kFT0AvsFT0C, HistTable), getHistType(kFT0AvsFT0C, HistTable), {Specs.at(kFT0AvsFT0C)}); } } @@ -301,6 +325,13 @@ class CollisionHistManager mHistogramRegistry->fill(HIST(AnalysisDir) + HIST(getHistName(kMult, HistTable)), col.mult()); mHistogramRegistry->fill(HIST(AnalysisDir) + HIST(getHistName(kCent, HistTable)), col.cent()); mHistogramRegistry->fill(HIST(AnalysisDir) + HIST(getHistName(kMagField, HistTable)), col.magField()); + + if (mPlotEventShape) { + if constexpr (utils::HasEventShape) { + mHistogramRegistry->fill(HIST(AnalysisDir) + HIST(getHistName(kQvector, HistTable)), col.qvec()); + mHistogramRegistry->fill(HIST(AnalysisDir) + HIST(getHistName(kEventPlaneAngle, HistTable)), col.eventPlaneAngle()); + } + } } template @@ -317,6 +348,7 @@ class CollisionHistManager mHistogramRegistry->fill(HIST(QaDir) + HIST(getHistName(kCentVsMult, HistTable)), col.cent(), col.mult()); mHistogramRegistry->fill(HIST(QaDir) + HIST(getHistName(kMultVsSphericity, HistTable)), col.mult(), col.sphericity()); mHistogramRegistry->fill(HIST(QaDir) + HIST(getHistName(kCentVsSphericity, HistTable)), col.cent(), col.sphericity()); + mHistogramRegistry->fill(HIST(QaDir) + HIST(getHistName(kFT0AvsFT0C, HistTable)), col.centFT0A(), col.centFT0C()); } } @@ -343,6 +375,7 @@ class CollisionHistManager } o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + bool mPlotEventShape = false; bool mPlot2d = false; }; } // namespace o2::analysis::femto::colhistmanager diff --git a/PWGCF/Femto/Core/dataTypes.h b/PWGCF/Femto/Core/dataTypes.h index 19e39de5828..e61a528dd5c 100644 --- a/PWGCF/Femto/Core/dataTypes.h +++ b/PWGCF/Femto/Core/dataTypes.h @@ -31,7 +31,8 @@ using TrackMaskType = uint64_t; using TrackType = uint16_t; // datatypes for v0s -using V0MaskType = uint16_t; +using V0MaskType = uint32_t; +using V0MaskType001 = uint16_t; // old data type, was too narrow using V0Type = uint16_t; // datatypes for kinks @@ -44,7 +45,8 @@ using TwoTrackResonanceMaskType = uint32_t; using TwoTrackResonanceType = uint16_t; // datatypes for cascades -using CascadeMaskType = uint16_t; +using CascadeMaskType = uint32_t; +using CascadeMaskType001 = uint16_t; // old data type, was too narrow using CascadeType = uint16_t; // datatype for origin of mc particle @@ -57,6 +59,14 @@ using ParticleType = uint16_t; using MomentumType = uint16_t; using TransverseMassType = uint16_t; +// datatype for charm hadrons +using CharmHadronMaskType = uint32_t; +using CharmHadronType = uint16_t; + +// datatypes for event shape enums +using QvecDetectorType = uint8_t; +using QvecHarmonicType = uint8_t; + } // namespace o2::analysis::femto::datatypes #endif // PWGCF_FEMTO_CORE_DATATYPES_H_ diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index 1e0e87fb4e3..50b2e030ccb 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -24,9 +24,11 @@ #include +#include #include #include #include +#include #include #include @@ -97,6 +99,9 @@ inline double getPdgMass(int pdgCode) case o2::constants::physics::Pdg::kLambdaCPlus: mass = o2::constants::physics::MassLambdaCPlus; break; + case o2::constants::physics::Pdg::kD0: + mass = o2::constants::physics::MassD0; + break; case o2::constants::physics::Pdg::kDeuteron: mass = o2::constants::physics::MassDeuteron; break; @@ -125,11 +130,20 @@ inline double getPdgMass(int pdgCode) } template -float qn(T const& col) -{ - float qn = std::sqrt(col.qvecFT0CReVec()[0] * col.qvecFT0CReVec()[0] + col.qvecFT0CImVec()[0] * col.qvecFT0CImVec()[0]) * std::sqrt(col.sumAmplFT0C()); - return qn; -} +concept HasQvectors = requires(T col) { + col.qvecFT0CReVec(); + col.qvecFT0CImVec(); + col.sumAmplFT0C(); + col.qvecFT0AReVec(); + col.qvecFT0AImVec(); + col.sumAmplFT0A(); +}; + +template +concept HasEventShape = requires(T col) { + col.qvec(); + col.eventPlaneAngle(); +}; /// Recalculate pT for Kinks (Sigmas) using kinematic constraints inline float calcPtnew(float pxMother, float pyMother, float pzMother, float pxDaughter, float pyDaughter, float pzDaughter) @@ -228,6 +242,93 @@ inline int signum(T x) return (T(0) < x) - (x < T(0)); } +template +inline T binLinear(float value, float lo, float hi, float step) +{ + float v = std::clamp(value, lo, hi); + auto idx = static_cast(std::round((v - lo) / step)); + auto maxIdx = static_cast(std::numeric_limits::max()) - static_cast(std::numeric_limits::min()); + idx = std::clamp(idx, static_cast(0), maxIdx); + return static_cast(idx + std::numeric_limits::min()); +} + +template +inline float unBinLinear(T binned, float lo, float step) +{ + auto idx = static_cast(binned) - static_cast(std::numeric_limits::min()); + return lo + static_cast(idx) * step; +} + +template +inline T binLogSigned(float signedValue, float magMin, float magMax) +{ + static_assert(std::is_unsigned_v, "binLogSigned requires an unsigned storage type"); + constexpr uint32_t TotalBits = sizeof(T) * 8; + constexpr uint32_t HalfLevels = 1u << (TotalBits - 1); + uint32_t sign = (signedValue < 0.f) ? 1u : 0u; + float mag = std::clamp(std::fabs(signedValue), magMin, magMax); + float logLo = std::log(magMin); + float logHi = std::log(magMax); + float step = (logHi - logLo) / static_cast(HalfLevels - 1); + auto idx = static_cast(std::round((std::log(mag) - logLo) / step)); + idx = std::clamp(idx, 0u, HalfLevels - 1); + return static_cast((sign << (TotalBits - 1)) | idx); +} + +template +inline float unBinLogSigned(T binned, float magMin, float magMax) +{ + constexpr uint32_t TotalBits = sizeof(T) * 8; + constexpr uint32_t HalfLevels = 1u << (TotalBits - 1); + constexpr T SignMask = static_cast(1u << (TotalBits - 1)); + constexpr T MagMask = static_cast(SignMask - 1); + float sign = (binned & SignMask) ? -1.f : 1.f; + uint32_t idx = binned & MagMask; + float logLo = std::log(magMin); + float logHi = std::log(magMax); + float step = (logHi - logLo) / static_cast(HalfLevels - 1); + float mag = std::exp(logLo + static_cast(idx) * step); + return sign * mag; +} + +template +inline int unBinSign(T binned) +{ + static_assert(std::is_unsigned_v, "unBinSign requires an unsigned storage type"); + constexpr uint64_t TotalBits = sizeof(T) * 8; + constexpr T SignMask = static_cast(uint64_t{1} << (TotalBits - 1)); + return (binned & SignMask) ? -1 : 1; +} + +template +inline T binLogUnsigned(float value, float magMin, float magMax) +{ + static_assert(std::is_unsigned_v, "binLogUnsigned requires an unsigned storage type"); + constexpr uint64_t TotalBits = sizeof(T) * 8; + constexpr uint64_t Levels = uint64_t{1} << TotalBits; // number of representable values, e.g. 65536 for uint16_t + float mag = std::clamp(value, magMin, magMax); + float logLo = std::log(magMin); + float logHi = std::log(magMax); + float step = (logHi - logLo) / static_cast(Levels - 1); + auto idx = static_cast(std::round((std::log(mag) - logLo) / step)); + idx = std::clamp(idx, uint64_t{0}, Levels - 1); + return static_cast(idx); +} + +template +inline float unBinLogUnsigned(T binned, float magMin, float magMax) +{ + constexpr uint64_t TotalBits = sizeof(T) * 8; + constexpr uint64_t Levels = uint64_t{1} << TotalBits; + uint64_t idx = binned; + float logLo = std::log(magMin); + float logHi = std::log(magMax); + float step = (logHi - logLo) / static_cast(Levels - 1); + float mag = std::exp(logLo + static_cast(idx) * step); + return mag; +} + }; // namespace utils }; // namespace o2::analysis::femto +// #endif // PWGCF_FEMTO_CORE_FEMTOUTILS_H_ diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h index 3584726eabf..b90fa2248f9 100644 --- a/PWGCF/Femto/Core/kinkBuilder.h +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -470,9 +470,11 @@ class KinkSelection : public baseselection::BaseSelection producedSigmas; + o2::framework::Produces producedLiteSigmas; o2::framework::Produces producedSigmaMasks; o2::framework::Produces producedSigmaExtras; o2::framework::Produces producedSigmaPlus; + o2::framework::Produces producedLiteSigmaPlus; o2::framework::Produces producedSigmaPlusMasks; o2::framework::Produces producedSigmaPlusExtras; }; @@ -480,9 +482,11 @@ struct KinkBuilderProducts : o2::framework::ProducesGroup { struct ConfKinkTables : o2::framework::ConfigurableGroup { std::string prefix = std::string("KinkTables"); o2::framework::Configurable produceSigmas{"produceSigmas", -1, "Produce Sigmas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteSigmas{"produceLiteSigmas", -1, "Produce LiteSigmas (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSigmaMasks{"produceSigmaMasks", -1, "Produce SigmaMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSigmaExtras{"produceSigmaExtras", -1, "Produce SigmaExtras (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSigmaPlus{"produceSigmaPlus", -1, "Produce SigmaPlus (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteSigmaPlus{"produceLiteSigmaPlus", -1, "Produce LiteSigmaPlus (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSigmaPlusMasks{"produceSigmaPlusMasks", -1, "Produce SigmaPlusMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSigmaPlusExtras{"produceSigmaPlusExtras", -1, "Produce SigmaPlusExtras (-1: auto; 0 off; 1 on)"}; }; @@ -494,21 +498,55 @@ class KinkBuilder KinkBuilder() = default; ~KinkBuilder() = default; - template - void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext, T5& trackBuilder) { if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { LOG(info) << "Initialize femto Sigma builder..."; mProduceSigmas = utils::enableTable("FSigmas_002", table.produceSigmas.value, initContext); + mProduceLiteSigmas = utils::enableTable("FLiteSigmas_001", table.produceLiteSigmas.value, initContext); mProduceSigmaMasks = utils::enableTable("FSigmaMasks_001", table.produceSigmaMasks.value, initContext); mProduceSigmaExtras = utils::enableTable("FSigmaExtras_001", table.produceSigmaExtras.value, initContext); + + if (mProduceSigmas && mProduceLiteSigmas) { + LOG(fatal) << "FSigmas and FLiteSigmas are mutually exclusive -- enable only one. " + << "FLiteSigmas is meant to replace FSigmas at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FSigmas from FLiteSigmas downstream."; + } + if (mProduceSigmas && !trackBuilder.producingTracks()) { + LOG(fatal) << "FSigmas is enabled, but the track builder is not producing FTracks (full precision). " + << "FSigmas stores the daughter index into FTracks -- enable TrackTables.produceTracks, " + << "or switch to FLiteSigmas if TrackTables.produceLiteTracks is enabled instead."; + } + if (mProduceLiteSigmas && !trackBuilder.producingLiteTracks()) { + LOG(fatal) << "FLiteSigmas is enabled, but the track builder is not producing FLiteTracks. " + << "FLiteSigmas stores the daughter index into FLiteTracks -- enable TrackTables.produceLiteTracks, " + << "or switch to FSigmas if TrackTables.produceTracks is enabled instead."; + } } if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { LOG(info) << "Initialize femto SigmaPlus builder..."; mProduceSigmaPlus = utils::enableTable("FSigmaPlus_001", table.produceSigmaPlus.value, initContext); + mProduceLiteSigmaPlus = utils::enableTable("FLiteSigmaPlus_001", table.produceLiteSigmaPlus.value, initContext); mProduceSigmaPlusMasks = utils::enableTable("FSigmaPlusMasks_001", table.produceSigmaPlusMasks.value, initContext); mProduceSigmaPlusExtras = utils::enableTable("FSigmaPlusExtras_001", table.produceSigmaPlusExtras.value, initContext); + + if (mProduceSigmaPlus && mProduceLiteSigmaPlus) { + LOG(fatal) << "FSigmaPlus and FLiteSigmaPlus are mutually exclusive -- enable only one. " + << "FLiteSigmaPlus is meant to replace FSigmaPlus at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FSigmaPlus from FLiteSigmaPlus downstream."; + } + if (mProduceSigmaPlus && !trackBuilder.producingTracks()) { + LOG(fatal) << "FSigmaPlus is enabled, but the track builder is not producing FTracks (full precision). " + << "FSigmaPlus stores the daughter index into FTracks -- enable TrackTables.produceTracks, " + << "or switch to FLiteSigmaPlus if TrackTables.produceLiteTracks is enabled instead."; + } + if (mProduceLiteSigmaPlus && !trackBuilder.producingLiteTracks()) { + LOG(fatal) << "FLiteSigmaPlus is enabled, but the track builder is not producing FLiteTracks. " + << "FLiteSigmaPlus stores the daughter index into FLiteTracks -- enable TrackTables.produceLiteTracks, " + << "or switch to FSigmaPlus if TrackTables.produceTracks is enabled instead."; + } } if (mProduceSigmas || mProduceSigmaMasks || mProduceSigmaExtras || mProduceSigmaPlus || mProduceSigmaPlusMasks || mProduceSigmaPlusExtras) { @@ -547,12 +585,12 @@ class KinkBuilder collisionBuilder.template fillCollision(collisionProducts, col); auto daughter = kink.template trackDaug_as(); - daughterIndex = trackBuilder.template getDaughterIndex(daughter, trackProducts, collisionProducts); + daughterIndex = trackBuilder.template getDaughterIndex(daughter, trackProducts, collisionBuilder); if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { - fillSigma(collisionProducts, kinkProducts, kink, daughterIndex); + fillSigma(collisionBuilder, kinkProducts, kink, daughterIndex); } if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { - fillSigmaPlus(collisionProducts, kinkProducts, kink, daughterIndex); + fillSigmaPlus(collisionBuilder, kinkProducts, kink, daughterIndex); } } } @@ -581,33 +619,42 @@ class KinkBuilder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); auto daughter = kink.template trackDaug_as(); - daughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, daughter, trackProducts, mcParticles, mcBuilder, mcProducts); + daughterIndex = trackBuilder.template getDaughterIndex(daughter, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { - fillSigma(collisionProducts, kinkProducts, kink, daughterIndex); - mcBuilder.template fillMcSigmaWithLabel(col, mcCols, daughter, mcParticles, mcProducts); + fillSigma(collisionBuilder, kinkProducts, kink, daughterIndex); + mcBuilder.template fillMcSigmaWithLabel(daughter, mcParticles, mcCols, mcProducts); } if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { - fillSigmaPlus(collisionProducts, kinkProducts, kink, daughterIndex); - mcBuilder.template fillMcSigmaPlusWithLabel(col, mcCols, daughter, mcParticles, mcProducts); + fillSigmaPlus(collisionBuilder, kinkProducts, kink, daughterIndex); + mcBuilder.template fillMcSigmaPlusWithLabel(daughter, mcParticles, mcCols, mcProducts); } } } template - void fillSigma(T1& collisionProducts, T2& kinkProducts, T3 const& kink, int64_t daughterIndex) + void fillSigma(T1& collisionBuilder, T2& kinkProducts, T3 const& kink, int64_t daughterIndex) { // Mass is calculated from original momentum components stored in kink table float mass = kink.mSigmaMinus(); + float signedPt = kink.mothSign() * mKinkSelection.getKinkMotherPt(); // Recalculated pT if (mProduceSigmas) { - kinkProducts.producedSigmas(collisionProducts.producedCollision.lastIndex(), - kink.mothSign() * mKinkSelection.getKinkMotherPt(), // Recalculated pT + kinkProducts.producedSigmas(collisionBuilder.collisionIndex(), + signedPt, mKinkSelection.getKinkMotherEta(), mKinkSelection.getKinkMotherPhi(), mass, daughterIndex); } + if (mProduceLiteSigmas) { + kinkProducts.producedLiteSigmas(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binSignedPt(signedPt), + o2::aod::femtobase::lite::binEta(mKinkSelection.getKinkMotherEta()), + o2::aod::femtobase::lite::binPhi(mKinkSelection.getKinkMotherPhi()), + o2::aod::femtokinks::lite::binSigmaMass(mass), + daughterIndex); + } if (mProduceSigmaMasks) { kinkProducts.producedSigmaMasks(mKinkSelection.getBitmask()); } @@ -624,19 +671,27 @@ class KinkBuilder } template - void fillSigmaPlus(T1& collisionProducts, T2& kinkProducts, T3 const& kink, int64_t daughterIndex) + void fillSigmaPlus(T1& collisionBuilder, T2& kinkProducts, T3 const& kink, int64_t daughterIndex) { // Mass is calculated from original momentum components stored in kink table float mass = kink.mSigmaPlus(); - + float signedPt = kink.mothSign() * mKinkSelection.getKinkMotherPt(); // Recalculated pT if (mProduceSigmaPlus) { - kinkProducts.producedSigmaPlus(collisionProducts.producedCollision.lastIndex(), - kink.mothSign() * mKinkSelection.getKinkMotherPt(), // Recalculated pT + kinkProducts.producedSigmaPlus(collisionBuilder.collisionIndex(), + signedPt, mKinkSelection.getKinkMotherEta(), mKinkSelection.getKinkMotherPhi(), mass, daughterIndex); } + if (mProduceLiteSigmaPlus) { + kinkProducts.producedLiteSigmaPlus(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binSignedPt(signedPt), + o2::aod::femtobase::lite::binEta(mKinkSelection.getKinkMotherEta()), + o2::aod::femtobase::lite::binPhi(mKinkSelection.getKinkMotherPhi()), + o2::aod::femtokinks::lite::binSigmaMass(mass), + daughterIndex); + } if (mProduceSigmaPlusMasks) { kinkProducts.producedSigmaPlusMasks(mKinkSelection.getBitmask()); } @@ -652,15 +707,18 @@ class KinkBuilder } } - bool fillAnyTable() { return mFillAnyTable; } + [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } + [[nodiscard]] bool isPassThrough() const { return mKinkSelection.isPassThrough(); } private: KinkSelection mKinkSelection; bool mFillAnyTable = false; bool mProduceSigmas = false; + bool mProduceLiteSigmas = false; bool mProduceSigmaMasks = false; bool mProduceSigmaExtras = false; bool mProduceSigmaPlus = false; + bool mProduceLiteSigmaPlus = false; bool mProduceSigmaPlusMasks = false; bool mProduceSigmaPlusExtras = false; }; diff --git a/PWGCF/Femto/Core/kinkHistManager.h b/PWGCF/Femto/Core/kinkHistManager.h index 1ffe73e272b..3e98b8865e0 100644 --- a/PWGCF/Femto/Core/kinkHistManager.h +++ b/PWGCF/Femto/Core/kinkHistManager.h @@ -386,11 +386,11 @@ class KinkHistManager } } - template - void fill(T1 const& kinkCandidate, T2 const& tracks, T3 const& mcParticles, T4 const& mcMothers, T5 const& mcPartonicMothers) + template + void fill(T1 const& kinkCandidate, T2 const& tracks, T3 const& col, T4 const& mcParticles, T5 const& mcMothers, T6 const& mcPartonicMothers) { auto chaDaughter = tracks.rawIteratorAt(kinkCandidate.chaDauId() - tracks.offset()); - mChaDauManager.template fill(chaDaughter, tracks, mcParticles, mcMothers, mcPartonicMothers); + mChaDauManager.template fill(chaDaughter, tracks, col, mcParticles, mcMothers, mcPartonicMothers); if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->fillAnalysis(kinkCandidate); } @@ -398,7 +398,7 @@ class KinkHistManager this->fillQa(kinkCandidate); } if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { - this->template fillMc(kinkCandidate, mcParticles, mcMothers, mcPartonicMothers); + this->template fillMc(kinkCandidate, col, mcParticles, mcMothers, mcPartonicMothers); } } @@ -530,8 +530,8 @@ class KinkHistManager } } - template - void fillMc(T1 const& kinkCandidate, T2 const& /*mcParticles*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/) + template + void fillMc(T1 const& kinkCandidate, T2 const& col, T3 const& /*mcParticles*/, T4 const& /*mcMothers*/, T5 const& /*mcPartonicMothers*/) { // No MC Particle if (!kinkCandidate.has_fMcParticle()) { @@ -546,17 +546,21 @@ class KinkHistManager } // Retrieve MC particle - auto mcParticle = kinkCandidate.template fMcParticle_as(); + auto mcParticle = kinkCandidate.template fMcParticle_as(); + + // whether a particle is associated to a wrong collision or not cannot be known by the producer so we check it here + bool fromWrongCollision = mcParticle.fMcColId() != col.fMcColId(); - // missidentifed particles are special case // whether a particle is missidentfied or not cannot be known by the producer so we check it here bool isMissidentified = mcParticle.pdgCode() != mPdgCode; mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kTruePt, HistTable)), mcParticle.pt()); mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kTrueEta, HistTable)), mcParticle.eta()); mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kTruePhi, HistTable)), mcParticle.phi()); - if (isMissidentified) { - mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kFromWrongCollision)); + } else if (isMissidentified) { + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); } else { mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), mcParticle.origin()); } @@ -564,7 +568,7 @@ class KinkHistManager // get mother if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), mother.pdgCode()); } else { mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), 0); @@ -572,7 +576,7 @@ class KinkHistManager // get partonic mother if (mcParticle.has_fMcPartMoth()) { - auto partonicMother = mcParticle.template fMcPartMoth_as(); + auto partonicMother = mcParticle.template fMcPartMoth_as(); mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), partonicMother.pdgCode()); } else { mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), 0); @@ -580,8 +584,9 @@ class KinkHistManager if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { if (mPlotOrigins) { - // check first if particle is missidentified - if (isMissidentified) { + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kFromWrongCollision, HistTable)), kinkCandidate.pt(), kinkCandidate.kinkAngle()); + } else if (isMissidentified) { // if it is, we fill it as such mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(McDir) + HIST(getHistName(kMissidentified, HistTable)), kinkCandidate.pt(), kinkCandidate.kinkAngle()); } else { @@ -598,7 +603,7 @@ class KinkHistManager break; case modes::McOrigin::kFromSecondaryDecay: if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); int motherPdgCode = std::abs(mother.pdgCode()); // Switch on PDG of the mother if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel1 && motherPdgCode == mPdgCodesSecondaryMother[0]) { diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index d37f09c36ab..488eeda4bb5 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -21,13 +21,18 @@ #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" +#include "Common/Core/RecoDecay.h" + #include +#include #include #include #include +#include #include +#include #include #include #include @@ -37,13 +42,13 @@ namespace o2::analysis::femto::mcbuilder { -constexpr int ProducedByDecay = 4; - struct ConfMc : o2::framework::ConfigurableGroup { std::string prefix = std::string("MonteCarlo"); o2::framework::Configurable passThrough{"passThrough", false, "Passthrough all MC collisions and particles"}; o2::framework::Configurable findLastPartonicMother{"findLastPartonicMother", true, "If true, the partonic mother will be the first parton directly after the initial collision. If false, the partonic mother will be the last parton before hadronization"}; o2::framework::Configurable etaAcceptanceMcOnly{"etaAcceptanceMcOnly", 0.8, "For MC ONLY processing. |eta| acceptance for estimating primary track multiplicity"}; + o2::framework::Configurable etaAcceptanceMcReco{"etaAcceptanceMcReco", 1, "For MC/RECO processing. |eta| acceptance for generated particles"}; + o2::framework::Configurable charmYGenMax{"charmYGenMax", 0.8f, "Max |y| (rapidity) for generated charm hadrons (mc-only truth acceptance)"}; }; struct McBuilderProducts : o2::framework::ProducesGroup { @@ -57,6 +62,7 @@ struct McBuilderProducts : o2::framework::ProducesGroup { o2::framework::Produces producedTrackLabels; o2::framework::Produces producedLambdaLabels; o2::framework::Produces producedK0shortLabels; + o2::framework::Produces producedD0Labels; o2::framework::Produces producedSigmaLabels; o2::framework::Produces producedSigmaPlusLabels; o2::framework::Produces producedXiLabels; @@ -75,6 +81,7 @@ struct ConfMcTables : o2::framework::ConfigurableGroup { o2::framework::Configurable producedTrackLabels{"producedTrackLabels", -1, "Produce track labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedLambdaLabels{"producedLambdaLabels", -1, "Produce lambda labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedK0shortLabels{"producedK0shortLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable producedD0Labels{"producedD0Labels", -1, "Produce D0 labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedSigmaLabels{"producedSigmaLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedSigmaPlusLabels{"producedSigmaPlusLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedXiLabels{"producedXiLabels", -1, "Produce xi labels (-1: auto; 0 off; 1 on)"}; @@ -124,6 +131,12 @@ class McBuilder { LOG(info) << "Initialize monte carlo builder..."; + mPassThrough = config.passThrough.value; + mEtaAcceptanceMcOnly = config.etaAcceptanceMcOnly.value; + mEtaAcceptanceMcReco = config.etaAcceptanceMcReco.value; + mFindLastPartonicMother = config.findLastPartonicMother.value; + mCharmYGenMax = config.charmYGenMax.value; + mProduceMcCollisions = utils::enableTable("FMcCols_001", table.produceMcCollisions.value, initContext); mProduceMcParticles = utils::enableTable("FMcParticles_001", table.produceMcParticles.value, initContext); mProduceMcMothers = utils::enableTable("FMcMothers_001", table.produceMcMothers.value, initContext); @@ -134,34 +147,34 @@ class McBuilder mProduceTrackLabels = utils::enableTable("FTrackLabels", table.producedTrackLabels.value, initContext); mProduceLambdaLabels = utils::enableTable("FLambdaLabels", table.producedLambdaLabels.value, initContext); mProduceK0shortLabels = utils::enableTable("FK0shortLabels", table.producedK0shortLabels.value, initContext); + mProduceD0Labels = utils::enableTable("FD0Labels", table.producedD0Labels.value, initContext); mProduceSigmaLabels = utils::enableTable("FSigmaLabels", table.producedSigmaLabels.value, initContext); mProduceSigmaPlusLabels = utils::enableTable("FSigmaPlusLabels", table.producedSigmaPlusLabels.value, initContext); mProduceXiLabels = utils::enableTable("FXiLabels", table.producedXiLabels.value, initContext); mProduceOmegaLabels = utils::enableTable("FOmegaLabels", table.producedOmegaLabels.value, initContext); if (mProduceMcCollisions || mProduceCollisionLabels || - mProduceMcParticles || mProduceMcMothers || mProduceMcPartonicMothers || - mProduceMcMotherLabels || + mProduceMcParticles || mProduceMcMotherLabels || + mProduceMcMothers || mProduceMcPartonicMothers || mProduceTrackLabels || mProduceLambdaLabels || mProduceK0shortLabels || mProduceSigmaLabels || mProduceSigmaPlusLabels || - mProduceXiLabels || mProduceOmegaLabels) { + mProduceXiLabels || mProduceOmegaLabels || + mProduceD0Labels) { mFillAnyTable = true; } else { LOG(info) << "No tables configured..."; LOG(info) << "Initialization done..."; return; } - mPassThrough = config.passThrough.value; - mEtaAcceptanceMcOnly = config.etaAcceptanceMcOnly.value; - mFindLastPartonicMother = config.findLastPartonicMother.value; LOG(info) << "Initialization done..."; } template - void fillMcCollisionWithLabel(T1& mcProducts, T2 const& col, T3 const& /*mcCols*/) + void fillMcCollisionWithLabel(T1 const& col, T2 const& /*mcCols*/, T3& mcProducts) { if (!mProduceCollisionLabels) { + mcProducts.producedCollisionLabels(-1); return; } // Case: This reconstructed collision has an MC collision @@ -171,7 +184,7 @@ class McBuilder auto it = mCollisionMap.find(originalIndex); if (it == mCollisionMap.end()) { // Not yet created → create it - auto mcCol = col.template mcCollision_as(); + auto mcCol = col.template mcCollision_as(); this->fillMcCollision(mcCol, mcProducts); } // Add label @@ -185,6 +198,10 @@ class McBuilder template void fillMcCollision(T1 const& mcCol, T2& mcProducts) { + // check if collision already exists + if (mCollisionMap.find(mcCol.globalIndex()) != mCollisionMap.end()) { + return; + } float centrality = -1; float multiplicity = -1; if constexpr (modes::isFlagSet(system, modes::System::kPP)) { @@ -204,18 +221,28 @@ class McBuilder } // for mc only - template - void fillMcCollision(T1 const& mcCol, T2 const& mcParticles, T3& mcProducts) + template + void fillMcCollision(T1 const& mcCol, T2 const& mcParticles, T3& mcProducts, T4& pdgDb) { + // check if collision already exists + if (mCollisionMap.find(mcCol.globalIndex()) != mCollisionMap.end()) { + return; + } + float centrality = 0; // no centrality estimator for mc only, so set to 0 float multiplicity = 0; // no multiplicity estimator for mc only - // define multiplicity ourselves by counting primary particles for |eta|,0.8 + // define multiplicity ourselves by counting primary particles for |eta|< some config threshold // this is similar to how define it in data for (auto const& mcParticle : mcParticles) { - if (mcParticle.isPhysicalPrimary() && (std::fabs(mcParticle.eta()) < mEtaAcceptanceMcOnly)) { - multiplicity += 1; + if (!mcParticle.isPhysicalPrimary() || std::fabs(mcParticle.eta()) > mEtaAcceptanceMcOnly) { + continue; + } + const auto* pdgParticle = pdgDb->GetParticle(mcParticle.pdgCode()); + if (pdgParticle == nullptr || std::fabs(pdgParticle->Charge()) < o2::constants::math::Almost0) { + continue; } + multiplicity += 1; } mcProducts.producedMcCollisions( @@ -228,78 +255,150 @@ class McBuilder template void fillMcParticle(T1 const& mcParticle, T2 const& mcParticles, T3 const& mcCol, T4& mcProducts) { + // charm hadrons get a prompt/non-prompt origin, consistent with the reco-matched path; + // all other particles use the generic getOrigin inside getOrCreateMcParticleRow + if (std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0) { + // truth-level acceptance for the efficiency denominator: keep only + // generated D0 -> K pi decays inside the rapidity acceptance + int8_t sign = 0; + if (!RecoDecay::isMatchedMCGen(mcParticles, mcParticle, o2::constants::physics::Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { + return; + } + if (std::abs(mcParticle.y()) > mCharmYGenMax) { + return; + } + } this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); } + /// Write the generated primary charged particles needed for the dNch/deta calculation template - void fillMcTrackWithLabel(T1 const& col, T2 const& mcCols, T3 const& track, T4 const& mcParticles, T5& mcProducts) + void fillMcPassThrough(T1 const& mcCols, T2 const& mcParticles, T3& perMcCollision, T4& mcProducts, T5& pdgDb) + { + if (!mPassThrough) { + return; + } + for (const auto& mcCol : mcCols) { + // every MC collision unconditionally: E_all is counted over all of them + this->fillMcCollision(mcCol, mcProducts); + + auto particlesThisCollision = mcParticles.sliceBy(perMcCollision, mcCol.globalIndex()); + for (const auto& mcParticle : particlesThisCollision) { + if (!mcParticle.isPhysicalPrimary() || std::fabs(mcParticle.eta()) > mEtaAcceptanceMcReco) { + continue; + } + const auto* pdgParticle = pdgDb->GetParticle(mcParticle.pdgCode()); + if (pdgParticle == nullptr || std::fabs(pdgParticle->Charge()) < o2::constants::math::Almost0) { + continue; + } + // NOTE: full mcParticles table, never the slice - the ancestry walk resolves global indices + this->fillMcParticle(mcParticle, mcParticles, mcCol, mcProducts); + } + } + } + + template + void fillMcTrackWithLabel(T1 const& track, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceTrackLabels) { mcProducts.producedTrackLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, track, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedTrackLabels(p); }); + fillMcLabelGeneric(track, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedTrackLabels(p); }); } - template - void fillMcLambdaWithLabel(T1 const& col, T2 const& mcCols, T3 const& lambda, T4 const& mcParticles, T5& mcProducts) + template + void fillMcLambdaWithLabel(T1 const& lambda, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceLambdaLabels) { mcProducts.producedLambdaLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, lambda, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedLambdaLabels(p); }); + fillMcLabelGeneric(lambda, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedLambdaLabels(p); }); } - template - void fillMcK0shortWithLabel(T1 const& col, T2 const& mcCols, T3 const& k0short, T4 const& mcParticles, T5& mcProducts) + template + void fillMcK0shortWithLabel(T1 const& k0short, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceK0shortLabels) { mcProducts.producedK0shortLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, k0short, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedK0shortLabels(p); }); + fillMcLabelGeneric(k0short, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedK0shortLabels(p); }); } + // D0 has no direct MC label (2-prong hypothesis built by PWGHF), so fillMcLabelGeneric + // cannot be reused. Both prongs are matched to a generated D0 -> K pi decay with + // RecoDecay::getMatchedMCRec, which returns the index of the generated mother; + // unmatched candidates get -1. template - void fillMcSigmaWithLabel(T1 const& col, T2 const& mcCols, T3 const& sigmaDaughter, T4 const& mcParticles, T5& mcProducts) + void fillMcD0WithLabel(T1 const& d0candidate, T2 const& /*tracks*/, T3 const& mcParticles, T4 const& /*mcCols*/, T5& mcProducts) + { + if (!mProduceD0Labels) { + mcProducts.producedD0Labels(-1); + return; + } + + auto prong0 = d0candidate.template prong0_as(); + auto prong1 = d0candidate.template prong1_as(); + auto arrayDaughters = std::array{prong0, prong1}; + int8_t sign = 0; + const int indexMcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + + if (indexMcRec < 0) { + mcProducts.producedD0Labels(-1); + return; + } + + auto mcParticle = mcParticles.rawIteratorAt(indexMcRec); + auto mcCol = mcParticle.template mcCollision_as(); + int64_t mcParticleRow = this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); + + mcProducts.producedD0Labels(mcParticleRow); + } + + template + void fillMcSigmaWithLabel(T1 const& sigmaDaughter, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceSigmaLabels) { + mcProducts.producedSigmaLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, sigmaDaughter, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedSigmaLabels(p); }, true); + fillMcLabelGeneric(sigmaDaughter, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedSigmaLabels(p); }, true); } - template - void fillMcSigmaPlusWithLabel(T1 const& col, T2 const& mcCols, T3 const& sigmaPlusDaughter, T4 const& mcParticles, T5& mcProducts) + template + void fillMcSigmaPlusWithLabel(T1 const& sigmaPlusDaughter, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceSigmaPlusLabels) { + mcProducts.producedSigmaPlusLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, sigmaPlusDaughter, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedSigmaPlusLabels(p); }, true); + fillMcLabelGeneric(sigmaPlusDaughter, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedSigmaPlusLabels(p); }, true); } - template - void fillMcXiWithLabel(T1 const& col, T2 const& mcCols, T3 const& xi, T4 const& mcParticles, T5& mcProducts) + template + void fillMcXiWithLabel(T1 const& xi, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceXiLabels) { mcProducts.producedXiLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, xi, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedXiLabels(p); }); + fillMcLabelGeneric(xi, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedXiLabels(p); }); } - template - void fillMcOmegaWithLabel(T1 const& col, T2 const& mcCols, T3 const& omega, T4 const& mcParticles, T5& mcProducts) + template + void fillMcOmegaWithLabel(T1 const& omega, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { if (!mProduceOmegaLabels) { mcProducts.producedOmegaLabels(-1); return; } - fillMcLabelGeneric(col, mcCols, omega, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedOmegaLabels(p); }); + fillMcLabelGeneric(omega, mcParticles, mcCols, mcProducts, [](auto& prod, int64_t p) { prod.producedOmegaLabels(p); }); } bool fillAnyTable() const { return mFillAnyTable; } + bool isPassThrough() const { return mPassThrough; } template void reset(T1 const& mcCollisions, T2 const& mcParticles) @@ -314,56 +413,40 @@ class McBuilder mMcPartonicMotherMap.reserve(mcParticles.size()); } - // mc only, then there is only 1 mc collision - template - void reset(T const& mcParticles) + private: + // classify a charm hadron as prompt (charm from a c quark) or non-prompt (charm from a + // beauty decay) from the mc decay tree; shared by the reco-matched and generator-level paths + template + modes::McOrigin getHeavyFlavourOrigin(T1 const& mcParticle, T2 const& mcParticles) { - mCollisionMap.clear(); - mMcParticleMap.clear(); - mMcParticleMap.reserve(mcParticles.size()); - mMcMotherMap.clear(); - mMcMotherMap.reserve(mcParticles.size()); - mMcPartonicMotherMap.clear(); - mMcPartonicMotherMap.reserve(mcParticles.size()); + const int charmOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle); + return (charmOrigin == RecoDecay::OriginType::NonPrompt) ? modes::McOrigin::kNonPrompt : modes::McOrigin::kPrompt; } - private: - template - modes::McOrigin getOrigin(T1 const& col, T2 const& /*mcCols*/, T3 const& mcParticle) + template + modes::McOrigin getOrigin(T1 const& mcParticle) { // whether a particle is misidentified or not can only be checked by qa/pair task later so it is not set here - - // check if reconstructed collision has a generated collision - if (!col.has_mcCollision()) { - return modes::McOrigin::kFromWrongCollision; - } - - // now check collision ids, if they do not match, then the track belongs to another collision - if (col.mcCollisionId() != mcParticle.mcCollisionId()) { - return modes::McOrigin::kFromWrongCollision; - } - + // whether a particle is associated to the wrong collision or not can only be checked by qa/pair task later so it is not set here if (mcParticle.isPhysicalPrimary()) { return modes::McOrigin::kPhysicalPrimary; } - if (mcParticle.has_mothers() && mcParticle.getProcess() == ProducedByDecay) { + // A non-primary the generator itself produced can only come from a decay the generator + // performed, and strong/EM decay products are primaries by definition - so this is a + // weak decay. NOTE: getProcess() returns kPrimary (0) for every generator particle, + // so the kPDecay check below never fires for them. + if (mcParticle.producedByGenerator()) { return modes::McOrigin::kFromSecondaryDecay; } - - // not a primary and not from a decay and not from a wrong collision, we label as material - return modes::McOrigin::kFromMaterial; - } - - template - modes::McOrigin getOrigin(T1 const& mcParticle) - { - if (mcParticle.isPhysicalPrimary()) { - return modes::McOrigin::kPhysicalPrimary; - } - if (mcParticle.has_mothers() && mcParticle.getProcess() == ProducedByDecay) { + // produced by transport: kPDecay means GEANT decayed it, the usual path for + // Lambda / K0s / Xi / Omega since ALICE hands them to transport undecayed + const int process = mcParticle.getProcess(); + if (process == TMCProcess::kPDecay || process == TMCProcess::kPRadDecay) { return modes::McOrigin::kFromSecondaryDecay; } + + // not a primary and not from a decay we label as material return modes::McOrigin::kFromMaterial; } @@ -381,21 +464,12 @@ class McBuilder return it->second; } - /// Mc-only entry point: no reconstructed collision to match against, so origin - /// is derived purely from the mc particle itself. template int64_t getOrCreateMcParticleRow(T1 const& mcParticle, T2 const& mcParticles, T3 const& mcCol, T4& mcProducts) { - auto origin = this->getOrigin(mcParticle); - return this->buildMcParticleRow(mcParticle, mcParticles, mcCol, origin, mcProducts); - } - - /// Reco-matched entry point: origin is derived by comparing the reconstructed - /// collision against the mc collision. - template - int64_t getOrCreateMcParticleRow(T1 const& col, T2 const& mcCols, T3 const& mcParticle, T4 const& mcParticles, T5 const& mcCol, T6& mcProducts) - { - auto origin = this->getOrigin(col, mcCols, mcParticle); + auto origin = std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0 + ? this->getHeavyFlavourOrigin(mcParticle, mcParticles) + : this->getOrigin(mcParticle); return this->buildMcParticleRow(mcParticle, mcParticles, mcCol, origin, mcProducts); } @@ -428,7 +502,7 @@ class McBuilder // --- mother --- int64_t mcMotherRow = -1; - if (mcParticle.has_mothers()) { + if (mProduceMcMothers && mcParticle.has_mothers()) { auto mothers = mcParticle.template mothers_as(); auto motherParticle = mothers.front(); auto mcMotherIndex = motherParticle.globalIndex(); @@ -451,9 +525,12 @@ class McBuilder // --- partonic mother --- int64_t mcPartonicMotherRow = -1; - int64_t mcPartonicMotherIndex = mFindLastPartonicMother - ? this->findLastPartonicMother(mcParticle, mcParticles) - : this->findFirstPartonicMother(mcParticle, mcParticles); + int64_t mcPartonicMotherIndex = -1; + if (mProduceMcPartonicMothers) { + mcPartonicMotherIndex = mFindLastPartonicMother + ? this->findLastPartonicMother(mcParticle, mcParticles) + : this->findFirstPartonicMother(mcParticle, mcParticles); + } if (mcPartonicMotherIndex >= 0) { auto itPM = mMcPartonicMotherMap.find(mcPartonicMotherIndex); if (itPM != mMcPartonicMotherMap.end()) { @@ -474,13 +551,12 @@ class McBuilder return mcParticleRow; } - template - void fillMcLabelGeneric(T1 const& col, - T2 const& mcCols, - T3 const& particle, - T4 const& mcParticles, - T5& mcProducts, - T6 writeLabels, + template + void fillMcLabelGeneric(T1 const& particle, + T2 const& mcParticles, + T3 const& /*mcCols*/, + T4& mcProducts, + T5 writeLabels, bool startFromMotherParticle = false) { if (!particle.has_mcParticle()) { @@ -488,21 +564,21 @@ class McBuilder return; } - auto mcParticle = particle.template mcParticle_as(); - auto mcCol = mcParticle.template mcCollision_as(); + auto mcParticle = particle.template mcParticle_as(); + auto mcCol = mcParticle.template mcCollision_as(); if (startFromMotherParticle) { // in case of e.g. sigmas we do not reconstruct the mother but the daughter, so here we want to start from the mother particle - auto mcDaughterParticle = particle.template mcParticle_as(); + auto mcDaughterParticle = particle.template mcParticle_as(); if (!mcDaughterParticle.has_mothers()) { writeLabels(mcProducts, -1); return; } - auto mothersOfDaughter = mcDaughterParticle.template mothers_as(); + auto mothersOfDaughter = mcDaughterParticle.template mothers_as(); mcParticle = mothersOfDaughter.front(); } - int64_t mcParticleRow = this->getOrCreateMcParticleRow(col, mcCols, mcParticle, mcParticles, mcCol, mcProducts); + int64_t mcParticleRow = this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); writeLabels(mcProducts, mcParticleRow); } @@ -594,7 +670,7 @@ class McBuilder } currentIndex = nextIndex; } - return -1; + return lastPartonIndex; } bool mPassThrough = false; @@ -609,13 +685,16 @@ class McBuilder bool mProduceTrackLabels = false; bool mProduceLambdaLabels = false; bool mProduceK0shortLabels = false; + bool mProduceD0Labels = false; bool mProduceSigmaLabels = false; bool mProduceSigmaPlusLabels = false; bool mProduceXiLabels = false; bool mProduceOmegaLabels = false; bool mProduceMcMotherLabels = false; + float mCharmYGenMax = 0.8f; - float mEtaAcceptanceMcOnly = 0.8; + float mEtaAcceptanceMcOnly = 0.8f; + float mEtaAcceptanceMcReco = 1.f; std::unordered_map mCollisionMap; diff --git a/PWGCF/Femto/Core/modes.h b/PWGCF/Femto/Core/modes.h index e3694abbf53..8398aa56488 100644 --- a/PWGCF/Femto/Core/modes.h +++ b/PWGCF/Femto/Core/modes.h @@ -97,16 +97,19 @@ enum class Particle : o2::analysis::femto::datatypes::ParticleType { kV0 = 3, kKink = 4, kCascade = 5, + kCharmHadron = 6, }; enum class McOrigin : o2::analysis::femto::datatypes::McOriginType { - kNoMcParticle = 0, // no associated mc particle normally indicated a wrongly reconstruced partilce - kFromWrongCollision = 1, // partilce originates from the wrong collision or a collision which was wrongly reconstructed (like a split vertex) + kNoMcParticle = 0, // no associated mc particle, normally indicated by wrongly reconstructed particle + kFromWrongCollision = 1, // particle originates from the wrong collision or a collision which was wrongly reconstructed (like a split vertex) kPhysicalPrimary = 2, // primary particle kFromSecondaryDecay = 3, // particle from secondary decay - kFromMaterial = 4, // partilce orginates from material - kMissidentified = 5, // partilce was kMissidentified (also know as fake) - kMcOriginLast = 6 + kFromMaterial = 4, // particle originates from material + kMissidentified = 5, // particle was kMissidentified (also know as fake) + kPrompt = 6, // HF only: charm hadron produced promptly (from c quark) + kNonPrompt = 7, // HF only: charm hadron from beauty decay + kMcOriginLast = 8 // kFromFakeRecoCollision, // kFromUnkown }; @@ -126,6 +129,10 @@ constexpr const char* mcOriginToString(McOrigin origin) return "FromMaterial"; case McOrigin::kMissidentified: return "Missidentified"; + case McOrigin::kPrompt: + return "Prompt"; + case McOrigin::kNonPrompt: + return "NonPrompt"; default: return "UnknownMcOrigin"; } @@ -136,7 +143,8 @@ enum class Track : o2::analysis::femto::datatypes::TrackType { kV0Daughter, kCascadeBachelor, kResonanceDaughter, - kKinkDaughter + kKinkDaughter, + kCharmDaughter }; enum class V0 : o2::analysis::femto::datatypes::V0Type { @@ -163,5 +171,23 @@ enum class TwoTrackResonance : o2::analysis::femto::datatypes::TwoTrackResonance kKstar0Bar }; +enum class CharmHadron : o2::analysis::femto::datatypes::CharmHadronType { + kD0, + kD0Bar, + kDplus, + kLc +}; + +enum class QvecDetector : o2::analysis::femto::datatypes::QvecDetectorType { + kFT0C = 0, + kFT0A = 1 +}; + +enum class QvecHarmonic : o2::analysis::femto::datatypes::QvecHarmonicType { + kN1 = 1, + kN2 = 2, + kN3 = 3 +}; + }; // namespace o2::analysis::femto::modes #endif // PWGCF_FEMTO_CORE_MODES_H_ diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index 879cd2486ba..4d7cbed796a 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -17,6 +17,7 @@ #define PWGCF_FEMTO_CORE_PAIRBUILDER_H_ #include "PWGCF/Femto/Core/cascadeHistManager.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" #include "PWGCF/Femto/Core/closePairRejection.h" #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/kinkHistManager.h" @@ -41,6 +42,7 @@ #include #include #include +#include #include namespace o2::analysis::femto::pairbuilder @@ -323,8 +325,10 @@ class PairV0V0Builder typename T14, typename T15, typename T16, + typename T17, typename T18, - typename T17> + typename T19, + typename T20> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confV0Selection1, @@ -339,37 +343,55 @@ class PairV0V0Builder std::map> const& colHistSpec, std::map> const& V0HistSpec1, std::map> const& V0HistSpec2, - std::map> const& PosDauHistSpec, - std::map> const& NegDauHistSpec, - std::map> const& pairHistSpec, - std::map> const& cprHistSpecPos, - std::map> const& cprHistSpecNeg) + std::map> const& PosDauHistSpec1, + std::map> const& NegDauHistSpec1, + std::map> const& PosDauHistSpec2, + std::map> const& NegDauHistSpec2, + std::map> const& pairHistSpec, + std::map> const& cprHistSpecPos, + std::map> const& cprHistSpecNeg) { - - // check if correlate the same tracks or not mSameSpecies = confMixing.sameSpecies.value; + if constexpr (v0Type1 != v0Type2) { + // two different v0 species can never be identical particles + if (mSameSpecies) { + LOG(warn) << "sameSpecies=true is impossible for different v0 species (v0Type1=" + << static_cast(v0Type1) << ", v0Type2=" << static_cast(v0Type2) + << "). Overriding sameSpecies to false."; + mSameSpecies = false; + } + } else { + // same v0 species: both values are legitimate (e.g. lambda-lambda vs lambda-antilambda), + // but running as different species only makes sense if the two selections are disjoint + if (!mSameSpecies && confV0Selection1.sign.value == confV0Selection2.sign.value) { + LOG(warn) << "sameSpecies=false for identical v0 species with identical sign (" + << confV0Selection1.sign.value << "). If both selections match the same " + << "candidates, this produces self-pairs and double counting."; + } + } + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPc.template init(confPairCuts); - if (mSameSpecies) { - mV0Cleaner1.init(confV0Cleaner1); - mV0HistManager1.template init(registry, V0HistSpec1, confV0Selection1, PosDauHistSpec, NegDauHistSpec); + mV0Cleaner1.init(confV0Cleaner1); + mV0Cleaner2.init(confV0Cleaner2); + + // the first v0 (and its daughters) is always present + mV0HistManager1.template init(registry, V0HistSpec1, confV0Selection1, PosDauHistSpec1, NegDauHistSpec1); + if (mSameSpecies) { mPairHistManagerSe.setMass(confV0Selection1.pdgCodeAbs.value, confV0Selection1.pdgCodeAbs.value); mPairHistManagerSe.setCharge(1, 1); - mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprPos); + mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); mPairHistManagerMe.setMass(confV0Selection1.pdgCodeAbs.value, confV0Selection1.pdgCodeAbs.value); mPairHistManagerMe.setCharge(1, 1); mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); } else { - mV0Cleaner1.init(confV0Cleaner1); - mV0Cleaner2.init(confV0Cleaner2); - mV0HistManager1.template init(registry, V0HistSpec1, confV0Selection1, PosDauHistSpec, NegDauHistSpec); - mV0HistManager2.template init(registry, V0HistSpec2, confV0Selection2, PosDauHistSpec, NegDauHistSpec); + mV0HistManager2.template init(registry, V0HistSpec2, confV0Selection2, PosDauHistSpec2, NegDauHistSpec2); mPairHistManagerSe.setMass(confV0Selection1.pdgCodeAbs.value, confV0Selection2.pdgCodeAbs.value); mPairHistManagerSe.setCharge(1, 1); @@ -385,6 +407,7 @@ class PairV0V0Builder mMixingDepth = confMixing.depth.value; // setup rng if necessary + // mDist is bounded at declaration, so it stays valid even if this branch is not taken if (confMixing.seed.value >= 0) { uint64_t randomSeed = 0; mMixIdenticalParticles = true; @@ -452,8 +475,8 @@ class PairV0V0Builder } } - template - void processMixedEvent(T1 const& cols, T2 const& trackTable, T3 const& /*v0table*/, T4& partition1, T5& partition2, T6& cache, T7& binsVtxMult, T8& binsVtxCent, T9& binsVtxMultCent) + template + void processMixedEvent(T1 const& cols, T2 const& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) { if (mSameSpecies) { @@ -537,7 +560,453 @@ class PairV0V0Builder int mMixingDepth = 5; bool mMixIdenticalParticles = false; std::mt19937 mRng; - std::uniform_int_distribution<> mDist; + std::uniform_int_distribution<> mDist{static_cast(pairprocesshelpers::kOrder12), + static_cast(pairprocesshelpers::kOrder21)}; +}; + +template +class PairD0D0Builder +{ + public: + PairD0D0Builder() = default; + ~PairD0D0Builder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confCollisionBinning, + T2 const& confD0Selection1, + T3 const& confD0Selection2, + T4 const& confD0Cleaner1, + T5 const& confD0Cleaner2, + T6 const& confCprPos, + T7 const& confCprNeg, + T8 const& confMixing, + T9 const& confPairBinning, + T10 const& confPairCuts, + std::map> const& colHistSpec, + std::map> const& D0HistSpec1, + std::map> const& D0HistSpec2, + std::map> const& PosDauHistSpec1, + std::map> const& NegDauHistSpec1, + std::map> const& PosDauHistSpec2, + std::map> const& NegDauHistSpec2, + std::map> const& pairHistSpec, + std::map> const& cprHistSpecPos, + std::map> const& cprHistSpecNeg) + { + mSameSpecies = confMixing.sameSpecies.value; + + if (mSameSpecies && confD0Selection1.sign.value != confD0Selection2.sign.value) { + LOG(warn) << "sameSpecies=true, but the two selections have different signs (" + << confD0Selection1.sign.value << " vs " << confD0Selection2.sign.value + << "). D0 and D0bar are not identical particles. Overriding sameSpecies to false."; + mSameSpecies = false; + } + if (!mSameSpecies && confD0Selection1.sign.value == confD0Selection2.sign.value) { + LOG(warn) << "sameSpecies=false for identical selections with identical sign (" + << confD0Selection1.sign.value << "). If both selections match the same " + << "candidates, this produces self-pairs and double counting."; + } + if (confD0Selection1.sign.value == 0 || confD0Selection2.sign.value == 0) { + LOG(warn) << "sign=0 accepts both the D0 and the D0bar hypothesis of the same candidate. " + << "Set an explicit sign (+1: D0, -1: D0bar) for both slots in a D0-D0 analysis."; + } + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); + mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPc.template init(confPairCuts); + + mD0Cleaner1.init(confD0Cleaner1); + mD0Cleaner2.init(confD0Cleaner2); + + mD0HistManager1.template init(registry, D0HistSpec1, confD0Selection1, PosDauHistSpec1, NegDauHistSpec1); + + auto prongPdgCodes = [](int sign) -> std::pair { + if (sign > 0) { + return {PDG_t::kPiPlus, PDG_t::kKMinus}; + } + return {PDG_t::kKPlus, PDG_t::kPiMinus}; + }; + auto [posDauPdg1, negDauPdg1] = prongPdgCodes(confD0Selection1.sign.value); + + if (mSameSpecies) { + mPairHistManagerSe.setMass(confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1, confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1); + mPairHistManagerSe.setCharge(1, 1); + mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + + mPairHistManagerMe.setMass(confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1, confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1); + mPairHistManagerMe.setCharge(1, 1); + mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + } else { + mD0HistManager2.template init(registry, D0HistSpec2, confD0Selection2, PosDauHistSpec2, NegDauHistSpec2); + auto [posDauPdg2, negDauPdg2] = prongPdgCodes(confD0Selection2.sign.value); + + mPairHistManagerSe.setMass(confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1, confD0Selection2.pdgCodeAbs.value, posDauPdg2, negDauPdg2); + mPairHistManagerSe.setCharge(1, 1); + mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + + mPairHistManagerMe.setMass(confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1, confD0Selection2.pdgCodeAbs.value, posDauPdg2, negDauPdg2); + mPairHistManagerMe.setCharge(1, 1); + mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + } + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + // setup rng if necessary + // mDist is bounded at declaration, so it stays valid even if this branch is not taken + if (confMixing.seed.value >= 0) { + uint64_t randomSeed = 0; + mMixIdenticalParticles = true; + if (confMixing.seed.value == 0) { + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } else { + randomSeed = static_cast(confMixing.seed.value); + } + mRng = std::mt19937(randomSeed); + } + } + + template + void processSameEvent(T1 const& col, T2 const& trackTable, T3& /*d0table*/, T4& partition1, T5& partition2, T6& cache) + { + if (mSameSpecies) { + auto d0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice1.size() < nLimitPartitionIdenticalParticles) { + return; + } + mColHistManager.template fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::PairOrder pairOrder = pairprocesshelpers::kOrder12; + if (mMixIdenticalParticles) { + pairOrder = static_cast(mDist(mRng)); + } + pairprocesshelpers::processSameEvent(d0Slice1, trackTable, col, mD0HistManager1, mPairHistManagerSe, mCprSe, mPc, pairOrder); + } else { + auto d0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto d0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice1.size() < nLimitPartitionParticles || d0Slice2.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(d0Slice1, d0Slice2, trackTable, col, mD0HistManager1, mD0HistManager2, mPairHistManagerSe, mCprSe, mPc); + } + } + + // mc + template + void processSameEvent(T1 const& col, T2 const& mcCols, T3 const& trackTable, T4 const& /*d0table*/, T5& partition1, T6& partition2, T7 const& mcParticles, T8 const& mcMothers, T9 const& mcPartonicMothers, T10& cache) + { + if (mSameSpecies) { + auto d0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice1.size() < nLimitPartitionIdenticalParticles) { + return; + } + mColHistManager.template fill(col, mcCols); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::PairOrder pairOrder = pairprocesshelpers::kOrder12; + if (mMixIdenticalParticles) { + pairOrder = static_cast(mDist(mRng)); + } + pairprocesshelpers::processSameEvent(d0Slice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mD0HistManager1, mPairHistManagerSe, mD0Cleaner1, mCprSe, mPc, pairOrder); + } else { + auto d0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto d0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice1.size() < nLimitPartitionParticles || d0Slice2.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col, mcCols); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(d0Slice1, d0Slice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mD0HistManager1, mD0HistManager2, mPairHistManagerSe, mD0Cleaner1, mD0Cleaner2, mCprSe, mPc); + } + } + + template + void processMixedEvent(T1 const& cols, T2 const& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + if (mSameSpecies) { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } else { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + } + + template + void processMixedEvent(T1 const& cols, T2 const& mcCols, T3& trackTable, T4& partition1, T5& partition2, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& cache, T10& binsVtxMult, T11& binsVtxCent, T12& binsVtxMultCent) + { + if (mSameSpecies) { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } else { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager1; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager2; + particlecleaner::ParticleCleaner mD0Cleaner1; + particlecleaner::ParticleCleaner mD0Cleaner2; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionV0V0 mCprSe; + closepairrejection::ClosePairRejectionV0V0 mCprMe; + paircleaner::V0V0PairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + bool mSameSpecies = false; + int mMixingDepth = 5; + bool mMixIdenticalParticles = false; + std::mt19937 mRng; + std::uniform_int_distribution<> mDist{static_cast(pairprocesshelpers::kOrder12), + static_cast(pairprocesshelpers::kOrder21)}; +}; + +template +class PairTrackD0Builder +{ + public: + PairTrackD0Builder() = default; + ~PairTrackD0Builder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confCollisionBinning, + T2 const& confTrackSelection, + T3 const& confTrackCleaner, + T4 const& confD0Selection, + T5 const& confD0Cleaner, + T6 const& confCpr, + T7 const& confMixing, + T8 const& confPairBinning, + T9 const& confPairCuts, + std::map>& colHistSpec, + std::map>& trackHistSpec, + std::map>& d0HistSpec, + std::map>& posDauHistSpec, + std::map>& negDauHistSpec, + std::map>& pairHistSpec, + std::map>& cprHistSpec) + { + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); + + mTrackHistManager.template init(registry, trackHistSpec, confTrackSelection); + mD0HistManager.template init(registry, d0HistSpec, confD0Selection, posDauHistSpec, negDauHistSpec); + + mTrackCleaner.init(confTrackCleaner); + mD0Cleaner.init(confD0Cleaner); + + // pdg codes of the D0 prongs depend on the hypothesis: + // D0 -> pi+ K- => PosDau = pion, NegDau = kaon + // D0bar -> K+ pi- => PosDau = kaon, NegDau = pion + int posDauPdg = 0; + int negDauPdg = 0; + if (confD0Selection.sign.value > 0) { + posDauPdg = PDG_t::kPiPlus; + negDauPdg = PDG_t::kKMinus; + } else { + posDauPdg = PDG_t::kKPlus; + negDauPdg = PDG_t::kPiMinus; + } + + mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerSe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confD0Selection.pdgCodeAbs.value, posDauPdg, negDauPdg); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confD0Selection.pdgCodeAbs.value, posDauPdg, negDauPdg); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + mPc.template init(confPairCuts); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*d0table*/, T5& d0Partition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() < nLimitPartitionParticles || d0Slice.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, col, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& d0Partition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + template + void processSameEvent(T1 const& col, T2 const& mcCols, T3 const& trackTable, T4& trackPartition, T5 const& /*d0table*/, T6& d0Partition, T7 const& mcParticles, T8 const& mcMothers, T9 const& mcPartonicMothers, T10& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() < nLimitPartitionParticles || d0Slice.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col, mcCols); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mTrackCleaner, mD0Cleaner, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2 const& mcCols, T3& trackTable, T4& trackPartition, T5& d0Partition, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& cache, T10& binsVtxMult, T11& binsVtxCent, T12& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager; + particlecleaner::ParticleCleaner mTrackCleaner; + particlecleaner::ParticleCleaner mD0Cleaner; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackV0 mCprSe; + closepairrejection::ClosePairRejectionTrackV0 mCprMe; + paircleaner::TrackV0PairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; }; template - void init(T const& PairCuts) + void init(T const& pairCuts) { if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { - mMixPairsWithCommonAncestor = PairCuts.mixOnlyCommonAncestor.value; - mMixPairsWithNonCommonAncestor = PairCuts.mixOnlyNonCommonAncestor.value; + mMixPairsWithCommonAncestor = pairCuts.mixOnlyCommonAncestor.value; + mMixPairsWithNonCommonAncestor = pairCuts.mixOnlyNonCommonAncestor.value; if (mMixPairsWithCommonAncestor && mMixPairsWithNonCommonAncestor) { LOG(fatal) << "Both mixing with common and non-common ancestor is activated. Breaking..."; } @@ -147,14 +147,14 @@ class V0V0PairCleaner : public BasePairCleaner // also works for particles decay public: V0V0PairCleaner() = default; template - bool isCleanPair(const T1& v01, const T2& v02, const T3& trackTable) const + bool isCleanPair(T1 const& v01, T2 const& v02, T3 const& trackTable) const { auto posDaughter1 = trackTable.rawIteratorAt(v01.posDauId() - trackTable.offset()); auto negDaughter1 = trackTable.rawIteratorAt(v01.negDauId() - trackTable.offset()); auto posDaughter2 = trackTable.rawIteratorAt(v02.posDauId() - trackTable.offset()); auto negDaughter2 = trackTable.rawIteratorAt(v02.negDauId() - trackTable.offset()); - // check all charge combinations - return this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && + return this->isCleanParticlePair(v01, v02) && + this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && this->isCleanParticlePair(posDaughter1, negDaughter2) && this->isCleanParticlePair(negDaughter1, posDaughter2); } @@ -181,7 +181,7 @@ class TrackV0PairCleaner : public BasePairCleaner // also works for particles de public: TrackV0PairCleaner() = default; template - bool isCleanPair(const T1& track, const T2& v0, const T3& trackTable) const + bool isCleanPair(T1 const& track, T2 const& v0, T3 const& trackTable) const { auto posDaughter = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); @@ -211,7 +211,7 @@ class TrackKinkPairCleaner : public BasePairCleaner public: TrackKinkPairCleaner() = default; template - bool isCleanPair(const T1& track, const T2& kink, const T3& trackTable) const + bool isCleanPair(T1 const& track, T2 const& kink, T3 const& trackTable) const { auto chaDaughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); return this->isCleanParticlePair(chaDaughter, track); @@ -240,7 +240,7 @@ class TrackCascadePairCleaner : public BasePairCleaner public: TrackCascadePairCleaner() = default; template - bool isCleanPair(const T1& track, const T2& cascade, const T3& trackTable) const + bool isCleanPair(T1 const& track, T2 const& cascade, T3 const& trackTable) const { auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); auto posDaughter = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index ed8f6054c4f..99d66198ad7 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -69,6 +69,8 @@ enum PairHist { kKstarVsMt, kKstarVsMult, kKstarVsCent, + // 3D: k* vs kT vs centrality + kKstarVsKtVsCent, // 2D with mass kKstarVsMass1, kKstarVsMass2, @@ -184,6 +186,7 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::Configurable usePdgMass{"usePdgMass", true, "(Reco) Use PDF masses for 4-vectors. If false, use reconstructed mass (if available). Not consulted for pure mc-truth pairs, which always use PDG mass"}; o2::framework::Configurable plot1D{"plot1D", true, "(Reco/Mc) Enable 1D histograms"}; o2::framework::Configurable plot2D{"plot2D", true, "(Reco/Mc) Enable 2D histograms"}; + o2::framework::Configurable plotKstarVsKtVsCent{"plotKstarVsKtVsCent", false, "(Reco/Mc) Enable 3D histogram (Kstar Vs Kt Vs Cent)"}; o2::framework::Configurable plotKstarVsMtVsMult{"plotKstarVsMtVsMult", false, "(Reco/Mc) Enable 3D histogram (Kstar Vs Mt Vs Mult)"}; o2::framework::Configurable plotKstarVsMtVsMultVsCent{"plotKstarVsMtVsMultVsCent", false, "(Reco/Mc) Enable 4D histogram (Kstar Vs Mt Vs Mult Vs Cent)"}; o2::framework::Configurable plotKstarVsMtVsPt1VsPt2{"plotKstarVsMtVsPt1VsPt2", false, "(Reco/Mc) Enable 4D histogram (Kstar Vs Mt Vs Pt1 Vs Pt2)"}; @@ -213,7 +216,7 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis pt2{"pt2", {{100, 0, 6}}, "Pt binning for particle 2"}; o2::framework::ConfigurableAxis mass1{"mass1", {{100, 0, 2}}, "Mass binning for particle 1 (if particle has mass getter, otherwise PDG mass)"}; o2::framework::ConfigurableAxis mass2{"mass2", {{100, 0, 2}}, "Mass binning for particle 2 (if particle has mass getter, otherwise PDG mass)"}; - o2::framework::ConfigurableAxis massInv{"massInv", {{100, 0, 2}}, "Invariant Mass binning"}; + o2::framework::ConfigurableAxis massInv{"massInv", {{100, 0, 5}}, "Invariant Mass binning"}; o2::framework::ConfigurableAxis dalitzMtot{"dalitzMtot", {{100, 0, 10}}, "Total invariant mass squared binning in darlitz plot"}; o2::framework::ConfigurableAxis dalitzM12{"dalitzM12", {{100, 0, 10}}, "Mass12 binning of darlitz plot"}; o2::framework::ConfigurableAxis dalitzM13{"dalitzM13", {{100, 0, 10}}, "Mass13 binning of darlitz plot"}; @@ -231,7 +234,7 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::Configurable shUseCent{"shUseCent", false, "SH: bin by centrality instead of multiplicity"}; o2::framework::ConfigurableAxis shCentBins{"shCentBins", {o2::framework::VARIABLE_WIDTH, 0.0f, 200.0f}, "SH: multiplicity/centrality bin edges (like FemtoUniverse confMultKstarBins)"}; o2::framework::ConfigurableAxis shKtBins{"shKtBins", {o2::framework::VARIABLE_WIDTH, 0.1f, 0.2f, 0.3f, 0.4f}, "SH: kT bin edges (like FemtoUniverse confKtKstarBins)"}; - o2::framework::Configurable shPlot1D{"shPlot1D", false, "(SH) Also fill 1D qinv/k* numerator/denominator (h1D) per (mult,kT) bin"}; + o2::framework::Configurable shPlot1D{"shPlot1D", false, "(SH) Also fill the 1D qinv/k* distribution (h1D) and the bin occupancy (BinCount) per (mult,kT) bin"}; }; struct ConfPairCuts : o2::framework::ConfigurableGroup { @@ -277,6 +280,7 @@ constexpr std::array, kPairHistogramLast> {kPt1VsMinv, o2::framework::HistType::kTH2F, "hPt1VsMinv", "p_{T,1} vs m_{Inv}; p_{T,1} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}, {kPt2VsMinv, o2::framework::HistType::kTH2F, "hPt2VsMinv", "p_{T,2} vs m_{Inv}; p_{T,2} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}, // n-D + {kKstarVsKtVsCent, o2::framework::HistType::kTHnSparseF, "hKstarVsKtVsCent", "k* vs k_{T} vs centrality; k* (GeV/#it{c}); k_{T} (GeV/#it{c}); Centrality (%);"}, {kKstarVsMtVsMult, o2::framework::HistType::kTHnSparseF, "hKstarVsMtVsMult", "k* vs m_{T} vs multiplicity; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); Multiplicity;"}, {kKstarVsMtVsMultVsCent, o2::framework::HistType::kTHnSparseF, "hKstarVsMtVsMultVsCent", "k* vs m_{T} vs multiplicity vs centrality; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); Multiplicity; Centrality (%);"}, // n-D with pt @@ -367,6 +371,7 @@ constexpr std::array, kPairHistogramLast> {kKstarVsMt, {(confAnalysis).kstar, (confAnalysis).mt}}, \ {kKstarVsMult, {(confAnalysis).kstar, (confAnalysis).multiplicity}}, \ {kKstarVsCent, {(confAnalysis).kstar, (confAnalysis).centrality}}, \ + {kKstarVsKtVsCent, {(confAnalysis).kstar, (confAnalysis).kt, (confAnalysis).centrality}}, \ {kKstarVsMass1, {(confAnalysis).kstar, (confAnalysis).mass1}}, \ {kKstarVsMass2, {(confAnalysis).kstar, (confAnalysis).mass2}}, \ {kMass1VsMass2, {(confAnalysis).mass1, (confAnalysis).mass2}}, \ @@ -491,6 +496,11 @@ constexpr char PrefixTrackTrackMe[] = "TrackTrack/ME/"; constexpr char PrefixTrackV0Se[] = "TrackV0/SE/"; constexpr char PrefixTrackV0Me[] = "TrackV0/ME/"; +constexpr char PrefixTrackD0Se[] = "TrackD0/SE/"; +constexpr char PrefixTrackD0Me[] = "TrackD0/ME/"; +constexpr char PrefixD0D0Se[] = "D0D0/SE/"; +constexpr char PrefixD0D0Me[] = "D0D0/ME/"; + constexpr char PrefixV0V0Se[] = "V0V0/SE/"; constexpr char PrefixV0V0Me[] = "V0V0/ME/"; @@ -536,6 +546,7 @@ class PairHistManager // flags for histograms mPlot1d = ConfPairBinning.plot1D.value; mPlot2d = ConfPairBinning.plot2D.value; + mPlotKstarVsKtVsCent = ConfPairBinning.plotKstarVsKtVsCent.value; mPlotKstarVsMtVsMult = ConfPairBinning.plotKstarVsMtVsMult.value; mPlotKstarVsMtVsMultVsCent = ConfPairBinning.plotKstarVsMtVsMultVsCent.value; @@ -575,6 +586,8 @@ class PairHistManager // copy bin edges, stripping the leading VARIABLE_WIDTH (0) marker mShCentEdges.assign(ConfPairBinning.shCentBins.value.begin() + 1, ConfPairBinning.shCentBins.value.end()); mShKtEdges.assign(ConfPairBinning.shKtBins.value.begin() + 1, ConfPairBinning.shKtBins.value.end()); + mShCentSpec = {ConfPairBinning.shCentBins, mShUseCent ? "centrality (%)" : "multiplicity"}; + mShKtSpec = {ConfPairBinning.shKtBins, "k_{T} (GeV/#it{c})"}; } // transverse mass type @@ -696,7 +709,9 @@ class PairHistManager } if (mPlotDalitz) { - if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && modes::isEqual(particleType2, modes::Particle::kV0)) { + if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || + modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || + modes::isEqual(particleType2, modes::Particle::kCharmHadron))) { auto posDaughter = trackTable.rawIteratorAt(particle2.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(particle2.negDauId() - trackTable.offset()); ROOT::Math::PtEtaPhiMVector posDau4v = ROOT::Math::PtEtaPhiMVector(posDaughter.pt(), posDaughter.eta(), posDaughter.phi(), mPdgMassPosDau2); @@ -936,6 +951,9 @@ class PairHistManager } // higher dimensional histograms + if (mPlotKstarVsKtVsCent) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsKtVsCent, HistTable), getHistDesc(kKstarVsKtVsCent, HistTable), getHistType(kKstarVsKtVsCent, HistTable), {Specs.at(kKstarVsKtVsCent)}); + } if (mPlotKstarVsMtVsMult) { mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMtVsMult, HistTable), getHistDesc(kKstarVsMtVsMult, HistTable), getHistType(kKstarVsMtVsMult, HistTable), {Specs.at(kKstarVsMtVsMult)}); } @@ -1013,80 +1031,80 @@ class PairHistManager const int nKt = static_cast(mShKtEdges.size()) - 1; mShYlmBuffer.assign(nJM, {}); - mShReal.resize(nCent); - mShImag.resize(nCent); + mShReal.resize(nJM); + mShImag.resize(nJM); mShCov.resize(nCent); mSh1D.resize(nCent); mShBinCount.resize(nCent); + + const std::string dir = std::string(prefix) + std::string(AnalysisDir) + "SH/"; + int ihist = 0; + for (int l = 0; l <= mShLMax; ++l) { + for (int m = -l; m <= l; ++m) { + std::string lm = std::to_string(l); + lm += (m < 0) ? std::to_string(l - m) : std::to_string(m); + std::string nameRe = dir; + nameRe += "ReYlm"; + nameRe += lm; + std::string nameIm = dir; + nameIm += "ImYlm"; + nameIm += lm; + // shared "Y_{l}^{m}" suffix for both titles + std::string ylmLabel = "Y_{"; + ylmLabel += std::to_string(l); + ylmLabel += "}^{"; + ylmLabel += std::to_string(m); + ylmLabel += "}"; + std::string titleRe = "Re "; + titleRe += ylmLabel; + titleRe += "; k* (GeV/#it{c}); mult/cent; k_{T} (GeV/#it{c})"; + std::string titleIm = "Im "; + titleIm += ylmLabel; + titleIm += "; k* (GeV/#it{c}); mult/cent; k_{T} (GeV/#it{c})"; + mShReal[ihist] = mHistogramRegistry->add(nameRe.c_str(), titleRe.c_str(), o2::framework::kTH3D, {mShKstarSpec, mShCentSpec, mShKtSpec}); + mShImag[ihist] = mHistogramRegistry->add(nameIm.c_str(), titleIm.c_str(), o2::framework::kTH3D, {mShKstarSpec, mShCentSpec, mShKtSpec}); + mShReal[ihist]->Sumw2(); + mShImag[ihist]->Sumw2(); + ++ihist; + } + } + + const int nAxisLM = 2 * nJM; + const o2::framework::AxisSpec covLmAxis{nAxisLM, -0.5, static_cast(nAxisLM) - 0.5, "l,m #times (re,im)"}; + for (int iCent = 0; iCent < nCent; ++iCent) { - mShReal[iCent].resize(nKt); - mShImag[iCent].resize(nKt); mShCov[iCent].resize(nKt); mSh1D[iCent].resize(nKt); mShBinCount[iCent].resize(nKt); - // folder name: mult_{low}_{high} - const std::string centFolder = "mult_" + std::to_string(static_cast(mShCentEdges[iCent])) + - "_" + std::to_string(static_cast(mShCentEdges[iCent + 1])); + // name suffix: mult_{low}_{high} + std::string centSuffix = "_mult_"; + centSuffix += std::to_string(static_cast(mShCentEdges[iCent])); + centSuffix += "_"; + centSuffix += std::to_string(static_cast(mShCentEdges[iCent + 1])); for (int iKt = 0; iKt < nKt; ++iKt) { - mShReal[iCent][iKt].resize(nJM); - mShImag[iCent][iKt].resize(nJM); - // folder name: kT_{low*100}_{high*100} - std::string ktFolder = "kT_"; - ktFolder += std::to_string(static_cast(mShKtEdges[iKt] * 100.0)); - ktFolder += "_"; - ktFolder += std::to_string(static_cast(mShKtEdges[iKt + 1] * 100.0)); - std::string dir = std::string(prefix) + std::string(AnalysisDir) + "SH/"; - dir += centFolder; - dir += "/"; - dir += ktFolder; - dir += "/"; - - int ihist = 0; - for (int l = 0; l <= mShLMax; ++l) { - for (int m = -l; m <= l; ++m) { - std::string lm = std::to_string(l); - lm += (m < 0) ? std::to_string(l - m) : std::to_string(m); - std::string nameRe = dir; - nameRe += "ReYlm"; - nameRe += lm; - std::string nameIm = dir; - nameIm += "ImYlm"; - nameIm += lm; - // shared "Y_{l}^{m}" suffix for both titles - std::string ylmLabel = "Y_{"; - ylmLabel += std::to_string(l); - ylmLabel += "}^{"; - ylmLabel += std::to_string(m); - ylmLabel += "}"; - std::string titleRe = "Re "; - titleRe += ylmLabel; - titleRe += "; k* (GeV/#it{c}); Re[A_{l}^{m}]"; - std::string titleIm = "Im "; - titleIm += ylmLabel; - titleIm += "; k* (GeV/#it{c}); Im[A_{l}^{m}]"; - mShReal[iCent][iKt][ihist] = mHistogramRegistry->add(nameRe.c_str(), titleRe.c_str(), o2::framework::kTH1D, {mShKstarSpec}); - mShImag[iCent][iKt][ihist] = mHistogramRegistry->add(nameIm.c_str(), titleIm.c_str(), o2::framework::kTH1D, {mShKstarSpec}); - mShReal[iCent][iKt][ihist]->Sumw2(); - mShImag[iCent][iKt][ihist]->Sumw2(); - ++ihist; - } - } + // name suffix: _mult_{low}_{high}_kT_{low*100}_{high*100} + std::string cellSuffix = centSuffix; + cellSuffix += "_kT_"; + cellSuffix += std::to_string(static_cast(mShKtEdges[iKt] * 100.0)); + cellSuffix += "_"; + cellSuffix += std::to_string(static_cast(mShKtEdges[iKt + 1] * 100.0)); // SH covariance TH3D - const int nAxisLM = 2 * nJM; - const o2::framework::AxisSpec covLmAxis{nAxisLM, -0.5, static_cast(nAxisLM) - 0.5, "l,m #times (re,im)"}; std::string nameCov = dir; nameCov += "Cov"; + nameCov += cellSuffix; mShCov[iCent][iKt] = mHistogramRegistry->add(nameCov.c_str(), "SH covariance; k* (GeV/#it{c}); l,m; l,m", o2::framework::kTH3D, {mShKstarSpec, covLmAxis, covLmAxis}); mShCov[iCent][iKt]->Sumw2(); - std::string nameBinCount = dir; - nameBinCount += "BinCount"; - mShBinCount[iCent][iKt] = mHistogramRegistry->add(nameBinCount.c_str(), "SH bin occupancy; k* (GeV/#it{c}); Entries", o2::framework::kTH1D, {mShKstarSpec}); - if (mShPlot1D) { + std::string nameBinCount = dir; + nameBinCount += "BinCount"; + nameBinCount += cellSuffix; + mShBinCount[iCent][iKt] = mHistogramRegistry->add(nameBinCount.c_str(), "SH bin occupancy; k* (GeV/#it{c}); Entries", o2::framework::kTH1D, {mShKstarSpec}); + std::string name1D = dir; name1D += "h1D"; + name1D += cellSuffix; mSh1D[iCent][iKt] = mHistogramRegistry->add(name1D.c_str(), "1D distribution; k* (GeV/#it{c}); Entries", o2::framework::kTH1D, {mShKstarSpec}); mSh1D[iCent][iKt]->Sumw2(); } @@ -1218,6 +1236,9 @@ class PairHistManager // n-D histograms are only filled if enabled // if "mass" getter does not exist for particle, it will be just set to 0 // the user has to make sure that in this case the bin number of this dimension is set to 1 + if (mPlotKstarVsKtVsCent) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsKtVsCent, HistTable)), mKstar, mKt, mCent); + } if (mPlotKstarVsMtVsMult) { mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMtVsMult, HistTable)), mKstar, mMt, mMult); } @@ -1285,13 +1306,14 @@ class PairHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQoutQsideQlong, HistTable)), mQout, mQside, mQlong); } if (mPlotSH) { - const int iCent = findShBin(mShUseCent ? mCent : mMult, mShCentEdges); + const float shCentValue = mShUseCent ? mCent : mMult; + const int iCent = findShBin(shCentValue, mShCentEdges); const int iKt = findShBin(mKt, mShKtEdges); if (iCent >= 0 && iKt >= 0) { mYlm.doYlmUpToL(mShLMax, mShOut, mShSide, mShLong, mShYlmBuffer.data()); for (std::size_t i = 0; i < mShYlmBuffer.size(); ++i) { - mShReal[iCent][iKt][i]->Fill(mShKv, std::real(mShYlmBuffer[i])); - mShImag[iCent][iKt][i]->Fill(mShKv, -std::imag(mShYlmBuffer[i])); + mShReal[i]->Fill(mShKv, shCentValue, mKt, std::real(mShYlmBuffer[i])); + mShImag[i]->Fill(mShKv, shCentValue, mKt, -std::imag(mShYlmBuffer[i])); } // covariance: outer product of the (re, -im) Ylm vector packed on 2*nJM axes // (each Ylm contributes two consecutive axis bins: even = real, odd = -imag) @@ -1305,8 +1327,8 @@ class PairHistManager } } - mShBinCount[iCent][iKt]->Fill(mShKv, 1.0); if (mShPlot1D) { + mShBinCount[iCent][iKt]->Fill(mShKv, 1.0); // FemtoUniverse h1D = f3d[0]: qinv (=2k*) for identical-LCMS, else k*. const float sh1DValue = (mShFrame == ShFrameLcmsIdentical) ? (2.0f * mKstar) : mKstar; mSh1D[iCent][iKt]->Fill(sh1DValue); @@ -1627,6 +1649,7 @@ class PairHistManager bool mPlot1d = true; bool mPlot2d = true; + bool mPlotKstarVsKtVsCent = false; bool mPlotKstarVsMtVsMult = false; bool mPlotKstarVsMtVsMultVsCent = false; @@ -1673,6 +1696,8 @@ class PairHistManager static constexpr int ShFramePrf = 2; o2::framework::AxisSpec mShKstarSpec{{60, 0.0f, 0.3f}, "k* (GeV/#it{c})"}; // set in init() + o2::framework::AxisSpec mShCentSpec{{1, 0.0f, 200.0f}, "mult/cent"}; + o2::framework::AxisSpec mShKtSpec{{3, 0.1f, 0.4f}, "k_{T} (GeV/#it{c})"}; // kinematics computed in setPair(): axis value + 3 components feeding Ylm float mShKv = 0.f; // kstar (non-identical) or qinv (identical) @@ -1680,9 +1705,9 @@ class PairHistManager float mShSide = 0.f; float mShLong = 0.f; - // SH histograms binned in [iCent][iKt][ihist]; ihist = l*(l+1)+m - std::vector>>> mShReal; - std::vector>>> mShImag; + // SH histograms per [ihist] (ihist = l*(l+1)+m); TH3: k* on X, mult/cent on Y, kT on Z + std::vector> mShReal; + std::vector> mShImag; // SH covariance matrix per [iCent][iKt]; TH3d: k* on X, 2*nJM (l,m x re/im) std::vector>> mShCov; bool mShPlot1D = false; diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index b4d05f37be5..9606051ff57 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -119,7 +119,7 @@ void processSameEvent(T1 const& SliceParticle, if (!ParticleCleaner.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle, SliceParticle))) { // check if particles are clean @@ -246,13 +246,13 @@ void processSameEvent(T1 const& SliceParticle1, if (!ParticleCleaner1.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager1.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager1.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& part : SliceParticle2) { if (!ParticleCleaner2.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager2.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager2.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(SliceParticle1, SliceParticle2))) { // check if particles are clean diff --git a/PWGCF/Femto/Core/particleCleaner.h b/PWGCF/Femto/Core/particleCleaner.h index 54e1aa0a36a..ea4b65a91c7 100644 --- a/PWGCF/Femto/Core/particleCleaner.h +++ b/PWGCF/Femto/Core/particleCleaner.h @@ -50,6 +50,11 @@ constexpr const char PrefixLambdaCleaner2[] = "LambdaCleaner2"; using ConfLambdaCleaner1 = ConfParticleCleaner; using ConfLambdaCleaner2 = ConfParticleCleaner; +constexpr const char PrefixD0Cleaner1[] = "D0Cleaner1"; +constexpr const char PrefixD0Cleaner2[] = "D0Cleaner2"; +using ConfD0Cleaner1 = ConfParticleCleaner; +using ConfD0Cleaner2 = ConfParticleCleaner; + constexpr const char PrefixK0shortCleaner1[] = "K0shortCleaner1"; constexpr const char PrefixK0shortCleaner2[] = "K0shortCleaner2"; using ConfK0shortCleaner1 = ConfParticleCleaner; diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index cb32840b0d7..68508aa4c70 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -163,6 +163,22 @@ (o2::aod::femtobase::stored::mass < (selection).massMax) && \ ncheckbit(o2::aod::femtokinks::mask, (selection).mask) +// partition for D0 +// sign of signedPt encodes the hypothesis: D0 (+) / D0bar (-) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define MAKE_D0_PARTITION(selection) \ + ifnode((selection).sign.node() != 0, \ + ifnode((selection).sign.node() > 0, o2::aod::femtobase::stored::signedPt > 0.f, o2::aod::femtobase::stored::signedPt < 0.f), true) && \ + (nabs(o2::aod::femtobase::stored::signedPt) > (selection).ptMin) && \ + (nabs(o2::aod::femtobase::stored::signedPt) < (selection).ptMax) && \ + (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ + (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ + (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ + (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ + (o2::aod::femtobase::stored::mass > (selection).massMin) && \ + (o2::aod::femtobase::stored::mass < (selection).massMax) && \ + ncheckbit(o2::aod::femtocharmhadrons::mask, (selection).mask) + // macros for mc collisions (mc only) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define MAKE_MC_COLLISION_FILTER(selection) \ diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index ab25867c8c9..c7a6f711faf 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -530,6 +530,7 @@ class TrackSelection : public baseselection::BaseSelection producedTracks; + o2::framework::Produces producedLiteTracks; o2::framework::Produces producedTrackMass; o2::framework::Produces producedTrackMasks; o2::framework::Produces producedTrackDcas; @@ -546,6 +547,7 @@ struct TrackBuilderProducts : o2::framework::ProducesGroup { struct ConfTrackTables : o2::framework::ConfigurableGroup { std::string prefix = std::string("TrackTables"); o2::framework::Configurable produceTracks{"produceTracks", -1, "Produce Tracks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteTracks{"produceLiteTracks", -1, "Produce LiteTracks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceTrackMasks{"produceTrackMasks", -1, "Produce TrackMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceTrackMass{"produceTrackMass", -1, "Produce TrackMass (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceTrackDcas{"produceTrackDcas", -1, "Produce TrackDcas (-1: auto; 0 off; 1 on)"}; @@ -566,12 +568,13 @@ class TrackBuilder TrackBuilder() = default; ~TrackBuilder() = default; - template - void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext, T5& collisionBuilder) { LOG(info) << "Initialize femto track builder..."; mProduceTracks = utils::enableTable("FTracks_001", table.produceTracks.value, initContext); + mProduceLiteTracks = utils::enableTable("FLiteTracks_001", table.produceLiteTracks.value, initContext); // new mProduceTrackMasks = utils::enableTable("FTrackMasks_001", table.produceTrackMasks.value, initContext); mProduceTrackMass = utils::enableTable("FTrackMass_001", table.produceTrackMass.value, initContext); mProduceTrackDcas = utils::enableTable("FTrackDcas_001", table.produceTrackDcas.value, initContext); @@ -584,7 +587,24 @@ class TrackBuilder mProduceTritonPids = utils::enableTable("FTritonPids_001", table.produceTritonPids.value, initContext); mProduceHeliumPids = utils::enableTable("FHeliumPids_001", table.produceHeliumPids.value, initContext); - if (mProduceTracks || mProduceTrackMasks || mProduceTrackMass || mProduceTrackDcas || mProduceTrackExtras || mProduceElectronPids || mProducePionPids || mProduceKaonPids || mProduceProtonPids || mProduceDeuteronPids || mProduceTritonPids || mProduceHeliumPids) { + if (mProduceTracks && mProduceLiteTracks) { + LOG(fatal) << "FTracks and FLiteTracks are mutually exclusive -- enable only one. " + << "FLiteTracks is meant to replace FTracks at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FTracks from FLiteTracks downstream."; + } + + if (mProduceTracks && !collisionBuilder.producingCollisions()) { + LOG(fatal) << "FTracks is enabled, but the collision builder is not producing FCols (full precision). " + << "FTracks stores the collision index into FCols -- enable CollisionTables.produceCollisions, " + << "or switch to FLiteTracks if CollisionTables.produceLiteCollisions is enabled instead."; + } + if (mProduceLiteTracks && !collisionBuilder.producingLiteCollisions()) { + LOG(fatal) << "FLiteTracks is enabled, but the collision builder is not producing FLiteCols. " + << "FLiteTracks stores the collision index into FLiteCols -- enable CollisionTables.produceLiteCollisions, " + << "or switch to FTracks if CollisionTables.produceCollisions is enabled instead."; + } + + if (mProduceTracks || mProduceLiteTracks || mProduceTrackMasks || mProduceTrackMass || mProduceTrackDcas || mProduceTrackExtras || mProduceElectronPids || mProducePionPids || mProduceKaonPids || mProduceProtonPids || mProduceDeuteronPids || mProduceTritonPids || mProduceHeliumPids) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -612,22 +632,33 @@ class TrackBuilder } collisionBuilder.template fillCollision(collisionProducts, col); - this->fillTrack(track, trackProducts, collisionProducts); + this->fillTrack(track, trackProducts, collisionBuilder); } } template - bool fillTrack(T1 const& track, T2& trackProducts, T3& collisionProducts) + bool fillTrack(T1 const& track, T2& trackProducts, T3& collisionBuilder) { - if (!mProduceTracks) { + if (!mProduceTracks && !mProduceLiteTracks) { return false; } + int64_t lastIndex = 0; + if (mProduceTracks) { + trackProducts.producedTracks(collisionBuilder.collisionIndex(), + track.pt() * track.sign(), + track.eta(), + track.phi()); + lastIndex = trackProducts.producedTracks.lastIndex(); + } - trackProducts.producedTracks(collisionProducts.producedCollision.lastIndex(), - track.pt() * track.sign(), - track.eta(), - track.phi()); - indexMap.emplace(track.globalIndex(), trackProducts.producedTracks.lastIndex()); + if (mProduceLiteTracks) { + trackProducts.producedLiteTracks(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binSignedPt(track.pt() * track.sign()), + o2::aod::femtobase::lite::binEta(track.eta()), + o2::aod::femtobase::lite::binPhi(track.phi())); + lastIndex = trackProducts.producedLiteTracks.lastIndex(); + } + indexMap.emplace(track.globalIndex(), lastIndex); if (mProduceTrackMasks) { if constexpr (type == modes::Track::kTrack) { @@ -724,54 +755,57 @@ class TrackBuilder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); // get track from the track table so we can dereference mc particle properly auto track = tracks.iteratorAt(trackWithItsPid.index()); - this->template fillMcTrack(col, collisionProducts, mcCols, track, trackWithItsPid, trackProducts, mcParticles, mcBuilder, mcProducts); + this->template fillMcTrack(track, trackWithItsPid, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); } } - template - bool fillMcTrack(T1 const& col, T2& collisionProducts, T3 const& mcCols, T4 const& track, T5 const& trackWithItsPid, T6& trackProducts, T7 const& mcParticles, T8& mcBuilder, T9& mcProducts) + template + bool fillMcTrack(T1 const& track, T2 const& trackWithItsPid, T3& trackProducts, T4 const& mcCols, T5& collisionBuilder, T6 const& mcParticles, T7& mcBuilder, T8& mcProducts) { - // return value added, mirroring fillTrack(), so getDaughterIndex can detect - // whether a row was actually added before trusting lastIndex(). - if (!mProduceTracks) { + if (!mProduceTracks && !mProduceLiteTracks) { return false; } - this->template fillTrack(trackWithItsPid, trackProducts, collisionProducts); - mcBuilder.template fillMcTrackWithLabel(col, mcCols, track, mcParticles, mcProducts); + this->template fillTrack(trackWithItsPid, trackProducts, collisionBuilder); + mcBuilder.template fillMcTrackWithLabel(track, mcParticles, mcCols, mcProducts); return true; } template - int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts) + int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionBuilder) { auto result = utils::getIndex(daughter.globalIndex(), indexMap); if (result) { return result.value(); } - if (!this->template fillTrack(daughter, trackProducts, collisionProducts)) { - LOG(fatal) << "Trying to register a daughter track, but FTracks table is disabled. " - << "Enable TrackTables.produceTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; + if (!this->template fillTrack(daughter, trackProducts, collisionBuilder)) { + LOG(fatal) << "Trying to register a daughter track, but FTracks or FLiteTrack table is disabled. " + << "Enable TrackTables.produceTracks/produceLiteTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; } - // daughter is last track which was added added - return trackProducts.producedTracks.lastIndex(); + // fillTrack already inserted the correct index (FTracks or FLiteTracks) into indexMap + return indexMap.at(daughter.globalIndex()); } - template - int64_t getDaughterIndex(const T1& col, T2& collisionProducts, T3 const& mcCols, const T4& daughter, T5& trackProducts, T6 const& mcParticles, T7& mcBuilder, T8& mcProducts) + template + int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3 const& mcCols, T4& collisionBuilder, T5 const& mcParticles, T6& mcBuilder, T7& mcProducts) { auto result = utils::getIndex(daughter.globalIndex(), indexMap); if (result) { // daugher already in track table return result.value(); } - if (!this->template fillMcTrack(col, collisionProducts, mcCols, daughter, daughter, trackProducts, mcParticles, mcBuilder, mcProducts)) { - LOG(fatal) << "Trying to register a MC daughter track, but FTracks table is disabled. " - << "Enable TrackTables.produceTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; + if (!this->template fillMcTrack(daughter, daughter, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts)) { + LOG(fatal) << "Trying to register a daughter track, but FTracks or FLiteTrack table is disabled. " + << "Enable TrackTables.produceTracks/produceLiteTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; } - // daughter is last track which was added added - return trackProducts.producedTracks.lastIndex(); + // fillTrack already inserted the correct index (FTracks or FLiteTracks) into indexMap + return indexMap.at(daughter.globalIndex()); } + [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } + [[nodiscard]] bool isPassThrough() const { return mTrackSelection.isPassThrough(); } + [[nodiscard]] bool producingTracks() const { return mProduceTracks; } + [[nodiscard]] bool producingLiteTracks() const { return mProduceLiteTracks; } + template void reset(T const& tracks) { @@ -783,6 +817,7 @@ class TrackBuilder TrackSelection mTrackSelection; bool mFillAnyTable = false; bool mProduceTracks = false; + bool mProduceLiteTracks = false; bool mProduceTrackMasks = false; bool mProduceTrackMass = false; bool mProduceTrackDcas = false; @@ -838,7 +873,6 @@ class TrackBuilderDerivedToDerived template void processTracks(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& cache, T6& newTrackTable, T7& newCollisionTable) { - indexMap.clear(); if (mLimitTrack1 > 0) { auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -883,6 +917,13 @@ class TrackBuilderDerivedToDerived return idx; } + template + void reset(T const& tracks) + { + indexMap.clear(); + indexMap.reserve(tracks.size()); + } + private: int mLimitTrack1 = 0; int mLimitTrack2 = 0; diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h index af36c02acf6..058f13af0cb 100644 --- a/PWGCF/Femto/Core/trackHistManager.h +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -154,8 +154,14 @@ struct ConfTrackBinning : o2::framework::ConfigurableGroup { constexpr const char PrefixTrackBinning1[] = "TrackBinning1"; constexpr const char PrefixTrackBinning2[] = "TrackBinning2"; constexpr const char PrefixTrackBinning3[] = "TrackBinning3"; -constexpr const char PrefixV0PosDauBinning[] = "V0PosDauBinning"; -constexpr const char PrefixV0NegDauBinning[] = "V0NegDauBinning"; +constexpr const char PrefixV01PosDauBinning[] = "V01PosDauBinning"; +constexpr const char PrefixV01NegDauBinning[] = "V01NegDauBinning"; +constexpr const char PrefixV02PosDauBinning[] = "V02PosDauBinning"; +constexpr const char PrefixV02NegDauBinning[] = "V02NegDauBinning"; +constexpr const char PrefixD01PosDauBinning[] = "D01PosDauBinning"; +constexpr const char PrefixD01NegDauBinning[] = "D01NegDauBinning"; +constexpr const char PrefixD02PosDauBinning[] = "D02PosDauBinning"; +constexpr const char PrefixD02NegDauBinning[] = "D02NegDauBinning"; constexpr const char PrefixCascadePosDauBinning[] = "CascadePosDauBinning"; constexpr const char PrefixCascadeNegDauBinning[] = "CascadeNegDauBinning"; constexpr const char PrefixCascadeBachelorBinning[] = "CascadeBachelorBinning"; @@ -170,8 +176,14 @@ constexpr const char PrefixKaonMinusBinning[] = "KaonMinusBinning"; using ConfTrackBinning1 = ConfTrackBinning; using ConfTrackBinning2 = ConfTrackBinning; using ConfTrackBinning3 = ConfTrackBinning; -using ConfV0PosDauBinning = ConfTrackBinning; -using ConfV0NegDauBinning = ConfTrackBinning; +using ConfV01PosDauBinning = ConfTrackBinning; +using ConfV01NegDauBinning = ConfTrackBinning; +using ConfV02PosDauBinning = ConfTrackBinning; +using ConfV02NegDauBinning = ConfTrackBinning; +using ConfD01PosDauBinning = ConfTrackBinning; +using ConfD01NegDauBinning = ConfTrackBinning; +using ConfD02PosDauBinning = ConfTrackBinning; +using ConfD02NegDauBinning = ConfTrackBinning; using ConfCascadePosDauBinning = ConfTrackBinning; using ConfCascadeNegDauBinning = ConfTrackBinning; using ConfCascadeBachelorBinning = ConfTrackBinning; @@ -255,8 +267,12 @@ constexpr const char PrefixTrackQaBinning1[] = "TrackQaBinning1"; constexpr const char PrefixTrackQaBinning2[] = "TrackQaBinning2"; constexpr const char PrefixResonancePosDauQaBinning[] = "ResonancePosDauQaBinning"; constexpr const char PrefixResonanceNegDauQaBinning[] = "ResonanceNegDauQaBinning"; -constexpr const char PrefixV0PosDauQaBinning[] = "V0PosDauQaBinning"; -constexpr const char PrefixV0NegDauQaBinning[] = "V0NegDauQaBinning"; +constexpr const char PrefixV01PosDauQaBinning[] = "V01PosDauQaBinning"; +constexpr const char PrefixV01NegDauQaBinning[] = "V01NegDauQaBinning"; +constexpr const char PrefixV02PosDauQaBinning[] = "V02PosDauQaBinning"; +constexpr const char PrefixV02NegDauQaBinning[] = "V02NegDauQaBinning"; +constexpr const char PrefixD01PosDauQaBinning[] = "D01PosDauQaBinning"; +constexpr const char PrefixD01NegDauQaBinning[] = "D01NegDauQaBinning"; constexpr const char PrefixCascadePosDauQaBinning[] = "CascadePosDauQaBinning"; constexpr const char PrefixCascadeNegDauQaBinning[] = "CascadeNegDauQaBinning"; constexpr const char PrefixCascadeBachelorQaBinning[] = "CascadeBachelorQaBinning"; @@ -266,8 +282,12 @@ using ConfTrackQaBinning1 = ConfTrackQaBinning; using ConfTrackQaBinning2 = ConfTrackQaBinning; using ConfResonancePosDauQaBinning = ConfTrackQaBinning; using ConfResonanceNegDauQaBinning = ConfTrackQaBinning; -using ConfV0PosDauQaBinning = ConfTrackQaBinning; -using ConfV0NegDauQaBinning = ConfTrackQaBinning; +using ConfV01PosDauQaBinning = ConfTrackQaBinning; +using ConfV01NegDauQaBinning = ConfTrackQaBinning; +using ConfV02PosDauQaBinning = ConfTrackQaBinning; +using ConfV02NegDauQaBinning = ConfTrackQaBinning; +using ConfD01PosDauQaBinning = ConfTrackQaBinning; +using ConfD01NegDauQaBinning = ConfTrackQaBinning; using ConfCascadePosDauQaBinning = ConfTrackQaBinning; using ConfCascadeNegDauQaBinning = ConfTrackQaBinning; using ConfCascadeBachelorQaBinning = ConfTrackQaBinning; @@ -509,6 +529,13 @@ constexpr char PrefixResonanceNegDaughter[] = "ResonanceNegDau/"; constexpr char PrefixResonancePosDaughterQa[] = "ResonancePosDauQa/"; constexpr char PrefixResonanceNegDaughterQa[] = "ResonanceNegDauQa/"; +constexpr char PrefixD01PosDaughter[] = "D01PosDau/"; +constexpr char PrefixD01NegDaughter[] = "D01NegDau/"; +constexpr char PrefixD02PosDaughter[] = "D02PosDau/"; +constexpr char PrefixD02NegDaughter[] = "D02NegDau/"; +constexpr char PrefixD01PosDaughterQa[] = "D01PosDauQa/"; +constexpr char PrefixD01NegDaughterQa[] = "D01NegDauQa/"; + constexpr char PrefixV01PosDaughter[] = "V01PosDau/"; constexpr char PrefixV01NegDaughter[] = "V01NegDau/"; constexpr char PrefixV02PosDaughter[] = "V02PosDau/"; @@ -613,8 +640,8 @@ class TrackHistManager } } - template - void fill(T1 const& track, T2 const& /*trackTable*/, T3 const& mcParticles, T4 const& mcMothers, T5 const& mcPartonicMothers) + template + void fill(T1 const& track, T2 const& /*trackTable*/, T3 const& col, T4 const& mcParticles, T5 const& mcMothers, T6 const& mcPartonicMothers) { if constexpr (isFlagSet(mode, modes::Mode::kReco)) { this->fillAnalysis(track); @@ -623,7 +650,7 @@ class TrackHistManager this->fillQa(track); } if constexpr (isFlagSet(mode, modes::Mode::kMc)) { - this->template fillMc(track, mcParticles, mcMothers, mcPartonicMothers); + this->template fillMc(track, col, mcParticles, mcMothers, mcPartonicMothers); } } @@ -931,8 +958,8 @@ class TrackHistManager } } - template - void fillMc(T1 const& track, T2 const& /*mcParticles*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/) + template + void fillMc(T1 const& track, T2 const& col, T3 const& /*mcParticles*/, T4 const& /*mcMothers*/, T5 const& /*mcPartonicMothers*/) { // No MC Particle if (!track.has_fMcParticle()) { @@ -947,7 +974,11 @@ class TrackHistManager } // Retrieve MC particle - auto mcParticle = track.template fMcParticle_as(); + auto mcParticle = track.template fMcParticle_as(); + + // particles associcated to wrong collision + // whether a particle is associated to a wrong collision or not cannot be known by the producer so we check it here + bool fromWrongCollision = mcParticle.fMcColId() != col.fMcColId(); // missidentifed particles are special case // whether a particle is missidentfied or not cannot be known by the producer so we check it here @@ -956,8 +987,10 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTruePtVsPt, HistTable)), mcParticle.pt(), track.pt()); mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueEtaVsEta, HistTable)), mcParticle.eta(), track.eta()); mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTruePhiVsPhi, HistTable)), mcParticle.phi(), track.phi()); - if (isMissidentified) { - mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kFromWrongCollision)); + } else if (isMissidentified) { + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); } else { mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), mcParticle.origin()); } @@ -965,7 +998,7 @@ class TrackHistManager // get mother if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), mother.pdgCode()); } else { mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), 0); @@ -973,7 +1006,7 @@ class TrackHistManager // get partonic mother if (mcParticle.has_fMcPartMoth()) { - auto partonicMother = mcParticle.template fMcPartMoth_as(); + auto partonicMother = mcParticle.template fMcPartMoth_as(); mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), partonicMother.pdgCode()); } else { mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), 0); @@ -981,8 +1014,10 @@ class TrackHistManager if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { if (mPlotOrigins) { - // check first if particle is missidentified - if (isMissidentified) { + // check first if particle is from a wrong collision + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kFromWrongCollision, HistTable)), track.pt(), track.dcaXY(), track.dcaZ()); + } else if (isMissidentified) { // if it is, we fill it as such mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kMissidentified, HistTable)), track.pt(), track.dcaXY(), track.dcaZ()); } else { @@ -991,15 +1026,12 @@ class TrackHistManager case modes::McOrigin::kPhysicalPrimary: mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kPrimary, HistTable)), track.pt(), track.dcaXY(), track.dcaZ()); break; - case modes::McOrigin::kFromWrongCollision: - mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kFromWrongCollision, HistTable)), track.pt(), track.dcaXY(), track.dcaZ()); - break; case modes::McOrigin::kFromMaterial: mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kFromMaterial, HistTable)), track.pt(), track.dcaXY(), track.dcaZ()); break; case modes::McOrigin::kFromSecondaryDecay: if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); int motherPdgCode = std::abs(mother.pdgCode()); // Switch on PDG of the mother if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel1 && motherPdgCode == mPdgCodesSecondaryMother[0]) { diff --git a/PWGCF/Femto/Core/tripletProcessHelpers.h b/PWGCF/Femto/Core/tripletProcessHelpers.h index 1bfbfad796b..932f91b37c4 100644 --- a/PWGCF/Femto/Core/tripletProcessHelpers.h +++ b/PWGCF/Femto/Core/tripletProcessHelpers.h @@ -35,7 +35,6 @@ enum TripletOrder : uint8_t { }; // process same event for identical 3 particles -// (no cleaner here — ParticleCleaner only operates on MC info, see the mc overload below) template @@ -170,7 +168,6 @@ void processSameEvent(T1 const& SliceParticle1, // 1&2 have same species } // process same event for 3 different particles -// (no cleaner here — ParticleCleaner only operates on MC info, see the mc overload below) template (part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle, SliceParticle, SliceParticle))) { @@ -320,7 +316,6 @@ void processSameEvent(T1 const& SliceParticle, } // process same event for 2 identical particles and one other with mc information -// NOTE: added `Cleaner1` (for particle 1&2) and `Cleaner3` (for particle 3, a different species) template @@ -347,13 +342,13 @@ void processSameEvent(T1 const& SliceParticle1, if (!Cleaner1.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager1.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager1.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& part : SliceParticle3) { if (!Cleaner3.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager3.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager3.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& p3 : SliceParticle3) { @@ -443,19 +438,19 @@ void processSameEvent(T1 const& SliceParticle1, if (!Cleaner1.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager1.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager1.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& part : SliceParticle2) { if (!Cleaner2.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager2.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager2.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& part : SliceParticle3) { if (!Cleaner3.isClean(part, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - ParticleHistManager3.template fill(part, TrackTable, mcParticles, mcMothers, mcPartonicMothers); + ParticleHistManager3.template fill(part, TrackTable, Collision, mcParticles, mcMothers, mcPartonicMothers); } for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(SliceParticle1, SliceParticle2, SliceParticle3))) { diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h index ba19d2abc9b..8fcdb65bbdb 100644 --- a/PWGCF/Femto/Core/v0Builder.h +++ b/PWGCF/Femto/Core/v0Builder.h @@ -51,8 +51,8 @@ struct ConfV0Filters : o2::framework::ConfigurableGroup { o2::framework::Configurable massMinLambda{"massMinLambda", 1.f, "Minimum mass for Lambda hypothesis"}; o2::framework::Configurable massMaxLambda{"massMaxLambda", 1.2f, "Maximum mass for Lambda hypothesis"}; o2::framework::Configurable rejectHypothesisK0short{"rejectHypothesisK0short", true, "Rejection of K0short hypothesis for Lambda candidates"}; - o2::framework::Configurable rejectMassMinK0short{"rejectMassMinK0short", 0.48f, "Minimum mass to rejection K0short hypothesis for Lambda candidates"}; - o2::framework::Configurable rejectMassMaxK0short{"rejectMassMaxK0short", 0.5f, "Maximum mass to rejection K0short hypothesis for Lambda candidates"}; + o2::framework::Configurable rejectMassMinK0short{"rejectMassMinK0short", 0.475f, "Minimum mass to rejection K0short hypothesis for Lambda candidates"}; + o2::framework::Configurable rejectMassMaxK0short{"rejectMassMaxK0short", 0.515f, "Maximum mass to rejection K0short hypothesis for Lambda candidates"}; o2::framework::Configurable massMinK0short{"massMinK0short", 0.45f, "Minimum mass for K0Short hypothesis"}; o2::framework::Configurable massMaxK0short{"massMaxK0short", 0.53f, "Maximum mass for K0Short hypothesis"}; o2::framework::Configurable rejectHypothesisLambda{"rejectHypothesisLambda", true, "Rejection of Lambda hypothesis for K0short candidates"}; @@ -64,14 +64,16 @@ struct ConfV0Filters : o2::framework::ConfigurableGroup { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define V0_DEFAULT_BITS \ o2::framework::Configurable passThrough{"passThrough", false, "If true, all V0s are passed through. Bits for all selections are stored."}; \ - o2::framework::Configurable> dcaDauMax{"dcaDauMax", {1.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> dcaDauMax{"dcaDauMax", {1.5f}, "Maximum DCA between the daughters at V0 decay vertex (cm)"}; \ o2::framework::Configurable> cpaMin{"cpaMin", {0.99f}, "Minimum cosine of pointing angle"}; \ o2::framework::Configurable> transRadMin{"transRadMin", {0.2f}, "Minimum transverse radius (cm)"}; \ o2::framework::Configurable> transRadMax{"transRadMax", {100.f}, "Maximum transverse radius (cm)"}; \ o2::framework::Configurable> decayVtxMax{"decayVtxMax", {100.f}, "Maximum distance in x,y,z of the decay vertex from primary vertex (cm)"}; \ o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| for daughter tracks"}; \ - o2::framework::Configurable> dauDcaMin{"dauDcaMin", {0.05f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ - o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; + o2::framework::Configurable> dauAbsDcaxyMin{"dauAbsDcaxyMin", {0.05f}, "Minimum DCAxy of the daughters from primary vertex (cm)"}; \ + o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; \ + o2::framework::Configurable requireTof{"requireTof", false, "If true, TOF PID is a minimal selection. If false, TOF PID is an optional"}; \ + o2::framework::Configurable keepTracksWithoutTof{"keepTracksWithoutTof", true, "If true, the bit mask for the TOF selection will be ture for all limits if the daugher track has no TOF"}; // derived selection bits for lambda struct ConfLambdaBits : o2::framework::ConfigurableGroup { @@ -81,6 +83,10 @@ struct ConfLambdaBits : o2::framework::ConfigurableGroup { o2::framework::Configurable> posDauTpcProton{"posDauTpcProton", {5.f}, "Maximum |nsimga_Proton| TPC for positive daughter tracks"}; o2::framework::Configurable> negDauTpcPion{"negDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for negative daughter tracks"}; o2::framework::Configurable> negDauTpcProton{"negDauTpcProton", {5.f}, "Maximum |nsimga_Proton| TPC negative for daughter tracks"}; + o2::framework::Configurable> posDauTofPion{"posDauTofPion", {}, "Maximum |nsigma_Pion| TOF for positive daughter tracks"}; + o2::framework::Configurable> posDauTofProton{"posDauTofProton", {}, "Maximum |nsigma_Proton| TOF for positive daughter tracks"}; + o2::framework::Configurable> negDauTofPion{"negDauTofPion", {}, "Maximum |nsigma_Pion| TOF for negative daughter tracks"}; + o2::framework::Configurable> negDauTofProton{"negDauTofProton", {}, "Maximum |nsigma_Proton| TOF for negative daughter tracks"}; }; // derived selection bits for K0Short @@ -89,6 +95,8 @@ struct ConfK0shortBits : o2::framework::ConfigurableGroup { V0_DEFAULT_BITS o2::framework::Configurable> posDauTpcPion{"posDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for positive daughter tracks"}; o2::framework::Configurable> negDauTpcPion{"negDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for negative daughter tracks"}; + o2::framework::Configurable> posDauTofPion{"posDauTofPion", {}, "Maximum |nsigma_Pion| TOF for positive daughter tracks"}; + o2::framework::Configurable> negDauTofPion{"negDauTofPion", {}, "Maximum |nsigma_Pion| TOF for negative daughter tracks"}; }; #undef V0_DEFAULT_BITS @@ -144,9 +152,9 @@ enum V0Sels { kTransRadMax, ///< max. transverse radius // selection for daughter - kDauAbsEtaMax, ///< Max. absolute pseudo rapidity - kDauDcaMin, ///< Min. DCA of the daughters at primary vertex - kDauTpcClsMin, ///< Min. number of TPC clusters of daughter + kDauAbsEtaMax, ///< Max. absolute pseudo rapidity + kDauAbsDcaxyMin, ///< Min. |DCAxy| of the daughters from primary vertex + kDauTpcClsMin, ///< Min. number of TPC clusters of daughter // pid selection for daughters kPosDaughTpcPion, ///< TPC Pion PID for positive daughter @@ -154,6 +162,11 @@ enum V0Sels { kNegDaughTpcPion, ///< TPC Pion PID for negative daughter kNegDaughTpcProton, ///< TPC Proton PID for negative daughter + kPosDaughTofPion, ///< TOF Pion PID for positive daughter + kPosDaughTofProton, ///< TOF Proton PID for positive daughter + kNegDaughTofPion, ///< TOF Pion PID for negative daughter + kNegDaughTofProton, ///< TOF Proton PID for negative daughter + kV0SelsMax }; @@ -169,13 +182,17 @@ const std::unordered_map v0SelectionNames = { {kTransRadMax, "Max. transverse radius"}, {kDauAbsEtaMax, "Max. absolute pseudo rapidity of daughters"}, - {kDauDcaMin, "Min. DCA of the daughters at primary vertex"}, + {kDauAbsDcaxyMin, "Min. |DCAxy| of the daughters from primary vertex"}, {kDauTpcClsMin, "Min. number of TPC clusters of daughters"}, {kPosDaughTpcPion, "TPC Pion PID for positive daughter"}, {kPosDaughTpcProton, "TPC Proton PID for positive daughter"}, {kNegDaughTpcPion, "TPC Pion PID for negative daughter"}, - {kNegDaughTpcProton, "TPC Proton PID for negative daughter"}}; + {kNegDaughTpcProton, "TPC Proton PID for negative daughter"}, + {kPosDaughTofPion, "TOF Pion PID for positive daughter"}, + {kPosDaughTofProton, "TOF Proton PID for positive daughter"}, + {kNegDaughTofPion, "TOF Pion PID for negative daughter"}, + {kNegDaughTofProton, "TOF Proton PID for negative daughter"}}; // enum for all track filters (loose pre-selection, applied before quality/PID cuts) enum V0Filters { @@ -191,7 +208,7 @@ enum V0Filters { kRejectionLambdaMass, kLambdaMassMin, kLambdaMassMax, - kTrackFiltersMax + kV0FiltersMax }; constexpr char LambdaFilterHistName[] = "hLambdaFilters"; @@ -231,6 +248,8 @@ class V0Selection : public baseselection::BaseSelectionaddSelection(kPosDaughTpcProton, v0SelectionNames.at(kPosDaughTpcProton), config.posDauTpcProton.value, limits::kAbsUpperLimit, true, true, false); this->addSelection(kNegDaughTpcPion, v0SelectionNames.at(kNegDaughTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kPosDaughTofProton, v0SelectionNames.at(kPosDaughTofProton), config.posDauTofProton.value, limits::kAbsUpperLimit, true, mRequireTof, false); + this->addSelection(kNegDaughTofPion, v0SelectionNames.at(kNegDaughTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false); } if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { this->addSelection(kPosDaughTpcPion, v0SelectionNames.at(kPosDaughTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); this->addSelection(kNegDaughTpcProton, v0SelectionNames.at(kNegDaughTpcProton), config.negDauTpcProton.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kPosDaughTofPion, v0SelectionNames.at(kPosDaughTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false); + this->addSelection(kNegDaughTofProton, v0SelectionNames.at(kNegDaughTofProton), config.negDauTofProton.value, limits::kAbsUpperLimit, true, mRequireTof, false); } } if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { @@ -258,14 +281,17 @@ class V0Selection : public baseselection::BaseSelectionaddSelection(kPosDaughTpcPion, v0SelectionNames.at(kPosDaughTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); this->addSelection(kNegDaughTpcPion, v0SelectionNames.at(kNegDaughTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kPosDaughTofPion, v0SelectionNames.at(kPosDaughTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false); + this->addSelection(kNegDaughTofPion, v0SelectionNames.at(kNegDaughTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false); } this->addSelection(kDcaDaughMax, v0SelectionNames.at(kDcaDaughMax), config.dcaDauMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kDecayVtxMax, v0SelectionNames.at(kDecayVtxMax), config.decayVtxMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kCpaMin, v0SelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kTransRadMin, v0SelectionNames.at(kTransRadMin), config.transRadMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kTransRadMax, v0SelectionNames.at(kTransRadMax), config.transRadMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kDauAbsEtaMax, v0SelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); - this->addSelection(kDauDcaMin, v0SelectionNames.at(kDauDcaMin), config.dauDcaMin.value, limits::kAbsLowerLimit, true, true, false); + this->addSelection(kDauAbsDcaxyMin, v0SelectionNames.at(kDauAbsDcaxyMin), config.dauAbsDcaxyMin.value, limits::kAbsLowerLimit, true, true, false); this->addSelection(kDauTpcClsMin, v0SelectionNames.at(kDauTpcClsMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); this->setupSelectionHistogram(registry); @@ -307,20 +333,50 @@ class V0Selection : public baseselection::BaseSelection(); auto negDaughter = v0candidate.template negTrack_as(); - std::array etaDaughters = {std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; - this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); + std::array etaAbsDaughters = {std::fabs(v0candidate.positiveeta()), std::fabs(v0candidate.negativeeta())}; + this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaAbsDaughters.begin(), etaAbsDaughters.end())); - std::array dcaDaughters = {std::hypot(posDaughter.dcaXY(), posDaughter.dcaZ()), std::hypot(negDaughter.dcaXY(), negDaughter.dcaZ())}; - this->evaluateObservable(kDauDcaMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); + std::array dcaxyAbsDaughters = {std::fabs(v0candidate.dcapostopv()), std::fabs(v0candidate.dcanegtopv())}; + this->evaluateObservable(kDauAbsDcaxyMin, *std::min_element(dcaxyAbsDaughters.begin(), dcaxyAbsDaughters.end())); std::array clustersDaughters = {1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); - // daughter pid selections - this->evaluateObservable(kPosDaughTpcPion, posDaughter.tpcNSigmaPi()); - this->evaluateObservable(kPosDaughTpcProton, posDaughter.tpcNSigmaPr()); - this->evaluateObservable(kNegDaughTpcPion, negDaughter.tpcNSigmaPi()); - this->evaluateObservable(kNegDaughTpcProton, negDaughter.tpcNSigmaPr()); + // PID of the daughters under the mass hypothesis of this v0 type + // TPC nSigma comes from the daughter track, TOF nSigma from the strangeness-tagged v0 candidate + // if the daughter has no TOF signal, feed 0 so the bit passes any limit (opt-in via keepTracksWithoutTof) + auto evaluateDaughterPid = [this](V0Sels tpcBit, float tpcNSigma, + V0Sels tofBit, float tofNSigma, bool hasTof) { + this->evaluateObservable(tpcBit, tpcNSigma); + if (hasTof) { + this->evaluateObservable(tofBit, tofNSigma); + } else if (mKeepTracksWithoutTof) { + this->evaluateObservable(tofBit, 0.f); + } + }; + + const bool posHasTof = v0candidate.positiveHasTOF(); + const bool negHasTof = v0candidate.negativeHasTOF(); + + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { + // Lambda -> p pi- + evaluateDaughterPid(kPosDaughTpcProton, posDaughter.tpcNSigmaPr(), + kPosDaughTofProton, v0candidate.tofNSigmaLaPr(), posHasTof); + evaluateDaughterPid(kNegDaughTpcPion, negDaughter.tpcNSigmaPi(), + kNegDaughTofPion, v0candidate.tofNSigmaLaPi(), negHasTof); + } else if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + // AntiLambda -> pbar pi+ + evaluateDaughterPid(kPosDaughTpcPion, posDaughter.tpcNSigmaPi(), + kPosDaughTofPion, v0candidate.tofNSigmaALaPi(), posHasTof); + evaluateDaughterPid(kNegDaughTpcProton, negDaughter.tpcNSigmaPr(), + kNegDaughTofProton, v0candidate.tofNSigmaALaPr(), negHasTof); + } else if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { + // K0short -> pi+ pi- + evaluateDaughterPid(kPosDaughTpcPion, posDaughter.tpcNSigmaPi(), + kPosDaughTofPion, v0candidate.tofNSigmaK0PiPlus(), posHasTof); + evaluateDaughterPid(kNegDaughTpcPion, negDaughter.tpcNSigmaPi(), + kNegDaughTofPion, v0candidate.tofNSigmaK0PiMinus(), negHasTof); + } this->assembleBitmask(); } @@ -423,13 +479,18 @@ class V0Selection : public baseselection::BaseSelection producedLambdas; + o2::framework::Produces producedLiteLambdas; o2::framework::Produces producedLambdaMasks; o2::framework::Produces producedLambdaExtras; o2::framework::Produces producedK0shorts; + o2::framework::Produces producedLiteK0shorts; o2::framework::Produces producedK0shortMasks; o2::framework::Produces producedK0shortExtras; }; @@ -437,9 +498,11 @@ struct V0BuilderProducts : o2::framework::ProducesGroup { struct ConfV0Tables : o2::framework::ConfigurableGroup { std::string prefix = std::string("V0Tables"); o2::framework::Configurable produceLambdas{"produceLambdas", -1, "Produce Lambdas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteLambdas{"produceLiteLambdas", -1, "Produce LiteLambdas (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceLambdaMasks{"produceLambdaMasks", -1, "Produce LambdaMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceLambdaExtras{"produceLambdaExtras", -1, "Produce LambdaExtras (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceK0shorts{"produceK0shorts", -1, "Produce K0shorts (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteK0shorts{"produceLiteK0shorts", -1, "Produce LiteK0shorts (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceK0shortMasks{"produceK0shortMasks", -1, "Produce K0shortMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceK0shortExtras{"produceK0shortExtras", -1, "Produce K0shortExtras (-1: auto; 0 off; 1 on)"}; }; @@ -451,8 +514,8 @@ class V0Builder V0Builder() = default; ~V0Builder() = default; - template - void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext, T5& trackBuilder) { if constexpr (modes::isEqual(v0Type, modes::V0::kLambda) || modes::isEqual(v0Type, modes::V0::kAntiLambda)) { if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { @@ -462,16 +525,51 @@ class V0Builder LOG(info) << "Initialize femto AntiLambda builder..."; } mProduceLambdas = utils::enableTable("FLambdas_001", table.produceLambdas.value, initContext); - mProduceLambdaMasks = utils::enableTable("FLambdaMasks_001", table.produceLambdaMasks.value, initContext); + mProduceLiteLambdas = utils::enableTable("FLiteLambdas_001", table.produceLiteLambdas.value, initContext); + mProduceLambdaMasks = utils::enableTable("FLambdaMasks_002", table.produceLambdaMasks.value, initContext); mProduceLambdaExtras = utils::enableTable("FLambdaExtras_001", table.produceLambdaExtras.value, initContext); + + if (mProduceLambdas && mProduceLiteLambdas) { + LOG(fatal) << "FLambdas and FLiteLambdas are mutually exclusive -- enable only one. " + << "FLiteLambdas is meant to replace FLambdas at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FLambdas from FLiteLambdas downstream."; + } + if (mProduceLambdas && !trackBuilder.producingTracks()) { + LOG(fatal) << "FLambdas is enabled, but the track builder is not producing FTracks (full precision). " + << "FLambdas stores daughter indices into FTracks -- enable TrackTables.produceTracks, " + << "or switch to FLiteLambdas if TrackTables.produceLiteTracks is enabled instead."; + } + if (mProduceLiteLambdas && !trackBuilder.producingLiteTracks()) { + LOG(fatal) << "FLiteLambdas is enabled, but the track builder is not producing FLiteTracks. " + << "FLiteLambdas stores daughter indices into FLiteTracks -- enable TrackTables.produceLiteTracks, " + << "or switch to FLambdas if TrackTables.produceTracks is enabled instead."; + } } if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { LOG(info) << "Initialize femto K0short builder..."; mProduceK0shorts = utils::enableTable("FK0shorts_001", table.produceK0shorts.value, initContext); - mProduceK0shortMasks = utils::enableTable("FK0shortMasks_001", table.produceK0shortMasks.value, initContext); + mProduceLiteK0shorts = utils::enableTable("FLiteK0shorts_001", table.produceLiteK0shorts.value, initContext); + mProduceK0shortMasks = utils::enableTable("FK0shortMasks_002", table.produceK0shortMasks.value, initContext); mProduceK0shortExtras = utils::enableTable("FK0shortExtras_001", table.produceK0shortExtras.value, initContext); + + if (mProduceK0shorts && mProduceLiteK0shorts) { + LOG(fatal) << "FK0shorts and FLiteK0shorts are mutually exclusive -- enable only one. " + << "FLiteK0shorts is meant to replace FK0shorts at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FK0shorts from FLiteK0shorts downstream."; + } + if (mProduceK0shorts && !trackBuilder.producingTracks()) { + LOG(fatal) << "FK0shorts is enabled, but the track builder is not producing FTracks (full precision). " + << "FK0shorts stores daughter indices into FTracks -- enable TrackTables.produceTracks, " + << "or switch to FLiteK0shorts if TrackTables.produceLiteTracks is enabled instead."; + } + if (mProduceLiteK0shorts && !trackBuilder.producingLiteTracks()) { + LOG(fatal) << "FLiteK0shorts is enabled, but the track builder is not producing FLiteTracks. " + << "FLiteK0shorts stores daughter indices into FLiteTracks -- enable TrackTables.produceLiteTracks, " + << "or switch to FK0shorts if TrackTables.produceTracks is enabled instead."; + } } - if (mProduceLambdas || mProduceLambdaMasks || mProduceLambdaExtras || mProduceK0shorts || mProduceK0shortMasks || mProduceK0shortExtras) { + if (mProduceLambdas || mProduceLiteLambdas || mProduceLambdaMasks || mProduceLambdaExtras || + mProduceK0shorts || mProduceLiteK0shorts || mProduceK0shortMasks || mProduceK0shortExtras) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -505,17 +603,17 @@ class V0Builder auto posDaughter = v0.template posTrack_as(); auto negDaughter = v0.template negTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts); - negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionBuilder); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionBuilder); if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { - fillLambda(collisionProducts, v0Products, v0, 1.f, posDaughterIndex, negDaughterIndex); + fillLambda(collisionBuilder, v0Products, v0, 1.f, posDaughterIndex, negDaughterIndex); } if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { - fillLambda(collisionProducts, v0Products, v0, -1.f, posDaughterIndex, negDaughterIndex); + fillLambda(collisionBuilder, v0Products, v0, -1.f, posDaughterIndex, negDaughterIndex); } if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { - fillK0short(collisionProducts, v0Products, v0, posDaughterIndex, negDaughterIndex); + fillK0short(collisionBuilder, v0Products, v0, posDaughterIndex, negDaughterIndex); } } } @@ -541,40 +639,46 @@ class V0Builder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); auto posDaughter = v0.template posTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, posDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); auto negDaughter = v0.template negTrack_as(); - negDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, negDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { - fillLambda(collisionProducts, v0Products, v0, 1.f, posDaughterIndex, negDaughterIndex); - mcBuilder.template fillMcLambdaWithLabel(col, mcCols, v0, mcParticles, mcProducts); + fillLambda(collisionBuilder, v0Products, v0, 1.f, posDaughterIndex, negDaughterIndex); + mcBuilder.template fillMcLambdaWithLabel(v0, mcParticles, mcCols, mcProducts); } if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { - fillLambda(collisionProducts, v0Products, v0, -1.f, posDaughterIndex, negDaughterIndex); - mcBuilder.template fillMcLambdaWithLabel(col, mcCols, v0, mcParticles, mcProducts); + fillLambda(collisionBuilder, v0Products, v0, -1.f, posDaughterIndex, negDaughterIndex); + mcBuilder.template fillMcLambdaWithLabel(v0, mcParticles, mcCols, mcProducts); } if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { - fillK0short(collisionProducts, v0Products, v0, posDaughterIndex, negDaughterIndex); - mcBuilder.template fillMcK0shortWithLabel(col, mcCols, v0, mcParticles, mcProducts); + fillK0short(collisionBuilder, v0Products, v0, posDaughterIndex, negDaughterIndex); + mcBuilder.template fillMcK0shortWithLabel(v0, mcParticles, mcCols, mcProducts); } } } template - void fillLambda(T1& collisionProducts, T2& v0Products, T3 const& v0, float sign, int64_t posDaughterIndex, int64_t negDaughterIndex) + void fillLambda(T1& collisionBuilder, T2& v0Products, T3 const& v0, float sign, int64_t posDaughterIndex, int64_t negDaughterIndex) { float mass = 0; float massAnti = 0; + float strangeTofPosDau = 0; + float strangeTofNegDau = 0; if (sign > 0.f) { mass = v0.mLambda(); massAnti = v0.mAntiLambda(); + strangeTofPosDau = v0.tofNSigmaLaPr(); + strangeTofNegDau = v0.tofNSigmaLaPi(); } else { mass = v0.mAntiLambda(); massAnti = v0.mLambda(); + strangeTofPosDau = v0.tofNSigmaALaPi(); + strangeTofNegDau = v0.tofNSigmaALaPr(); } if (mProduceLambdas) { - v0Products.producedLambdas(collisionProducts.producedCollision.lastIndex(), + v0Products.producedLambdas(collisionBuilder.collisionIndex(), sign * v0.pt(), v0.eta(), v0.phi(), @@ -582,6 +686,15 @@ class V0Builder posDaughterIndex, negDaughterIndex); } + if (mProduceLiteLambdas) { + v0Products.producedLiteLambdas(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binSignedPt(sign * v0.pt()), + o2::aod::femtobase::lite::binEta(v0.eta()), + o2::aod::femtobase::lite::binPhi(v0.phi()), + o2::aod::femtov0s::lite::binLambdaMass(mass), + posDaughterIndex, + negDaughterIndex); + } if (mProduceLambdaMasks) { v0Products.producedLambdaMasks(mV0Selection.getBitmask()); } @@ -591,6 +704,8 @@ class V0Builder v0.mK0Short(), v0.v0cosPA(), v0.dcaV0daughters(), + strangeTofPosDau, + strangeTofNegDau, v0.v0radius(), v0.x(), v0.y(), @@ -599,10 +714,10 @@ class V0Builder } template - void fillK0short(T1& collisionProducts, T2& v0Products, T3 const& v0, int64_t posDaughterIndex, int64_t negDaughterIndex) + void fillK0short(T1& collisionBuilder, T2& v0Products, T3 const& v0, int64_t posDaughterIndex, int64_t negDaughterIndex) { if (mProduceK0shorts) { - v0Products.producedK0shorts(collisionProducts.producedCollision.lastIndex(), + v0Products.producedK0shorts(collisionBuilder.collisionIndex(), v0.pt(), v0.eta(), v0.phi(), @@ -610,6 +725,15 @@ class V0Builder posDaughterIndex, negDaughterIndex); } + if (mProduceLiteK0shorts) { + v0Products.producedLiteK0shorts(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binUnsignedPt(v0.pt()), + o2::aod::femtobase::lite::binEta(v0.eta()), + o2::aod::femtobase::lite::binPhi(v0.phi()), + o2::aod::femtov0s::lite::binK0shortMass(v0.mK0Short()), + posDaughterIndex, + negDaughterIndex); + } if (mProduceK0shortMasks) { v0Products.producedK0shortMasks(mV0Selection.getBitmask()); } @@ -619,6 +743,8 @@ class V0Builder v0.mAntiLambda(), v0.v0cosPA(), v0.dcaV0daughters(), + v0.tofNSigmaK0PiPlus(), + v0.tofNSigmaK0PiMinus(), v0.v0radius(), v0.x(), v0.y(), @@ -627,14 +753,17 @@ class V0Builder } [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } + [[nodiscard]] bool isPassThrough() const { return mV0Selection.isPassThrough(); } private: V0Selection mV0Selection; bool mFillAnyTable = false; bool mProduceLambdas = false; + bool mProduceLiteLambdas = false; bool mProduceLambdaMasks = false; bool mProduceLambdaExtras = false; bool mProduceK0shorts = false; + bool mProduceLiteK0shorts = false; bool mProduceK0shortMasks = false; bool mProduceK0shortExtras = false; }; diff --git a/PWGCF/Femto/Core/v0HistManager.h b/PWGCF/Femto/Core/v0HistManager.h index 9f7e7736d61..598d2766d6f 100644 --- a/PWGCF/Femto/Core/v0HistManager.h +++ b/PWGCF/Femto/Core/v0HistManager.h @@ -53,6 +53,8 @@ enum V0Hist { kMassK0short, kCosPa, kDecayDauDca, + kStrangeTofPosDau, + kStrangeTofNegDau, kDecayVtxX, kDecayVtxY, kDecayVtxZ, @@ -69,6 +71,8 @@ enum V0Hist { kLambdaMassVsAntiLambdaMass, kK0shortMassVsLambdaMass, kK0shortMassVsAntiLambdaMass, + kStrangeTofVsTofPosDau, + kStrangeTofVsTofNegDau, // mc kOrigin, kPdg, @@ -117,8 +121,12 @@ struct ConfK0shortBinning : o2::framework::ConfigurableGroup { constexpr const char PrefixLambdaBinning1[] = "LambdaBinning1"; using ConfLambdaBinning1 = ConfLambdaBinning; +constexpr const char PrefixLambdaBinning2[] = "LambdaBinning2"; +using ConfLambdaBinning2 = ConfLambdaBinning; constexpr const char PrefixK0shortBinning1[] = "K0shortBinning1"; using ConfK0shortBinning1 = ConfK0shortBinning; +constexpr const char PrefixK0shortBinning2[] = "K0shortBinning2"; +using ConfK0shortBinning2 = ConfK0shortBinning; template struct ConfV0QaBinning : o2::framework::ConfigurableGroup { @@ -133,6 +141,7 @@ struct ConfV0QaBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis massLambda{"massLambda", {{200, 1, 1.2}}, "mass for antiparticle hypothesis"}; o2::framework::ConfigurableAxis massAntiLambda{"massAntiLambda", {{100, 1, 1.2}}, "mass for antiparticle hypothesis"}; o2::framework::ConfigurableAxis massK0short{"massK0short", {{200, 0.45, 0.55}}, "Mass for k0short hypothesis"}; + o2::framework::ConfigurableAxis strangeTof{"strangeTof", {{500, -5, 5}}, "Strangeness TOF vs TOF Nsigma for daughters"}; }; constexpr const char PrefixLambdaQaBinning1[] = "LambdaQaBinning1"; @@ -155,6 +164,8 @@ constexpr std::array, kV0HistLast> HistTable = { {kMassK0short, o2::framework::HistType::kTH1F, "hMassK0short", "K^{0}_{s} mass; m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2}); Entries"}, {kCosPa, o2::framework::HistType::kTH1F, "hCosPa", "Cosine of pointing angle; cos(#alpha); Entries"}, {kDecayDauDca, o2::framework::HistType::kTH1F, "hDauDca", "Daughter DCA at decay vertex ; DCA_{Decay vertex} (cm); Entries"}, + {kStrangeTofPosDau, o2::framework::HistType::kTH1F, "hStrangeTofPosDau", "Strange TOF of positive Daughter ; n#sigma_{TOF, strange}; Entries"}, + {kStrangeTofNegDau, o2::framework::HistType::kTH1F, "hStrangeTofNegDau", "Strange TOF of negative Daughter ; n#sigma+{TOF, strange}; Entries"}, {kDecayVtxX, o2::framework::HistType::kTH1F, "hDecayVtxX", "X coordinate of decay vertex ; DV_{X} (cm); Entries"}, {kDecayVtxY, o2::framework::HistType::kTH1F, "hDecayVtxY", "Y coordinate of decay vertex ; DV_{Y} (cm); Entries"}, {kDecayVtxZ, o2::framework::HistType::kTH1F, "hDecayVtxZ", "Z coordinate of decay vertex ; DV_{Z} (cm); Entries"}, @@ -170,6 +181,8 @@ constexpr std::array, kV0HistLast> HistTable = { {kK0shortMassVsLambdaMass, o2::framework::HistType::kTH2F, "hK0shortMassVsLambdaMass", " K^{0}_{S} mass vs #Lambda mass; m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2}); m_{p#pi^{-}} (GeV/#it{c}^{2})"}, {kK0shortMassVsAntiLambdaMass, o2::framework::HistType::kTH2F, "hK0shortMassVsAntiLambdaMass", "K^{0}_{S} mass vs #bar{#Lambda} mass; m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2}); m_{#bar{p}#pi^{+}} (GeV/#it{c}^{2})"}, {kLambdaMassVsAntiLambdaMass, o2::framework::HistType::kTH2F, "hLambdaMassVsAntiLambdaMass", "#Lambda mass vs #bar{#Lambda}; m_{p#pi^{-}} (GeV/#it{c}^{2}); m_{#bar{p}#pi^{+}} (GeV/#it{c}^{2})"}, + {kStrangeTofVsTofPosDau, o2::framework::HistType::kTH2F, "hStrangeTofVsTofPosDau", "TOF_{Strange} vs TOF_{Tracking} of positive Daughter; n#sigma_{TOF, strange}; n#sigma_{TOF, tracking}"}, + {kStrangeTofVsTofNegDau, o2::framework::HistType::kTH2F, "hStrangeTofVsTofNegDau", "TOF_{Strange} vs TOF_{Tracking} of negative Daughter; n#sigma_{TOF, strange}; n#sigma_{TOF, tracking}"}, {kOrigin, o2::framework::HistType::kTH1F, "hOrigin", "Status Codes (=Origin); Status Code; Entries"}, {kPdg, o2::framework::HistType::kTH1F, "hPdg", "PDG Codes of reconstructed v0; PDG Code; Entries"}, {kPdgMother, o2::framework::HistType::kTH1F, "hPdgMother", "PDG Codes of mother of reconstructed v0; PDG Code; Entries"}, @@ -207,27 +220,31 @@ constexpr std::array, kV0HistLast> HistTable = { {kPdgPartonicMother, {(conf).pdgCodes}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define V0_HIST_QA_MAP(confAnalysis, confQa) \ - {kCosPa, {(confQa).cosPa}}, \ - {kDecayDauDca, {(confQa).dauDcaAtDecay}}, \ - {kDecayVtxX, {(confQa).decayVertex}}, \ - {kDecayVtxY, {(confQa).decayVertex}}, \ - {kDecayVtxZ, {(confQa).decayVertex}}, \ - {kDecayVtx, {(confQa).decayVertex}}, \ - {kTransRadius, {(confQa).transRadius}}, \ - {kPtVsEta, {(confAnalysis).pt, (confAnalysis).eta}}, \ - {kPtVsPhi, {(confAnalysis).pt, (confAnalysis).phi}}, \ - {kPhiVsEta, {(confAnalysis).phi, (confAnalysis).eta}}, \ - {kPtVsCosPa, {(confAnalysis).pt, (confQa).cosPa}}, \ - {kMassLambda, {(confQa).massLambda}}, \ - {kMassAntiLambda, {(confQa).massAntiLambda}}, \ - {kMassK0short, {(confQa).massK0short}}, \ - {kPtVsLambdaMass, {(confAnalysis).pt, (confQa).massLambda}}, \ - {kPtVsAntiLambdaMass, {(confAnalysis).pt, (confQa).massAntiLambda}}, \ - {kPtVsK0shortMass, {(confAnalysis).pt, (confQa).massK0short}}, \ - {kLambdaMassVsAntiLambdaMass, {(confQa).massLambda, (confQa).massAntiLambda}}, \ - {kK0shortMassVsLambdaMass, {(confQa).massK0short, (confQa).massLambda}}, \ - {kK0shortMassVsAntiLambdaMass, {(confQa).massK0short, (confQa).massAntiLambda}}, +#define V0_HIST_QA_MAP(confAnalysis, confQa) \ + {kCosPa, {(confQa).cosPa}}, \ + {kDecayDauDca, {(confQa).dauDcaAtDecay}}, \ + {kStrangeTofPosDau, {(confQa).strangeTof}}, \ + {kStrangeTofNegDau, {(confQa).strangeTof}}, \ + {kDecayVtxX, {(confQa).decayVertex}}, \ + {kDecayVtxY, {(confQa).decayVertex}}, \ + {kDecayVtxZ, {(confQa).decayVertex}}, \ + {kDecayVtx, {(confQa).decayVertex}}, \ + {kTransRadius, {(confQa).transRadius}}, \ + {kPtVsEta, {(confAnalysis).pt, (confAnalysis).eta}}, \ + {kPtVsPhi, {(confAnalysis).pt, (confAnalysis).phi}}, \ + {kPhiVsEta, {(confAnalysis).phi, (confAnalysis).eta}}, \ + {kPtVsCosPa, {(confAnalysis).pt, (confQa).cosPa}}, \ + {kMassLambda, {(confQa).massLambda}}, \ + {kMassAntiLambda, {(confQa).massAntiLambda}}, \ + {kMassK0short, {(confQa).massK0short}}, \ + {kPtVsLambdaMass, {(confAnalysis).pt, (confQa).massLambda}}, \ + {kPtVsAntiLambdaMass, {(confAnalysis).pt, (confQa).massAntiLambda}}, \ + {kPtVsK0shortMass, {(confAnalysis).pt, (confQa).massK0short}}, \ + {kLambdaMassVsAntiLambdaMass, {(confQa).massLambda, (confQa).massAntiLambda}}, \ + {kK0shortMassVsLambdaMass, {(confQa).massK0short, (confQa).massLambda}}, \ + {kK0shortMassVsAntiLambdaMass, {(confQa).massK0short, (confQa).massAntiLambda}}, \ + {kStrangeTofVsTofPosDau, {(confQa).strangeTof, (confQa).strangeTof}}, \ + {kStrangeTofVsTofNegDau, {(confQa).strangeTof, (confQa).strangeTof}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define V0_HIST_MC_QA_MAP(confAnalysis, confQa) \ @@ -412,25 +429,25 @@ class V0HistManager this->fillAnalysis(v0candidate); } if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { - this->fillQa(v0candidate); + this->fillQa(v0candidate, posDaughter, negDaughter); } } - template - void fill(T1 const& v0candidate, T2 const& tracks, T3 const& mcParticles, T4 const& mcMothers, T5 const& mcPartonicMothers) + template + void fill(T1 const& v0candidate, T2 const& tracks, T3 const& col, T4 const& mcParticles, T5 const& mcMothers, T6 const& mcPartonicMothers) { auto posDaughter = tracks.rawIteratorAt(v0candidate.posDauId() - tracks.offset()); - mPosDauManager.template fill(posDaughter, tracks, mcParticles, mcMothers, mcPartonicMothers); + mPosDauManager.template fill(posDaughter, tracks, col, mcParticles, mcMothers, mcPartonicMothers); auto negDaughter = tracks.rawIteratorAt(v0candidate.negDauId() - tracks.offset()); - mNegDauManager.template fill(negDaughter, tracks, mcParticles, mcMothers, mcPartonicMothers); + mNegDauManager.template fill(negDaughter, tracks, col, mcParticles, mcMothers, mcPartonicMothers); if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->fillAnalysis(v0candidate); } if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { - this->fillQa(v0candidate); + this->fillQa(v0candidate, posDaughter, negDaughter); } if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { - this->template fillMc(v0candidate, mcParticles, mcMothers, mcPartonicMothers); + this->template fillMc(v0candidate, col, mcParticles, mcMothers, mcPartonicMothers); } } @@ -467,6 +484,8 @@ class V0HistManager mHistogramRegistry->add(qaDir + getHistNameV2(kCosPa, HistTable), getHistDesc(kCosPa, HistTable), getHistType(kCosPa, HistTable), {V0Specs.at(kCosPa)}); mHistogramRegistry->add(qaDir + getHistNameV2(kDecayDauDca, HistTable), getHistDesc(kDecayDauDca, HistTable), getHistType(kDecayDauDca, HistTable), {V0Specs.at(kDecayDauDca)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofPosDau, HistTable), getHistDesc(kStrangeTofPosDau, HistTable), getHistType(kStrangeTofPosDau, HistTable), {V0Specs.at(kStrangeTofPosDau)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofNegDau, HistTable), getHistDesc(kStrangeTofNegDau, HistTable), getHistType(kStrangeTofNegDau, HistTable), {V0Specs.at(kStrangeTofNegDau)}); mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxX, HistTable), getHistDesc(kDecayVtxX, HistTable), getHistType(kDecayVtxX, HistTable), {V0Specs.at(kDecayVtxX)}); mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxY, HistTable), getHistDesc(kDecayVtxY, HistTable), getHistType(kDecayVtxY, HistTable), {V0Specs.at(kDecayVtxY)}); mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxZ, HistTable), getHistDesc(kDecayVtxZ, HistTable), getHistType(kDecayVtxZ, HistTable), {V0Specs.at(kDecayVtxZ)}); @@ -488,6 +507,8 @@ class V0HistManager mHistogramRegistry->add(qaDir + getHistNameV2(kLambdaMassVsAntiLambdaMass, HistTable), getHistDesc(kLambdaMassVsAntiLambdaMass, HistTable), getHistType(kLambdaMassVsAntiLambdaMass, HistTable), {V0Specs.at(kLambdaMassVsAntiLambdaMass)}); mHistogramRegistry->add(qaDir + getHistNameV2(kK0shortMassVsLambdaMass, HistTable), getHistDesc(kK0shortMassVsLambdaMass, HistTable), getHistType(kK0shortMassVsLambdaMass, HistTable), {V0Specs.at(kK0shortMassVsLambdaMass)}); mHistogramRegistry->add(qaDir + getHistNameV2(kK0shortMassVsAntiLambdaMass, HistTable), getHistDesc(kK0shortMassVsAntiLambdaMass, HistTable), getHistType(kK0shortMassVsAntiLambdaMass, HistTable), {V0Specs.at(kK0shortMassVsAntiLambdaMass)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofVsTofPosDau, HistTable), getHistDesc(kStrangeTofVsTofPosDau, HistTable), getHistType(kStrangeTofVsTofPosDau, HistTable), {V0Specs.at(kStrangeTofVsTofPosDau)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kStrangeTofVsTofNegDau, HistTable), getHistDesc(kStrangeTofVsTofNegDau, HistTable), getHistType(kStrangeTofVsTofNegDau, HistTable), {V0Specs.at(kStrangeTofVsTofNegDau)}); } } @@ -549,11 +570,13 @@ class V0HistManager } } - template - void fillQa(T const& v0candidate) + template + void fillQa(T1 const& v0candidate, T2 const& posDau, T3 const& negDau) { mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kCosPa, HistTable)), v0candidate.cosPa()); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayDauDca, HistTable)), v0candidate.dauDca()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofPosDau, HistTable)), v0candidate.strangeTofPosDau()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofNegDau, HistTable)), v0candidate.strangeTofNegDau()); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxX, HistTable)), v0candidate.decayVtxX()); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxY, HistTable)), v0candidate.decayVtxY()); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxZ, HistTable)), v0candidate.decayVtxZ()); @@ -563,21 +586,29 @@ class V0HistManager float massLambda = 0; float massAntiLambda = 0; float massK0short = 0; + float tofPosDau = 0; + float tofNegDau = 0; if constexpr (modes::isEqual(v0, modes::V0::kLambda) || modes::isEqual(v0, modes::V0::kAntiLambda)) { massK0short = v0candidate.massK0short(); if (v0candidate.sign() > 0) { massLambda = v0candidate.mass(); massAntiLambda = v0candidate.massAnti(); + tofPosDau = posDau.tofNSigmaPr(); + tofNegDau = negDau.tofNSigmaPi(); } else { massLambda = v0candidate.massAnti(); massAntiLambda = v0candidate.mass(); + tofPosDau = posDau.tofNSigmaPi(); + tofNegDau = negDau.tofNSigmaPr(); } } if constexpr (modes::isEqual(v0, modes::V0::kK0short)) { massK0short = v0candidate.mass(); massLambda = v0candidate.massLambda(); massAntiLambda = v0candidate.massAntiLambda(); + tofPosDau = posDau.tofNSigmaPi(); + tofNegDau = posDau.tofNSigmaPi(); } mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassLambda, HistTable)), massLambda); @@ -596,11 +627,13 @@ class V0HistManager mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kLambdaMassVsAntiLambdaMass, HistTable)), massLambda, massAntiLambda); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kK0shortMassVsLambdaMass, HistTable)), massK0short, massLambda); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kK0shortMassVsAntiLambdaMass, HistTable)), massK0short, massAntiLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofVsTofPosDau, HistTable)), v0candidate.strangeTofPosDau(), tofPosDau); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kStrangeTofVsTofNegDau, HistTable)), v0candidate.strangeTofNegDau(), tofNegDau); } } - template - void fillMc(T1 const& v0Candidate, T2 const& /*mcParticles*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/) + template + void fillMc(T1 const& v0Candidate, T2 const& col, T3 const& /*mcParticles*/, T4 const& /*mcMothers*/, T5 const& /*mcPartonicMothers*/) { // No MC Particle if (!v0Candidate.has_fMcParticle()) { @@ -615,16 +648,20 @@ class V0HistManager } // Retrieve MC particle - auto mcParticle = v0Candidate.template fMcParticle_as(); + auto mcParticle = v0Candidate.template fMcParticle_as(); + + // whether a particle is associated to a wrong collision or not cannot be known by the producer so we check it here + bool fromWrongCollision = mcParticle.fMcColId() != col.fMcColId(); - // missidentifed particles are special case // whether a particle is missidentfied or not cannot be known by the producer so we check it here bool isMissidentified = mcParticle.pdgCode() != mPdgCode; mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kTruePtVsPt, HistTable)), mcParticle.pt(), v0Candidate.pt()); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kTrueEtaVsEta, HistTable)), mcParticle.eta(), v0Candidate.eta()); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kTruePhiVsPhi, HistTable)), mcParticle.phi(), v0Candidate.phi()); - if (isMissidentified) { + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kFromWrongCollision)); + } else if (isMissidentified) { mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kMissidentified)); } else { mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), mcParticle.origin()); @@ -633,7 +670,7 @@ class V0HistManager // get mother if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), mother.pdgCode()); } else { mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), 0); @@ -641,7 +678,7 @@ class V0HistManager // get partonic mother if (mcParticle.has_fMcPartMoth()) { - auto partonicMother = mcParticle.template fMcPartMoth_as(); + auto partonicMother = mcParticle.template fMcPartMoth_as(); mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), partonicMother.pdgCode()); } else { mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kPdgPartonicMother, HistTable)), 0); @@ -650,7 +687,9 @@ class V0HistManager if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { if (mPlotOrigins) { // check first if particle is missidentified - if (isMissidentified) { + if (fromWrongCollision) { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kFromWrongCollision, HistTable)), v0Candidate.pt(), v0Candidate.cosPa()); + } else if (isMissidentified) { // if it is, we fill it as such mHistogramRegistry->fill(HIST(v0Prefix) + HIST(McDir) + HIST(getHistName(kMissidentified, HistTable)), v0Candidate.pt(), v0Candidate.cosPa()); } else { @@ -667,7 +706,7 @@ class V0HistManager break; case modes::McOrigin::kFromSecondaryDecay: if (mcParticle.has_fMcMother()) { - auto mother = mcParticle.template fMcMother_as(); + auto mother = mcParticle.template fMcMother_as(); int motherPdgCode = std::abs(mother.pdgCode()); // Switch on PDG of the mother if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel1 && motherPdgCode == mPdgCodesSecondaryMother[0]) { diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index d60c5a3ce49..000e9430469 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -17,14 +17,15 @@ #define PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ #include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include #include #include -#include #include #include @@ -36,14 +37,52 @@ namespace femtocollisions DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CollisionMaskType); //! Bitmask for collision selections DECLARE_SOA_COLUMN(CollisionTag, collisionTag, o2::analysis::femto::datatypes::CollisionTagType); //! Bitmask for collision selections -DECLARE_SOA_COLUMN(PosX, posX, float); //! x coordinate of vertex -DECLARE_SOA_COLUMN(PosY, posY, float); //! y coordinate of vertex -DECLARE_SOA_COLUMN(PosZ, posZ, float); //! z coordinate of vertex -DECLARE_SOA_COLUMN(Mult, mult, float); //! Multiplicity estimator set by producer -DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (~= multiplicity percentile) estimator set by producer -DECLARE_SOA_COLUMN(MagField, magField, int8_t); //! Magnetic field in kG (5 kG at normal configuration and 2kG in low B field configuration) -DECLARE_SOA_COLUMN(Sphericity, sphericity, float); //! Sphericity of the event -DECLARE_SOA_COLUMN(Qn, qn, float); //! qn bins for dividing eventsfemtab +DECLARE_SOA_COLUMN(PosX, posX, float); //! x coordinate of vertex +DECLARE_SOA_COLUMN(PosY, posY, float); //! y coordinate of vertex +DECLARE_SOA_COLUMN(PosZ, posZ, float); //! z coordinate of vertex +DECLARE_SOA_COLUMN(Mult, mult, float); //! Multiplicity estimator set by producer +DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (~= multiplicity percentile) estimator set by producer +DECLARE_SOA_COLUMN(MagField, magField, int8_t); //! Magnetic field in kG (5 kG at normal configuration and 2kG in low B field configuration) +DECLARE_SOA_COLUMN(Sphericity, sphericity, float); //! Sphericity of the event +DECLARE_SOA_COLUMN(Qvec, qvec, float); //! qvector +DECLARE_SOA_COLUMN(EventPlaneAngle, eventPlaneAngle, float); //! event plane angle (for corresponding q vector) + +namespace lite +{ +constexpr float PosZMin = -20.f; +constexpr float PosZMax = 20.f; +constexpr float PosZStep = 0.5f; // bin vtz in 0.5cm steps +constexpr float CentMin = 0.f; +constexpr float CentMax = 100.f; +constexpr float CentStep = 0.5f; // bin centrality in 0.5% steps +constexpr float MultStep = 1.f; // round multiplicity to nearest integer + +inline uint8_t binPosZ(float posZ) { return o2::analysis::femto::utils::binLinear(posZ, PosZMin, PosZMax, PosZStep); } +inline float unBinPosZ(uint8_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, PosZMin, PosZStep); } + +inline uint8_t binCent(float cent) { return o2::analysis::femto::utils::binLinear(cent, CentMin, CentMax, CentStep); } +inline float unBinCent(uint8_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, CentMin, CentStep); } + +inline uint16_t binMult(float mult) { return o2::analysis::femto::utils::binLinear(mult, 0.f, 65535.f, MultStep); } // use full range of uint16_t +inline float unBinMult(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, 0.f, MultStep); } + +DECLARE_SOA_COLUMN(BinnedPosZ, binnedPosZ, uint8_t); +DECLARE_SOA_COLUMN(BinnedMult, binnedMult, uint16_t); +DECLARE_SOA_COLUMN(BinnedCent, binnedCent, uint8_t); + +DECLARE_SOA_DYNAMIC_COLUMN(PosZ, posZ, + [](uint8_t binnedPosZ) -> float { + return unBinPosZ(binnedPosZ); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Mult, mult, + [](uint16_t binnedMult) -> float { + return unBinMult(binnedMult); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Cent, cent, + [](uint8_t binnedCent) -> float { + return unBinCent(binnedCent); + }); +} // namespace lite } // namespace femtocollisions // table for basic collision information @@ -57,6 +96,20 @@ using FCols = FCols_001; using FCol = FCols::iterator; using StoredFCols = StoredFCols_001; +// table for basic collision information, compressed/binned information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteCols_001, "FLITECOL", 1, //! femto collisions, binned information + o2::soa::Index<>, + femtocollisions::lite::BinnedPosZ, + femtocollisions::lite::BinnedMult, + femtocollisions::lite::BinnedCent, + femtocollisions::MagField, + femtocollisions::lite::PosZ, + femtocollisions::lite::Mult, + femtocollisions::lite::Cent); +using FLiteCols = FLiteCols_001; +using FLiteCol = FLiteCols::iterator; +using StoredFLiteCols = StoredFLiteCols_001; + // table for collisions selections DECLARE_SOA_TABLE_STAGED_VERSIONED(FColMasks_001, "FCOLMASK", 1, //! collision masks femtocollisions::Mask); @@ -68,9 +121,10 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FColSphericities_001, "FCOLSPHERICITY", 1, // using FColSphericities = FColSphericities_001; // table for qn values -DECLARE_SOA_TABLE_STAGED_VERSIONED(FColQns_001, "FCOLQN", 1, //! qn vector - femtocollisions::Qn); -using FColQns = FColQns_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColShapes_001, "FCOLSHAPE", 1, //! event shape + femtocollisions::Qvec, + femtocollisions::EventPlaneAngle); +using FColShapes = FColShapes_001; // table for primary vertex location DECLARE_SOA_TABLE_STAGED_VERSIONED(FColPos_001, "FCOLPOS", 1, //! full vertex position @@ -90,17 +144,19 @@ using FColMults = FColMults_001; // table for different centrality (multiplicity percentile) estimators DECLARE_SOA_TABLE_STAGED_VERSIONED(FColCents_001, "FCOLCENT", 1, //! centralities cent::CentFT0A, //! centrality from FT0A - cent::CentFT0C); //! centrality from FT0C + cent::CentFT0C, //! centrality from FT0C + cent::CentFT0M); //! centrality from FT0M using FColCents = FColCents_001; namespace femtobase // all "basic" information to perform femto analysis, i.e. collision index and kinematics -// split kinematics in stored, i.e. stored in derived data, and dynmaic, i.e. can be computed on the fly +// split kinematics in stored, i.e. stored in derived data, and dynamic, i.e. can be computed on the fly { namespace stored { // static columns DECLARE_SOA_INDEX_COLUMN(FCol, fCol); //! collision index of femto collision table +DECLARE_SOA_INDEX_COLUMN(FLiteCol, fLiteCol); //! collision index of femto collision table DECLARE_SOA_COLUMN(SignedPt, signedPt, float); //! signed pt DECLARE_SOA_COLUMN(Pt, pt, float); //! pt DECLARE_SOA_COLUMN(Eta, eta, float); //! eta @@ -119,7 +175,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! transverse momentum [](float signedPt) -> float { return std::fabs(signedPt); }); -// use fabs for pt so it can also be used with signed pt DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! momentum in x [](float pt, float phi) -> float { return std::fabs(pt) * std::sin(phi); @@ -141,6 +196,72 @@ DECLARE_SOA_DYNAMIC_COLUMN(Theta, theta, //! theta return 2.f * std::atan(std::exp(-eta)); }); } // namespace dynamic + +namespace lite +{ + +constexpr float EtaMin = -1.5f; +constexpr float EtaMax = 1.5f; +constexpr float EtaStep = (EtaMax - EtaMin) / 65536.f; + +constexpr float PhiMin = 0.f; +constexpr float PhiMax = constants::math::TwoPI; // phi is bound on [0,2pi) +constexpr float PhiStep = (PhiMax - PhiMin) / 65536.f; + +constexpr float PtMagMin = 0.1f; // lowest pt cut for pions is usually 0.12-0.14 GeV/c +constexpr float PtMagMax = 6.f; // sensible upper limit for pt + +inline uint16_t binEta(float eta) { return o2::analysis::femto::utils::binLinear(eta, EtaMin, EtaMax, EtaStep); } +inline float unBinEta(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, EtaMin, EtaStep); } + +inline uint16_t binPhi(float phi) { return o2::analysis::femto::utils::binLinear(phi, PhiMin, PhiMax, PhiStep); } +inline float unBinPhi(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, PhiMin, PhiStep); } + +inline uint16_t binSignedPt(float signedPt) { return o2::analysis::femto::utils::binLogSigned(signedPt, PtMagMin, PtMagMax); } +inline float unBinSignedPt(uint16_t binned) { return o2::analysis::femto::utils::unBinLogSigned(binned, PtMagMin, PtMagMax); } + +inline uint16_t binUnsignedPt(float unsignedPt) { return o2::analysis::femto::utils::binLogUnsigned(unsignedPt, PtMagMin, PtMagMax); } +inline float unBinUnsignedPt(uint16_t binned) { return o2::analysis::femto::utils::unBinLogUnsigned(binned, PtMagMin, PtMagMax); } + +DECLARE_SOA_COLUMN(SignedBinnedPt, signedBinnedPt, uint16_t); +DECLARE_SOA_COLUMN(UnsignedBinnedPt, unsignedBinnedPt, uint16_t); +DECLARE_SOA_COLUMN(BinnedEta, binnedEta, uint16_t); +DECLARE_SOA_COLUMN(BinnedPhi, binnedPhi, uint16_t); + +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, + [](uint16_t signedBinnedPt) -> int { + return o2::analysis::femto::utils::unBinSign(signedBinnedPt); + }); +DECLARE_SOA_DYNAMIC_COLUMN(SignedPt, signedPt, + [](uint16_t signedBinnedPt) -> float { + return unBinSignedPt(signedBinnedPt); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, + [](uint16_t binnedEta) -> float { + return unBinEta(binnedEta); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, + [](uint16_t binnedPhi) -> float { + return unBinPhi(binnedPhi); + }); + +namespace signedpt +{ +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](uint16_t signedBinnedPt) -> float { + return std::fabs(unBinSignedPt(signedBinnedPt)); + }); +} // namespace signedpt + +namespace unsignedpt +{ +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](uint16_t unsignedBinnedPt) -> float { + return unBinUnsignedPt(unsignedBinnedPt); + }); +} // namespace unsignedpt + +} // namespace lite } // namespace femtobase namespace femtotracks @@ -240,6 +361,22 @@ using FTracks = FTracks_001; using FTrack = FTracks::iterator; using StoredFTracks = StoredFTracks_001; +// table for basic track information, compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteTracks_001, "FLITETRACK", 1, //! femto tracks, binned kinematics + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtobase::lite::Sign, + femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi); +using FLiteTracks = FLiteTracks_001; +using FLiteTrack = FLiteTracks::iterator; +using StoredFLiteTracks = StoredFLiteTracks_001; + // table for track selections and PID selections DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackMasks_001, "FTRACKMASK", 1, //! track masks femtotracks::Mask); @@ -416,19 +553,26 @@ namespace femtov0s { // columns for bit masks DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::V0MaskType); //! Bitmask for v0 selections +// +namespace legacy001 +{ +DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::V0MaskType001); //! Bitmask for v0 selections +} // columns for debug information -DECLARE_SOA_COLUMN(MassAnti, massAnti, float); //! mass of particle using antiparticle hypothesis (for Lambda/AntiLambda extra table) -DECLARE_SOA_COLUMN(MassLambda, massLambda, float); //! Mass of Lambda (for k0short table) -DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); //! Mass of AntiLambda (for k0short table) -DECLARE_SOA_COLUMN(MassK0short, massK0short, float); //! Mass of K0short (for lambda/antitlambda table) -DECLARE_SOA_COLUMN(CosPa, cosPa, float); //! Lambda daughter DCA at decay vertex -DECLARE_SOA_COLUMN(DauDca, dauDca, float); //! Lambda daughter DCA at decay vertex -DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Lambda transvers radius -DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! x coordinate of Lambda decay vertex -DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! y coordinate of Lambda decay vertex -DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! z coordinate of Lambda decay vertex -DECLARE_SOA_DYNAMIC_COLUMN(DecayVtx, decayVtx, //! distance of decay vertex from nominal interaction point +DECLARE_SOA_COLUMN(MassAnti, massAnti, float); //! mass of particle using antiparticle hypothesis (for Lambda/AntiLambda extra table) +DECLARE_SOA_COLUMN(MassLambda, massLambda, float); //! Mass of Lambda (for k0short table) +DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); //! Mass of AntiLambda (for k0short table) +DECLARE_SOA_COLUMN(MassK0short, massK0short, float); //! Mass of K0short (for lambda/antitlambda table) +DECLARE_SOA_COLUMN(CosPa, cosPa, float); //! Lambda daughter DCA at decay vertex +DECLARE_SOA_COLUMN(DauDca, dauDca, float); //! Lambda daughter DCA at decay vertex +DECLARE_SOA_COLUMN(StrangeTofPosDau, strangeTofPosDau, float); //! TOF Strangeness for positive daughter +DECLARE_SOA_COLUMN(StrangeTofNegDau, strangeTofNegDau, float); //! TOF Strangeness for negative daughter +DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Lambda transvers radius +DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! x coordinate of Lambda decay vertex +DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! y coordinate of Lambda decay vertex +DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! z coordinate of Lambda decay vertex +DECLARE_SOA_DYNAMIC_COLUMN(DecayVtx, decayVtx, //! distance of decay vertex from nominal interaction point [](float vtxX, float vtxY, float vtxZ) -> float { return std::hypot(vtxX, vtxY, vtxZ); }); @@ -437,6 +581,42 @@ DECLARE_SOA_DYNAMIC_COLUMN(DecayVtx, decayVtx, //! distance of decay DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! index column for positive daughter track DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! index column for negative daughter track +namespace lite +{ + +constexpr float LambdaMassMin = 1.05f; // Kinematic lower limit +constexpr float LambdaMassMax = 1.30f; +constexpr float LambdaMassStep = (LambdaMassMax - LambdaMassMin) / 65536.f; + +// K0short: PDG mass 0.497611 GeV roughly ±100 MeV window +constexpr float K0shortMassMin = 0.4f; +constexpr float K0shortMassMax = 0.6f; +constexpr float K0shortMassStep = (K0shortMassMax - K0shortMassMin) / 65536.f; + +inline uint16_t binLambdaMass(float lambdaMass) { return o2::analysis::femto::utils::binLinear(lambdaMass, LambdaMassMin, LambdaMassMax, LambdaMassStep); } +inline float unBinLambdaMass(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, LambdaMassMin, LambdaMassStep); } + +inline uint16_t binK0shortMass(float lambdaMass) { return o2::analysis::femto::utils::binLinear(lambdaMass, K0shortMassMin, K0shortMassMax, K0shortMassStep); } +inline float unBinK0shortMass(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, K0shortMassMin, K0shortMassStep); } + +DECLARE_SOA_COLUMN(BinnedLambdaMass, binnedLambdaMass, uint16_t); +DECLARE_SOA_COLUMN(BinnedK0shortMass, binnedK0shortMass, uint16_t); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaMass, lambdaMass, + [](uint16_t binnedLambdaMass) -> float { + return unBinLambdaMass(binnedLambdaMass); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(K0shortMass, k0shortMass, + [](uint16_t binnedK0shortMass) -> float { + return unBinK0shortMass(binnedK0shortMass); + }); + +// index for lite track table +DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FLiteTracks, "_PosDau"); //! index column for positive daughter track +DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FLiteTracks, "_NegDau"); //! index column for negative daughter track + +} // namespace lite } // namespace femtov0s // table for basic lambda information @@ -459,16 +639,42 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdas_001, "FLAMBDA", 1, //! femto lambdas using FLambdas = FLambdas_001; using StoredFLambdas = StoredFLambdas_001; -DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaMasks_001, "FLAMBDAMASK", 1, //! lambda masks +// table for basic lambda information with compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteLambdas_001, "FLITELAMBDA", 1, + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtov0s::lite::BinnedLambdaMass, + femtov0s::lite::PosDauId, + femtov0s::lite::NegDauId, + femtobase::lite::Sign, + femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi, + femtov0s::lite::LambdaMass); +using FLiteLambdas = FLiteLambdas_001; +using FLiteLambda = FLiteLambdas::iterator; +using StoredFLiteLambdas = StoredFLiteLambdas_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaMasks_001, "FLAMBDAMASK", 1, //! legacy lambda mask + femtov0s::legacy001::Mask); + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaMasks_002, "FLAMBDAMASK", 2, //! lambda mask femtov0s::Mask); -using FLambdaMasks = FLambdaMasks_001; -using StoredFLambdaMasks = StoredFLambdaMasks_001; + +using FLambdaMasks = FLambdaMasks_002; +using StoredFLambdaMasks = StoredFLambdaMasks_002; DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaExtras_001, "FLAMBDAEXTRA", 1, //! lambda extra information femtov0s::MassAnti, // put mass of antiparticle, i.e. antilambda mass for lambdas and vice versa femtov0s::MassK0short, femtov0s::CosPa, femtov0s::DauDca, + femtov0s::StrangeTofPosDau, + femtov0s::StrangeTofNegDau, femtov0s::TransRadius, femtov0s::DecayVtxX, femtov0s::DecayVtxY, @@ -495,16 +701,39 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shorts_001, "FK0SHORT", 1, //! femto k0sho using FK0shorts = FK0shorts_001; using StoredFK0shorts = StoredFK0shorts_001; -DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortMasks_001, "FK0SHORTMASK", 1, //! k0short masks +// table for basic lambda information with compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteK0shorts_001, "FLITEK0SHORT", 1, + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::UnsignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtov0s::lite::BinnedK0shortMass, + femtov0s::lite::PosDauId, + femtov0s::lite::NegDauId, + femtobase::lite::unsignedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi, + femtov0s::lite::K0shortMass); +using FLiteK0shorts = FLiteK0shorts_001; +using FLiteK0short = FLiteK0shorts::iterator; +using StoredFLiteK0shorts = StoredFLiteK0shorts_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortMasks_001, "FK0SHORTMASK", 1, //! legacy k0short masks + femtov0s::legacy001::Mask); + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortMasks_002, "FK0SHORTMASK", 2, //! k0short masks femtov0s::Mask); -using FK0shortMasks = FK0shortMasks_001; -using StoredFK0shortMasks = StoredFK0shortMasks_001; +using FK0shortMasks = FK0shortMasks_002; +using StoredFK0shortMasks = StoredFK0shortMasks_002; DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortExtras_001, "FK0SHORTEXTRA", 1, //! k0short extra information femtov0s::MassLambda, femtov0s::MassAntiLambda, femtov0s::CosPa, femtov0s::DauDca, + femtov0s::StrangeTofPosDau, + femtov0s::StrangeTofNegDau, femtov0s::TransRadius, femtov0s::DecayVtxX, femtov0s::DecayVtxY, @@ -529,13 +758,35 @@ DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Transverse decay radius // id column for charged daughter track DECLARE_SOA_INDEX_COLUMN_FULL(ChaDau, chaDau, int32_t, FTracks, "_ChaDau"); //! + +namespace lite +{ +// Sigma (using a shared window covering both Sigma- 1.19745 and Sigma+ 1.18937) with roughly +-100 MeV +constexpr float SigmaMassMin = 1.1f; +constexpr float SigmaMassMax = 1.3f; +constexpr float SigmaMassStep = (SigmaMassMax - SigmaMassMin) / 65536.f; + +inline uint16_t binSigmaMass(float mass) { return o2::analysis::femto::utils::binLinear(mass, SigmaMassMin, SigmaMassMax, SigmaMassStep); } +inline float unBinSigmaMass(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, SigmaMassMin, SigmaMassStep); } + +DECLARE_SOA_COLUMN(BinnedSigmaMass, binnedSigmaMass, uint16_t); + +DECLARE_SOA_DYNAMIC_COLUMN(SigmaMass, sigmaMass, + [](uint16_t binnedSigmaMass) -> float { + return unBinSigmaMass(binnedSigmaMass); + }); + +// index for lite track table +DECLARE_SOA_INDEX_COLUMN_FULL(ChaDau, chaDau, int32_t, FLiteTracks, "_ChaDau"); //! charged daughter index, into FLiteTracks +} // namespace lite + } // namespace femtokinks // table for basic sigma information DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_001, "FSIGMA", 1, o2::soa::Index<>, - femtobase::stored::FColId, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) - femtobase::stored::SignedPt, + femtobase::stored::FColId, + femtobase::stored::SignedPt, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) femtobase::stored::Eta, femtobase::stored::Phi, femtobase::stored::Mass, @@ -551,8 +802,8 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_001, "FSIGMA", 1, // table for basic sigma information DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_002, "FSIGMA", 2, o2::soa::Index<>, - femtobase::stored::FColId, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) - femtobase::stored::SignedPt, + femtobase::stored::FColId, + femtobase::stored::SignedPt, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) femtobase::stored::Eta, femtobase::stored::Phi, femtobase::stored::Mass, @@ -565,10 +816,33 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_002, "FSIGMA", 2, femtobase::dynamic::Pz, femtobase::dynamic::Theta); using FSigmas = FSigmas_002; +using FSigma = FSigmas::iterator; +using StoredFSigmas = StoredFSigmas_002; + +// table for basic sigma information, compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteSigmas_001, "FLITESIGMA", 1, + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtokinks::lite::BinnedSigmaMass, + femtokinks::lite::ChaDauId, + femtobase::lite::Sign, + femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi, + femtokinks::lite::SigmaMass); +using FLiteSigmas = FLiteSigmas_001; +using FLiteSigma = FLiteSigmas::iterator; +using StoredFLiteSigmas = StoredFLiteSigmas_001; DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaMasks_001, "FSIGMAMASKS", 1, femtokinks::Mask); using FSigmaMasks = FSigmaMasks_001; +using FSigmamask = FSigmaMasks::iterator; +using StoredFSigmaMasks = StoredFSigmaMasks_001; DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaExtras_001, "FSIGMAEXTRAS", 1, femtokinks::KinkAngle, @@ -584,8 +858,8 @@ using FSigmaExtras = FSigmaExtras_001; // table for basic sigma plus information DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlus_001, "FSIGMAPLUS", 1, o2::soa::Index<>, - femtobase::stored::FColId, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) - femtobase::stored::SignedPt, + femtobase::stored::FColId, + femtobase::stored::SignedPt, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) femtobase::stored::Eta, femtobase::stored::Phi, femtobase::stored::Mass, @@ -598,6 +872,27 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlus_001, "FSIGMAPLUS", 1, femtobase::dynamic::Pz, femtobase::dynamic::Theta); using FSigmaPlus = FSigmaPlus_001; +using FSigmaPlusRow = FSigmaPlus::iterator; +using StoredFSigmaPlus = StoredFSigmaPlus_001; + +// table for basic sigma plus information, compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteSigmaPlus_001, "FLITESIGMAPLUS", 1, + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtokinks::lite::BinnedSigmaMass, + femtokinks::lite::ChaDauId, + femtobase::lite::Sign, + femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi, + femtokinks::lite::SigmaMass); +using FLiteSigmaPlus = FLiteSigmaPlus_001; +using FLiteSigmaPlusRow = FLiteSigmaPlus::iterator; +using StoredFLiteSigmaPlus = StoredFLiteSigmaPlus_001; DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusMasks_001, "FSIGMAPLUSMASKS", 1, femtokinks::Mask); @@ -619,6 +914,11 @@ namespace femtocascades // columns for cascade bit masks DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CascadeMaskType); //! Bitmask for cascade selections +namespace legacy001 +{ +DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CascadeMaskType001); //! Bitmask for cascade selections +} + // columns for cascad debug information DECLARE_SOA_COLUMN(MassXi, massXi, float); //! Mass of xi DECLARE_SOA_COLUMN(MassOmega, massOmega, float); //! Mass of omega @@ -630,11 +930,46 @@ DECLARE_SOA_COLUMN(LambdaCosPa, lambdaCosPa, float); //! cosine of DECLARE_SOA_COLUMN(LambdaDauDca, lambdaDauDca, float); //! Lambda daughter DCA at decay vertex DECLARE_SOA_COLUMN(LambdaTransRadius, lambdaTransRadius, float); //! Lambda transvers radius DECLARE_SOA_COLUMN(LambdaDcaToPv, lambdaDcaToPv, float); //! Lambda transvers radius +DECLARE_SOA_COLUMN(StrangeTofBachelor, strangeTofBachelor, float); //! Lambda transvers radius // id columns for bachelor // following same style as strangeness tables were we do not store the id of the lambda, but its daughters DECLARE_SOA_INDEX_COLUMN_FULL(Bachelor, bachelor, int32_t, FTracks, "_Bachelor"); //! bachelor id +namespace lite +{ + +// Xi-: PDG mass 1.32171 GeV, roughly ±100 MeV window +constexpr float XiMassMin = 1.22f; +constexpr float XiMassMax = 1.42f; +constexpr float XiMassStep = (XiMassMax - XiMassMin) / 65536.f; + +// Omega-: PDG mass 1.67245 GeV, roughly ±100 MeV window +constexpr float OmegaMassMin = 1.57f; +constexpr float OmegaMassMax = 1.77f; +constexpr float OmegaMassStep = (OmegaMassMax - OmegaMassMin) / 65536.f; + +inline uint16_t binXiMass(float mass) { return o2::analysis::femto::utils::binLinear(mass, XiMassMin, XiMassMax, XiMassStep); } +inline float unBinXiMass(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, XiMassMin, XiMassStep); } + +inline uint16_t binOmegaMass(float mass) { return o2::analysis::femto::utils::binLinear(mass, OmegaMassMin, OmegaMassMax, OmegaMassStep); } +inline float unBinOmegaMass(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, OmegaMassMin, OmegaMassStep); } + +DECLARE_SOA_COLUMN(BinnedXiMass, binnedXiMass, uint16_t); +DECLARE_SOA_COLUMN(BinnedOmegaMass, binnedOmegaMass, uint16_t); + +DECLARE_SOA_DYNAMIC_COLUMN(XiMass, xiMass, + [](uint16_t binnedXiMass) -> float { + return unBinXiMass(binnedXiMass); + }); +DECLARE_SOA_DYNAMIC_COLUMN(OmegaMass, omegaMass, + [](uint16_t binnedOmegaMass) -> float { + return unBinOmegaMass(binnedOmegaMass); + }); + +// index for lite track table +DECLARE_SOA_INDEX_COLUMN_FULL(Bachelor, bachelor, int32_t, FLiteTracks, "_Bachelor"); //! bachelor index, into FLiteTracks +} // namespace lite } // namespace femtocascades DECLARE_SOA_TABLE_STAGED_VERSIONED(FXis_001, "FXI", 1, //! femto xis @@ -655,12 +990,37 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FXis_001, "FXI", 1, //! femto xis femtobase::dynamic::Pz, femtobase::dynamic::Theta); using FXis = FXis_001; +using FXi = FXis::iterator; using StoredFXis = StoredFXis_001; -DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiMasks_001, "FXIMASK", 1, //! xi masks +// table for basic xi information, compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteXis_001, "FLITEXI", 1, + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtocascades::lite::BinnedXiMass, + femtocascades::lite::BachelorId, + femtov0s::lite::PosDauId, + femtov0s::lite::NegDauId, + femtobase::lite::Sign, + femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi, + femtocascades::lite::XiMass); +using FLiteXis = FLiteXis_001; +using FLiteXi = FLiteXis::iterator; +using StoredFLiteXis = StoredFLiteXis_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiMasks_001, "FXIMASK", 1, //! legacy xi masks + femtocascades::legacy001::Mask); + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiMasks_002, "FXIMASK", 2, //! xi masks femtocascades::Mask); -using FXiMasks = FXiMasks_001; -using StoredFXiMasks = StoredFXiMasks_001; +using FXiMasks = FXiMasks_002; +using StoredFXiMasks = StoredFXiMasks_002; DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiExtras_001, "FXIEXTRA", 1, //! xi extra information femtocascades::MassOmega, @@ -671,7 +1031,10 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiExtras_001, "FXIEXTRA", 1, //! xi extra in femtocascades::LambdaCosPa, femtocascades::LambdaDauDca, femtocascades::LambdaTransRadius, - femtocascades::LambdaDcaToPv); + femtocascades::LambdaDcaToPv, + femtocascades::StrangeTofBachelor, + femtov0s::StrangeTofPosDau, + femtov0s::StrangeTofNegDau); using FXiExtras = FXiExtras_001; DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegas_001, "FOMEGA", 1, //! femto omegas @@ -692,12 +1055,37 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegas_001, "FOMEGA", 1, //! femto omegas femtobase::dynamic::Pz, femtobase::dynamic::Theta); using FOmegas = FOmegas_001; +using FOmega = FOmegas::iterator; using StoredFOmegas = StoredFOmegas_001; -DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaMasks_001, "FOMEGAMASK", 1, //! omega masks +// table for basic omega information, compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteOmegas_001, "FLITEOMEGA", 1, + o2::soa::Index<>, + femtobase::stored::FLiteColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtocascades::lite::BinnedOmegaMass, + femtocascades::lite::BachelorId, + femtov0s::lite::PosDauId, + femtov0s::lite::NegDauId, + femtobase::lite::Sign, + femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, + femtobase::lite::Eta, + femtobase::lite::Phi, + femtocascades::lite::OmegaMass); +using FLiteOmegas = FLiteOmegas_001; +using FLiteOmega = FLiteOmegas::iterator; +using StoredFLiteOmegas = StoredFLiteOmegas_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaMasks_001, "FOMEGAMASK", 1, //! legacy omega masks + femtocascades::legacy001::Mask); + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaMasks_002, "FOMEGAMASK", 2, //! omega masks femtocascades::Mask); -using FOmegaMasks = FOmegaMasks_001; -using StoredFOmegaMasks = StoredFOmegaMasks_001; +using FOmegaMasks = FOmegaMasks_002; +using StoredFOmegaMasks = StoredFOmegaMasks_002; DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaExtras_001, "FOMEGAEXTRA", 1, //! omega extra information femtocascades::MassXi, @@ -708,11 +1096,81 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaExtras_001, "FOMEGAEXTRA", 1, //! omega femtocascades::LambdaCosPa, femtocascades::LambdaDauDca, femtocascades::LambdaTransRadius, - femtocascades::LambdaDcaToPv); + femtocascades::LambdaDcaToPv, + femtocascades::StrangeTofBachelor, + femtov0s::StrangeTofPosDau, + femtov0s::StrangeTofNegDau); using FOmegaExtras = FOmegaExtras_001; -// tables for monte carlo +namespace femtocharmhadrons +{ +// bitmask column +DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CharmHadronMaskType); //! selection bitmask + +// daughter links: row indices into the femto track table +DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! + prong (pion in D0) +DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! - prong (kaon in D0) + +// QA/debug columns +DECLARE_SOA_COLUMN(Cpa, cpa, float); +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! d0*d0 of the two prongs +DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); +// ML BDT scores: [0] background, [1] prompt (D0 from c), [2] non-prompt (D0 from b decay) +DECLARE_SOA_COLUMN(MlProbD0Bkg, mlProbD0Bkg, float); //! D0 hypothesis: background score +DECLARE_SOA_COLUMN(MlProbD0Prompt, mlProbD0Prompt, float); //! D0 hypothesis: prompt score +DECLARE_SOA_COLUMN(MlProbD0NonPrompt, mlProbD0NonPrompt, float); //! D0 hypothesis: non-prompt score +DECLARE_SOA_COLUMN(MlProbD0barBkg, mlProbD0barBkg, float); //! D0bar hypothesis: background +DECLARE_SOA_COLUMN(MlProbD0barPrompt, mlProbD0barPrompt, float); //! D0bar hypothesis: prompt +DECLARE_SOA_COLUMN(MlProbD0barNonPrompt, mlProbD0barNonPrompt, float); //! D0bar hypothesis: non-prompt +DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int8_t); //! PWGHF selection flag +DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int8_t); //! PWGHF selection flag +} // namespace femtocharmhadrons + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0s_001, "FD0", 1, //! femto D0/D0bar (kinematics only) + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, //! sign encodes D0(+)/D0bar(-) + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, //! mass of the accepted hypothesis + femtocharmhadrons::PosDauId, + femtocharmhadrons::NegDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FD0s = FD0s_001; +using StoredFD0s = StoredFD0s_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Masks_001, "FD0MASK", 1, //! femto D0 selection bitmask + femtocharmhadrons::Mask); +using FD0Masks = FD0Masks_001; +using StoredFD0Masks = StoredFD0Masks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Extras_001, "FD0EXTRA", 1, //! femto D0 QA / debug + femtocharmhadrons::Cpa, + femtocharmhadrons::CpaXY, + femtocharmhadrons::DecayLength, + femtocharmhadrons::DecayLengthXY, + femtocharmhadrons::ImpactParameterProduct, + femtocharmhadrons::CosThetaStar, + femtocharmhadrons::MlProbD0Bkg, + femtocharmhadrons::MlProbD0Prompt, + femtocharmhadrons::MlProbD0NonPrompt, + femtocharmhadrons::MlProbD0barBkg, + femtocharmhadrons::MlProbD0barPrompt, + femtocharmhadrons::MlProbD0barNonPrompt, + femtocharmhadrons::IsSelD0, // raw PWGHF selection flags + femtocharmhadrons::IsSelD0bar); +using FD0Extras = FD0Extras_001; +// tables for monte carlo namespace femtomccollisions { // DECLARE_SOA_COLUMN(Mult, mult, int); //! Multiplicity of the event as given by the generator in |eta|<0.8 @@ -795,6 +1253,8 @@ DECLARE_SOA_TABLE(FLambdaLabels, "AOD", "FLAMBDALABEL", femtolabels::FMcParticle DECLARE_SOA_TABLE(FK0shortLabels, "AOD", "FK0SHORTLABEL", femtolabels::FMcParticleId); +DECLARE_SOA_TABLE(FD0Labels, "AOD", "FD0LABEL", femtolabels::FMcParticleId); + DECLARE_SOA_TABLE(FSigmaLabels, "AOD", "FSIGMALABEL", femtolabels::FMcParticleId); DECLARE_SOA_TABLE(FSigmaPlusLabels, "AOD", "FSIGMAPLUSLABEL", femtolabels::FMcParticleId); diff --git a/PWGCF/Femto/FemtoNuclei/CMakeLists.txt b/PWGCF/Femto/FemtoNuclei/CMakeLists.txt index 27462d99baf..03068dcd4aa 100644 --- a/PWGCF/Femto/FemtoNuclei/CMakeLists.txt +++ b/PWGCF/Femto/FemtoNuclei/CMakeLists.txt @@ -10,3 +10,5 @@ # or submit itself to any jurisdiction. add_subdirectory(TableProducer) +add_subdirectory(Tasks) + diff --git a/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h b/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h index ce8e83575fe..babbf2105ae 100644 --- a/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h +++ b/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h @@ -50,8 +50,15 @@ DECLARE_SOA_COLUMN(InnerParamTPCNu, innerParamTPCNu, float); DECLARE_SOA_COLUMN(SignalTPCHad, signalTPCHad, float); DECLARE_SOA_COLUMN(InnerParamTPCHad, innerParamTPCHad, float); DECLARE_SOA_COLUMN(NClsTPCNu, nClsTPCNu, uint8_t); +DECLARE_SOA_COLUMN(NClsTPCHad, nClsTPCHad, uint8_t); +DECLARE_SOA_COLUMN(NCrossedRowsTPCNu, nCrossedRowsTPCNu, uint8_t); +DECLARE_SOA_COLUMN(NCrossedRowsTPCHad, nCrossedRowsTPCHad, uint8_t); DECLARE_SOA_COLUMN(NSigmaTPCNu, nSigmaTPCNu, float); DECLARE_SOA_COLUMN(NSigmaTPCHad, nSigmaTPCHad, float); +DECLARE_SOA_COLUMN(NSigmaTOFNu, nSigmaTOFNu, float); +DECLARE_SOA_COLUMN(NSigmaITSNu, nSigmaITSNu, float); +DECLARE_SOA_COLUMN(NSigmaTOFHad, nSigmaTOFHad, float); +DECLARE_SOA_COLUMN(NSigmaITSHad, nSigmaITSHad, float); DECLARE_SOA_COLUMN(NSigmaTPCHadPi, nSigmaTPCHadPi, float); DECLARE_SOA_COLUMN(NSigmaTPCHadKa, nSigmaTPCHadKa, float); DECLARE_SOA_COLUMN(NSigmaTPCHadPr, nSigmaTPCHadPr, float); @@ -73,6 +80,26 @@ DECLARE_SOA_COLUMN(ItsClusterSizeHad, itsClusterSizeHad, uint32_t); DECLARE_SOA_COLUMN(SharedClustersNu, sharedClustersNu, uint8_t); DECLARE_SOA_COLUMN(SharedClustersHad, sharedClustersHad, uint8_t); +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); + +// Reconstructed-MC pair information. The signed generated pT follows the +// convention used by PtNu/PtHad: particles are positive and antiparticles +// are negative. +DECLARE_SOA_COLUMN(PtNuMC, ptNuMC, float); +DECLARE_SOA_COLUMN(EtaNuMC, etaNuMC, float); +DECLARE_SOA_COLUMN(PhiNuMC, phiNuMC, float); +DECLARE_SOA_COLUMN(PtHadMC, ptHadMC, float); +DECLARE_SOA_COLUMN(EtaHadMC, etaHadMC, float); +DECLARE_SOA_COLUMN(PhiHadMC, phiHadMC, float); +DECLARE_SOA_COLUMN(KstarMC, kstarMC, float); +DECLARE_SOA_COLUMN(PdgCodeNuMC, pdgCodeNuMC, int32_t); +DECLARE_SOA_COLUMN(PdgCodeHadMC, pdgCodeHadMC, int32_t); +DECLARE_SOA_COLUMN(IsPhysicalPrimaryNuMC, isPhysicalPrimaryNuMC, bool); +DECLARE_SOA_COLUMN(IsPhysicalPrimaryHadMC, isPhysicalPrimaryHadMC, bool); +DECLARE_SOA_COLUMN(SameMCCollision, sameMCCollision, bool); +DECLARE_SOA_COLUMN(MatchesRecoMCCollision, matchesRecoMCCollision, bool); + DECLARE_SOA_COLUMN(IsBkgUS, isBkgUS, bool); DECLARE_SOA_COLUMN(IsBkgEM, isBkgEM, bool); @@ -101,6 +128,9 @@ DECLARE_SOA_TABLE(HadronNucleiTable, "AOD", "HADNUCLEITABLE", hadron_nuclei_tables::SignalTPCHad, hadron_nuclei_tables::InnerParamTPCHad, hadron_nuclei_tables::NClsTPCNu, + hadron_nuclei_tables::NClsTPCHad, + hadron_nuclei_tables::NCrossedRowsTPCNu, + hadron_nuclei_tables::NCrossedRowsTPCHad, hadron_nuclei_tables::NSigmaTPCNu, hadron_nuclei_tables::NSigmaTPCHadPi, hadron_nuclei_tables::NSigmaTPCHadKa, @@ -117,7 +147,28 @@ DECLARE_SOA_TABLE(HadronNucleiTable, "AOD", "HADNUCLEITABLE", hadron_nuclei_tables::ItsClusterSizeNu, hadron_nuclei_tables::ItsClusterSizeHad, hadron_nuclei_tables::SharedClustersNu, - hadron_nuclei_tables::SharedClustersHad) + hadron_nuclei_tables::SharedClustersHad, + hadron_nuclei_tables::DeltaEta, + hadron_nuclei_tables::DeltaPhi, + hadron_nuclei_tables::NSigmaTPCHad, + hadron_nuclei_tables::NSigmaTOFNu, + hadron_nuclei_tables::NSigmaITSNu, + hadron_nuclei_tables::NSigmaTOFHad, + hadron_nuclei_tables::NSigmaITSHad) +DECLARE_SOA_TABLE(HadronNucleiTableMC, "AOD", "HADNUCLEIMC", + hadron_nuclei_tables::PtNuMC, + hadron_nuclei_tables::EtaNuMC, + hadron_nuclei_tables::PhiNuMC, + hadron_nuclei_tables::PtHadMC, + hadron_nuclei_tables::EtaHadMC, + hadron_nuclei_tables::PhiHadMC, + hadron_nuclei_tables::KstarMC, + hadron_nuclei_tables::PdgCodeNuMC, + hadron_nuclei_tables::PdgCodeHadMC, + hadron_nuclei_tables::IsPhysicalPrimaryNuMC, + hadron_nuclei_tables::IsPhysicalPrimaryHadMC, + hadron_nuclei_tables::SameMCCollision, + hadron_nuclei_tables::MatchesRecoMCCollision) DECLARE_SOA_TABLE(HadronHyperTable, "AOD", "HADHYPERTABLE", hadron_nuclei_tables::PtHyp, hadron_nuclei_tables::EtaHyp, diff --git a/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx b/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx index 2d7b4310774..146aae79d92 100644 --- a/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx +++ b/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx @@ -67,6 +67,7 @@ #include #include #include +#include #include using namespace o2; @@ -77,7 +78,8 @@ using std::array; using CollBracket = o2::math_utils::Bracket; using CollisionsFull = soa::Join; using CollisionsFullMC = soa::Join; -using TrackCandidates = soa::Join; +using TrackCandidates = soa::Join; +using TrackCandidatesMC = soa::Join; namespace { @@ -87,12 +89,9 @@ const std::vector betheBlochParticleNames{"De", "He3"}; const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; constexpr std::array tmpRadiiTPC{{85.f, 105.f, 125.f, 145.f, 165.f, 185.f, 205.f, 225.f, 245.f}}; constexpr int DeuteronPDG = o2::constants::physics::Pdg::kDeuteron; +constexpr int TritonPDG = o2::constants::physics::Pdg::kTriton; constexpr int He3PDG = o2::constants::physics::Pdg::kHelium3; -constexpr float He3RigidityMin = 0.8f; -constexpr int He3TPCNClsFoundMin = 110; constexpr float He3TPCChi2NClMin = 0.5f; -constexpr float He3TPCNSigmaMax = 3.0f; -constexpr float He3ITSNSigmaMin = -1.5f; using PairLorentzVector = ROOT::Math::LorentzVector>; enum Selections { @@ -132,12 +131,19 @@ struct HadNucandidate { float momNuTPC = -99.f; float momHadTPC = -99.f; uint8_t nTPCClustersNu = 0u; + uint8_t nTPCClustersHad = 0u; + uint8_t nTPCCrossedRowsNu = 0u; + uint8_t nTPCCrossedRowsHad = 0u; uint8_t sharedClustersNu = 0u; uint8_t sharedClustersHad = 0u; float chi2TPCNu = -10.f; float chi2TPCHad = -10.f; float nSigmaNu = -10.f; float nSigmaHad = -10.f; + float nSigmaTOFNu = -10.f; + float nSigmaITSNu = -10.f; + float nSigmaTOFHad = -10.f; + float nSigmaITSHad = -10.f; float nSigmaTPCHadPi = -10.f; float nSigmaTPCHadKa = -10.f; float nSigmaTPCHadPr = -10.f; @@ -162,6 +168,8 @@ struct HadNucandidate { int trackIDNu = -1; int trackIDHad = -1; + float deltaEta = -99.f; + float deltaPhi = -99.f; float kstar = 1.f; float mT = 1.f; @@ -173,6 +181,7 @@ struct HadNucandidate { struct HadNucleiFemto { Produces mOutputDataTable; + Produces mOutputMCTable; Produces mOutputHyperDataTable; Produces mOutputMultiplicityTable; @@ -236,7 +245,6 @@ struct HadNucleiFemto { std::string prefix{"deuteronPid"}; // Deuteron purity and PID cuts Configurable settingCutPinMinDe{"settingCutPinMinDe", 0.0f, "Minimum Pin for De"}; - Configurable settingCutClSizeItsDe{"settingCutClSizeItsDe", 4.0f, "Minimum ITS cluster size for De"}; Configurable settingCutDeptMin{"settingCutDeptMin", 0.6f, "Minimum PT cut on De"}; Configurable settingCutDeptMax{"settingCutDeptMax", 1.6f, "Maximum PT cut on De"}; Configurable settingCutPinMinTOFITSDe{"settingCutPinMinTOFITSDe", 1.2f, "Minimum p to apply the TOF ITS cut on De"}; @@ -247,6 +255,31 @@ struct HadNucleiFemto { Configurable settingUseProtonMassForKstarMt{"settingUseProtonMassForKstarMt", false, "If true, use proton mass instead of deuteron mass for kstar and mT"}; } deuteronPid; + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"helium3Pid"}; + Configurable settingRigidityMinHe3{"settingRigidityMinHe3", 0.8f, "Minimum He3 TPC rigidity"}; + Configurable settingTPCNClsFoundMinHe3{"settingTPCNClsFoundMinHe3", 110, "Minimum found TPC clusters for He3"}; + Configurable settingTPCCrossedRowsMinHe3{"settingTPCCrossedRowsMinHe3", 70, "Minimum crossed TPC rows for He3"}; + Configurable settingTPCNSigmaMaxHe3{"settingTPCNSigmaMaxHe3", 3.f, "Maximum absolute TPC n-sigma for He3"}; + Configurable settingITSNSigmaMinHe3{"settingITSNSigmaMinHe3", -1.5f, "Minimum ITS n-sigma for He3"}; + } helium3Pid; + + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"tritonPid"}; + // Triton track-quality, purity and PID cuts + Configurable settingPIDMomentumSplitTr{"settingPIDMomentumSplitTr", 2.f, "Momentum separating low- and high-momentum triton TPC PID"}; + Configurable settingCutTPCNsigmaLowPTr{"settingCutTPCNsigmaLowPTr", 3.f, "Maximum absolute TPC n-sigma for tritons below the momentum split"}; + Configurable settingCutITSNsigmaLowPTr{"settingCutITSNsigmaLowPTr", 3.f, "Maximum absolute ITS n-sigma for tritons below the momentum split"}; + Configurable settingCutTPCNsigmaHighPMinTr{"settingCutTPCNsigmaHighPMinTr", -2.f, "Minimum TPC n-sigma for tritons above the momentum split"}; + Configurable settingCutTPCNsigmaHighPMaxTr{"settingCutTPCNsigmaHighPMaxTr", 3.f, "Maximum TPC n-sigma for tritons above the momentum split"}; + Configurable settingTOFMassMomentumMinTr{"settingTOFMassMomentumMinTr", 1.2f, "Minimum momentum to apply the triton TOF mass cut"}; + Configurable settingTOFMassMinTr{"settingTOFMassMinTr", 2.5f, "Minimum triton TOF mass"}; + Configurable settingTOFMassMaxTr{"settingTOFMassMaxTr", 3.4f, "Maximum triton TOF mass"}; + Configurable settingTPCRejectNsig{"settingTPCRejectNsig", 3.f, "Minimum absolute TPC n-sigma from deuteron, proton and pion hypotheses"}; + } tritonPid; + struct : o2::framework::ConfigurableGroup { // cppcheck-suppress unusedStructMember std::string prefix{"CPR"}; @@ -258,6 +291,16 @@ struct HadNucleiFemto { Configurable settingClosePairSpecificRadius{"settingClosePairSpecificRadius", 85.f, "TPC radius in cm used when close pair rejection mode is 2"}; } CPR; + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"mc"}; + Configurable settingRequireSel8{"settingRequireSel8", true, "Apply the same sel8 event selection to reconstructed MC as to data"}; + Configurable settingRequireTruthSpecies{"settingRequireTruthSpecies", true, "Store only truth-matched pion-nucleus pairs"}; + Configurable settingRequireSameMCCollision{"settingRequireSameMCCollision", true, "Require the two truth particles to come from the same MC collision"}; + Configurable settingRequireRecoMCCollisionMatch{"settingRequireRecoMCCollisionMatch", true, "Require both truth particles to match the reconstructed collision MC label"}; + Configurable settingRequirePhysicalPrimaries{"settingRequirePhysicalPrimaries", false, "Store only pairs in which both truth particles are physical primaries"}; + } mc; + struct : o2::framework::ConfigurableGroup { // cppcheck-suppress unusedStructMember std::string prefix{"hypertriton"}; @@ -271,8 +314,9 @@ struct HadNucleiFemto { std::string prefix{"output"}; // Output and QA controls Configurable settingFillTable{"settingFillTable", false, "Enable table filling"}; - Configurable settingFillTableLowKstarOnly{"settingFillTableLowKstarOnly", false, "If true, fill the output table only for pion-deuteron pairs below the kstar threshold"}; + Configurable settingFillTableLowKstarOnly{"settingFillTableLowKstarOnly", false, "If true, apply the configured low-kstar threshold to pion-deuteron and pion-triton pairs"}; Configurable settingFillTablePiDeKstarMax{"settingFillTablePiDeKstarMax", 0.1f, "Maximum kstar for pion-deuteron pairs written to the output table"}; + Configurable settingFillTablePiTrKstarMax{"settingFillTablePiTrKstarMax", 0.1f, "Maximum kstar for pion-triton pairs written to the output table"}; Configurable settingFillMultiplicity{"settingFillMultiplicity", false, "Fill multiplicity table"}; Configurable settingUseBBcomputeDeNsigma{"settingUseBBcomputeDeNsigma", false, "Use BB params to compute De TPC Nsigma"}; } output; @@ -307,15 +351,16 @@ struct HadNucleiFemto { } pidCalibration; Preslice mPerCol = aod::track::collisionId; + Preslice mPerColMC = aod::track::collisionId; PresliceUnsorted hypPerCol = o2::aod::hyperrec::collisionId; // binning for EM background ConfigurableAxis axisVertex{"axisVertex", {30, -10, 10}, "Binning for vtxz"}; ConfigurableAxis axisCentrality{"axisCentrality", {40, 0, 100}, "Binning for centrality"}; using BinningType = ColumnBinningPolicy; + using SelectedCollisions = soa::Filtered; BinningType binningPolicy{{axisVertex, axisCentrality}, true}; SliceCache cache; - SameKindPair mPair{binningPolicy, eventMixing.settingNoMixedEvents, -1, &cache}; // Pair hyperPair{binningPolicy, eventMixing.settingNoMixedEvents, -1, &cache}; std::array mBBparamsNucleus{}; @@ -339,6 +384,7 @@ struct HadNucleiFemto { {"hCentrality", "Centrality", {HistType::kTH1F, {{100, 0.0f, 100.0f}}}}, {"hSkipReasons", "Why storedEvent skipped;Reason;Counts", {HistType::kTH1F, {{5, -0.5, 4.5}}}}, {"hEvents", "; Events;", {HistType::kTH1F, {{3, -0.5, 2.5}}}}, + {"hMixedEventSelections", "Mixed-event collision selection;Step;Counts", {HistType::kTH1F, {{4, -0.5, 3.5}}}}, // Candidate topology and kinematics {"hTrackSel", "Accepted hadron tracks", {HistType::kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}}}, @@ -363,8 +409,14 @@ struct HadNucleiFemto { {"hHadPin", "P distribution; #it{p} (GeV/#it{c})", {HistType::kTH1F, {{120, -4.0f, 4.0f}}}}, {"hHadEta", "eta distribution; #eta(had)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, {"hHadPhi", "phi distribution; phi(had)", {HistType::kTH1F, {{600, -4.0f, 4.0f}}}}, - {"h2CPRBefore", "Close pair rejection before cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{160, -2.0f, 2.0f}, {160, -3.2f, 3.2f}}}}, - {"h2CPRAfter", "Close pair rejection after cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{160, -2.0f, 2.0f}, {160, -3.2f, 3.2f}}}}, + {"h2CPRBefore", "Close pair rejection before cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{300, -0.15f, 0.15f}, {400, -0.2f, 0.2f}}}}, + {"h2CPRAfter", "Close pair rejection after cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{300, -0.15f, 0.15f}, {400, -0.2f, 0.2f}}}}, + + // Reconstructed MC pair QA + {"MC/hPairFlow", "MC pair flow;step;counts", {HistType::kTH1F, {{7, -0.5f, 6.5f}}}}, + {"MC/hKstarRecVsGen", "Reconstructed versus generated k*;generated k* (GeV/c);reconstructed k* (GeV/c)", {HistType::kTH2F, {{300, 0.f, 3.f}, {300, 0.f, 3.f}}}}, + {"MC/hPtNuRecVsGen", "Reconstructed versus generated signed nucleus pT;generated pT (GeV/c);reconstructed pT (GeV/c)", {HistType::kTH2F, {{280, -7.f, 7.f}, {280, -7.f, 7.f}}}}, + {"MC/hPtHadRecVsGen", "Reconstructed versus generated signed pion pT;generated pT (GeV/c);reconstructed pT (GeV/c)", {HistType::kTH2F, {{280, -7.f, 7.f}, {280, -7.f, 7.f}}}}, // dE/dx {"h2dEdxNucandidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, @@ -380,6 +432,7 @@ struct HadNucleiFemto { {"h2NSigmaNuITS", "NsigmaNu ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} Nu", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {120, -3.0f, 3.0f}}}}, {"h2NsigmaNuTOF", "NsigmaNu TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(Nu)", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {200, -5.0f, 5.0f}}}}, {"h2NsigmaNuTOF_preselection", "NsigmaNu TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(Nu)", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {400, -10.0f, 10.0f}}}}, + {"h2MassTOFTr", "Triton TOF mass; signed #it{p} (GeV/#it{c}); m_{TOF} (GeV/#it{c}^{2})", {HistType::kTH2F, {{240, -6.0f, 6.0f}, {200, 0.0f, 5.0f}}}}, // Hadron PID {"h2NsigmaHadComb", "NsigmaHad TPCTOF comb distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{comb}(had)", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {100, 0.0f, 5.0f}}}}, @@ -433,6 +486,20 @@ struct HadNucleiFemto { void init(o2::framework::InitContext&) { + constexpr int closePairRadiusModePv = 0; + constexpr int closePairRadiusModeSpecificTpc = 2; + if (CPR.settingEnableClosePairRejection.value) { + if (CPR.settingClosePairDeltaEtaMax.value <= 0.f || CPR.settingClosePairDeltaPhiMax.value <= 0.f) { + LOG(fatal) << "Close-pair rejection requires positive delta-eta and delta-phi-star limits"; + } + if (CPR.settingClosePairRadiusMode.value < closePairRadiusModePv || CPR.settingClosePairRadiusMode.value > closePairRadiusModeSpecificTpc) { + LOG(fatal) << "Invalid close-pair radius mode " << CPR.settingClosePairRadiusMode.value << "; expected 0, 1, or 2"; + } + if (CPR.settingClosePairRadiusMode.value == closePairRadiusModeSpecificTpc && CPR.settingClosePairSpecificRadius.value <= 0.f) { + LOG(fatal) << "Close-pair rejection at a specific TPC radius requires a positive radius"; + } + } + mZorroSummary.setObject(mZorro.getZorroSummary()); mRunNumber = 0; @@ -451,12 +518,14 @@ struct HadNucleiFemto { int mat{static_cast(pidCalibration.settingMaterialCorrection)}; mFitter.setMatCorrType(static_cast(mat)); - const int numParticles = 5; - const char* betheBlochLabel = nucleusBetheBlochLabel(); - for (int i = 0; i < numParticles; i++) { - mBBparamsNucleus[i] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, Form("p%i", i)); + if (!useTritonNucleus()) { + const int numParticles = 5; + const char* betheBlochLabel = nucleusBetheBlochLabel(); + for (int i = 0; i < numParticles; i++) { + mBBparamsNucleus[i] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, Form("p%i", i)); + } + mBBparamsNucleus[5] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, "resolution"); } - mBBparamsNucleus[5] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, "resolution"); std::vector selectionLabels = {"All", "Track selection", "PID"}; for (int i = 0; i < Selections::kAll; i++) { @@ -468,25 +537,44 @@ struct HadNucleiFemto { for (int i = 0; i < Selections::kAll; i++) { mQaRegistry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(i + 1, eventsLabels[i].c_str()); } + + const std::array mixedEventLabels = {"All collisions", "Event selection", "Mixing pool", "Mixed combinations"}; + for (size_t i = 0; i < mixedEventLabels.size(); i++) { + mQaRegistry.get(HIST("hMixedEventSelections"))->GetXaxis()->SetBinLabel(i + 1, mixedEventLabels[i].c_str()); + } } + template void initCCDB(const aod::BCsWithTimestamps::iterator& bc) { if (mRunNumber == bc.runNumber()) { return; } - if (zorro.settingSkimmedProcessing) { - mZorro.initCCDB(mCcdb.service, bc.runNumber(), bc.timestamp(), useHelium3Nucleus() ? "fHe" : "fDe"); - mZorro.populateHistRegistry(mQaRegistry, bc.runNumber()); + if constexpr (!isMC) { + if (zorro.settingSkimmedProcessing) { + mZorro.initCCDB(mCcdb.service, bc.runNumber(), bc.timestamp(), zorroTriggerMask()); + mZorro.populateHistRegistry(mQaRegistry, bc.runNumber()); + } } mRunNumber = bc.runNumber(); const float defaultBzValue = -999.0f; + + // A fixed field is sufficient for CPR and DCAFitter when material + // corrections are disabled. This also makes local MC tests independent + // of an AliEn token when the CCDB payload is stored on Grid. + if (ccdb.settingDbz > defaultBzValue && pidCalibration.settingMaterialCorrection == 0) { + mDbz = ccdb.settingDbz; + mFitter.setBz(mDbz); + LOG(info) << "Using configured magnetic field of " << mDbz << " kZG"; + return; + } + auto run3GrpTimestamp = bc.timestamp(); auto* grpo = mCcdb->getForTimeStamp(ccdb.settingGrpPath, run3GrpTimestamp); o2::parameters::GRPMagField* grpmag = nullptr; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); - if (ccdb.settingDbz < defaultBzValue) { + if (ccdb.settingDbz <= defaultBzValue) { // Fetch magnetic field from ccdb for current collision mDbz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; @@ -499,7 +587,7 @@ struct HadNucleiFemto { LOG(fatal) << "Got nullptr from CCDB for path " << ccdb.settingGrpmagPath << " of object GRPMagField and " << ccdb.settingGrpPath << " of object GRPObject for timestamp " << run3GrpTimestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); - if (ccdb.settingDbz < defaultBzValue) { + if (ccdb.settingDbz <= defaultBzValue) { // Fetch magnetic field from ccdb for current collision mDbz = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; @@ -507,35 +595,61 @@ struct HadNucleiFemto { mDbz = ccdb.settingDbz; } } + mFitter.setBz(mDbz); } // ================================================================================================================== template - bool selectCollision(const Tcollision& collision, const aod::BCsWithTimestamps&) + bool passesEventSelection(const Tcollision& collision) { - mQaRegistry.fill(HIST("hEvents"), 0); + // CPR uses phi* and therefore needs the magnetic field for MC as well. + auto bc = collision.template bc_as(); + initCCDB(bc); if constexpr (isMC) { - if (/*!collision.sel8() ||*/ std::abs(collision.posZ()) > eventMixing.settingCutVertex) { + if ((mc.settingRequireSel8.value && !collision.sel8()) || std::abs(collision.posZ()) > eventMixing.settingCutVertex) { return false; } } else { - auto bc = collision.template bc_as(); - initCCDB(bc); - if (!collision.sel8() || std::abs(collision.posZ()) > eventMixing.settingCutVertex) { return false; } + } + + return true; + } + + template + bool passesZorroSelection(const Tcollision& collision) + { + if (!zorro.settingSkimmedProcessing) { + return true; + } + auto bc = collision.template bc_as(); + return mZorro.isSelected(bc.globalBC()); + } + + template + bool selectCollision(const Tcollision& collision, const aod::BCsWithTimestamps&) + { + mQaRegistry.fill(HIST("hEvents"), 0); + + if (!passesEventSelection(collision)) { + return false; + } + + mQaRegistry.fill(HIST("hEvents"), 1); + + if constexpr (!isMC) { if (zorro.settingSkimmedProcessing) { - bool zorroSelected = mZorro.isSelected(collision.template bc_as().globalBC()); - if (zorroSelected) { - mQaRegistry.fill(HIST("hEvents"), 2); + if (!passesZorroSelection(collision)) { + return false; } + mQaRegistry.fill(HIST("hEvents"), 2); } } - mQaRegistry.fill(HIST("hEvents"), 1); mQaRegistry.fill(HIST("hNcontributor"), collision.numContrib()); mQaRegistry.fill(HIST("hVtxZ"), collision.posZ()); return true; @@ -649,16 +763,51 @@ struct HadNucleiFemto { candidate.itsNClsInnerBarrel() < minITSNClsInnerBarrel); } + template + bool selectTrackTr(const Ttrack& candidate) + { + constexpr float maxAbsEta = 0.8f; + constexpr float maxAbsDcaXY = 0.2f; + constexpr float maxAbsDcaZ = 0.2f; + constexpr int minTPCCrossedRows = 70; + constexpr float maxTPCChi2NCl = 5.f; + constexpr float maxTPCFractionSharedCls = 0.3f; + constexpr int minITSNCls = 5; + constexpr float maxITSChi2NCl = 10.f; + + return !(std::abs(candidate.eta()) >= maxAbsEta || + std::abs(candidate.dcaXY()) >= maxAbsDcaXY || + std::abs(candidate.dcaZ()) >= maxAbsDcaZ || + candidate.tpcNClsCrossedRows() < minTPCCrossedRows || + candidate.tpcChi2NCl() >= maxTPCChi2NCl || + candidate.tpcFractionSharedCls() >= maxTPCFractionSharedCls || + candidate.itsNCls() < minITSNCls || + candidate.itsChi2NCl() >= maxITSChi2NCl); + } + bool useDeuteronNucleus() const { return species.settingNuPDGCode.value == DeuteronPDG; } + bool useTritonNucleus() const + { + return species.settingNuPDGCode.value == TritonPDG; + } + bool useHelium3Nucleus() const { return species.settingNuPDGCode.value == He3PDG; } + const char* zorroTriggerMask() const + { + if (useTritonNucleus()) { + return "fTritonFemto"; + } + return useHelium3Nucleus() ? "fHe" : "fDe"; + } + const char* nucleusBetheBlochLabel() const { return useHelium3Nucleus() ? "He3" : "De"; @@ -674,6 +823,9 @@ struct HadNucleiFemto { if (useHelium3Nucleus()) { return static_cast(o2::constants::physics::MassHelium3); } + if (useTritonNucleus()) { + return static_cast(o2::constants::physics::MassTriton); + } return static_cast(o2::constants::physics::MassDeuteron); } @@ -684,11 +836,10 @@ struct HadNucleiFemto { return false; } - constexpr int minTPCNClsCrossedRows = 70; constexpr float crossedRowsToFindableRatio = 0.8f; return !(candidate.itsNCls() < trackCut.settingCutNCls || - candidate.tpcNClsFound() < He3TPCNClsFoundMin || - candidate.tpcNClsCrossedRows() < minTPCNClsCrossedRows || + candidate.tpcNClsFound() < helium3Pid.settingTPCNClsFoundMinHe3 || + candidate.tpcNClsCrossedRows() < helium3Pid.settingTPCCrossedRowsMinHe3 || candidate.tpcNClsCrossedRows() < crossedRowsToFindableRatio * candidate.tpcNClsFindable() || candidate.tpcChi2NCl() > trackCut.settingCutChi2tpcHigh || candidate.tpcChi2NCl() < He3TPCChi2NClMin || @@ -701,6 +852,9 @@ struct HadNucleiFemto { if (useHelium3Nucleus()) { return selectTrackHe3(candidate); } + if (useTritonNucleus()) { + return selectTrackTr(candidate); + } if (useDeuteronNucleus()) { return selectTrackDe(candidate); } @@ -723,12 +877,23 @@ struct HadNucleiFemto { return species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus) && useDeuteronNucleus(); } + bool isPionTritonPair() const + { + return species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus) && useTritonNucleus(); + } + bool shouldFillOutputTable(const HadNucandidate& hadNucand) const { - if (!output.settingFillTableLowKstarOnly.value || !isPionDeuteronPair()) { + if (!output.settingFillTableLowKstarOnly.value) { return true; } - return hadNucand.kstar < output.settingFillTablePiDeKstarMax.value; + if (isPionDeuteronPair()) { + return hadNucand.kstar < output.settingFillTablePiDeKstarMax.value; + } + if (isPionTritonPair()) { + return hadNucand.kstar < output.settingFillTablePiTrKstarMax.value; + } + return true; } template @@ -772,40 +937,64 @@ struct HadNucleiFemto { } template - bool isClosePair(const Ttrack1& firstTrack, const Ttrack2& secondTrack) + bool computeClosePairDeltas(const Ttrack1& firstTrack, const Ttrack2& secondTrack, float& deltaEta, float& deltaPhi) const { constexpr int closePairRadiusModePv = 0; constexpr int closePairRadiusModeSpecificTpc = 2; constexpr float invalidPhiStar = 999.f; + constexpr float invalidOutputDelta = -99.f; + + deltaEta = invalidOutputDelta; + deltaPhi = invalidOutputDelta; if (!CPR.settingEnableClosePairRejection.value) { return false; } - if (firstTrack.sign() != secondTrack.sign()) { + + float selectedDeltaPhi = averagePhiStar(firstTrack, secondTrack); + if (CPR.settingClosePairRadiusMode.value == closePairRadiusModePv) { + selectedDeltaPhi = wrapDeltaPhi(firstTrack.phi() - secondTrack.phi()); + } else if (CPR.settingClosePairRadiusMode.value == closePairRadiusModeSpecificTpc) { + const float firstPhi = phiAtSpecificRadiiTPC(firstTrack, CPR.settingClosePairSpecificRadius.value); + const float secondPhi = phiAtSpecificRadiiTPC(secondTrack, CPR.settingClosePairSpecificRadius.value); + if (firstPhi == invalidPhiStar || secondPhi == invalidPhiStar) { + return false; + } + selectedDeltaPhi = wrapDeltaPhi(firstPhi - secondPhi); + } + + if (selectedDeltaPhi == invalidPhiStar) { return false; } - const float deta = firstTrack.eta() - secondTrack.eta(); - const float dphiAtPV = wrapDeltaPhi(firstTrack.phi() - secondTrack.phi()); - const float dphiAtSpecificRadius = wrapDeltaPhi(phiAtSpecificRadiiTPC(firstTrack, CPR.settingClosePairSpecificRadius.value) - phiAtSpecificRadiiTPC(secondTrack, CPR.settingClosePairSpecificRadius.value)); - const float dphiAvg = averagePhiStar(firstTrack, secondTrack); + deltaEta = firstTrack.eta() - secondTrack.eta(); + deltaPhi = selectedDeltaPhi; + return true; + } - float dphiToCut = dphiAvg; - if (CPR.settingClosePairRadiusMode.value == closePairRadiusModePv) { - dphiToCut = dphiAtPV; - } else if (CPR.settingClosePairRadiusMode.value == closePairRadiusModeSpecificTpc) { - dphiToCut = dphiAtSpecificRadius; + template + bool isClosePair(const Ttrack1& firstTrack, const Ttrack2& secondTrack, bool fillQA) + { + if (!CPR.settingEnableClosePairRejection.value) { + return false; + } + if (firstTrack.sign() != secondTrack.sign()) { + return false; } - if (dphiToCut == invalidPhiStar) { + float deltaEta = -99.f; + float deltaPhi = -99.f; + if (!computeClosePairDeltas(firstTrack, secondTrack, deltaEta, deltaPhi)) { return false; } - mQaRegistry.fill(HIST("h2CPRBefore"), deta, dphiToCut); - const bool isRejected = std::pow(dphiToCut, 2.f) / std::pow(CPR.settingClosePairDeltaPhiMax.value, 2.f) + - std::pow(deta, 2.f) / std::pow(CPR.settingClosePairDeltaEtaMax.value, 2.f) < + if (fillQA) { + mQaRegistry.fill(HIST("h2CPRBefore"), deltaEta, deltaPhi); + } + const bool isRejected = std::pow(deltaPhi, 2.f) / std::pow(CPR.settingClosePairDeltaPhiMax.value, 2.f) + + std::pow(deltaEta, 2.f) / std::pow(CPR.settingClosePairDeltaEtaMax.value, 2.f) < 1.f; - if (!isRejected) { - mQaRegistry.fill(HIST("h2CPRAfter"), deta, dphiToCut); + if (fillQA && !isRejected) { + mQaRegistry.fill(HIST("h2CPRAfter"), deltaEta, deltaPhi); } return isRejected; } @@ -989,6 +1178,37 @@ struct HadNucleiFemto { return -10.f; } + template + float getHadronTOFNSigma(const Ttrack& candidate) const + { + if (species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus)) { + return candidate.tofNSigmaPi(); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kKPlus)) { + return candidate.tofNSigmaKa(); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kProton)) { + return candidate.tofNSigmaPr(); + } + return -10.f; + } + + template + float getHadronITSNSigma(const Ttrack& candidate) const + { + o2::aod::ITSResponse itsResponse; + if (species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus)) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kKPlus)) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kProton)) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + return -10.f; + } + template float computeNSigmaDe(const Ttrack& candidate) { @@ -1085,20 +1305,20 @@ struct HadNucleiFemto { const float correctedTPCinnerParam = correctedTPCInnerParamHe3(candidate); mQaRegistry.fill(HIST("h2dEdx"), candidate.sign() * correctedTPCinnerParam, candidate.tpcSignal()); - if (correctedTPCinnerParam < He3RigidityMin) { + if (correctedTPCinnerParam < helium3Pid.settingRigidityMinHe3) { return false; } const float nSigmaHe3 = computeNSigmaHe3(candidate); mQaRegistry.fill(HIST("h2NsigmaNuTPC_preselection"), candidate.sign() * 2.f * candidate.pt(), nSigmaHe3); - if (std::abs(nSigmaHe3) > He3TPCNSigmaMax) { + if (std::abs(nSigmaHe3) > helium3Pid.settingTPCNSigmaMaxHe3) { return false; } o2::aod::ITSResponse itsResponse; - const float itsNsigmaHe3 = itsResponse.nSigmaITS(candidate.itsClusterSizes(), 2.f * candidate.p(), candidate.eta()); + const float itsNsigmaHe3 = itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); mQaRegistry.fill(HIST("h2NSigmaNuITS_preselection"), candidate.sign() * 2.f * candidate.pt(), itsNsigmaHe3); - if (itsNsigmaHe3 < He3ITSNSigmaMin) { + if (itsNsigmaHe3 < helium3Pid.settingITSNSigmaMinHe3) { return false; } @@ -1108,12 +1328,71 @@ struct HadNucleiFemto { return true; } + template + float computeTOFMass(const Ttrack& candidate) const + { + if (!candidate.hasTOF()) { + return -1.f; + } + float beta = o2::pid::tof::Beta::GetBeta(candidate); + beta = std::clamp(beta, 1.e-4f, 1.f - 1.e-6f); + return std::abs(candidate.tpcInnerParam()) * std::sqrt(1.f / (beta * beta) - 1.f); + } + + template + bool selectionPIDTr(const Ttrack& candidate) + { + const float tpcNSigmaTr = candidate.tpcNSigmaTr(); + const float absP = std::abs(candidate.p()); + o2::aod::ITSResponse itsResponse; + const float itsNSigmaTr = itsResponse.nSigmaITS(candidate.itsClusterSizes(), absP, candidate.eta()); + + mQaRegistry.fill(HIST("h2dEdx"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + mQaRegistry.fill(HIST("h2NsigmaNuTPC_preselection"), candidate.sign() * candidate.pt(), tpcNSigmaTr); + mQaRegistry.fill(HIST("h2NSigmaNuITS_preselection"), candidate.sign() * candidate.pt(), itsNSigmaTr); + + if (std::abs(candidate.tpcNSigmaDe()) < tritonPid.settingTPCRejectNsig || + std::abs(candidate.tpcNSigmaPr()) < tritonPid.settingTPCRejectNsig || + std::abs(candidate.tpcNSigmaPi()) < tritonPid.settingTPCRejectNsig) { + return false; + } + + if (absP < tritonPid.settingPIDMomentumSplitTr) { + if (std::abs(tpcNSigmaTr) >= tritonPid.settingCutTPCNsigmaLowPTr || + std::abs(itsNSigmaTr) >= tritonPid.settingCutITSNsigmaLowPTr) { + return false; + } + } else if (tpcNSigmaTr <= tritonPid.settingCutTPCNsigmaHighPMinTr || + tpcNSigmaTr >= tritonPid.settingCutTPCNsigmaHighPMaxTr) { + return false; + } + + if (absP > tritonPid.settingTOFMassMomentumMinTr) { + if (!candidate.hasTOF()) { + return false; + } + const float massTOFTr = computeTOFMass(candidate); + mQaRegistry.fill(HIST("h2MassTOFTr"), candidate.sign() * absP, massTOFTr); + if (massTOFTr <= tritonPid.settingTOFMassMinTr || massTOFTr >= tritonPid.settingTOFMassMaxTr) { + return false; + } + } + + mQaRegistry.fill(HIST("h2dEdxNucandidates"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + mQaRegistry.fill(HIST("h2NsigmaNuTPC"), candidate.sign() * candidate.pt(), tpcNSigmaTr); + mQaRegistry.fill(HIST("h2NSigmaNuITS"), candidate.sign() * candidate.pt(), itsNSigmaTr); + return true; + } + template bool selectionPIDNu(const Ttrack& candidate) { if (useHelium3Nucleus()) { return selectionPIDHe3(candidate); } + if (useTritonNucleus()) { + return selectionPIDTr(candidate); + } if (useDeuteronNucleus()) { return selectionPIDDe(candidate); } @@ -1126,9 +1405,43 @@ struct HadNucleiFemto { if (useHelium3Nucleus()) { return computeNSigmaHe3(candidate); } + if (useTritonNucleus()) { + return candidate.tpcNSigmaTr(); + } return computeNSigmaDe(candidate); } + template + float getNucleusTOFNSigma(const Ttrack& candidate) const + { + if (useHelium3Nucleus()) { + return candidate.tofNSigmaHe(); + } + if (useTritonNucleus()) { + return candidate.tofNSigmaTr(); + } + if (useDeuteronNucleus()) { + return candidate.tofNSigmaDe(); + } + return -10.f; + } + + template + float getNucleusITSNSigma(const Ttrack& candidate) const + { + o2::aod::ITSResponse itsResponse; + if (useHelium3Nucleus()) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (useTritonNucleus()) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (useDeuteronNucleus()) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + return -10.f; + } + float averageClusterSizeCosl(uint32_t itsClusterSizes, float eta) { float average = 0; @@ -1256,6 +1569,7 @@ struct HadNucleiFemto { hadNucand.signNu = trackDe.sign(); hadNucand.signHad = trackHad.sign(); + computeClosePairDeltas(trackDe, trackHad, hadNucand.deltaEta, hadNucand.deltaPhi); hadNucand.dcaxyNu = trackDe.dcaXY(); hadNucand.dcaxyHad = trackHad.dcaXY(); @@ -1269,8 +1583,15 @@ struct HadNucleiFemto { hadNucand.momHadTPC = trackHad.tpcInnerParam(); hadNucand.nTPCClustersNu = trackDe.tpcNClsFound(); + hadNucand.nTPCClustersHad = trackHad.tpcNClsFound(); + hadNucand.nTPCCrossedRowsNu = trackDe.tpcNClsCrossedRows(); + hadNucand.nTPCCrossedRowsHad = trackHad.tpcNClsCrossedRows(); hadNucand.nSigmaNu = getNucleusTPCNSigma(trackDe); hadNucand.nSigmaHad = getHadronTPCNSigma(trackHad); + hadNucand.nSigmaTOFNu = getNucleusTOFNSigma(trackDe); + hadNucand.nSigmaITSNu = getNucleusITSNSigma(trackDe); + hadNucand.nSigmaTOFHad = getHadronTOFNSigma(trackHad); + hadNucand.nSigmaITSHad = getHadronITSNSigma(trackHad); hadNucand.nSigmaTPCHadPi = trackHad.tpcNSigmaPi(); hadNucand.nSigmaTPCHadKa = trackHad.tpcNSigmaKa(); hadNucand.nSigmaTPCHadPr = trackHad.tpcNSigmaPr(); @@ -1312,7 +1633,10 @@ struct HadNucleiFemto { hadNucand.massTOFHad = trackHad.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); } - const float massLightNucleusForKstarMt = useHelium3Nucleus() ? static_cast(o2::constants::physics::MassHelium3) : (deuteronPid.settingUseProtonMassForKstarMt ? static_cast(o2::constants::physics::MassProton) : static_cast(o2::constants::physics::MassDeuteron)); + float massLightNucleusForKstarMt = nucleusMass(); + if (useDeuteronNucleus() && deuteronPid.settingUseProtonMassForKstarMt) { + massLightNucleusForKstarMt = static_cast(o2::constants::physics::MassProton); + } hadNucand.kstar = computePairKstar(hadNucand.momHad, mMassHad, hadNucand.momNu, massLightNucleusForKstarMt); hadNucand.mT = computePairMT(hadNucand.momHad, mMassHad, hadNucand.momNu, massLightNucleusForKstarMt); @@ -1429,7 +1753,7 @@ struct HadNucleiFemto { continue; } hasHadronSelected = true; - if (isClosePair(track0, track1)) { + if (isClosePair(track0, track1, /*fillQA*/ true)) { continue; } @@ -1495,7 +1819,7 @@ struct HadNucleiFemto { if (!selectTrackHadron(hadCand) || !selectionPIDHadron(hadCand)) { continue; } - if (isClosePair(DeCand, hadCand)) { + if (isClosePair(DeCand, hadCand, /*fillQA*/ true)) { continue; } @@ -1530,6 +1854,9 @@ struct HadNucleiFemto { hadNucand.tpcSignalHad, hadNucand.momHadTPC, hadNucand.nTPCClustersNu, + hadNucand.nTPCClustersHad, + hadNucand.nTPCCrossedRowsNu, + hadNucand.nTPCCrossedRowsHad, hadNucand.nSigmaNu, hadNucand.nSigmaTPCHadPi, hadNucand.nSigmaTPCHadKa, @@ -1546,7 +1873,14 @@ struct HadNucleiFemto { hadNucand.itsClSizeNu, hadNucand.itsClSizeHad, hadNucand.sharedClustersNu, - hadNucand.sharedClustersHad); + hadNucand.sharedClustersHad, + hadNucand.deltaEta, + hadNucand.deltaPhi, + hadNucand.nSigmaHad, + hadNucand.nSigmaTOFNu, + hadNucand.nSigmaITSNu, + hadNucand.nSigmaTOFHad, + hadNucand.nSigmaITSHad); if (output.settingFillMultiplicity) { mOutputMultiplicityTable( collision.globalIndex(), @@ -1557,6 +1891,35 @@ struct HadNucleiFemto { } } + template + void fillMCTable(const HadNucandidate& hadNucand, const TparticleNu& particleNu, const TparticleHad& particleHad, bool sameMCCollision, bool matchesRecoMCCollision) + { + const float signedPtNuMC = particleNu.pdgCode() >= 0 ? particleNu.pt() : -particleNu.pt(); + const float signedPtHadMC = particleHad.pdgCode() >= 0 ? particleHad.pt() : -particleHad.pt(); + const std::array momentumNuMC{particleNu.px(), particleNu.py(), particleNu.pz()}; + const std::array momentumHadMC{particleHad.px(), particleHad.py(), particleHad.pz()}; + const float kstarMC = computePairKstar(momentumHadMC, mMassHad, momentumNuMC, nucleusMass()); + + mOutputMCTable( + signedPtNuMC, + particleNu.eta(), + particleNu.phi(), + signedPtHadMC, + particleHad.eta(), + particleHad.phi(), + kstarMC, + particleNu.pdgCode(), + particleHad.pdgCode(), + particleNu.isPhysicalPrimary(), + particleHad.isPhysicalPrimary(), + sameMCCollision, + matchesRecoMCCollision); + + mQaRegistry.fill(HIST("MC/hKstarRecVsGen"), kstarMC, hadNucand.kstar); + mQaRegistry.fill(HIST("MC/hPtNuRecVsGen"), signedPtNuMC, hadNucand.recoPtNu()); + mQaRegistry.fill(HIST("MC/hPtHadRecVsGen"), signedPtHadMC, hadNucand.recoPtHad()); + } + template void fillTableHyper(const HadNucandidate& hadNucand, const Tcoll& collision) { @@ -1700,6 +2063,89 @@ struct HadNucleiFemto { // ================================================================================================================== + void processMC(const CollisionsFullMC& collisions, const TrackCandidatesMC& tracks, const aod::McParticles&, const aod::BCsWithTimestamps& bcs) + { + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + + for (const auto& collision : collisions) { + mTrackPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + if (mc.settingRequireRecoMCCollisionMatch.value && !collision.has_mcCollision()) { + continue; + } + + const uint64_t collIdx = collision.globalIndex(); + mGoodCollisions[collIdx] = true; + auto tracksThisCollision = tracks.sliceBy(mPerColMC, collIdx); + tracksThisCollision.bindExternalIndices(&tracks); + + // This is deliberately the same pair builder as for data. It applies + // nucleus/pion selections and CPR before truth matching. + pairTracksSameEvent(tracksThisCollision, collision.centFT0C()); + + for (const auto& trackPair : mTrackPairs) { + mQaRegistry.fill(HIST("MC/hPairFlow"), 0); + auto trackNu = tracks.rawIteratorAt(trackPair.tr0Idx); + auto trackHad = tracks.rawIteratorAt(trackPair.tr1Idx); + + if (!trackNu.has_mcParticle() || !trackHad.has_mcParticle()) { + continue; + } + mQaRegistry.fill(HIST("MC/hPairFlow"), 1); + + const auto particleNu = trackNu.template mcParticle_as(); + const auto particleHad = trackHad.template mcParticle_as(); + const bool truthSpeciesMatch = std::abs(particleNu.pdgCode()) == std::abs(species.settingNuPDGCode.value) && + std::abs(particleHad.pdgCode()) == std::abs(species.settingHadPDGCode.value); + if (mc.settingRequireTruthSpecies.value && !truthSpeciesMatch) { + continue; + } + mQaRegistry.fill(HIST("MC/hPairFlow"), 2); + + const bool sameMCCollision = particleNu.mcCollisionId() == particleHad.mcCollisionId(); + if (mc.settingRequireSameMCCollision.value && !sameMCCollision) { + continue; + } + mQaRegistry.fill(HIST("MC/hPairFlow"), 3); + + const bool matchesRecoMCCollision = collision.has_mcCollision() && + particleNu.mcCollisionId() == collision.mcCollisionId() && + particleHad.mcCollisionId() == collision.mcCollisionId(); + if (mc.settingRequireRecoMCCollisionMatch.value && !matchesRecoMCCollision) { + continue; + } + mQaRegistry.fill(HIST("MC/hPairFlow"), 4); + + if (mc.settingRequirePhysicalPrimaries.value && + (!particleNu.isPhysicalPrimary() || !particleHad.isPhysicalPrimary())) { + continue; + } + mQaRegistry.fill(HIST("MC/hPairFlow"), 5); + + HadNucandidate hadNucand; + if (!fillCandidateInfo(trackNu, trackHad, trackPair.collBracket, collisions, hadNucand, tracks, /*isMixedEvent*/ false)) { + continue; + } + mQaRegistry.fill(HIST("MC/hPairFlow"), 6); + auto selectedCollision = collisions.rawIteratorAt(hadNucand.collisionID); + fillKstar(hadNucand, selectedCollision); + fillHistograms(hadNucand); + + if (output.settingFillTable && shouldFillOutputTable(hadNucand)) { + fillTable(hadNucand, selectedCollision); + fillMCTable(hadNucand, particleNu, particleHad, sameMCCollision, matchesRecoMCCollision); + } + } + } + } + PROCESS_SWITCH(HadNucleiFemto, processMC, "Process reconstructed MC same-event pairs", false); + + // ================================================================================================================== + void processSameEvent(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) { mGoodCollisions.clear(); @@ -1761,24 +2207,52 @@ struct HadNucleiFemto { } PROCESS_SWITCH(HadNucleiFemto, processSameEventHyper, "Process Same event", false); - void processMixedEvent(const CollisionsFull& collisions, const TrackCandidates& tracks) + void processMixedEvent(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps&) { LOG(debug) << "Processing mixed event"; - mTrackPairs.clear(); - for (const auto& [c1, tracks1, c2, tracks2] : mPair) { - if (!c1.sel8() || !c2.sel8()) { + // Zorro is a runtime selection, so build its filtered collision table before applying the mixing depth. + soa::SelectionVector selectedCollisionRows; + int64_t rowIndex = 0; + for (const auto& collision : collisions) { + mQaRegistry.fill(HIST("hMixedEventSelections"), 0); + if (!passesEventSelection(collision)) { + ++rowIndex; continue; } + mQaRegistry.fill(HIST("hMixedEventSelections"), 1); + if (!passesZorroSelection(collision)) { + ++rowIndex; + continue; + } + selectedCollisionRows.push_back(rowIndex++); + mQaRegistry.fill(HIST("hMixedEventSelections"), 2); + } + + SelectedCollisions selectedCollisions{{collisions.asArrowTableRef()}, std::move(selectedCollisionRows)}; + collisions.copyIndexBindings(selectedCollisions); + auto tracksTuple = std::make_tuple(tracks); + SameKindPair selectedPairs{binningPolicy, eventMixing.settingNoMixedEvents, -1, selectedCollisions, tracksTuple, &cache}; + + for (const auto& [c1, tracks1, c2, tracks2] : selectedPairs) { + mQaRegistry.fill(HIST("hMixedEventSelections"), 3); mQaRegistry.fill(HIST("hNcontributor"), c1.numContrib()); mQaRegistry.fill(HIST("hVtxZ"), c1.posZ()); + auto bc1 = c1.template bc_as(); + auto bc2 = c2.template bc_as(); + initCCDB(bc1); + mTrackPairs.clear(); pairTracksEventMixing(tracks1, tracks2); + fillPairs(collisions, tracks, /*isMixedEvent*/ true); + + initCCDB(bc2); + mTrackPairs.clear(); pairTracksEventMixing(tracks2, tracks1); + fillPairs(collisions, tracks, /*isMixedEvent*/ true); } - - fillPairs(collisions, tracks, /*isMixedEvent*/ true); + mTrackPairs.clear(); } PROCESS_SWITCH(HadNucleiFemto, processMixedEvent, "Process Mixed event", false); @@ -1863,8 +2337,14 @@ struct HadNucleiFemto { const float signedPtHe3 = track.sign() * 2.f * track.pt(); mQaRegistry.fill(HIST("purity/h2NsigmaNuTPC_preselection"), signedPtHe3, tpcNSigmaHe3); o2::aod::ITSResponse itsResponse; - const float itsNSigmaHe3 = itsResponse.nSigmaITS(track.itsClusterSizes(), 2.f * track.p(), track.eta()); + const float itsNSigmaHe3 = itsResponse.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); mQaRegistry.fill(HIST("purity/h2NSigmaNuITS_preselection"), signedPtHe3, itsNSigmaHe3); + } else if (passTrackNu && useTritonNucleus()) { + const float tpcNSigmaTr = track.tpcNSigmaTr(); + o2::aod::ITSResponse itsResponse; + const float itsNSigmaTr = itsResponse.nSigmaITS(track.itsClusterSizes(), std::abs(track.p()), track.eta()); + mQaRegistry.fill(HIST("purity/h2NsigmaNuTPC_preselection"), track.sign() * track.pt(), tpcNSigmaTr); + mQaRegistry.fill(HIST("purity/h2NSigmaNuITS_preselection"), track.sign() * track.pt(), itsNSigmaTr); } const bool isHadronSelected = passTrackHad && selectionPIDHadron(track); diff --git a/PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt b/PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt new file mode 100644 index 00000000000..9709ae21578 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2019-2026 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. + +o2physics_add_dpl_workflow(pi-de-femto-systematics + SOURCES piDeFemtoSystematics.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx b/PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx new file mode 100644 index 00000000000..c12af02d7d2 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx @@ -0,0 +1,854 @@ +// Copyright 2019-2026 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 piDeFemtoSystematics.cxx +/// \brief Histogram-only pion-deuteron femtoscopy task for train subwagon cut variations +/// +/// The task intentionally produces no derived AOD tables. A train subwagon +/// supplies one complete set of cuts. The default wagon and every systematic +/// subwagon therefore run the same event and pair workflow, while a systematic +/// subwagon changes exactly one configurable cut. + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +using CollisionsFull = soa::Join; +using TrackCandidates = soa::Join; + +namespace +{ +constexpr std::array BetheBlochDeDefault{-136.71, 0.441, 0.2269, 1.347, 0.8035, 0.09}; +const std::vector betheBlochParticleNames{"De"}; +const std::vector betheBlochParameterNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr std::array tpcRadii{{85.f, 105.f, 125.f, 145.f, 165.f, 185.f, 205.f, 225.f, 245.f}}; +constexpr int NumberOfBetheBlochShapeParameters = 5; +constexpr int BetheBlochResolutionIndex = 5; +constexpr double AutomaticMagneticFieldThreshold = -998.; +constexpr float NominalL3Current = 30000.f; +constexpr float InvalidPhiStar = 999.f; +constexpr int ClosePairRadiusModeAtPV = 0; +constexpr int ClosePairRadiusModeAtSpecificRadius = 2; +using PairLorentzVector = ROOT::Math::LorentzVector>; + +enum SelectionStep { + kAllTracks = 0, + kTrackCuts, + kPidCuts, + kNSelectionSteps +}; + +enum PairChannel { + kLikeSignMatter = 0, + kLikeSignAntimatter, + kUnlikeSignMatter, + kUnlikeSignAntimatter, + kNPairChannels +}; +} // namespace + +struct PiDeFemtoSystematics { + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"event"}; + Configurable vertexZMax{"vertexZMax", 10.f, "Maximum absolute collision z vertex"}; + Configurable numberOfMixedEvents{"numberOfMixedEvents", 5, "Number of mixed events per event"}; + } eventCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"pion"}; + Configurable ptMin{"ptMin", 0.14f, "Minimum pion pT"}; + Configurable ptMax{"ptMax", 4.0f, "Maximum pion pT"}; + Configurable etaMax{"etaMax", 0.8f, "Maximum absolute pion eta"}; + Configurable itsInnerBarrelClustersMin{"itsInnerBarrelClustersMin", 3, "Minimum pion ITS inner-barrel clusters"}; + Configurable itsClustersMin{"itsClustersMin", 7, "Minimum pion ITS clusters"}; + Configurable tpcClustersMin{"tpcClustersMin", 80, "Minimum pion found TPC clusters"}; + Configurable tpcCrossedRowsMin{"tpcCrossedRowsMin", 90, "Minimum pion crossed TPC rows"}; + Configurable dcaXYOffset{"dcaXYOffset", 0.004f, "Pion DCAxy cut offset"}; + Configurable dcaXYPtCoefficient{"dcaXYPtCoefficient", 0.013f, "Pion DCAxy inverse-pT coefficient"}; + Configurable dcaZOffset{"dcaZOffset", 0.004f, "Pion DCAz cut offset"}; + Configurable dcaZPtCoefficient{"dcaZPtCoefficient", 0.013f, "Pion DCAz inverse-pT coefficient"}; + Configurable combinedPidMomentumMin{"combinedPidMomentumMin", 0.5f, "Momentum above which pion TPC+TOF PID is required"}; + Configurable tpcNsigmaMax{"tpcNsigmaMax", 3.f, "Maximum absolute pion TPC n-sigma below the TOF threshold"}; + Configurable combinedNsigmaMax{"combinedNsigmaMax", 3.f, "Maximum pion combined TPC+TOF n-sigma"}; + } pionCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"deuteron"}; + Configurable ptMin{"ptMin", 0.6f, "Minimum deuteron pT"}; + Configurable ptMax{"ptMax", 2.0f, "Maximum deuteron pT"}; + Configurable etaMax{"etaMax", 0.8f, "Maximum absolute deuteron eta"}; + Configurable tpcClustersMin{"tpcClustersMin", 110, "Minimum deuteron found TPC clusters"}; + Configurable tpcCrossedRowsMin{"tpcCrossedRowsMin", 100, "Minimum deuteron crossed TPC rows"}; + Configurable itsClustersMin{"itsClustersMin", 5, "Minimum deuteron ITS clusters"}; + Configurable itsInnerBarrelClustersMin{"itsInnerBarrelClustersMin", 1, "Minimum deuteron ITS inner-barrel clusters"}; + Configurable sharedTPCClustersMax{"sharedTPCClustersMax", 160, "Maximum deuteron shared TPC clusters"}; + Configurable sharedTPCFractionMax{"sharedTPCFractionMax", 1.f, "Maximum deuteron shared TPC-cluster fraction"}; + Configurable tpcInnerParamMin{"tpcInnerParamMin", 0.f, "Minimum deuteron TPC inner parameter"}; + Configurable tofMomentumMin{"tofMomentumMin", 1.2f, "TPC inner parameter above which combined TPC+TOF PID is required"}; + Configurable nsigmaMax{"nsigmaMax", 2.5f, "Common deuteron TPC, ITS and combined PID threshold"}; + Configurable requireIndividualNsigma{"requireIndividualNsigma", false, "Also apply individual TPC and TOF cuts in the combined PID branch"}; + Configurable dcaXYOffset{"dcaXYOffset", 0.004f, "Deuteron DCAxy cut offset"}; + Configurable dcaXYPtCoefficient{"dcaXYPtCoefficient", 0.013f, "Deuteron DCAxy inverse-pT coefficient"}; + Configurable dcaZOffset{"dcaZOffset", 0.004f, "Deuteron DCAz cut offset"}; + Configurable dcaZPtCoefficient{"dcaZPtCoefficient", 0.013f, "Deuteron DCAz inverse-pT coefficient"}; + } deuteronCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"pair"}; + Configurable enableClosePairRejection{"enableClosePairRejection", true, "Enable pion-deuteron close-pair rejection"}; + Configurable closePairDeltaEtaMax{"closePairDeltaEtaMax", 0.01f, "CPR ellipse delta-eta radius"}; + Configurable closePairDeltaPhiMax{"closePairDeltaPhiMax", 0.01f, "CPR ellipse delta-phi-star radius"}; + Configurable closePairRadiusMode{"closePairRadiusMode", 1, "CPR mode: 0 PV, 1 average TPC phi-star, 2 one TPC radius"}; + Configurable closePairSpecificRadius{"closePairSpecificRadius", 85.f, "TPC radius in cm for CPR mode 2"}; + } pairCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"analysis"}; + Configurable useBetheBlochDeuteronNsigma{"useBetheBlochDeuteronNsigma", false, "Compute deuteron TPC n-sigma from the configured Bethe-Bloch parameters"}; + Configurable lowKstarYieldMax{"lowKstarYieldMax", 0.3f, "Upper kstar used for the SE-yield stability check"}; + } analysisSettings; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"zorro"}; + Configurable skimmedProcessing{"skimmedProcessing", false, "Process a Zorro-selected deuteron skim"}; + } zorroSettings; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"ccdb"}; + Configurable magneticField{"magneticField", -999., "Magnetic field; -999 reads it from CCDB"}; + Configurable url{"url", "http://alice-ccdb.cern.ch", "CCDB URL"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "GRP object path"}; + Configurable grpMagPath{"grpMagPath", "GLO/Config/GRPMagField", "GRP magnetic-field object path"}; + Configurable materialCorrection{"materialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Material correction used by the optional pair DCA fitter"}; + } ccdbSettings; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"pidCalibration"}; + Configurable> betheBlochParameters{"betheBlochParameters", + {BetheBlochDeDefault.data(), 1, 6, betheBlochParticleNames, betheBlochParameterNames}, + "Deuteron TPC Bethe-Bloch parameters"}; + } pidCalibration; + + ConfigurableAxis mixingVertexAxis{"mixingVertexAxis", {30, -10., 10.}, "Event-mixing z-vertex bins"}; + ConfigurableAxis mixingCentralityAxis{"mixingCentralityAxis", {40, 0., 100.}, "Event-mixing centrality bins"}; + ConfigurableAxis kstarAxis{"kstarAxis", {300, 0., 3.}, "kstar axis"}; + ConfigurableAxis mtAxis{"mtAxis", {240, 0.8, 3.2}, "pair mT axis"}; + ConfigurableAxis centralityAxis{"centralityAxis", {100, 0., 100.}, "centrality axis"}; + + using MixingBinning = ColumnBinningPolicy; + MixingBinning mixingBinning{{mixingVertexAxis, mixingCentralityAxis}, true}; + SliceCache cache; + SameKindPair mixedEventPairs{ + mixingBinning, eventCuts.numberOfMixedEvents, -1, &cache}; + Preslice tracksPerCollision = aod::track::collisionId; + + HistogramRegistry registry{"PiDeFemtoSystematics", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + Service ccdb{}; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + o2::vertexing::DCAFitterN<2> pairFitter; + + std::array betheBlochDe{}; + int currentRunNumber{0}; + float magneticField{0.f}; + + void init(InitContext const&) + { + const AxisSpec channelAxis{kNPairChannels, -0.5, static_cast(kNPairChannels) - 0.5, "pair channel"}; + registry.add("Pairs/hSE", "Same-event pion-deuteron pairs", HistType::kTHnSparseF, + {kstarAxis, mtAxis, centralityAxis, channelAxis}); + registry.add("Pairs/hME", "Mixed-event pion-deuteron pairs", HistType::kTHnSparseF, + {kstarAxis, mtAxis, centralityAxis, channelAxis}); + registry.add("Pairs/hSELowKstarYield", "SE low-kstar yield;pair channel;Entries", + HistType::kTH1F, {channelAxis}); + registry.add("Pairs/hMELowKstarYield", "ME low-kstar yield;pair channel;Entries", + HistType::kTH1F, {channelAxis}); + registry.add("Pairs/hCPRBefore", "CPR before selection;#Delta#eta;#Delta#varphi^{*}", + HistType::kTH2F, {{300, -0.15, 0.15}, {400, -0.2, 0.2}}); + registry.add("Pairs/hCPRAfter", "CPR after selection;#Delta#eta;#Delta#varphi^{*}", + HistType::kTH2F, {{300, -0.15, 0.15}, {400, -0.2, 0.2}}); + registry.add("Event/hCounter", "Event selection;step;Entries", + HistType::kTH1F, {{3, -0.5, 2.5}}); + registry.add("Event/hVertexZ", "Selected collision vertex;z (cm);Entries", + HistType::kTH1F, {{200, -20., 20.}}); + registry.add("Event/hCentrality", "Selected collision centrality;FT0C percentile;Entries", + HistType::kTH1F, {{100, 0., 100.}}); + registry.add("Pion/hSelection", "Pion selection;step;Entries", + HistType::kTH1F, {{kNSelectionSteps, -0.5, static_cast(kNSelectionSteps) - 0.5}}); + registry.add("Pion/hPt", "Selected pions;signed p_{T} (GeV/#it{c});Entries", + HistType::kTH1F, {{400, -5., 5.}}); + registry.add("Pion/hEta", "Selected pions;#eta;Entries", + HistType::kTH1F, {{200, -1., 1.}}); + registry.add("Pion/hTPCNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{TPC}", + HistType::kTH2F, {{400, -5., 5.}, {200, -5., 5.}}); + registry.add("Pion/hTOFNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{TOF}", + HistType::kTH2F, {{280, -7., 7.}, {200, -5., 5.}}); + registry.add("Pion/hITSNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{ITS}", + HistType::kTH2F, {{280, -7., 7.}, {120, -3., 3.}}); + registry.add("Pion/hTPCTOFNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{TPC+TOF}", + HistType::kTH2F, {{280, -7., 7.}, {100, 0., 5.}}); + registry.add("Deuteron/hSelection", "Deuteron selection;step;Entries", + HistType::kTH1F, {{kNSelectionSteps, -0.5, static_cast(kNSelectionSteps) - 0.5}}); + registry.add("Deuteron/hPt", "Selected deuterons;signed p_{T} (GeV/#it{c});Entries", + HistType::kTH1F, {{400, -5., 5.}}); + registry.add("Deuteron/hEta", "Selected deuterons;#eta;Entries", + HistType::kTH1F, {{200, -1., 1.}}); + registry.add("Deuteron/hTPCNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{TPC}", + HistType::kTH2F, {{400, -5., 5.}, {200, -5., 5.}}); + registry.add("Deuteron/hTOFNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{TOF}", + HistType::kTH2F, {{280, -7., 7.}, {200, -5., 5.}}); + registry.add("Deuteron/hITSNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{ITS}", + HistType::kTH2F, {{280, -7., 7.}, {120, -3., 3.}}); + registry.add("Deuteron/hTPCTOFNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{TPC+TOF}", + HistType::kTH2F, {{280, -7., 7.}, {100, 0., 5.}}); + registry.add("Deuteron/hTPCClusters", "Selected deuterons;TPC clusters;Entries", + HistType::kTH1F, {{161, -0.5, 160.5}}); + registry.add("Deuteron/hTPCCrossedRows", "Selected deuterons;TPC crossed rows;Entries", + HistType::kTH1F, {{161, -0.5, 160.5}}); + + addCutConfigurationHistogram(); + setAxisLabels(); + + zorroSummary.setObject(zorro.getZorroSummary()); + ccdb->setURL(ccdbSettings.url.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + pairFitter.setPropagateToPCA(true); + pairFitter.setMaxR(200.); + pairFitter.setMinParamChange(1.e-3); + pairFitter.setMinRelChi2Change(0.9); + pairFitter.setMaxDZIni(1.e9); + pairFitter.setMaxChi2(1.e9); + pairFitter.setUseAbsDCA(true); + pairFitter.setMatCorrType( + static_cast(ccdbSettings.materialCorrection.value)); + + for (int i = 0; i < NumberOfBetheBlochShapeParameters; ++i) { + betheBlochDe[i] = pidCalibration.betheBlochParameters->get("De", Form("p%i", i)); + } + betheBlochDe[BetheBlochResolutionIndex] = pidCalibration.betheBlochParameters->get("De", "resolution"); + } + + void setAxisLabels() + { + const std::array channelLabels{ + "LS matter", "LS antimatter", "US matter", "US antimatter"}; + const auto setSparseChannelLabels = [&channelLabels](THnSparse* histogram) { + for (int channel = 0; channel < kNPairChannels; ++channel) { + histogram->GetAxis(3)->SetBinLabel(channel + 1, channelLabels[channel]); + } + }; + setSparseChannelLabels(registry.get(HIST("Pairs/hSE")).get()); + setSparseChannelLabels(registry.get(HIST("Pairs/hME")).get()); + + const auto setYieldChannelLabels = [&channelLabels](TH1* histogram) { + for (int channel = 0; channel < kNPairChannels; ++channel) { + histogram->GetXaxis()->SetBinLabel(channel + 1, channelLabels[channel]); + } + }; + setYieldChannelLabels(registry.get(HIST("Pairs/hSELowKstarYield")).get()); + setYieldChannelLabels(registry.get(HIST("Pairs/hMELowKstarYield")).get()); + + const std::array selectionLabels{"all", "track cuts", "PID"}; + const auto setSelectionLabels = [&selectionLabels](TH1* histogram) { + for (int step = 0; step < kNSelectionSteps; ++step) { + histogram->GetXaxis()->SetBinLabel(step + 1, selectionLabels[step]); + } + }; + setSelectionLabels(registry.get(HIST("Pion/hSelection")).get()); + setSelectionLabels(registry.get(HIST("Deuteron/hSelection")).get()); + auto eventCounter = registry.get(HIST("Event/hCounter")); + eventCounter->GetXaxis()->SetBinLabel(1, "all"); + eventCounter->GetXaxis()->SetBinLabel(2, "sel8 and vertex"); + eventCounter->GetXaxis()->SetBinLabel(3, "Zorro"); + } + + void addCutConfigurationHistogram() + { + const std::vector> cuts{ + {"pionPtMin", pionCuts.ptMin.value}, + {"pionPtMax", pionCuts.ptMax.value}, + {"pionEtaMax", pionCuts.etaMax.value}, + {"pionITSInnerBarrelClustersMin", pionCuts.itsInnerBarrelClustersMin.value}, + {"pionITSClustersMin", pionCuts.itsClustersMin.value}, + {"pionTPCClustersMin", pionCuts.tpcClustersMin.value}, + {"pionTPCCrossedRowsMin", pionCuts.tpcCrossedRowsMin.value}, + {"pionDCAxyOffset", pionCuts.dcaXYOffset.value}, + {"pionDCAxyPtCoefficient", pionCuts.dcaXYPtCoefficient.value}, + {"pionDCAzOffset", pionCuts.dcaZOffset.value}, + {"pionDCAzPtCoefficient", pionCuts.dcaZPtCoefficient.value}, + {"pionCombinedPidMomentumMin", pionCuts.combinedPidMomentumMin.value}, + {"pionTPCNsigmaMax", pionCuts.tpcNsigmaMax.value}, + {"pionCombinedNsigmaMax", pionCuts.combinedNsigmaMax.value}, + {"deuteronPtMin", deuteronCuts.ptMin.value}, + {"deuteronPtMax", deuteronCuts.ptMax.value}, + {"deuteronEtaMax", deuteronCuts.etaMax.value}, + {"deuteronTPCClustersMin", deuteronCuts.tpcClustersMin.value}, + {"deuteronTPCCrossedRowsMin", deuteronCuts.tpcCrossedRowsMin.value}, + {"deuteronITSClustersMin", deuteronCuts.itsClustersMin.value}, + {"deuteronITSInnerBarrelClustersMin", deuteronCuts.itsInnerBarrelClustersMin.value}, + {"deuteronSharedTPCClustersMax", deuteronCuts.sharedTPCClustersMax.value}, + {"deuteronSharedTPCFractionMax", deuteronCuts.sharedTPCFractionMax.value}, + {"deuteronTPCInnerParamMin", deuteronCuts.tpcInnerParamMin.value}, + {"deuteronTOFMomentumMin", deuteronCuts.tofMomentumMin.value}, + {"deuteronNsigmaMax", deuteronCuts.nsigmaMax.value}, + {"requireIndividualNsigma", deuteronCuts.requireIndividualNsigma.value}, + {"deuteronDCAxyOffset", deuteronCuts.dcaXYOffset.value}, + {"deuteronDCAxyPtCoefficient", deuteronCuts.dcaXYPtCoefficient.value}, + {"deuteronDCAzOffset", deuteronCuts.dcaZOffset.value}, + {"deuteronDCAzPtCoefficient", deuteronCuts.dcaZPtCoefficient.value}, + {"enableCPR", pairCuts.enableClosePairRejection.value}, + {"cprDeltaEtaMax", pairCuts.closePairDeltaEtaMax.value}, + {"cprDeltaPhiMax", pairCuts.closePairDeltaPhiMax.value}, + {"cprRadiusMode", pairCuts.closePairRadiusMode.value}, + {"cprSpecificRadius", pairCuts.closePairSpecificRadius.value}, + {"useBetheBlochDeuteronNsigma", analysisSettings.useBetheBlochDeuteronNsigma.value}, + {"skimmedProcessing", zorroSettings.skimmedProcessing.value}, + {"vertexZMax", eventCuts.vertexZMax.value}, + {"numberOfMixedEvents", eventCuts.numberOfMixedEvents.value}}; + + const AxisSpec cutAxis{static_cast(cuts.size()), -0.5, + static_cast(cuts.size()) - 0.5, "cut"}; + registry.add("Config/hCutValues", "Configured cut values;cut;value", + HistType::kTH1D, {cutAxis}); + auto histogram = registry.get(HIST("Config/hCutValues")); + for (std::size_t index = 0; index < cuts.size(); ++index) { + histogram->GetXaxis()->SetBinLabel(static_cast(index) + 1, cuts[index].first.c_str()); + histogram->SetBinContent(static_cast(index) + 1, cuts[index].second); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (currentRunNumber == bc.runNumber()) { + return; + } + if (zorroSettings.skimmedProcessing.value) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fDe"); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + + auto* grp = ccdb->getForTimeStamp( + ccdbSettings.grpPath.value, bc.timestamp()); + if (grp) { + o2::base::Propagator::initFieldFromGRP(grp); + magneticField = ccdbSettings.magneticField.value < AutomaticMagneticFieldThreshold ? grp->getNominalL3Field() + : ccdbSettings.magneticField.value; + } else { + auto* grpMag = ccdb->getForTimeStamp( + ccdbSettings.grpMagPath.value, bc.timestamp()); + if (!grpMag) { + LOG(fatal) << "Could not load magnetic field from " << ccdbSettings.grpPath.value + << " or " << ccdbSettings.grpMagPath.value; + } + o2::base::Propagator::initFieldFromGRP(grpMag); + magneticField = ccdbSettings.magneticField.value < AutomaticMagneticFieldThreshold + ? std::lround(5.f * grpMag->getL3Current() / NominalL3Current) + : ccdbSettings.magneticField.value; + } + currentRunNumber = bc.runNumber(); + } + + template + bool isCollisionSelected(Collision const& collision, bool fillQA) + { + if (fillQA) { + registry.fill(HIST("Event/hCounter"), 0.); + } + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!collision.sel8() || std::abs(collision.posZ()) > eventCuts.vertexZMax.value) { + return false; + } + if (zorroSettings.skimmedProcessing.value) { + if (!zorro.isSelected(bc.globalBC())) { + return false; + } + if (fillQA) { + registry.fill(HIST("Event/hCounter"), 2.); + } + } + if (fillQA) { + registry.fill(HIST("Event/hCounter"), 1.); + registry.fill(HIST("Event/hVertexZ"), collision.posZ()); + registry.fill(HIST("Event/hCentrality"), collision.centFT0C()); + } + return true; + } + + template + bool passPionTrackCuts(Track const& track) const + { + const float absPt = std::abs(track.pt()); + if (absPt <= 0.f || absPt < pionCuts.ptMin.value || absPt > pionCuts.ptMax.value || + std::abs(track.eta()) > pionCuts.etaMax.value) { + return false; + } + if (track.itsNClsInnerBarrel() < pionCuts.itsInnerBarrelClustersMin.value || + track.itsNCls() < pionCuts.itsClustersMin.value || + track.tpcNClsFound() < pionCuts.tpcClustersMin.value || + track.tpcNClsCrossedRows() < pionCuts.tpcCrossedRowsMin.value) { + return false; + } + const float dcaXYMax = pionCuts.dcaXYOffset.value + + pionCuts.dcaXYPtCoefficient.value / absPt; + const float dcaZMax = pionCuts.dcaZOffset.value + + pionCuts.dcaZPtCoefficient.value / absPt; + return std::abs(track.dcaXY()) <= dcaXYMax && + std::abs(track.dcaZ()) <= dcaZMax; + } + + template + bool passPionPID(Track const& track) const + { + const float tpcNsigma = track.tpcNSigmaPi(); + if (std::abs(track.p()) <= pionCuts.combinedPidMomentumMin.value) { + return std::abs(tpcNsigma) <= pionCuts.tpcNsigmaMax.value; + } + if (!track.hasTOF()) { + return false; + } + const float tofNsigma = track.tofNSigmaPi(); + if (std::hypot(tpcNsigma, tofNsigma) > + pionCuts.combinedNsigmaMax.value) { + return false; + } + return !deuteronCuts.requireIndividualNsigma.value || + (std::abs(tpcNsigma) <= pionCuts.combinedNsigmaMax.value && + std::abs(tofNsigma) <= pionCuts.combinedNsigmaMax.value); + } + + template + bool passDeuteronTrackCuts(Track const& track) const + { + const float absPt = std::abs(track.pt()); + if (absPt <= 0.f || absPt < deuteronCuts.ptMin.value || + absPt > deuteronCuts.ptMax.value || + std::abs(track.eta()) > deuteronCuts.etaMax.value) { + return false; + } + if (track.tpcNClsFound() < deuteronCuts.tpcClustersMin.value || + track.tpcNClsCrossedRows() < deuteronCuts.tpcCrossedRowsMin.value || + track.tpcNClsShared() > deuteronCuts.sharedTPCClustersMax.value || + track.tpcFractionSharedCls() > deuteronCuts.sharedTPCFractionMax.value || + track.itsNCls() < deuteronCuts.itsClustersMin.value || + track.itsNClsInnerBarrel() < deuteronCuts.itsInnerBarrelClustersMin.value) { + return false; + } + const float dcaXYMax = deuteronCuts.dcaXYOffset.value + + deuteronCuts.dcaXYPtCoefficient.value / absPt; + const float dcaZMax = deuteronCuts.dcaZOffset.value + + deuteronCuts.dcaZPtCoefficient.value / absPt; + return std::abs(track.dcaXY()) <= dcaXYMax && + std::abs(track.dcaZ()) <= dcaZMax; + } + + template + float deuteronTPCNsigma(Track const& track) const + { + if (!analysisSettings.useBetheBlochDeuteronNsigma.value) { + return track.tpcNSigmaDe(); + } + const float expected = o2::common::BetheBlochAleph( + static_cast(track.tpcInnerParam() / + o2::constants::physics::MassDeuteron), + betheBlochDe[0], betheBlochDe[1], betheBlochDe[2], + betheBlochDe[3], betheBlochDe[4]); + return static_cast((track.tpcSignal() - expected) / + (expected * betheBlochDe[BetheBlochResolutionIndex])); + } + + template + bool passDeuteronPID(Track const& track) const + { + const float tpcInnerParam = track.tpcInnerParam(); + if (std::abs(tpcInnerParam) < deuteronCuts.tpcInnerParamMin.value) { + return false; + } + const float tpcNsigma = deuteronTPCNsigma(track); + if (track.hasTOF() && + tpcInnerParam > deuteronCuts.tofMomentumMin.value) { + const float tofNsigma = track.tofNSigmaDe(); + if (std::hypot(tpcNsigma, tofNsigma) > deuteronCuts.nsigmaMax.value) { + return false; + } + return !deuteronCuts.requireIndividualNsigma.value || + (std::abs(tpcNsigma) <= deuteronCuts.nsigmaMax.value && + std::abs(tofNsigma) <= deuteronCuts.nsigmaMax.value); + } + if (tpcInnerParam <= deuteronCuts.tofMomentumMin.value) { + if (std::abs(tpcNsigma) > deuteronCuts.nsigmaMax.value) { + return false; + } + o2::aod::ITSResponse itsResponse; + const float itsNsigma = + itsResponse.nSigmaITS( + track.itsClusterSizes(), track.p(), track.eta()); + return std::abs(itsNsigma) <= deuteronCuts.nsigmaMax.value; + } + return false; + } + + template + void fillSingleParticleQA(Tracks const& tracks) + { + for (auto const& track : tracks) { + registry.fill(HIST("Pion/hSelection"), static_cast(kAllTracks)); + if (passPionTrackCuts(track)) { + registry.fill(HIST("Pion/hSelection"), static_cast(kTrackCuts)); + if (passPionPID(track)) { + registry.fill(HIST("Pion/hSelection"), static_cast(kPidCuts)); + const float signedPt = track.sign() * track.pt(); + const float tpcNsigma = track.tpcNSigmaPi(); + registry.fill(HIST("Pion/hPt"), signedPt); + registry.fill(HIST("Pion/hEta"), track.eta()); + registry.fill(HIST("Pion/hTPCNsigma"), signedPt, tpcNsigma); + o2::aod::ITSResponse itsResponse; + const float itsNsigma = itsResponse.nSigmaITS( + track.itsClusterSizes(), track.p(), track.eta()); + registry.fill(HIST("Pion/hITSNsigma"), signedPt, itsNsigma); + if (track.hasTOF() && + std::abs(track.p()) > pionCuts.combinedPidMomentumMin.value) { + const float tofNsigma = track.tofNSigmaPi(); + registry.fill(HIST("Pion/hTOFNsigma"), signedPt, tofNsigma); + registry.fill(HIST("Pion/hTPCTOFNsigma"), signedPt, + std::hypot(tpcNsigma, tofNsigma)); + } + } + } + + registry.fill(HIST("Deuteron/hSelection"), + static_cast(kAllTracks)); + if (passDeuteronTrackCuts(track)) { + registry.fill(HIST("Deuteron/hSelection"), + static_cast(kTrackCuts)); + if (passDeuteronPID(track)) { + registry.fill(HIST("Deuteron/hSelection"), + static_cast(kPidCuts)); + const float signedPt = track.sign() * track.pt(); + const float tpcNsigma = deuteronTPCNsigma(track); + registry.fill(HIST("Deuteron/hPt"), signedPt); + registry.fill(HIST("Deuteron/hEta"), track.eta()); + registry.fill(HIST("Deuteron/hTPCNsigma"), signedPt, tpcNsigma); + if (track.tpcInnerParam() <= deuteronCuts.tofMomentumMin.value) { + o2::aod::ITSResponse itsResponse; + const float itsNsigma = + itsResponse.nSigmaITS( + track.itsClusterSizes(), track.p(), track.eta()); + registry.fill(HIST("Deuteron/hITSNsigma"), signedPt, itsNsigma); + } else if (track.hasTOF()) { + const float tofNsigma = track.tofNSigmaDe(); + registry.fill(HIST("Deuteron/hTOFNsigma"), signedPt, tofNsigma); + registry.fill(HIST("Deuteron/hTPCTOFNsigma"), signedPt, + std::hypot(tpcNsigma, tofNsigma)); + } + registry.fill(HIST("Deuteron/hTPCClusters"), + static_cast(track.tpcNClsFound())); + registry.fill(HIST("Deuteron/hTPCCrossedRows"), + static_cast(track.tpcNClsCrossedRows())); + } + } + } + } + + template + float phiAtRadius(Track const& track, float radius) const + { + const float absPt = std::abs(track.pt()); + if (absPt <= 0.f) { + return InvalidPhiStar; + } + const float argument = + 0.3f * static_cast(track.sign()) * 0.1f * magneticField * + radius * 0.01f / (2.f * absPt); + if (std::abs(argument) >= 1.f) { + return InvalidPhiStar; + } + return track.phi() - std::asin(argument); + } + + static float wrapDeltaPhi(float deltaPhi) + { + return std::atan2(std::sin(deltaPhi), std::cos(deltaPhi)); + } + + template + float averagePhiStar(FirstTrack const& first, + SecondTrack const& second) const + { + float sum = 0.f; + int entries = 0; + for (const auto& radius : tpcRadii) { + const float firstPhi = phiAtRadius(first, radius); + const float secondPhi = phiAtRadius(second, radius); + if (firstPhi == InvalidPhiStar || secondPhi == InvalidPhiStar) { + continue; + } + sum += wrapDeltaPhi(firstPhi - secondPhi); + ++entries; + } + return entries > 0 ? sum / static_cast(entries) : InvalidPhiStar; + } + + template + bool isClosePair(FirstTrack const& first, SecondTrack const& second, + bool fillQA) + { + if (!pairCuts.enableClosePairRejection.value || + first.sign() != second.sign()) { + return false; + } + const float deltaEta = first.eta() - second.eta(); + float deltaPhi = averagePhiStar(first, second); + if (pairCuts.closePairRadiusMode.value == ClosePairRadiusModeAtPV) { + deltaPhi = wrapDeltaPhi(first.phi() - second.phi()); + } else if (pairCuts.closePairRadiusMode.value == ClosePairRadiusModeAtSpecificRadius) { + const float firstPhi = + phiAtRadius(first, pairCuts.closePairSpecificRadius.value); + const float secondPhi = + phiAtRadius(second, pairCuts.closePairSpecificRadius.value); + if (firstPhi == InvalidPhiStar || secondPhi == InvalidPhiStar) { + return false; + } + deltaPhi = wrapDeltaPhi(firstPhi - secondPhi); + } + if (deltaPhi == InvalidPhiStar || + pairCuts.closePairDeltaEtaMax.value <= 0.f || + pairCuts.closePairDeltaPhiMax.value <= 0.f) { + return false; + } + if (fillQA) { + registry.fill(HIST("Pairs/hCPRBefore"), deltaEta, deltaPhi); + } + const bool rejected = + deltaEta * deltaEta / + (pairCuts.closePairDeltaEtaMax.value * pairCuts.closePairDeltaEtaMax.value) + + deltaPhi * deltaPhi / + (pairCuts.closePairDeltaPhiMax.value * pairCuts.closePairDeltaPhiMax.value) < + 1.f; + if (fillQA && !rejected) { + registry.fill(HIST("Pairs/hCPRAfter"), deltaEta, deltaPhi); + } + return rejected; + } + + template + bool hasValidPairFit(FirstTrack const& first, SecondTrack const& second) + { + try { + return pairFitter.process(getTrackParCov(first), + getTrackParCov(second)) > 0; + } catch (...) { + return false; + } + } + + float pairKstar(std::array const& pionMomentum, + std::array const& deuteronMomentum) const + { + const PairLorentzVector pion( + pionMomentum[0], pionMomentum[1], pionMomentum[2], + o2::constants::physics::MassPiPlus); + const PairLorentzVector deuteron( + deuteronMomentum[0], deuteronMomentum[1], deuteronMomentum[2], + o2::constants::physics::MassDeuteron); + const PairLorentzVector pair = pion + deuteron; + const float beta = pair.Beta(); + const ROOT::Math::Boost boost( + -beta * std::cos(pair.Phi()) * std::sin(pair.Theta()), + -beta * std::sin(pair.Phi()) * std::sin(pair.Theta()), + -beta * std::cos(pair.Theta())); + const PairLorentzVector relativeMomentum = + boost(pion) - boost(deuteron); + return 0.5f * relativeMomentum.P(); + } + + float pairMT(std::array const& pionMomentum, + std::array const& deuteronMomentum) const + { + const PairLorentzVector pion( + pionMomentum[0], pionMomentum[1], pionMomentum[2], + o2::constants::physics::MassPiPlus); + const PairLorentzVector deuteron( + deuteronMomentum[0], deuteronMomentum[1], deuteronMomentum[2], + o2::constants::physics::MassDeuteron); + const float kT = 0.5f * (pion + deuteron).Pt(); + const float averageMass = + 0.5f * (o2::constants::physics::MassPiPlus + + o2::constants::physics::MassDeuteron); + return std::hypot(kT, averageMass); + } + + static int pairChannel(int deuteronSign, int pionSign) + { + const bool unlikeSign = deuteronSign * pionSign < 0; + const bool antimatter = deuteronSign < 0; + return 2 * static_cast(unlikeSign) + + static_cast(antimatter); + } + + template + void fillPair(DeuteronTrack const& deuteron, PionTrack const& pion, + float centrality, bool mixedEvent) + { + const std::array deuteronMomentum{ + deuteron.px(), deuteron.py(), deuteron.pz()}; + const std::array pionMomentum{ + pion.px(), pion.py(), pion.pz()}; + const float kstar = pairKstar(pionMomentum, deuteronMomentum); + const float mt = pairMT(pionMomentum, deuteronMomentum); + const auto channel = static_cast( + pairChannel(deuteron.sign(), pion.sign())); + if (mixedEvent) { + registry.fill(HIST("Pairs/hME"), kstar, mt, centrality, channel); + if (kstar < analysisSettings.lowKstarYieldMax.value) { + registry.fill(HIST("Pairs/hMELowKstarYield"), channel); + } + } else { + registry.fill(HIST("Pairs/hSE"), kstar, mt, centrality, channel); + if (kstar < analysisSettings.lowKstarYieldMax.value) { + registry.fill(HIST("Pairs/hSELowKstarYield"), channel); + } + } + } + + template + void buildPairs(DeuteronTracks const& deuteronTracks, + PionTracks const& pionTracks, float centrality, + bool mixedEvent) + { + for (auto const& deuteron : deuteronTracks) { + if (!passDeuteronTrackCuts(deuteron) || + !passDeuteronPID(deuteron)) { + continue; + } + for (auto const& pion : pionTracks) { + if (!mixedEvent && deuteron.globalIndex() == pion.globalIndex()) { + continue; + } + if (!passPionTrackCuts(pion) || !passPionPID(pion)) { + continue; + } + if (isClosePair(deuteron, pion, !mixedEvent)) { + continue; + } + if (!mixedEvent && !hasValidPairFit(deuteron, pion)) { + continue; + } + fillPair(deuteron, pion, centrality, mixedEvent); + } + } + } + + void processSameEvent(CollisionsFull const& collisions, + TrackCandidates const& tracks, + aod::BCsWithTimestamps const&) + { + for (auto const& collision : collisions) { + if (!isCollisionSelected(collision, true)) { + continue; + } + auto collisionTracks = + tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + collisionTracks.bindExternalIndices(&tracks); + fillSingleParticleQA(collisionTracks); + buildPairs(collisionTracks, collisionTracks, + collision.centFT0C(), false); + } + } + PROCESS_SWITCH(PiDeFemtoSystematics, processSameEvent, + "Fill same-event pion-deuteron pairs", true); + + void processMixedEvent(CollisionsFull const& /*collisions*/, + TrackCandidates const& /*tracks*/, + aod::BCsWithTimestamps const&) + { + for (auto const& [collision1, tracks1, collision2, tracks2] : + mixedEventPairs) { + if (!collision1.sel8() || !collision2.sel8()) { + continue; + } + auto bc1 = collision1.template bc_as(); + auto bc2 = collision2.template bc_as(); + initCCDB(bc1); + buildPairs(tracks1, tracks2, collision1.centFT0C(), true); + initCCDB(bc2); + buildPairs(tracks2, tracks1, collision2.centFT0C(), true); + } + } + PROCESS_SWITCH(PiDeFemtoSystematics, processMixedEvent, + "Fill mixed-event pion-deuteron pairs", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Femto/TableProducer/CMakeLists.txt b/PWGCF/Femto/TableProducer/CMakeLists.txt index 8fb76cfc5fb..70caef3c49c 100644 --- a/PWGCF/Femto/TableProducer/CMakeLists.txt +++ b/PWGCF/Femto/TableProducer/CMakeLists.txt @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. o2physics_add_dpl_workflow(femto-producer - SOURCES femtoProducer.cxx + SOURCES ./femtoProducer.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) @@ -19,11 +19,21 @@ o2physics_add_dpl_workflow(femto-producer-derived-to-derived PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-producer-lite-converter + SOURCES ./femtoProducerLiteConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-producer-kink-pt-converter SOURCES ./femtoProducerKinkPtConverter.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-producer-mask-converter-001-to-002 + SOURCES ./femtoProducerMaskConverter001To002.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-producer-resonances SOURCES ./femtoProducerResonances.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 328e2f61bc1..e28b6ea656a 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -14,13 +14,17 @@ /// \author Anton Riedel, TU München, anton.riedel@tum.de #include "PWGCF/Femto/Core/cascadeBuilder.h" +#include "PWGCF/Femto/Core/charmHadronBuilder.h" #include "PWGCF/Femto/Core/collisionBuilder.h" #include "PWGCF/Femto/Core/kinkBuilder.h" #include "PWGCF/Femto/Core/mcBuilder.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/trackBuilder.h" #include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/mcCentrality.h" @@ -41,21 +45,27 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include +#include using namespace o2::analysis::femto; namespace o2::analysis::femto::rawinputs { -using Run3PpCollisions = o2::soa::Join; +using Run3PpCollisions = o2::soa::Join; using Run3PpMcRecoCollisions = o2::soa::Join; using Run3PpMcGenCollisions = o2::soa::Join; -using Run3PbPbCollisions = o2::soa::Join; +using Run3PbPbCollisions = o2::soa::Join; +using Run3PbPbCollisionsWithEventShape = o2::soa::Join; using Run3PbPbMcRecoCollisions = o2::soa::Join; using Run3PbPbMcGenCollisions = o2::soa::Join; @@ -67,10 +77,13 @@ using Run3FullPidTracks = o2::aod::pidTOFbeta, o2::aod::pidTOFmass>; using Run3McRecoTracks = soa::Join; -using Run3Vzeros = o2::aod::V0Datas; -using Run3RecoVzeros = o2::soa::Join; +using Run3Vzeros = o2::soa::Join; +using Run3RecoVzeros = o2::soa::Join; -using Run3Cascades = o2::aod::CascDatas; +using Run3D0s = soa::Join; +using Run3RecoD0s = soa::Join; + +using Run3Cascades = o2::soa::Join; using Run3RecoCascades = o2::soa::Join; using Run3Kinks = o2::aod::KinkCands; @@ -82,8 +95,13 @@ using Run3McGenParticles = o2::aod::McParticles; struct FemtoProducer { o2::framework::Preslice perMcCollision = o2::aod::mcparticle::mcCollisionId; + o2::framework::Preslice perColRecoTracks = o2::aod::track::collisionId; + o2::framework::Preslice perColRecoV0s = o2::aod::v0data::collisionId; + o2::framework::Preslice perColRecoCascades = o2::aod::cascdata::collisionId; + o2::framework::Preslice perColRecoKinks = o2::aod::kinkcand::collisionId; + o2::framework::Preslice perColRecoD0s = o2::aod::hf_cand::collisionId; - // ccdb + // ccdb config collisionbuilder::ConfCcdb confCcdb; // collision builder @@ -111,6 +129,14 @@ struct FemtoProducer { v0builder::V0Builder lambdaBuilder; v0builder::V0Builder antilambdaBuilder; + // charm hadron builder + charmhadronbuilder::CharmHadronBuilderProducts charmHadronBuilderProducts; + charmhadronbuilder::ConfD0Filters confD0Filters; + charmhadronbuilder::ConfD0Bits confD0Bits; + charmhadronbuilder::ConfD0Tables confD0Tables; + charmhadronbuilder::CharmHadronBuilder d0Builder; + charmhadronbuilder::CharmHadronBuilder d0barBuilder; + // cascade builder cascadebuilder::CascadeBuilderProducts cascadeBuilderProducts; cascadebuilder::ConfCascadeTables confCascadeTables; @@ -136,24 +162,58 @@ struct FemtoProducer { mcbuilder::McBuilder mcBuilder; // histogramming - // add histograms in next iteration o2::framework::HistogramRegistry hRegistry{"FemtoProducer", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; // data members o2::framework::Service ccdb = {}; /// Accessing the CCDB + o2::framework::Service pdgDb = {}; void init(o2::framework::InitContext& context) { + // ---- ccdb --------------------------------------------------------------- + LOG(info) << "Setting up connection to CCDB with URL: " << confCcdb.ccdbUrl.value; + ccdb->setURL(confCcdb.ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + // ---- builders ----------------------------------------------------------- + // Order matters here: CollisionBuilder must init before TrackBuilder (which checks + // collisionBuilder.producingCollisions()/producingLiteCollisions()), and TrackBuilder + // must init before the V0/Cascade/Kink builders (which check + // trackBuilder.producingTracks()/producingLiteTracks()). + collisionBuilder.init(&hRegistry, confCollisionFilters, confCollisionBits, confCollisionRctFlags, confCcdb, confCollisionTables, context); + trackBuilder.init(&hRegistry, confTrackBits, confTrackFilters, confTrackTables, context, collisionBuilder); + + k0shortBuilder.init(&hRegistry, confK0shortBits, confV0Filters, confV0Tables, context, trackBuilder); + lambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context, trackBuilder); + antilambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context, trackBuilder); + + d0Builder.init(&hRegistry, confD0Bits, confD0Filters, confD0Tables, context); + d0barBuilder.init(&hRegistry, confD0Bits, confD0Filters, confD0Tables, context); + + sigmaBuilder.init(&hRegistry, confSigmaBits, confKinkFilters, confKinkTables, context, trackBuilder); + sigmaPlusBuilder.init(&hRegistry, confSigmaPlusBits, confKinkFilters, confKinkTables, context, trackBuilder); + + xiBuilder.init(&hRegistry, confXiBits, confCascadeFilters, confCascadeTables, context, trackBuilder); + omegaBuilder.init(&hRegistry, confOmegaBits, confCascadeFilters, confCascadeTables, context, trackBuilder); + + mcBuilder.init(confMc, confMcTables, context); + + // ---- guard: enabled tables vs. enabled process function ------------------ if ((xiBuilder.fillAnyTable() || omegaBuilder.fillAnyTable()) && (!doprocessTracksV0sCascadesRun3pp && !doprocessTracksV0sCascadesRun3PbPb && - !doprocessTracksV0sCascadesKinksRun3pp && !doprocessTracksV0sCascadesRun3ppMc)) { + !doprocessTracksV0sCascadesKinksRun3pp && !doprocessTracksV0sCascadesRun3ppMc && + !doprocessTracksV0sCascadesRun3PbPbMc)) { LOG(fatal) << "At least one cascade table is enabled, but wrong process function is enabled. Breaking..."; } if ((lambdaBuilder.fillAnyTable() || antilambdaBuilder.fillAnyTable() || k0shortBuilder.fillAnyTable()) && (!doprocessTracksV0sCascadesRun3pp && !doprocessTracksV0sCascadesRun3PbPb && !doprocessTracksV0sRun3pp && !doprocessTracksV0sCascadesKinksRun3pp && !doprocessTracksV0sRun3ppMc && !doprocessTracksV0sRun3PbPb && !doprocessTracksV0sRun3PbPbMc && - !doprocessTracksV0sCascadesRun3ppMc && !doprocessTracksV0sKinksRun3ppMc)) { + !doprocessTracksV0sCascadesRun3ppMc && !doprocessTracksV0sCascadesRun3PbPbMc && + !doprocessTracksV0sKinksRun3ppMc)) { LOG(fatal) << "At least one v0 table is enabled, but wrong process function is enabled. Breaking..."; } if ((sigmaBuilder.fillAnyTable() || sigmaPlusBuilder.fillAnyTable()) && @@ -161,46 +221,91 @@ struct FemtoProducer { !doprocessTracksKinksRun3ppMc && !doprocessTracksV0sKinksRun3ppMc)) { LOG(fatal) << "At least one kink table is enabled, but wrong process function is enabled. Breaking..."; } + if ((d0Builder.fillAnyTable() || d0barBuilder.fillAnyTable()) && + (!doprocessTracksD0sRun3pp && !doprocessTracksD0sRun3PbPb && + !doprocessTracksD0sRun3ppMc && !doprocessTracksD0sRun3PbPbMc)) { + LOG(fatal) << "At least one d0 table is enabled, but wrong process function is enabled. Breaking..."; + } if (mcBuilder.fillAnyTable() && - (!doprocessTracksV0sRun3ppMc && !doprocessTracksKinksRun3ppMc && - !doprocessTracksV0sCascadesRun3ppMc && !doprocessTracksV0sKinksRun3ppMc && - !doprocessTracksRun3ppMc && !doprocessTracksRun3PbPbMc && !doprocessTracksV0sRun3PbPbMc && + (!doprocessTracksRun3ppMc && !doprocessTracksRun3PbPbMc && + !doprocessTracksV0sRun3ppMc && !doprocessTracksV0sRun3PbPbMc && + !doprocessTracksV0sCascadesRun3ppMc && !doprocessTracksV0sCascadesRun3PbPbMc && + !doprocessTracksKinksRun3ppMc && !doprocessTracksV0sKinksRun3ppMc && + !doprocessTracksD0sRun3ppMc && !doprocessTracksD0sRun3PbPbMc && !doprocessMcOnly)) { LOG(fatal) << "At least one mc table is enabled, but wrong process function is enabled. Breaking..."; } - // init ccdb - LOG(info) << "Setting up connection to CCDB with URL: " << confCcdb.ccdbUrl.value; - ccdb->setURL(confCcdb.ccdbUrl.value); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - ccdb->setCreatedNotAfter(now); - - // collision selection - collisionBuilder.init(&hRegistry, confCollisionFilters, confCollisionBits, confCollisionRctFlags, confCcdb, confCollisionTables, context); - - // configure track builder - trackBuilder.init(&hRegistry, confTrackBits, confTrackFilters, confTrackTables, context); - - // configure v0 builder - k0shortBuilder.init(&hRegistry, confK0shortBits, confV0Filters, confV0Tables, context); - lambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context); - antilambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context); - - // configure kink builder - sigmaBuilder.init(&hRegistry, confSigmaBits, confKinkFilters, confKinkTables, context); - sigmaPlusBuilder.init(&hRegistry, confSigmaPlusBits, confKinkFilters, confKinkTables, context); - - // cascade selections - xiBuilder.init(&hRegistry, confXiBits, confCascadeFilters, confCascadeTables, context); - omegaBuilder.init(&hRegistry, confOmegaBits, confCascadeFilters, confCascadeTables, context); + // ---- guard: pass-through consistency across builders --------------------- + { + std::vector> passThroughFlags; + auto add = [&passThroughFlags](const std::string& name, bool enabled, bool passThrough) { + if (enabled) { + passThroughFlags.emplace_back(name, passThrough); + } + }; + // substitute the real accessors if they live on the builders rather than the conf groups + add("collision", collisionBuilder.fillAnyTable(), collisionBuilder.isPassThrough()); + add("track", trackBuilder.fillAnyTable(), trackBuilder.isPassThrough()); + add("k0short", k0shortBuilder.fillAnyTable(), k0shortBuilder.isPassThrough()); + add("lambda", lambdaBuilder.fillAnyTable(), lambdaBuilder.isPassThrough()); + add("antilambda", antilambdaBuilder.fillAnyTable(), antilambdaBuilder.isPassThrough()); + add("d0", d0Builder.fillAnyTable(), d0Builder.isPassThrough()); + add("d0bar", d0barBuilder.fillAnyTable(), d0barBuilder.isPassThrough()); + add("sigma", sigmaBuilder.fillAnyTable(), sigmaBuilder.isPassThrough()); + add("sigmaplus", sigmaPlusBuilder.fillAnyTable(), sigmaPlusBuilder.isPassThrough()); + add("xi", xiBuilder.fillAnyTable(), xiBuilder.isPassThrough()); + add("omega", omegaBuilder.fillAnyTable(), omegaBuilder.isPassThrough()); + add("mc", mcBuilder.fillAnyTable(), mcBuilder.isPassThrough()); + + const bool anyPassThrough = std::any_of(passThroughFlags.begin(), passThroughFlags.end(), + [](const auto& f) { return f.second; }); + const bool allPassThrough = std::all_of(passThroughFlags.begin(), passThroughFlags.end(), + [](const auto& f) { return f.second; }); + + if (anyPassThrough && !allPassThrough) { + LOG(warn) << "Builders disagree about pass-through mode:"; + for (const auto& [name, passThrough] : passThroughFlags) { + LOG(warn) << " " << name << " builder: pass-through = " << (passThrough ? "true" : "false"); + } + LOG(warn) << "This is legal, but check it is intended:"; + LOG(warn) << " - collisions in pass-through, particles not: every collision is written, " + << "but the particle tables only cover collisions with a candidate."; + LOG(warn) << " - particles in pass-through, collisions not: the extra particle rows hang off " + << "a candidate-biased event sample, which will bias event-normalised observables."; + } + } - // configure mcBuilder - mcBuilder.init(confMc, confMcTables, context); + // ---- guard: exactly one process function --------------------------------- + const int nProcesses = + static_cast(doprocessTracksRun3pp) + + static_cast(doprocessTracksRun3PbPb) + + static_cast(doprocessTracksRun3PbPbWithEventShape) + + static_cast(doprocessTracksV0sRun3pp) + + static_cast(doprocessTracksV0sRun3PbPb) + + static_cast(doprocessTracksV0sCascadesRun3pp) + + static_cast(doprocessTracksV0sCascadesRun3PbPb) + + static_cast(doprocessTracksKinksRun3pp) + + static_cast(doprocessTracksV0sCascadesKinksRun3pp) + + static_cast(doprocessTracksD0sRun3pp) + + static_cast(doprocessTracksD0sRun3PbPb) + + static_cast(doprocessTracksRun3ppMc) + + static_cast(doprocessTracksRun3PbPbMc) + + static_cast(doprocessTracksV0sRun3ppMc) + + static_cast(doprocessTracksV0sRun3PbPbMc) + + static_cast(doprocessTracksV0sCascadesRun3ppMc) + + static_cast(doprocessTracksV0sCascadesRun3PbPbMc) + + static_cast(doprocessTracksKinksRun3ppMc) + + static_cast(doprocessTracksV0sKinksRun3ppMc) + + static_cast(doprocessTracksD0sRun3ppMc) + + static_cast(doprocessTracksD0sRun3PbPbMc) + + static_cast(doprocessMcOnly); + + if (nProcesses != 1) { + LOG(fatal) << "Exactly one process function must be enabled, found " << nProcesses << ". Breaking..."; + } hRegistry.print(); - LOG(warn) << __LINE__; } // processing collisions @@ -210,21 +315,39 @@ struct FemtoProducer { collisionBuilder.reset(); auto bc = col.template bc_as(); collisionBuilder.initCollision(bc, col, tracks, ccdb, hRegistry); - // do not fill collsions into the table here - // collisions are filled if at least one partilce is found in the collisions - return collisionBuilder.checkCollision(col); + if (!collisionBuilder.checkCollision(col)) { + return false; + } + // Normally the collision row is written lazily, once a candidate is found. In + // pass-through we need every accepted collision, including those with no candidate, + // otherwise event-normalised observables lose exactly those events. + if (collisionBuilder.isPassThrough()) { + collisionBuilder.fillCollision(collisionBuilderProducts, col); + } + return true; } template bool processMcCollisions(T1 const& col, T2 const& mcCols, T3 const& /* bcs*/, T4 const& tracks, T5 const& mcParticles) { collisionBuilder.reset(); - mcBuilder.reset(mcCols, mcParticles); // we call this function always first so we reset the mcBuilder here + // in pass-through the maps are built once per timeframe + // resetting here would wipe them and duplicate every mc collision and particle + if (!mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + } auto bc = col.template bc_as(); collisionBuilder.initCollision(bc, col, tracks, ccdb, hRegistry); - // do not fill collsions into the table here - // collisions are filled if at least one partilce is found in the collisions - return collisionBuilder.checkCollision(col, mcCols); + if (!collisionBuilder.checkCollision(col, mcCols)) { + return false; + } + // NOTE: must be fillMcCollision, not fillCollision - fillMcCollision returns early on + // mCollisionAlreadyFilled, so filling the collision first would permanently skip + // the collision label + if (collisionBuilder.isPassThrough()) { + collisionBuilder.fillMcCollision(collisionBuilderProducts, col, mcCols, mcProducts, mcBuilder); + } + return true; } // processing tracks @@ -287,7 +410,24 @@ struct FemtoProducer { omegaBuilder.fillMcCascades(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, cascadeBuilderProducts, cascades, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); } - // proccess functions + // processing D0s + template + void processD0s(T1 const& col, T2 const& tracks, T3 const& candidates) + { + d0Builder.fillD0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + d0barBuilder.fillD0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + } + template + void processMcD0s(T1 const& col, T2 const& mcCols, T3 const& tracks, T4 const& candidates, T5 const& mcParticles) + { + d0Builder.fillMcD0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + d0barBuilder.fillMcD0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + } + + // ========================================================================== + // process functions - data + // ========================================================================== + void processTracksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks) @@ -299,7 +439,7 @@ struct FemtoProducer { o2::aod::pidits::ITSNSigmaPr, o2::aod::pidits::ITSNSigmaDe, o2::aod::pidits::ITSNSigmaTr, o2::aod::pidits::ITSNSigmaHe>(tracks); processTracks(col, tracksWithItsPid); } - PROCESS_SWITCH(FemtoProducer, processTracksRun3pp, "Process tracks", true); + PROCESS_SWITCH(FemtoProducer, processTracksRun3pp, "Provide tracks", true); void processTracksRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, @@ -312,9 +452,21 @@ struct FemtoProducer { o2::aod::pidits::ITSNSigmaPr, o2::aod::pidits::ITSNSigmaDe, o2::aod::pidits::ITSNSigmaTr, o2::aod::pidits::ITSNSigmaHe>(tracks); processTracks(col, tracksWithItsPid); } - PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPb, "Process tracks in PbPB collisions", false); + PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPb, "Provide tracks in PbPb collisions", false); + + void processTracksRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + } + PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPbWithEventShape, "Provide tracks in PbPb collisions with event shape information", false); - // process tracks and v0s void processTracksV0sRun3pp(rawinputs::Run3PpCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, @@ -327,8 +479,8 @@ struct FemtoProducer { o2::aod::pidits::ITSNSigmaPr, o2::aod::pidits::ITSNSigmaDe, o2::aod::pidits::ITSNSigmaTr, o2::aod::pidits::ITSNSigmaHe>(tracks); processTracks(col, tracksWithItsPid); processV0s(col, tracks, v0s); - }; - PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3pp, "Process tracks and v0s", false); + } + PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3pp, "Provide tracks and v0s", false); void processTracksV0sRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, @@ -342,26 +494,9 @@ struct FemtoProducer { o2::aod::pidits::ITSNSigmaPr, o2::aod::pidits::ITSNSigmaDe, o2::aod::pidits::ITSNSigmaTr, o2::aod::pidits::ITSNSigmaHe>(tracks); processTracks(col, tracksWithItsPid); processV0s(col, tracks, v0s); - }; - PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3PbPb, "Process tracks and v0s in PbPB collisions", false); - - // process tracks and kinks - void processTracksKinksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, - o2::aod::BCsWithTimestamps const& bcs, - rawinputs::Run3FullPidTracks const& tracks, - rawinputs::Run3Kinks const& kinks) - { - if (!processCollisions(col, bcs, tracks)) { - return; - } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processKinks(col, tracks, kinks); } - PROCESS_SWITCH(FemtoProducer, processTracksKinksRun3pp, "Process tracks and kinks", false); + PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3PbPb, "Provide tracks and v0s in PbPb collisions", false); - // process tracks, v0s and cascades void processTracksV0sCascadesRun3pp(rawinputs::Run3PpCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, @@ -377,7 +512,7 @@ struct FemtoProducer { processV0s(col, tracks, v0s); processCascades(col, tracks, cascades); } - PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3pp, "Provide Tracks, V0s and Cascades for Run3", false); + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3pp, "Provide tracks, v0s and cascades", false); void processTracksV0sCascadesRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, @@ -394,9 +529,23 @@ struct FemtoProducer { processV0s(col, tracks, v0s); processCascades(col, tracks, cascades); } - PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3PbPb, "Provide Tracks, V0s and Cascades for Run3", false); + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3PbPb, "Provide tracks, v0s and cascades in PbPb collisions", false); + + void processTracksKinksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3Kinks const& kinks) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processKinks(col, tracks, kinks); + } + PROCESS_SWITCH(FemtoProducer, processTracksKinksRun3pp, "Provide tracks and kinks", false); - // process tracks, v0s, cascades and kinks void processTracksV0sCascadesKinksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, @@ -411,143 +560,337 @@ struct FemtoProducer { o2::aod::pidits::ITSNSigmaPr, o2::aod::pidits::ITSNSigmaDe, o2::aod::pidits::ITSNSigmaTr, o2::aod::pidits::ITSNSigmaHe>(tracks); processTracks(col, tracksWithItsPid); processV0s(col, tracks, v0s); - processKinks(col, tracks, kinks); processCascades(col, tracks, cascades); + processKinks(col, tracks, kinks); } - PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesKinksRun3pp, "Provide Tracks, V0s and Cascades for Run3", false); + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesKinksRun3pp, "Provide tracks, v0s, cascades and kinks", false); - // process monte carlo tracks - void processTracksRun3ppMc(rawinputs::Run3PpMcRecoCollisions::iterator const& col, - rawinputs::Run3PpMcGenCollisions const& mcCols, + void processTracksD0sRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3D0s const& candidates) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processD0s(col, tracks, candidates); + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3pp, "Provide tracks and D0s", false); + + void processTracksD0sRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3D0s const& candidates) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processD0s(col, tracks, candidates); + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPb, "Provide tracks and D0s in PbPb collisions", false); + + // ========================================================================== + // process functions - monte carlo (ungrouped) + // + // No argument is an ::iterator, so DPL hands over the full timeframe tables and + // does no auto-grouping. Tables that are iterated over (tracks, v0s, cascades, + // kinks) are sliced per collision; the full track table is passed alongside so + // the v0/cascade/kink builders can resolve their daughter indices. + // These functions own the per-timeframe reset of the mc builder maps, which is + // why processMcCollisions skips its own reset in pass-through mode. + // ========================================================================== + + void processTracksRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); } - PROCESS_SWITCH(FemtoProducer, processTracksRun3ppMc, "Provide reconstructed and generated Tracks", false); + PROCESS_SWITCH(FemtoProducer, processTracksRun3ppMc, "Provide reconstructed and generated tracks", false); - void processTracksRun3PbPbMc(rawinputs::Run3PbPbMcRecoCollisions::iterator const& col, - rawinputs::Run3PbPbMcGenCollisions const& mcCols, + void processTracksRun3PbPbMc(rawinputs::Run3PbPbMcGenCollisions const& mcCols, + rawinputs::Run3PbPbMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); } - PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPbMc, "Provide reconstructed and generated Tracks in PbPb collisions", false); + PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPbMc, "Provide reconstructed and generated tracks in PbPb collisions", false); - // process monte carlo tracks and v0s - void processTracksV0sRun3ppMc(rawinputs::Run3PpMcRecoCollisions::iterator const& col, - rawinputs::Run3PpMcGenCollisions const& mcCols, + void processTracksV0sRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, rawinputs::Run3RecoVzeros const& v0s, rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto v0sThisCol = v0s.sliceBy(perColRecoV0s, col.globalIndex()); + processMcV0s(col, mcCols, tracks, v0sThisCol, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); - processMcV0s(col, mcCols, tracks, v0s, mcParticles); } PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3ppMc, "Provide reconstructed and generated tracks and v0s", false); - void processTracksV0sRun3PbPbMc(rawinputs::Run3PbPbMcRecoCollisions::iterator const& col, - rawinputs::Run3PbPbMcGenCollisions const& mcCols, + void processTracksV0sRun3PbPbMc(rawinputs::Run3PbPbMcGenCollisions const& mcCols, + rawinputs::Run3PbPbMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, rawinputs::Run3RecoVzeros const& v0s, rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto v0sThisCol = v0s.sliceBy(perColRecoV0s, col.globalIndex()); + processMcV0s(col, mcCols, tracks, v0sThisCol, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); - processMcV0s(col, mcCols, tracks, v0s, mcParticles); } PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3PbPbMc, "Provide reconstructed and generated tracks and v0s in PbPb collisions", false); - // process monte carlo tracks and kinks - void processTracksKinksRun3ppMc(rawinputs::Run3PpMcRecoCollisions::iterator const& col, - rawinputs::Run3PpMcGenCollisions const& mcCols, + void processTracksV0sCascadesRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3RecoVzeros const& v0s, + rawinputs::Run3RecoCascades const& cascades, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto v0sThisCol = v0s.sliceBy(perColRecoV0s, col.globalIndex()); + processMcV0s(col, mcCols, tracks, v0sThisCol, mcParticles); + + auto cascadesThisCol = cascades.sliceBy(perColRecoCascades, col.globalIndex()); + processMcCascades(col, mcCols, tracks, cascadesThisCol, mcParticles); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3ppMc, "Provide reconstructed and generated tracks, v0s and cascades", false); + + void processTracksV0sCascadesRun3PbPbMc(rawinputs::Run3PbPbMcGenCollisions const& mcCols, + rawinputs::Run3PbPbMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3RecoVzeros const& v0s, + rawinputs::Run3RecoCascades const& cascades, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto v0sThisCol = v0s.sliceBy(perColRecoV0s, col.globalIndex()); + processMcV0s(col, mcCols, tracks, v0sThisCol, mcParticles); + + auto cascadesThisCol = cascades.sliceBy(perColRecoCascades, col.globalIndex()); + processMcCascades(col, mcCols, tracks, cascadesThisCol, mcParticles); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3PbPbMc, "Provide reconstructed and generated tracks, v0s and cascades in PbPb collisions", false); + + void processTracksKinksRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, rawinputs::Run3Kinks const& kinks, rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto kinksThisCol = kinks.sliceBy(perColRecoKinks, col.globalIndex()); + processMcKinks(col, mcCols, tracks, kinksThisCol, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); - processMcKinks(col, mcCols, tracks, kinks, mcParticles); } PROCESS_SWITCH(FemtoProducer, processTracksKinksRun3ppMc, "Provide reconstructed and generated tracks and kinks", false); - // process monte carlo tracks and v0s and kinks (adding cascades later here) - void processTracksV0sKinksRun3ppMc(rawinputs::Run3PpMcRecoCollisions::iterator const& col, - rawinputs::Run3PpMcGenCollisions const& mcCols, + void processTracksV0sKinksRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, rawinputs::Run3RecoVzeros const& v0s, rawinputs::Run3Kinks const& kinks, rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto v0sThisCol = v0s.sliceBy(perColRecoV0s, col.globalIndex()); + processMcV0s(col, mcCols, tracks, v0sThisCol, mcParticles); + + auto kinksThisCol = kinks.sliceBy(perColRecoKinks, col.globalIndex()); + processMcKinks(col, mcCols, tracks, kinksThisCol, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); - processMcV0s(col, mcCols, tracks, v0s, mcParticles); - processMcKinks(col, mcCols, tracks, kinks, mcParticles); } - PROCESS_SWITCH(FemtoProducer, processTracksV0sKinksRun3ppMc, "Provide reconstructed and generated tracks and v0s and kinks", false); + PROCESS_SWITCH(FemtoProducer, processTracksV0sKinksRun3ppMc, "Provide reconstructed and generated tracks, v0s and kinks", false); - // process monte carlo tracks and v0s - void processTracksV0sCascadesRun3ppMc(rawinputs::Run3PpMcRecoCollisions::iterator const& col, - rawinputs::Run3PpMcGenCollisions const& mcCols, - o2::aod::BCsWithTimestamps const& bcs, - rawinputs::Run3McRecoTracks const& tracks, - rawinputs::Run3RecoVzeros const& v0s, - rawinputs::Run3RecoCascades const& cascades, - rawinputs::Run3McGenParticles const& mcParticles) + void processTracksD0sRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3RecoD0s const& d0s, + rawinputs::Run3McGenParticles const& mcParticles) { - if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { - return; + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto d0sThisCol = d0s.sliceBy(perColRecoD0s, col.globalIndex()); + processMcD0s(col, mcCols, tracks, d0sThisCol, mcParticles); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); - processMcV0s(col, mcCols, tracks, v0s, mcParticles); - processMcCascades(col, mcCols, tracks, cascades, mcParticles); } - PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3ppMc, "Provide reconstructed and generated tracks and v0s", false); + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3ppMc, "Provide reconstructed and generated tracks and D0s", false); + + void processTracksD0sRun3PbPbMc(rawinputs::Run3PbPbMcGenCollisions const& mcCols, + rawinputs::Run3PbPbMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3RecoD0s const& d0s, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto d0sThisCol = d0s.sliceBy(perColRecoD0s, col.globalIndex()); + processMcD0s(col, mcCols, tracks, d0sThisCol, mcParticles); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPbMc, "Provide reconstructed and generated tracks and D0s in PbPb collisions", false); + + // ========================================================================== + // process functions - generator level only (for MCGEN datasets) + // ========================================================================== - // process generator level only input (for MCGEN datasets) - // do not preslice mcParticles tables for each collision, otherwise the finding of the partonic mother can fail + // do not preslice the mcParticles table passed to fillMcParticle, otherwise the finding of the partonic mother can fail void processMcOnly(o2::aod::McCollisions const& mcCols, o2::aod::McParticles const& mcParticles) { - mcBuilder.reset(mcParticles); + mcBuilder.reset(mcCols, mcParticles); for (const auto& mcCol : mcCols) { - mcBuilder.fillMcCollision(mcCol, mcParticles, mcProducts); auto particlesThisCollision = mcParticles.sliceBy(perMcCollision, mcCol.globalIndex()); + mcBuilder.fillMcCollision(mcCol, particlesThisCollision, mcProducts, pdgDb); for (const auto& mcParticle : particlesThisCollision) { mcBuilder.fillMcParticle(mcParticle, mcParticles, mcCol, mcProducts); } diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx index 128f4e4db02..bde9713d72e 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -115,7 +115,7 @@ struct FemtoProducerDerivedToDerived { kinkBuilder.init(confKinkBuilder); if ((static_cast(doprocessTracks) + static_cast(doprocessTracksWithMass) + static_cast(doprocessTracksLambdas) + static_cast(doprocessLambdas) + static_cast(doprocessTracksXis) + static_cast(doprocessTracksOmegas) + static_cast(doprocessTracksK0shorts) + static_cast(doprocessTracksSigma) + static_cast(doprocessTracksSigmaPlus)) > 1) { - LOG(fatal) << "Only one proccess function can be activated"; + LOG(fatal) << "Only one proccess function can be activated!"; } } @@ -125,6 +125,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); } @@ -135,6 +136,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); } @@ -145,6 +147,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -156,6 +159,7 @@ struct FemtoProducerDerivedToDerived { if (v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); } @@ -166,6 +170,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); cascadeBuilder.processXis(col, xis, tracks, xiPartition, trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -177,6 +182,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || cascadeBuilder.collisionHasTooFewOmegas(col, omegas, omegaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); cascadeBuilder.processOmegas(col, omegas, tracks, omegaPartition, trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -188,6 +194,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -199,6 +206,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || kinkBuilder.collisionHasTooFewSigma(col, sigma, sigmaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); kinkBuilder.processSigma(col, sigma, tracks, sigmaPartition, trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -210,6 +218,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, sigmaPlusPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusPartition, trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); diff --git a/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx new file mode 100644 index 00000000000..3a5add169c1 --- /dev/null +++ b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx @@ -0,0 +1,136 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file femtoProducerLiteConverter.cxx +/// \brief Task that converts FLite* tables (binned kinematics) back to their full-precision counterparts +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoProducerLiteConverter { + o2::framework::Produces producedCols; + o2::framework::Produces producedTracks; + o2::framework::Produces producedLambdas; + o2::framework::Produces producedK0shorts; + o2::framework::Produces producedXis; + o2::framework::Produces producedOmegas; + o2::framework::Produces producedSigmas; + o2::framework::Produces producedSigmaPlus; + + void init(o2::framework::InitContext&) + { + } + + void processLiteCols(o2::aod::FLiteCols::iterator const& liteCol) + { + producedCols(liteCol.posZ(), + liteCol.mult(), + liteCol.cent(), + liteCol.magField()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteCols, "Convert FLiteCols to FCols", true); + + void processLiteTracks(o2::aod::FLiteTracks::iterator const& liteTrack) + { + producedTracks(liteTrack.fLiteColId(), + liteTrack.signedPt(), + liteTrack.eta(), + liteTrack.phi()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteTracks, "Convert FLiteTracks to FTracks", true); + + void processLiteLambdas(o2::aod::FLiteLambdas::iterator const& liteLambda) + { + producedLambdas(liteLambda.fLiteColId(), + liteLambda.signedPt(), + liteLambda.eta(), + liteLambda.phi(), + liteLambda.lambdaMass(), + liteLambda.posDauId(), + liteLambda.negDauId()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteLambdas, "Convert FLiteLambdas to FLambdas", false); + + void processLiteK0shorts(o2::aod::FLiteK0shorts::iterator const& liteK0short) + { + producedK0shorts(liteK0short.fLiteColId(), + liteK0short.pt(), + liteK0short.eta(), + liteK0short.phi(), + liteK0short.k0shortMass(), + liteK0short.posDauId(), + liteK0short.negDauId()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteK0shorts, "Convert FLiteK0shorts to FK0shorts", false); + + void processLiteXis(o2::aod::FLiteXis::iterator const& liteXi) + { + producedXis(liteXi.fLiteColId(), + liteXi.signedPt(), + liteXi.eta(), + liteXi.phi(), + liteXi.xiMass(), + liteXi.bachelorId(), + liteXi.posDauId(), + liteXi.negDauId()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteXis, "Convert FLiteXis to FXis", false); + + void processLiteOmegas(o2::aod::FLiteOmegas::iterator const& liteOmega) + { + producedOmegas(liteOmega.fLiteColId(), + liteOmega.signedPt(), + liteOmega.eta(), + liteOmega.phi(), + liteOmega.omegaMass(), + liteOmega.bachelorId(), + liteOmega.posDauId(), + liteOmega.negDauId()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteOmegas, "Convert FLiteOmegas to FOmegas", false); + + void processLiteSigmas(o2::aod::FLiteSigmas::iterator const& liteSigma) + { + producedSigmas(liteSigma.fLiteColId(), + liteSigma.signedPt(), + liteSigma.eta(), + liteSigma.phi(), + liteSigma.sigmaMass(), + liteSigma.chaDauId()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteSigmas, "Convert FLiteSigmas to FSigmas", false); + + void processLiteSigmaPlus(o2::aod::FLiteSigmaPlus::iterator const& liteSigmaPlus) + { + producedSigmaPlus(liteSigmaPlus.fLiteColId(), + liteSigmaPlus.signedPt(), + liteSigmaPlus.eta(), + liteSigmaPlus.phi(), + liteSigmaPlus.sigmaMass(), + liteSigmaPlus.chaDauId()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteSigmaPlus, "Convert FLiteSigmaPlus to FSigmaPlus", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{o2::framework::adaptAnalysisTask(context)}; + return workflow; +} diff --git a/PWGCF/Femto/TableProducer/femtoProducerMaskConverter001To002.cxx b/PWGCF/Femto/TableProducer/femtoProducerMaskConverter001To002.cxx new file mode 100644 index 00000000000..b1a57b7bfed --- /dev/null +++ b/PWGCF/Femto/TableProducer/femtoProducerMaskConverter001To002.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file femtoProducerMaskConverter001To002.cxx +/// \brief Task that converts *Masks_001 tables to *Masks_002 +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoProducerMaskConverter001To002 { + o2::framework::Produces producedLambdaMasks; + o2::framework::Produces producedK0shortMasks; + o2::framework::Produces producedXiMasks; + o2::framework::Produces producedOmegaMasks; + + void init(o2::framework::InitContext&) + { + } + + void processLambdaMasks001(o2::aod::FLambdaMasks_001::iterator const& lambdaMaskOld) + { + producedLambdaMasks(static_cast(lambdaMaskOld.mask())); + } + PROCESS_SWITCH(FemtoProducerMaskConverter001To002, processLambdaMasks001, "Convert LambdaMasks_001 to LambdaMasks_002", false); + + void processK0shortMasks001(o2::aod::FK0shortMasks_001::iterator const& k0shortOld) + { + producedK0shortMasks(static_cast(k0shortOld.mask())); + } + PROCESS_SWITCH(FemtoProducerMaskConverter001To002, processK0shortMasks001, "Convert K0shortMasks_001 to K0shortMasks_002", false); + + void processXiMasks001(o2::aod::FXiMasks_001::iterator const& xiMaskOld) + { + producedXiMasks(static_cast(xiMaskOld.mask())); + } + PROCESS_SWITCH(FemtoProducerMaskConverter001To002, processXiMasks001, "Convert XiMasks_001 to XiMasks_002", false); + + void processOmegaMasks001(o2::aod::FOmegaMasks_001::iterator const& omegaMaskOld) + { + producedOmegaMasks(static_cast(omegaMaskOld.mask())); + } + PROCESS_SWITCH(FemtoProducerMaskConverter001To002, processOmegaMasks001, "Convert OmegaMasks_001 to OmegaMasks_002", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{o2::framework::adaptAnalysisTask(context)}; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/CMakeLists.txt b/PWGCF/Femto/Tasks/CMakeLists.txt index 9e612ee28a4..593e560699d 100644 --- a/PWGCF/Femto/Tasks/CMakeLists.txt +++ b/PWGCF/Femto/Tasks/CMakeLists.txt @@ -49,6 +49,21 @@ o2physics_add_dpl_workflow(femto-pair-track-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-pair-track-d0 + SOURCES femtoPairTrackD0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-d0-d0 + SOURCES femtoPairD0D0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-d0-qa + SOURCES femtoD0Qa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-pair-track-two-track-resonance SOURCES femtoPairTrackTwoTrackResonance.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGCF/Femto/Tasks/femtoCascadeQa.cxx b/PWGCF/Femto/Tasks/femtoCascadeQa.cxx index 9b627838165..63daed2c1a5 100644 --- a/PWGCF/Femto/Tasks/femtoCascadeQa.cxx +++ b/PWGCF/Femto/Tasks/femtoCascadeQa.cxx @@ -41,7 +41,7 @@ using namespace o2::analysis::femto; struct FemtoCascadeQa { - using FemtoCollisions = o2::soa::Join; + using FemtoCollisions = o2::soa::Join; using FilteredFemtoCollisions = o2::soa::Filtered; using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; @@ -195,7 +195,7 @@ struct FemtoCascadeQa { if (!xiCleaner.isClean(xi, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - xiHistManager.fill(xi, tracks, mcParticles, mcMothers, mcPartonicMothers); + xiHistManager.fill(xi, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoCascadeQa, processXiMc, "Process Xis with MC information", false); @@ -224,7 +224,7 @@ struct FemtoCascadeQa { if (!omegaCleaner.isClean(omega, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - omegaHistManager.fill(omega, tracks, mcParticles, mcMothers, mcPartonicMothers); + omegaHistManager.fill(omega, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoCascadeQa, processOmegaMc, "Process Omegas with MC information", false); diff --git a/PWGCF/Femto/Tasks/femtoD0Qa.cxx b/PWGCF/Femto/Tasks/femtoD0Qa.cxx new file mode 100644 index 00000000000..94ee74b0b4a --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoD0Qa.cxx @@ -0,0 +1,161 @@ +// Copyright 2019-2026 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 femtoD0Qa.cxx +/// \brief QA task for D0 mesons +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#include "PWGCF/Femto/Core/charmHadronBuilder.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoD0Qa { + + // setup collisions + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + // setup D0s, joined with the mask for the partition and the QA columns + using FemtoD0s = o2::soa::Join; + // setup tracks with full pid information for the daughter QA + using FemtoTracks = o2::soa::Join; + + // setup monte carlo, joining the labels that link reco to generated particles + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoD0sWithLabel = o2::soa::Join; + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoMcParticlesWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup for collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + // setup for D0s + charmhadronbuilder::ConfD0Selection1 confD0Selection; + + o2::framework::Partition d0Partition = MAKE_D0_PARTITION(confD0Selection); + o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; + o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(confD0Selection); + o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + + charmhadronhistmanager::ConfD0Binning1 confD0Binning; + charmhadronhistmanager::ConfD0QaBinning1 confD0QaBinning; + charmhadronhistmanager::CharmHadronHistManager< + charmhadronhistmanager::PrefixD0Qa, + trackhistmanager::PrefixD01PosDaughterQa, + trackhistmanager::PrefixD01NegDaughterQa, + modes::CharmHadron::kD0> + d0HistManager; + + // setup for daughters + trackhistmanager::ConfD01PosDauBinning confD01PosDaughterBinning; + trackhistmanager::ConfD01PosDauQaBinning confD01PosDaughterQaBinning; + + trackhistmanager::ConfD01NegDauBinning confD01NegDaughterBinning; + trackhistmanager::ConfD01NegDauQaBinning confD01NegDaughterQaBinning; + + o2::framework::HistogramRegistry hRegistry{"FemtoD0Qa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + bool processData = doprocessD0; + + std::map> colHistSpec; + std::map> posDaughterHistSpec; + std::map> negDaughterHistSpec; + std::map> d0HistSpec; + std::map> d0QaHistSpec; + + if (processData) { + colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); + posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); + negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); + d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); + d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); + d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); + } else { + colHistSpec = colhistmanager::makeColMcQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); + posDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); + negDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); + d0HistSpec = charmhadronhistmanager::makeD0McQaHistSpecMap(confD0Binning, confD0QaBinning); + d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); + d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); + } + + hRegistry.print(); + }; + + void processD0(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + { + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice.size() == 0) { + return; + } + colHistManager.fill(col); + for (auto const& d0 : d0Slice) { + d0HistManager.fill(d0, tracks); + } + } + PROCESS_SWITCH(FemtoD0Qa, processD0, "Process D0s", true); + + void processD0Mc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + auto d0Slice = d0WithLabelPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice.size() == 0) { + return; + } + colHistManager.fill(col, mcCols); + for (auto const& d0 : d0Slice) { + d0HistManager.fill(d0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + } + } + PROCESS_SWITCH(FemtoD0Qa, processD0Mc, "Process D0s with MC information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoKinkQa.cxx b/PWGCF/Femto/Tasks/femtoKinkQa.cxx index 877c0905b83..f1b456def84 100644 --- a/PWGCF/Femto/Tasks/femtoKinkQa.cxx +++ b/PWGCF/Femto/Tasks/femtoKinkQa.cxx @@ -43,7 +43,7 @@ using namespace o2::analysis::femto; struct FemtoKinkQa { // setup tables - using FemtoCollisions = o2::soa::Join; + using FemtoCollisions = o2::soa::Join; using FilteredFemtoCollisions = o2::soa::Filtered; using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; @@ -186,7 +186,7 @@ struct FemtoKinkQa { if (!sigmaCleaner.isClean(sigma, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - sigmaHistManager.fill(sigma, tracks, mcParticles, mcMothers, mcPartonicMothers); + sigmaHistManager.fill(sigma, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoKinkQa, processSigmaMc, "Process sigmas", false); @@ -215,7 +215,7 @@ struct FemtoKinkQa { if (!sigmaPlusCleaner.isClean(sigmaPlus, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - sigmaPlusHistManager.fill(sigmaPlus, tracks, mcParticles, mcMothers, mcPartonicMothers); + sigmaPlusHistManager.fill(sigmaPlus, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoKinkQa, processSigmaPlusMc, "Process sigmas", false); diff --git a/PWGCF/Femto/Tasks/femtoPairD0D0.cxx b/PWGCF/Femto/Tasks/femtoPairD0D0.cxx new file mode 100644 index 00000000000..47a5959f2ca --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairD0D0.cxx @@ -0,0 +1,220 @@ +// Copyright 2019-2026 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 femtoPairD0D0.cxx +/// \brief Tasks that computes correlation between two D0 mesons +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#include "PWGCF/Femto/Core/charmHadronBuilder.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/particleCleaner.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +// Each pair slot (1 and 2) has its own selection, cleaner, binning and partition. +// The sign of the selection picks the decay hypothesis: +// d0-d0 : D0Selection1.sign = +1, D0Selection2.sign = +1, Mixing.sameSpecies = true +// d0bar-d0bar : D0Selection1.sign = -1, D0Selection2.sign = -1, Mixing.sameSpecies = true +// d0-d0bar : D0Selection1.sign = +1, D0Selection2.sign = -1, Mixing.sameSpecies = false +struct FemtoPairD0D0 { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoTracks = o2::aod::FTracks; + using FemtoD0s = o2::soa::Join; + + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoD0sWithLabel = o2::soa::Join; + + using FemtoMcParticlesWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup for daughters + // separate binning per d0 slot, so that both hypotheses can be binned independently + trackhistmanager::ConfD01PosDauBinning confD01PosDauBinning; + trackhistmanager::ConfD01NegDauBinning confD01NegDauBinning; + trackhistmanager::ConfD02PosDauBinning confD02PosDauBinning; + trackhistmanager::ConfD02NegDauBinning confD02NegDauBinning; + + // setup d0s + charmhadronbuilder::ConfD0Selection1 confD0Selection1; + charmhadronbuilder::ConfD0Selection2 confD0Selection2; + particlecleaner::ConfD0Cleaner1 confD0Cleaner1; + particlecleaner::ConfD0Cleaner2 confD0Cleaner2; + charmhadronhistmanager::ConfD0Binning1 confD0Binning1; + charmhadronhistmanager::ConfD0Binning2 confD0Binning2; + + o2::framework::Partition d0Partition1 = MAKE_D0_PARTITION(confD0Selection1); + o2::framework::Partition d0Partition2 = MAKE_D0_PARTITION(confD0Selection2); + o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition d0WithLabelPartition1 = MAKE_D0_PARTITION(confD0Selection1); + o2::framework::Partition d0WithLabelPartition2 = MAKE_D0_PARTITION(confD0Selection2); + o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairD0D0Builder< + charmhadronhistmanager::PrefixD01, + trackhistmanager::PrefixD01PosDaughter, + trackhistmanager::PrefixD01NegDaughter, + charmhadronhistmanager::PrefixD02, + trackhistmanager::PrefixD02PosDaughter, + trackhistmanager::PrefixD02NegDaughter, + pairhistmanager::PrefixD0D0Se, + pairhistmanager::PrefixD0D0Me, + closepairrejection::PrefixD0D0PosSe, + closepairrejection::PrefixD0D0NegSe, + closepairrejection::PrefixD0D0PosMe, + closepairrejection::PrefixD0D0NegMe, + modes::CharmHadron::kD0, + modes::CharmHadron::kD0> + pairD0D0Builder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + o2::framework::ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + o2::framework::HistogramRegistry hRegistry{"FemtoD0D0", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprD0DaugherD0DaughterPos confCprPos; + closepairrejection::ConfCprD0DaugherD0DaughterNeg confCprNeg; + + void init(o2::framework::InitContext&) + { + bool processData = doprocessSameEvent || doprocessMixedEvent; + bool processMc = doprocessSameEventMc || doprocessMixedEventMc; + + if (processData && processMc) { + LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; + } + if (!processData && !processMc) { + LOG(fatal) << "Neither data nor mc processing is enabled. Breaking..."; + } + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + std::map> colHistSpec; + std::map> posDauSpec1; + std::map> negDauSpec1; + std::map> posDauSpec2; + std::map> negDauSpec2; + std::map> d0HistSpec1; + std::map> d0HistSpec2; + std::map> pairD0D0HistSpec; + std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); + std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); + + if (processData) { + colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + posDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confD01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confD01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confD02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confD02NegDauBinning); + d0HistSpec1 = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning1); + d0HistSpec2 = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning2); + pairD0D0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg); + } else { + colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + posDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confD01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confD01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confD02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confD02NegDauBinning); + d0HistSpec1 = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning1); + d0HistSpec2 = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning2); + pairD0D0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg); + } + } + + void processSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& d0s) + { + pairD0D0Builder.processSameEvent(col, tracks, d0s, d0Partition1, d0Partition2, cache); + } + PROCESS_SWITCH(FemtoPairD0D0, processSameEvent, "Enable processing same event processing for d0-d0", true); + + void processSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& d0s, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairD0D0Builder.processSameEvent(col, mcCols, tracks, d0s, d0WithLabelPartition1, d0WithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); + } + PROCESS_SWITCH(FemtoPairD0D0, processSameEventMc, "Enable processing same event processing for d0-d0 with mc information", false); + + void processMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + { + pairD0D0Builder.processMixedEvent(cols, tracks, d0Partition1, d0Partition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairD0D0, processMixedEvent, "Enable processing mixed event processing for d0-d0", true); + + void processMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairD0D0Builder.processMixedEvent(cols, mcCols, tracks, d0WithLabelPartition1, d0WithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairD0D0, processMixedEventMc, "Enable processing mixed event processing for d0-d0 with mc information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx b/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx index 0c0a4553359..01c25a60146 100644 --- a/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx +++ b/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx @@ -107,7 +107,7 @@ struct FemtoPairMcParticleMcParticle { { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx index e9433fb4f2b..1c08e4b14a7 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx @@ -177,7 +177,7 @@ struct FemtoPairTrackCascade { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx new file mode 100644 index 00000000000..61ab3340f73 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx @@ -0,0 +1,203 @@ +// Copyright 2019-2026 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 femtoPairTrackD0.cxx +/// \brief Tasks that computes correlation between tracks and D0 mesons +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#include "PWGCF/Femto/Core/charmHadronBuilder.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/particleCleaner.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoPairTrackD0 { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoTracks = o2::soa::Join; + using FemtoD0s = o2::soa::Join; + + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoD0sWithLabel = o2::soa::Join; + using FemtoMcParticlesWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 confTrackSelection; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + particlecleaner::ConfTrackCleaner1 confTrackCleaner; + + o2::framework::Partition trackPartition = MAKE_TRACK_PARTITION(confTrackSelection); + o2::framework::Preslice perColTracks = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition trackWithLabelPartition = MAKE_TRACK_PARTITION(confTrackSelection); + o2::framework::Preslice perColTracksWithLabel = o2::aod::femtobase::stored::fColId; + + // setup for D0 daughters + trackhistmanager::ConfD01PosDauBinning confPosDauBinning; + trackhistmanager::ConfD01NegDauBinning confNegDauBinning; + + // setup D0s + charmhadronbuilder::ConfD0Selection1 d0Selection; + charmhadronhistmanager::ConfD0Binning1 confD0Binning; + particlecleaner::ConfD0Cleaner1 confD0Cleaner; + + o2::framework::Partition d0Partition = MAKE_D0_PARTITION(d0Selection); + o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(d0Selection); + o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairTrackD0Builder< + trackhistmanager::PrefixTrack1, + charmhadronhistmanager::PrefixD01, + trackhistmanager::PrefixD01PosDaughter, + trackhistmanager::PrefixD01NegDaughter, + pairhistmanager::PrefixTrackD0Se, + pairhistmanager::PrefixTrackD0Me, + closepairrejection::PrefixTrackD0DaughterSe, + closepairrejection::PrefixTrackD0DaughterMe, + modes::CharmHadron::kD0> + pairTrackD0Builder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + o2::framework::ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + o2::framework::HistogramRegistry hRegistry{"FemtoTrackD0", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprTrackD0Daughter confCpr; + + void init(o2::framework::InitContext&) + { + bool processData = doprocessSameEvent || doprocessMixedEvent; + bool processMc = doprocessSameEventMc || doprocessMixedEventMc; + + if (processData && processMc) { + LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; + } + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + std::map> colHistSpec; + std::map> trackHistSpec; + std::map> posDauSpec; + std::map> negDauSpec; + std::map> d0HistSpec; + std::map> pairTrackD0HistSpec; + std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + + if (processData) { + colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); + posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); + pairTrackD0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + } else { + colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + trackHistSpec = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning); + posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + d0HistSpec = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning); + pairTrackD0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + } + + hRegistry.print(); + }; + + void processSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& d0s) + { + pairTrackD0Builder.processSameEvent(col, tracks, trackPartition, d0s, d0Partition, cache); + } + PROCESS_SWITCH(FemtoPairTrackD0, processSameEvent, "Enable processing same event processing for tracks and D0s", true); + + void processMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + { + pairTrackD0Builder.processMixedEvent(cols, tracks, trackPartition, d0Partition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackD0, processMixedEvent, "Enable processing mixed event processing for tracks and D0s", true); + + void processSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& d0s, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairTrackD0Builder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition, d0s, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + } + PROCESS_SWITCH(FemtoPairTrackD0, processSameEventMc, "Enable processing same event processing for tracks and D0s with MC information", false); + + void processMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairTrackD0Builder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackD0, processMixedEventMc, "Enable processing mixed event processing for tracks and D0s with MC information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx index dd7ac4bfbb1..3572e577537 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx @@ -167,7 +167,7 @@ struct FemtoPairTrackKink { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx index ddf110af478..cb49fed5e8d 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx @@ -129,7 +129,7 @@ struct FemtoPairTrackTrack { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx index 69087f58180..73cf010fb31 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx @@ -84,8 +84,8 @@ struct FemtoPairTrackV0 { o2::framework::Preslice perColtracksWithLabel = o2::aod::femtobase::stored::fColId; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + trackhistmanager::ConfV01PosDauBinning confPosDauBinning; + trackhistmanager::ConfV01NegDauBinning confNegDauBinning; // setup lambdas v0builder::ConfLambdaSelection1 lambdaSelection; @@ -169,7 +169,7 @@ struct FemtoPairTrackV0 { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx b/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx index 6a0e25e40d2..d742aba5be4 100644 --- a/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx +++ b/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx @@ -70,8 +70,8 @@ struct FemtoPairV0TwoTrackResonance { colhistmanager::ConfCollisionBinning confCollisionBinning; // setup for daughters for v0s - trackhistmanager::ConfV0PosDauBinning confV0PosDauBinning; - trackhistmanager::ConfV0NegDauBinning confV0NegDauBinning; + trackhistmanager::ConfV01PosDauBinning confV0PosDauBinning; + trackhistmanager::ConfV01NegDauBinning confV0NegDauBinning; // setup lambdas v0builder::ConfLambdaSelection1 lambdaSelection; diff --git a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx index 7ebc4f3c7fd..82ae5b62bb4 100644 --- a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx @@ -43,6 +43,13 @@ using namespace o2::analysis::femto; +// Each pair slot (1 and 2) has its own selection, cleaner, binning and partition, so that +// any combination of v0s can be correlated: +// lambda-lambda : LambdaSelection1 == LambdaSelection2, Mixing.sameSpecies = true +// lambda-antilambda : LambdaSelection1/2 differ only in sign, Mixing.sameSpecies = false +// k0short-k0short : K0shortSelection1 == K0shortSelection2, Mixing.sameSpecies = true +// lambda-k0short : LambdaSelection1 and K0shortSelection2, Mixing.sameSpecies = false +// Slot N always uses selection N, cleaner N, binning N and partition N. struct FemtoPairV0V0 { // setup tables @@ -72,30 +79,44 @@ struct FemtoPairV0V0 { colhistmanager::ConfCollisionBinning confCollisionBinning; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + // separate binning per v0 slot, so that e.g. lambda (proton/pion daughters) and + // k0short (pion/pion daughters) can be binned independently + trackhistmanager::ConfV01PosDauBinning confV01PosDauBinning; + trackhistmanager::ConfV01NegDauBinning confV01NegDauBinning; + trackhistmanager::ConfV02PosDauBinning confV02PosDauBinning; + trackhistmanager::ConfV02NegDauBinning confV02NegDauBinning; // setup lambdas - v0builder::ConfLambdaSelection1 confLambdaSelection; - particlecleaner::ConfLambdaCleaner1 confLambdaCleaner; - v0histmanager::ConfLambdaBinning1 confLambdaBinning; - - o2::framework::Partition lambdaPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + v0builder::ConfLambdaSelection1 confLambdaSelection1; + v0builder::ConfLambdaSelection2 confLambdaSelection2; + particlecleaner::ConfLambdaCleaner1 confLambdaCleaner1; + particlecleaner::ConfLambdaCleaner2 confLambdaCleaner2; + v0histmanager::ConfLambdaBinning1 confLambdaBinning1; + v0histmanager::ConfLambdaBinning2 confLambdaBinning2; + + o2::framework::Partition lambdaPartition1 = MAKE_LAMBDA_PARTITION(confLambdaSelection1); + o2::framework::Partition lambdaPartition2 = MAKE_LAMBDA_PARTITION(confLambdaSelection2); o2::framework::Preslice perColLambdas = o2::aod::femtobase::stored::fColId; - o2::framework::Partition lambdaWithLabelPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); - o2::framework::Preslice perCollambdasWithLabel = o2::aod::femtobase::stored::fColId; + o2::framework::Partition lambdaWithLabelPartition1 = MAKE_LAMBDA_PARTITION(confLambdaSelection1); + o2::framework::Partition lambdaWithLabelPartition2 = MAKE_LAMBDA_PARTITION(confLambdaSelection2); + o2::framework::Preslice perColLambdasWithLabel = o2::aod::femtobase::stored::fColId; // setup k0shorts - v0builder::ConfK0shortSelection1 confK0shortSelection; - particlecleaner::ConfK0shortCleaner1 confK0shortCleaner; - v0histmanager::ConfK0shortBinning1 confK0shortBinning; + v0builder::ConfK0shortSelection1 confK0shortSelection1; + v0builder::ConfK0shortSelection2 confK0shortSelection2; + particlecleaner::ConfK0shortCleaner1 confK0shortCleaner1; + particlecleaner::ConfK0shortCleaner2 confK0shortCleaner2; + v0histmanager::ConfK0shortBinning1 confK0shortBinning1; + v0histmanager::ConfK0shortBinning2 confK0shortBinning2; - o2::framework::Partition k0shortPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); - o2::framework::Preslice perColk0shorts = o2::aod::femtobase::stored::fColId; + o2::framework::Partition k0shortPartition1 = MAKE_K0SHORT_PARTITION(confK0shortSelection1); + o2::framework::Partition k0shortPartition2 = MAKE_K0SHORT_PARTITION(confK0shortSelection2); + o2::framework::Preslice perColK0shorts = o2::aod::femtobase::stored::fColId; - o2::framework::Partition k0shortWithLabelPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); - o2::framework::Preslice perColk0shortsWithLabel = o2::aod::femtobase::stored::fColId; + o2::framework::Partition k0shortWithLabelPartition1 = MAKE_K0SHORT_PARTITION(confK0shortSelection1); + o2::framework::Partition k0shortWithLabelPartition2 = MAKE_K0SHORT_PARTITION(confK0shortSelection2); + o2::framework::Preslice perColK0shortsWithLabel = o2::aod::femtobase::stored::fColId; // setup pairs pairhistmanager::ConfPairBinning confPairBinning; @@ -169,16 +190,26 @@ struct FemtoPairV0V0 { void init(o2::framework::InitContext&) { - bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent; - bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc || doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; + bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || + doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent; + bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc || + doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc || + doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; if (processData && processMc) { LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; } + if (!processData && !processMc) { + LOG(fatal) << "Neither data nor mc processing is enabled. Breaking..."; + } - bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; - bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; - bool processLambdaK0short = doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent || doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; + bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; + bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || + doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; + bool processLambdaK0short = doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent || + doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; if (static_cast(processLambdaLambda) + static_cast(processK0shortK0short) + static_cast(processLambdaK0short) > 1) { LOG(fatal) << "Only one of lambda-lambda, k0short-k0short or lambda-k0short processing can be enabled. Breaking..."; @@ -186,140 +217,146 @@ struct FemtoPairV0V0 { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; // setup histograms std::map> colHistSpec; - std::map> posDauSpec; - std::map> negDauSpec; - std::map> lambdaHistSpec; - std::map> k0shortHistSpec; + std::map> posDauSpec1; + std::map> negDauSpec1; + std::map> posDauSpec2; + std::map> negDauSpec2; + std::map> lambdaHistSpec1; + std::map> lambdaHistSpec2; + std::map> k0shortHistSpec1; + std::map> k0shortHistSpec2; std::map> pairV0V0HistSpec; std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { - lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + lambdaHistSpec1 = v0histmanager::makeV0HistSpecMap(confLambdaBinning1); + lambdaHistSpec2 = v0histmanager::makeV0HistSpecMap(confLambdaBinning2); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { - k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processK0shortK0short) { + k0shortHistSpec1 = v0histmanager::makeV0HistSpecMap(confK0shortBinning1); + k0shortHistSpec2 = v0histmanager::makeV0HistSpecMap(confK0shortBinning2); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for lambda-k0short - if (doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent) { - lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confK0shortSelection, confLambdaCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processLambdaK0short) { + lambdaHistSpec1 = v0histmanager::makeV0HistSpecMap(confLambdaBinning1); + k0shortHistSpec2 = v0histmanager::makeV0HistSpecMap(confK0shortBinning2); + pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { - lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + lambdaHistSpec1 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning1); + lambdaHistSpec2 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning2); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { - k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processK0shortK0short) { + k0shortHistSpec1 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning1); + k0shortHistSpec2 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning2); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for lambda-k0short - if (doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent) { - lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confK0shortSelection, confLambdaCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processLambdaK0short) { + lambdaHistSpec1 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning1); + k0shortHistSpec2 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning2); + pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } - }; + } void processLambdaLambdaSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) { - pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, lambdaPartition, cache); + pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition1, lambdaPartition2, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-lambda", true); void processLambdaLambdaSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, lambdaWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition1, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-lambda with mc information", false); - void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas) + void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/) { - pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, lambdaPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdaPartition1, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-lambda", true); void processLambdaLambdaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, lambdaWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition1, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-lambda with mc information", false); void processK0shortK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) { - pairK0shortK0shortBuilder.processSameEvent(col, tracks, k0shorts, k0shortPartition, k0shortPartition, cache); + pairK0shortK0shortBuilder.processSameEvent(col, tracks, k0shorts, k0shortPartition1, k0shortPartition2, cache); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortSameEvent, "Enable processing same event processing for k0short-k0short", false); void processK0shortK0shortSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& k0shorts, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairK0shortK0shortBuilder.processSameEvent(col, mcCols, tracks, k0shorts, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + pairK0shortK0shortBuilder.processSameEvent(col, mcCols, tracks, k0shorts, k0shortWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortSameEventMc, "Enable processing same event processing for k0short-k0short with mc information", false); - void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) + void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& /*k0shorts*/) { - pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shorts, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shortPartition1, k0shortPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortMixedEvent, "Enable processing mixed event processing for k0short-k0short", false); void processK0shortK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortMixedEventMc, "Enable processing mixed event processing for k0short-k0short with mc information", false); void processLambdaK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas, FemtoK0shorts const& /*k0shorts*/) { - pairLambdaK0shortBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, k0shortPartition, cache); + pairLambdaK0shortBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition1, k0shortPartition2, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortSameEvent, "Enable processing same event processing for lambda-k0short", false); void processLambdaK0shortSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaK0shortBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + pairLambdaK0shortBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortSameEventMc, "Enable processing same event processing for lambda-k0short with mc information", false); - void processLambdaK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas, FemtoK0shorts const& /*k0shorts*/) + void processLambdaK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/, FemtoK0shorts const& /*k0shorts*/) { - pairLambdaK0shortBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaK0shortBuilder.processMixedEvent(cols, tracks, lambdaPartition1, k0shortPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortMixedEvent, "Enable processing mixed event processing for lambda-k0short", false); void processLambdaK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaK0shortBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaK0shortBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortMixedEventMc, "Enable processing mixed event processing for lambda-k0short with mc information", false); }; diff --git a/PWGCF/Femto/Tasks/femtoTrackQa.cxx b/PWGCF/Femto/Tasks/femtoTrackQa.cxx index 7a460bb3c15..5a5f081e954 100644 --- a/PWGCF/Femto/Tasks/femtoTrackQa.cxx +++ b/PWGCF/Femto/Tasks/femtoTrackQa.cxx @@ -41,10 +41,14 @@ using namespace o2::analysis::femto; struct FemtoTrackQa { // setup tables - using FemtoCollisions = o2::soa::Join; + using FemtoCollisions = o2::soa::Join; using FilteredFemtoCollisions = o2::soa::Filtered; using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + using FemtoCollisionsWithEventShape = o2::soa::Join; + using FilteredFemtoCollisionsWithEventShape = o2::soa::Filtered; + using FilteredFemtoCollisionWithEventShape = FilteredFemtoCollisionsWithEventShape::iterator; + using FemtoCollisionsWithLabel = o2::soa::Join; using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; @@ -83,16 +87,16 @@ struct FemtoTrackQa { void init(o2::framework::InitContext&) { - if ((static_cast(doprocessData) + static_cast(doprocessMc)) > 1) { + if ((static_cast(doprocessData) + static_cast(doprocessMc) + static_cast(doprocessDataWithEventShape)) > 1) { LOG(fatal) << "More than 1 process function is activated. Breaking..."; } - bool processData = doprocessData; + bool processDataFlag = doprocessData || doprocessDataWithEventShape; trackCleaner.init(confTrackCleaner); std::map> colHistSpec; std::map> trackHistSpec; - if (processData) { + if (processDataFlag) { colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); trackHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confTrackBinning, confTrackQaBinning); @@ -130,10 +134,23 @@ struct FemtoTrackQa { if (!trackCleaner.isClean(track, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - trackHistManager.fill(track, tracks, mcParticles, mcMothers, mcPartonicMothers); + trackHistManager.fill(track, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoTrackQa, processMc, "Track QA in Monte Carlo", false); + + void processDataWithEventShape(FilteredFemtoCollisionWithEventShape const& col, FemtoTracks const& tracks) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() == 0) { + return; + } + colHistManager.fill(col); + for (auto const& track : trackSlice) { + trackHistManager.fill(track, tracks); + } + }; + PROCESS_SWITCH(FemtoTrackQa, processDataWithEventShape, "Track QA in Data with event shape information", false); }; o2::framework::WorkflowSpec diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx index 6bddc62672e..fca9c8cad9f 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx @@ -198,7 +198,7 @@ struct FemtoTripletTrackTrackCascade { } // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx index 8b9db111c69..cbdbc3e2345 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx @@ -134,7 +134,7 @@ struct FemtoTripletTrackTrackTrack { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx index 5be5c5d372a..6fe9a688384 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx @@ -94,8 +94,8 @@ struct FemtoTripletTrackTrackV0 { o2::framework::Preslice perColtracksWithLabel = o2::aod::femtobase::stored::fColId; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + trackhistmanager::ConfV01PosDauBinning confPosDauBinning; + trackhistmanager::ConfV01NegDauBinning confNegDauBinning; // setup lambdas v0builder::ConfLambdaSelection1 confLambdaSelection; diff --git a/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx b/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx index 7e22720b6c6..fbb62a1003f 100644 --- a/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx +++ b/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx @@ -40,7 +40,7 @@ using namespace o2::analysis::femto; struct FemtoTwotrackresonanceQa { // setup tables - using FemtoCollisions = o2::soa::Join; + using FemtoCollisions = o2::soa::Join; using FemtoCollision = FemtoCollisions::iterator; using FilteredFemtoCollisions = o2::soa::Filtered; diff --git a/PWGCF/Femto/Tasks/femtoV0Qa.cxx b/PWGCF/Femto/Tasks/femtoV0Qa.cxx index bcd8aa7a246..18e6a485e99 100644 --- a/PWGCF/Femto/Tasks/femtoV0Qa.cxx +++ b/PWGCF/Femto/Tasks/femtoV0Qa.cxx @@ -42,7 +42,7 @@ using namespace o2::analysis::femto; struct FemtoV0Qa { // setup tables - using FemtoCollisions = o2::soa::Join; + using FemtoCollisions = o2::soa::Join; using FilteredFemtoCollisions = o2::soa::Filtered; using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; @@ -112,11 +112,11 @@ struct FemtoV0Qa { k0shortHistManager; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confV0PosDaughterBinning; - trackhistmanager::ConfV0PosDauQaBinning confV0PosDaughterQaBinning; + trackhistmanager::ConfV01PosDauBinning confV0PosDaughterBinning; + trackhistmanager::ConfV01PosDauQaBinning confV0PosDaughterQaBinning; - trackhistmanager::ConfV0NegDauBinning confV0NegDaughterBinning; - trackhistmanager::ConfV0NegDauQaBinning confV0NegDaughterQaBinning; + trackhistmanager::ConfV01NegDauBinning confV0NegDaughterBinning; + trackhistmanager::ConfV01NegDauQaBinning confV0NegDaughterQaBinning; o2::framework::HistogramRegistry hRegistry{"FemtoV0Qa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; @@ -190,7 +190,7 @@ struct FemtoV0Qa { if (!k0shortCleaner.isClean(k0short, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - k0shortHistManager.fill(k0short, tracks, mcParticles, mcMothers, mcPartonicMothers); + k0shortHistManager.fill(k0short, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoV0Qa, processK0shortMc, "Process k0shorts with MC information", false); @@ -219,7 +219,7 @@ struct FemtoV0Qa { if (!lambdaCleaner.isClean(lambda, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - lambdaHistManager.fill(lambda, tracks, mcParticles, mcMothers, mcPartonicMothers); + lambdaHistManager.fill(lambda, tracks, col, mcParticles, mcMothers, mcPartonicMothers); } } PROCESS_SWITCH(FemtoV0Qa, processLambdaMc, "Process lambdas with MC informaton", false); diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx index 65a5e2d3824..7460651def8 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx @@ -16,21 +16,31 @@ #include "PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h" #include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" #include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamMath.h" #include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" #include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" #include +#include +#include #include +#include +#include +#include +#include #include -#include +#include +#include +#include #include -#include +#include #include #include #include +#include #include #include using namespace o2; diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx index f3f3c82f65f..4de102546a0 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx @@ -1419,7 +1419,7 @@ struct FemtoUniverseProducerTask { aod::femtouniverseparticle::ParticleType::kV0Child, cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosCuts), confIsUseCutculator ? cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID) : pidBitmask(postrack), - 0., + postrack.dcaXY(), childIDs, 0, postrack.sign()); @@ -1439,7 +1439,7 @@ struct FemtoUniverseProducerTask { aod::femtouniverseparticle::ParticleType::kV0Child, cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), confIsUseCutculator ? cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID) : pidBitmask(negtrack), - 0., + negtrack.dcaXY(), childIDs, 0, negtrack.sign()); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx index 6a16a93a958..bd7362e67b0 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx @@ -13,6 +13,7 @@ /// \brief Task for track and cascade correlations and QA /// \author Barbara Chytla, WUT Warsaw, barbara.chytla@cern.ch /// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch +/// \author Tomasz Pawlaczyk, WUT Warsaw, tpawlacz@cern.ch #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" @@ -459,11 +460,15 @@ struct femtoUniversePairTaskTrackCascadeExtended { // NOLINT(cppcoreguidelines-p if (!isParticleTOF(posChild, CascChildTable[cascparticleconfigs.confCascType1][0], &posChildTOF) || !isParticleTOF(negChild, CascChildTable[cascparticleconfigs.confCascType1][1], &negChildTOF) || !isParticleTOF(bachelor, CascChildTable[cascparticleconfigs.confCascType1][2], &bachelorTOF)) continue; + CascQAExtra.fill(HIST("hMassXiSelected"), part.mLambda()); + CascQAExtra.fill(HIST("hInvMpT"), part.pt(), part.mLambda()); + + if (!invMCascade(part.mLambda(), part.mAntiLambda(), cascparticleconfigs.confCascType1)) + continue; + CascQAExtra.fill(HIST("hPtXi"), part.pt()); CascQAExtra.fill(HIST("hEtaXi"), part.eta()); CascQAExtra.fill(HIST("hPhiXi"), part.phi()); - CascQAExtra.fill(HIST("hMassXiSelected"), part.mLambda()); - CascQAExtra.fill(HIST("hInvMpT"), part.pt(), part.mLambda()); } } @@ -483,6 +488,9 @@ struct femtoUniversePairTaskTrackCascadeExtended { // NOLINT(cppcoreguidelines-p if (!isParticleTOF(posChildExt, CascChildTable[cascparticleconfigs.confCascType1][0], &posChildTOFExt) || !isParticleTOF(negChildExt, CascChildTable[cascparticleconfigs.confCascType1][1], &negChildTOFExt) || !isParticleTOF(bachelorExt, CascChildTable[cascparticleconfigs.confCascType1][2], &bachelorTOFExt)) continue; + if (!invMCascade(part.mLambda(), part.mAntiLambda(), cascparticleconfigs.confCascType1)) + continue; + CascQAExtra.fill(HIST("hDCAV0Daughters"), casc.dcaV0daughters()); CascQAExtra.fill(HIST("hV0CosPA"), casc.cpav0()); CascQAExtra.fill(HIST("hV0TranRad"), casc.v0radius()); @@ -527,11 +535,15 @@ struct femtoUniversePairTaskTrackCascadeExtended { // NOLINT(cppcoreguidelines-p if (!isParticleTOF(posChild, CascChildTable[cascparticleconfigs.confCascType1][0], &posChildTOF) || !isParticleTOF(negChild, CascChildTable[cascparticleconfigs.confCascType1][1], &negChildTOF) || !isParticleTOF(bachelor, CascChildTable[cascparticleconfigs.confCascType1][2], &bachelorTOF)) continue; + CascQAExtra.fill(HIST("hMassXiSelected"), part.mLambda()); + CascQAExtra.fill(HIST("hInvMpT"), part.pt(), part.mLambda()); + + if (!invMCascade(part.mLambda(), part.mAntiLambda(), cascparticleconfigs.confCascType1)) + continue; + CascQAExtra.fill(HIST("hPtXi"), part.pt()); CascQAExtra.fill(HIST("hEtaXi"), part.eta()); CascQAExtra.fill(HIST("hPhiXi"), part.phi()); - CascQAExtra.fill(HIST("hMassXiSelected"), part.mLambda()); - CascQAExtra.fill(HIST("hInvMpT"), part.pt(), part.mLambda()); } } } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx index 03baec4f934..31901da383b 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx @@ -94,8 +94,10 @@ struct FemtoUniversePairTaskTrackD0 { Service pdgMC{}; using FemtoFullParticles = soa::Join; + using FemtoFullSigmaParticles = soa::Join; SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + Preslice perColFullSigma = aod::femtouniverseparticle::fdCollisionId; using FemtoMcRecoParticles = soa::Join; Preslice perColMc = aod::femtouniverseparticle::fdCollisionId; @@ -190,24 +192,25 @@ struct FemtoUniversePairTaskTrackD0 { /// Partitions for particle 1 Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); + Partition partsTrackFullSigma = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); Partition partsTrackMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); Partition partsTrackMCTruth = (aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pidCut == static_cast(ConfTrack.confPDGCodeTrack)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); /// Partitions for particle 2 /// Partition with all D0/D0bar mesons (which pass one and double mass hypothesis) - Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > 0.0f) || (aod::femtouniverseparticle::mAntiLambda > 0.0f)) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > 0.0f) || (aod::femtouniverseparticle::mAntiLambda > 0.0f)) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0 mesons only (one and double mass hypothesis) - Partition partsAllD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsAllD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0 mesons only (one mass hypothesis) - Partition partsD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0s selected from the side-band (SB) regions (candidates with double mass hypothesis included) - Partition partsD0sFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0sFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0bar mesons only (one and double mass hypothesis) - Partition partsAllD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsAllD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0bar mesons only (one mass hypothesis) - Partition partsD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0bars selected from the side-band (SB) regions (candidates with double mass hypothesis included) - Partition partsD0barsFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0barsFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition for MC Reco prompt D0/D0bar mesons Partition partsPromptD0MCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); Partition partsPromptD0barMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); @@ -261,13 +264,15 @@ struct FemtoUniversePairTaskTrackD0 { ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {360, 0., 36.}, "Cand. pT bins"}; } ConfThnAxes; - Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; - Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + struct : o2::framework::ConfigurableGroup { + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + } ConfCPR; Configurable confRemoveSoftPions{"confRemoveSoftPions", false, "Enable to remove soft pions from D* decays"}; Configurable confSoftPionD0Flag{"confSoftPionD0Flag", false, "Enable soft pion check for D0s"}; @@ -317,10 +322,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofProton) { return std::abs(nsigmaTPCPr) < ConfTrack.confNsigmaTPCProton; } - if (mom > ConfTrack.minMomPidTpcTofProton) { - return std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombinedProton; - } - return false; + return std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombinedProton; } bool isProtonNSigmaRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCKa, float nsigmaTOFKa) @@ -328,10 +330,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofProton) { return std::abs(nsigmaTPCPi) < ConfTrack.confNsigmaTPCPrRejectPiNsigma || std::abs(nsigmaTPCKa) < ConfTrack.confNsigmaTPCPrRejectKaNsigma; } - if (mom > ConfTrack.minMomPidTpcTofProton) { - return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombPrRejectPiNsigma || std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPrRejectKaNsigma; - } - return false; + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombPrRejectPiNsigma || std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPrRejectKaNsigma; } bool isKaonNSigma(float mom, float nsigmaTPCKa, float nsigmaTOFKa) @@ -339,10 +338,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofKaon) { return std::abs(nsigmaTPCKa) < ConfTrack.confNsigmaTPCKaon; } - if (mom > ConfTrack.minMomPidTpcTofKaon) { - return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombinedKaon; - } - return false; + return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombinedKaon; } bool isKaonNSigmaRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCPr, float nsigmaTOFPr) @@ -350,10 +346,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofKaon) { return std::abs(nsigmaTPCPi) < ConfTrack.confNsigmaTPCKaRejectPiNsigma || std::abs(nsigmaTPCPr) < ConfTrack.confNsigmaTPCKaRejectPrNsigma; } - if (mom > ConfTrack.minMomPidTpcTofKaon) { - return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombKaRejectPiNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombKaRejectPrNsigma; - } - return false; + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombKaRejectPiNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombKaRejectPrNsigma; } bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) @@ -361,10 +354,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofPion) { return std::abs(nsigmaTPCPi) < ConfTrack.confNsigmaTPCPion; } - if (mom > ConfTrack.minMomPidTpcTofPion) { - return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombinedPion; - } - return false; + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombinedPion; } bool isPionNSigmaRejected(float mom, float nsigmaTPCKa, float nsigmaTOFKa, float nsigmaTPCPr, float nsigmaTOFPr) @@ -372,10 +362,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofPion) { return std::abs(nsigmaTPCKa) < ConfTrack.confNsigmaTPCPiRejectKaNsigma || std::abs(nsigmaTPCPr) < ConfTrack.confNsigmaTPCPiRejectPrNsigma; } - if (mom > ConfTrack.minMomPidTpcTofPion) { - return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPiRejectKaNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombPiRejectPrNsigma; - } - return false; + return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPiRejectKaNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombPiRejectPrNsigma; } bool isParticleNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) @@ -468,6 +455,20 @@ struct FemtoUniversePairTaskTrackD0 { qaRegistry.add("Hadron/nSigmaTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); qaRegistry.add("Hadron/nSigmaCombKa", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Ka}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + if (doprocessPurityQA && std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kProton) { + qaRegistry.add("PurityQA/nSigmaFullTPCPr", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPr}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullTOFPr", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPr}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullCombPr", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Pr}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + } else if (doprocessPurityQA && std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kPiPlus) { + qaRegistry.add("PurityQA/nSigmaFullTPCPi", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPi}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullTOFPi", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPi}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullCombPi", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Pi}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + } else if (doprocessPurityQA && std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kKPlus) { + qaRegistry.add("PurityQA/nSigmaFullTPCKa", "; #it{p} (GeV/#it{c}); n#sigma_{TPCKa}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullCombKa", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Ka}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + } + // D0/D0bar histograms auto vbins = (std::vector)binsPt; auto vFivePtBins = (std::vector)binsPtFive; @@ -476,7 +477,7 @@ struct FemtoUniversePairTaskTrackD0 { const AxisSpec thnAxisPromptScore{ConfThnAxes.thnConfigAxisPromptScore, "BDT score prompt"}; const AxisSpec thnAxisMass{ConfThnAxes.thnConfigAxisMass, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{ConfThnAxes.thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - std::vector axesTHn = {thnAxisNonPromptScore, thnAxisPromptScore, thnAxisMass, thnAxisPt}; + std::vector axesTHn = {thnAxisPromptScore, thnAxisNonPromptScore, thnAxisMass, thnAxisPt}; if (doEfficiencyCorr) { registry.add("D0D0bar_oneMassHypo/hMassVsPtEffCorr", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -615,8 +616,8 @@ struct FemtoUniversePairTaskTrackD0 { softPionRemoval.init(&qaRegistry); pairCleaner.init(&qaRegistry); - if (confIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfBothTracks.confDeltaEtaAxis, ConfBothTracks.confDeltaPhiStarAxis, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); + if (ConfCPR.confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfBothTracks.confDeltaEtaAxis, ConfBothTracks.confDeltaPhiStarAxis, ConfCPR.confCPRdeltaPhiCutMin.value, ConfCPR.confCPRdeltaPhiCutMax.value, ConfCPR.confCPRdeltaEtaCutMin.value, ConfCPR.confCPRdeltaEtaCutMax.value, ConfCPR.confCPRChosenRadii.value, ConfCPR.confCPRPlotPerRadii.value); } vPIDTrack = ConfTrack.confPIDTrack.value; @@ -836,7 +837,7 @@ struct FemtoUniversePairTaskTrackD0 { } } // // Close Pair Rejection - if (confIsCPR.value) { + if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } @@ -1036,7 +1037,7 @@ struct FemtoUniversePairTaskTrackD0 { } } // // Close Pair Rejection - if (confIsCPR.value) { + if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } @@ -1532,6 +1533,42 @@ struct FemtoUniversePairTaskTrackD0 { } } PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMcTruth, "Process MC truth data", false); + + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processPurityQA(aod::FdCollision const& col, + FemtoFullSigmaParticles const&) + { + fillCollision(col); + + auto theGroupPartsOne = partsTrackFullSigma->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + for (const auto& part : theGroupPartsOne) { + + if (!isParticleNSigma(part.p(), part.tpcFullNSigmaPr(), part.tofFullNSigmaPr(), part.tpcFullNSigmaPi(), part.tofFullNSigmaPi(), part.tpcFullNSigmaKa(), part.tofFullNSigmaKa())) { + continue; + } + if (ConfTrack.confDoPartNsigmaRejection && isParticleNSigmaRejected(part.p(), part.tpcFullNSigmaPi(), part.tofFullNSigmaPi(), part.tpcFullNSigmaKa(), part.tofFullNSigmaKa(), part.tpcFullNSigmaPr(), part.tofFullNSigmaPr())) { + continue; + } + + trackHistoPartTrack.fillQA(part); + if (std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kProton) { + qaRegistry.fill(HIST("PurityQA/nSigmaFullTPCPr"), part.p(), part.tpcFullNSigmaPr()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullTOFPr"), part.p(), part.tofFullNSigmaPr()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullCombPr"), part.p(), std::hypot(part.tpcFullNSigmaPr(), part.tofFullNSigmaPr())); + } else if (std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kPiPlus) { + qaRegistry.fill(HIST("PurityQA/nSigmaFullTPCPi"), part.p(), part.tpcFullNSigmaPi()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullTOFPi"), part.p(), part.tofFullNSigmaPi()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullCombPi"), part.p(), std::hypot(part.tpcFullNSigmaPi(), part.tofFullNSigmaPi())); + } else if (std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kKPlus) { + qaRegistry.fill(HIST("PurityQA/nSigmaFullTPCKa"), part.p(), part.tpcFullNSigmaKa()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullTOFKa"), part.p(), part.tofFullNSigmaKa()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullCombKa"), part.p(), std::hypot(part.tpcFullNSigmaKa(), part.tofFullNSigmaKa())); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processPurityQA, "Enable processing QA for purity estimation", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx index 5fc9dd9c59a..3cd734acc13 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx @@ -26,6 +26,7 @@ #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include +#include #include #include #include @@ -43,6 +44,8 @@ #include #include +#include + #include #include #include @@ -59,18 +62,30 @@ using namespace o2::soa; namespace { -// static constexpr int NPart = 2; -// static constexpr int NCuts = 5; -static const std::vector partNames{"PhiCandidate", "Track"}; -static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -// static const float cutsTable[NPart][NCuts]{ //unused variable -// {4.05f, 1.f, 3.f, 3.f, 100.f}, -// {4.05f, 1.f, 3.f, 3.f, 100.f}}; +const std::vector partNames{"PhiCandidate", "Track"}; +const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; + +// Constants for pT / momentum +constexpr float kMomCutLow = 0.5f; +constexpr float kMomCutKaonLow = 0.3f; +constexpr float kMomCutKaonMid = 0.45f; +constexpr float kMomCutKaonHigh = 0.55f; +constexpr float kMomCutKaonMax = 1.5f; + +// Constants for nSigma cuts +constexpr float kNSigmaStrict = 1.0f; +constexpr float kNSigmaMedium = 2.0f; +constexpr float kNSigmaStandard = 3.0f; + +// Helper constants and indices +constexpr int kInvalidMCPartId = -1; +constexpr int kPhiDaughterOffsetPos = 2; +constexpr int kPhiDaughterOffsetNeg = 1; } // namespace struct FemtoUniversePairTaskTrackPhi { - Service pdgMC; + Service pdgMC = {}; using FilteredFemtoFullParticles = soa::Join; @@ -80,73 +95,74 @@ struct FemtoUniversePairTaskTrackPhi { using FemtoRecoParticles = soa::Join; Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; - Configurable ConfZVertexCut{"ConfZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; - Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; - Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZVertexCut); + Configurable confZVertexCut{"confZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + // Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); using FilteredFDCollisions = soa::Filtered; using FilteredFDCollision = FilteredFDCollisions::iterator; - Configurable ConfCPRIsEnabled{"ConfCPRIsEnabled", false, "Close Pair Rejection"}; - Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable ConfCPRInvMassCutMin{"ConfCPRInvMassCutMin", 1.014, "Invariant mass (low) cut for Close Pair Rejection"}; - Configurable ConfCPRInvMassCutMax{"ConfCPRInvMassCutMax", 1.026, "Invariant mass (high) cut for Close Pair Rejection"}; - Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confCPRIsEnabled{"confCPRIsEnabled", false, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRInvMassCutMin{"confCPRInvMassCutMin", 1.014, "Invariant mass (low) cut for Close Pair Rejection"}; + Configurable confCPRInvMassCutMax{"confCPRInvMassCutMax", 1.026, "Invariant mass (high) cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; ConfigurableAxis confDeltaEtaAxis{"confDeltaEtaAxis", {100, -0.15, 0.15}, "DeltaEta"}; ConfigurableAxis confDeltaPhiStarAxis{"confDeltaPhiStarAxis", {100, -0.15, 0.15}, "DeltaPhiStar"}; /// Table for both particles - Configurable ConfPIDProtonNsigmaCombined{"ConfPIDProtonNsigmaCombined", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; - Configurable ConfPIDProtonNsigmaTPC{"ConfPIDProtonNsigmaTPC", 3.0, "TPC Proton Sigma for momentum < 0.5"}; - Configurable ConfPIDKaonNsigmaReject{"ConfPIDKaonNsigmaReject", 3.0, "Reject if particle could be a Kaon combined nsigma value."}; - Configurable ConfPIDPionNsigmaReject{"ConfPIDPionNsigmaReject", 3.0, "Reject if particle could be a Pion combined nsigma value."}; - Configurable ConfPIDProtonNsigmaReject{"ConfPIDProtonNsigmaReject", 3.0, "Reject if particle could be a Proton combined nsigma value."}; - Configurable ConfPIDPionNsigmaCombined{"ConfPIDPionNsigmaCombined", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; - Configurable ConfPIDPionNsigmaTPC{"ConfPIDPionNsigmaTPC", 3.0, "TPC Pion Sigma for momentum < 0.5"}; - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - Configurable ConfBinsPhi{"ConfBinsPhi", 29, "Number of phi bins in deta dphi"}; - Configurable ConfBinsEta{"ConfBinsEta", 29, "Number of eta bins in deta dphi"}; + Configurable confPIDProtonNsigmaCombined{"confPIDProtonNsigmaCombined", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; + Configurable confPIDProtonNsigmaTPC{"confPIDProtonNsigmaTPC", 3.0, "TPC Proton Sigma for momentum < 0.5"}; + Configurable confPIDKaonNsigmaReject{"confPIDKaonNsigmaReject", 3.0, "Reject if particle could be a Kaon combined nsigma value."}; + Configurable confPIDPionNsigmaReject{"confPIDPionNsigmaReject", 3.0, "Reject if particle could be a Pion combined nsigma value."}; + Configurable confPIDProtonNsigmaReject{"confPIDProtonNsigmaReject", 3.0, "Reject if particle could be a Proton combined nsigma value."}; + Configurable confPIDPionNsigmaCombined{"confPIDPionNsigmaCombined", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; + Configurable confPIDPionNsigmaTPC{"confPIDPionNsigmaTPC", 3.0, "TPC Pion Sigma for momentum < 0.5"}; + Configurable confIsMC{"confIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confBinsPhi{"confBinsPhi", 29, "Number of phi bins in deta dphi"}; + Configurable confBinsEta{"confBinsEta", 29, "Number of eta bins in deta dphi"}; /// Particle 1 --- IDENTIFIED TRACK - Configurable ConfTrackPDGCode{"ConfTrackPDGCode", 2212, "Particle 2 - PDG code"}; - Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; - Configurable ConfTrackIsIdentified{"ConfTrackIsIdentified", true, "Enable PID for the track"}; - Configurable ConfTrackIsRejected{"ConfTrackIsRejected", true, "Enable PID rejection for the track other species than the identified one."}; - Configurable ConfTrackPtPIDLimit{"ConfTrackPtPIDLimit", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; - Configurable ConfTrackPtLow{"ConfTrackPtLow", 0.5, "Lower limit of the hadron pT."}; - Configurable ConfTrackPtHigh{"ConfTrackPtHigh", 2.5, "Higher limit of the hadron pT."}; + Configurable confTrackPDGCode{"confTrackPDGCode", 2212, "Particle 2 - PDG code"}; + Configurable confTrackSign{"confTrackSign", 1, "Track sign"}; + Configurable confTrackIsIdentified{"confTrackIsIdentified", true, "Enable PID for the track"}; + Configurable confTrackIsRejected{"confTrackIsRejected", true, "Enable PID rejection for the track other species than the identified one."}; + Configurable confTrackPtPIDLimit{"confTrackPtPIDLimit", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; + Configurable confTrackPtLow{"confTrackPtLow", 0.5, "Lower limit of the hadron pT."}; + Configurable confTrackPtHigh{"confTrackPtHigh", 2.5, "Higher limit of the hadron pT."}; + Configurable confTrackUseRun3PIDforKaons{"confTrackUseRun3PIDforKaons", true, "Use Run3 PID for kaons from Veronika Barbasova's AN (https://alice-notes.web.cern.ch/node/1758). If this is on the other PID methods are ignored for kaons."}; /// Partitions for the track (particle 1) Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && - (aod::femtouniverseparticle::sign == ConfTrackSign) && - (aod::femtouniverseparticle::pt > ConfTrackPtLow) && - (aod::femtouniverseparticle::pt < ConfTrackPtHigh); + (aod::femtouniverseparticle::sign == confTrackSign) && + (aod::femtouniverseparticle::pt > confTrackPtLow) && + (aod::femtouniverseparticle::pt < confTrackPtHigh); Partition partsTrackMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && - (aod::femtouniverseparticle::sign == ConfTrackSign) && - (aod::femtouniverseparticle::pt > ConfTrackPtLow) && - (aod::femtouniverseparticle::pt < ConfTrackPtHigh); + (aod::femtouniverseparticle::sign == confTrackSign) && + (aod::femtouniverseparticle::pt > confTrackPtLow) && + (aod::femtouniverseparticle::pt < confTrackPtHigh); /// Particle 2 --- PHI MESON - Configurable ConfPhiPtLow{"ConfPhiPtLow", 0.8, "Lower limit of the Phi pT."}; - Configurable ConfPhiPtHigh{"ConfPhiPtHigh", 4.0, "Higher limit of the Phi pT."}; + Configurable confPhiPtLow{"confPhiPtLow", 0.8, "Lower limit of the Phi pT."}; + Configurable confPhiPtHigh{"confPhiPtHigh", 4.0, "Higher limit of the Phi pT."}; Configurable confInvMassLowLimitPhi{"confInvMassLowLimitPhi", 1.011, "Lower limit of the Phi invariant mass"}; // change that to do invariant mass cut Configurable confInvMassUpLimitPhi{"confInvMassUpLimitPhi", 1.027, "Upper limit of the Phi invariant mass"}; /// Partitions for the Phi meson (particle 2) Partition partsPhi = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)) && - (aod::femtouniverseparticle::pt > ConfPhiPtLow) && - (aod::femtouniverseparticle::pt < ConfPhiPtHigh) && + (aod::femtouniverseparticle::pt > confPhiPtLow) && + (aod::femtouniverseparticle::pt < confPhiPtHigh) && (aod::femtouniverseparticle::tempFitVar > confInvMassLowLimitPhi) && (aod::femtouniverseparticle::tempFitVar < confInvMassUpLimitPhi); Partition partsPhiMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)) && - (aod::femtouniverseparticle::pt > ConfPhiPtLow) && - (aod::femtouniverseparticle::pt < ConfPhiPtHigh) && + (aod::femtouniverseparticle::pt > confPhiPtLow) && + (aod::femtouniverseparticle::pt < confPhiPtHigh) && (aod::femtouniverseparticle::tempFitVar > confInvMassLowLimitPhi) && (aod::femtouniverseparticle::tempFitVar < confInvMassUpLimitPhi); @@ -169,21 +185,21 @@ struct FemtoUniversePairTaskTrackPhi { FemtoUniverseEventHisto eventHisto; /// particle part - ConfigurableAxis ConfBinsTempFitVar{"ConfBinsTempFitVar", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarInvMass{"ConfBinsTempFitVarInvMass", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarpT{"ConfBinsTempFitVarpT", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarPDG{"ConfBinsTempFitVarPDG", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarDCA{"ConfBinsTempFitVarDCA", {300, -3.0, 3.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVar{"confBinsTempFitVar", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarInvMass{"confBinsTempFitVarInvMass", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarpT{"confBinsTempFitVarpT", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarPDG{"confBinsTempFitVarPDG", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarDCA{"confBinsTempFitVarDCA", {300, -3.0, 3.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis ConfBinsMult{"ConfBinsMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task - ConfigurableAxis ConfBinsVtx{"ConfBinsVtx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfBins3DmT{"ConfBins3DmT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfBins3Dmult{"ConfBins3Dmult", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confBinsMult{"confBinsMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task + ConfigurableAxis confBinsVtx{"confBinsVtx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis confBins3DmT{"confBins3DmT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confBins3Dmult{"confBins3Dmult", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfBinskstar{"ConfBinskstar", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfBinskT{"ConfBinskT", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfBinsmT{"ConfBinsmT", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis confBinskstar{"confBinskstar", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confBinskT{"confBinskT", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confBinsmT{"confBinsmT", {225, 0., 7.5}, "binning mT"}; FemtoUniverseContainer sameEventCont; FemtoUniverseContainer mixedEventCont; @@ -201,158 +217,92 @@ struct FemtoUniversePairTaskTrackPhi { HistogramRegistry registryDCA{"registryDCA", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry registryMCpT{"registryMCpT", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - ColumnBinningPolicy colBinning{{ConfBinsVtx, ConfBinsMult}, true}; + ColumnBinningPolicy colBinning{{confBinsVtx, confBinsMult}, true}; HistogramRegistry effCorrRegistry{"EfficiencyCorrection", {}, OutputObjHandlingPolicy::AnalysisObject}; EffCorConfigurableGroup effCorConfGroup; EfficiencyCorrection effCorrection{&effCorConfGroup}; - float weight = 1; + float mWeight = 1.0f; // PID for protons bool isProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx { - if (mom < ConfTrackPtPIDLimit) { - if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaTPC) { - return true; - } else { - return false; - } - } else if (mom > ConfTrackPtPIDLimit) { - if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaCombined) { - return true; - } else { - return false; - } + if (mom < confTrackPtPIDLimit) { + return std::abs(nsigmaTPCPr) < confPIDProtonNsigmaTPC; } - return false; + return std::hypot(nsigmaTOFPr, nsigmaTPCPr) < confPIDProtonNsigmaCombined; } bool isProtonRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - if (mom < 0.5) { + if (mom < kMomCutLow) { return true; } - if (mom > 0.5) { - if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaReject) { - return true; - } else if (std::hypot(nsigmaTOFK, nsigmaTPCK) < ConfPIDKaonNsigmaReject) { - return true; - } else { - return false; - } - } else { - return false; - } + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < confPIDPionNsigmaReject || std::hypot(nsigmaTOFK, nsigmaTPCK) < confPIDKaonNsigmaReject; } - bool isKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isKaonNSigma(float mom, bool hasTOF, float nsigmaTPCK, float nsigmaTOFK) { - if (mom < 0.3) { // 0.0-0.3 - if (std::abs(nsigmaTPCK) < 3.0) { - return true; - } else { - return false; - } - } else if (mom < 0.45) { // 0.30 - 0.45 - if (std::abs(nsigmaTPCK) < 2.0) { - return true; - } else { - return false; - } - } else if (mom < 0.55) { // 0.45-0.55 - if (std::abs(nsigmaTPCK) < 1.0) { - return true; - } else { - return false; + if (confTrackUseRun3PIDforKaons) { + if (mom < kMomCutLow) { + return std::abs(nsigmaTPCK) < kNSigmaStandard; } - } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) - if ((std::abs(nsigmaTOFK) < 3.0) && (std::abs(nsigmaTPCK) < 3.0)) { - { - return true; - } - } else { - return false; + if (hasTOF) { // if TOF is available, use combine nsigma + return std::hypot(nsigmaTOFK, nsigmaTPCK) < kNSigmaStandard; } - } else if (mom > 1.5) { // 1.5 - - if ((std::abs(nsigmaTOFK) < 2.0) && (std::abs(nsigmaTPCK) < 3.0)) { - return true; - } else { - return false; - } - } else { - return false; + // if TOF is not available, use TPC nsigma + return std::abs(nsigmaTPCK) < kNSigmaStandard; + } + + if (mom < kMomCutKaonLow) { // 0.0-0.3 + return std::abs(nsigmaTPCK) < kNSigmaStandard; + } + if (mom < kMomCutKaonMid) { // 0.30 - 0.45 + return std::abs(nsigmaTPCK) < kNSigmaMedium; + } + if (mom < kMomCutKaonHigh) { // 0.45-0.55 + return std::abs(nsigmaTPCK) < kNSigmaStrict; } + if (mom < kMomCutKaonMax) { // 0.55-1.5 (now we use TPC and TOF) + return std::hypot(nsigmaTOFK, nsigmaTPCK) < kNSigmaStandard; + } + if (mom > kMomCutKaonMax) { // 1.5 - + return (std::abs(nsigmaTOFK) < kNSigmaMedium) && (std::abs(nsigmaTPCK) < kNSigmaStandard); + } + return false; } bool isKaonRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi) { - if (mom < 0.5) { - if (std::abs(nsigmaTPCPi) < ConfPIDPionNsigmaReject) { - return true; - } else if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } - } - if (mom > 0.5) { - if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaReject) { - return true; - } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } else { - return false; - } - } else { - return false; + if (mom < kMomCutLow) { + return (std::abs(nsigmaTPCPi) < confPIDPionNsigmaReject) || (std::abs(nsigmaTPCPr) < confPIDProtonNsigmaReject); } + return (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < confPIDPionNsigmaReject) || (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < confPIDProtonNsigmaReject); } bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) { - if (true) { - if (mom < 0.5) { - if (std::abs(nsigmaTPCPi) < ConfPIDPionNsigmaTPC) { - return true; - } else { - return false; - } - } else if (mom > 0.5) { - if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaCombined) { - return true; - } else { - return false; - } - } + if (mom < kMomCutLow) { + return (std::abs(nsigmaTPCPi) < confPIDPionNsigmaTPC); } - return false; + return (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < confPIDPionNsigmaCombined); } bool isPionRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCK, float nsigmaTOFK) { - if (mom < 0.5) { - if (std::abs(nsigmaTPCK) < ConfPIDKaonNsigmaReject) { - return true; - } else if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } - } - if (mom > 0.5) { - if (std::hypot(nsigmaTOFK, nsigmaTPCK) < ConfPIDKaonNsigmaReject) { - return true; - } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } else { - return false; - } - } else { - return false; + if (mom < kMomCutLow) { + return (std::abs(nsigmaTPCK) < confPIDKaonNsigmaReject) || (std::abs(nsigmaTPCPr) < confPIDProtonNsigmaReject); } + return (std::hypot(nsigmaTOFK, nsigmaTPCK) < confPIDKaonNsigmaReject) || (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < confPIDProtonNsigmaReject); } bool isParticleNSigmaAccepted(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - switch (ConfTrackPDGCode) { + bool hasTOF = std::isfinite(nsigmaTOFPr) || std::isfinite(nsigmaTOFPi) || std::isfinite(nsigmaTOFK); + + switch (confTrackPDGCode) { case 2212: // Proton case -2212: // anty Proton return isProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); @@ -363,7 +313,7 @@ struct FemtoUniversePairTaskTrackPhi { break; case 321: // Kaon+ case -321: // Kaon- - return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + return isKaonNSigma(mom, hasTOF, nsigmaTPCK, nsigmaTOFK); break; default: return false; @@ -372,7 +322,7 @@ struct FemtoUniversePairTaskTrackPhi { bool isParticleNSigmaRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - switch (ConfTrackPDGCode) { + switch (confTrackPDGCode) { case 2212: // Proton case -2212: // anty Proton return isProtonRejected(mom, nsigmaTPCPi, nsigmaTOFPi, nsigmaTPCK, nsigmaTOFK); @@ -398,8 +348,8 @@ struct FemtoUniversePairTaskTrackPhi { void init(InitContext&) { - if (ConfIsMC) { - hTrackDCA.init(®istryDCA, ConfBinsTempFitVarpT, ConfBinsTempFitVarDCA, true, ConfTrackPDGCode, true); + if (confIsMC) { + hTrackDCA.init(®istryDCA, confBinsTempFitVarpT, confBinsTempFitVarDCA, true, confTrackPDGCode, true); registryMCpT.add("MCReco/C_phi_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); registryMCpT.add("MCReco/NC_phi_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); @@ -411,9 +361,9 @@ struct FemtoUniversePairTaskTrackPhi { effCorrection.init( &effCorrRegistry, { - static_cast(ConfBinsTempFitVarpT), - {ConfBinsEta, -1, 1}, - ConfBinsMult, + static_cast(confBinsTempFitVarpT), + {confBinsEta, -1, 1}, + confBinsMult, }); eventHisto.init(&qaRegistry); @@ -480,30 +430,30 @@ struct FemtoUniversePairTaskTrackPhi { registryMCreco.add("MCrecoPhi", "MC reco Phi;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); registryMCreco.add("MCrecoPhiPt", "MC reco Phi; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{500, 0, 5}}); - trackHistoPartPhi.init(&qaRegistry, ConfBinsTempFitVarpT, ConfBinsTempFitVarInvMass, ConfIsMC, 333); - trackHistoPartTrack.init(&qaRegistry, ConfBinsTempFitVarpT, ConfBinsTempFitVar, ConfIsMC, ConfTrackPDGCode); + trackHistoPartPhi.init(&qaRegistry, confBinsTempFitVarpT, confBinsTempFitVarInvMass, confIsMC, 333); + trackHistoPartTrack.init(&qaRegistry, confBinsTempFitVarpT, confBinsTempFitVar, confIsMC, confTrackPDGCode); mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - sameEventCont.init(&resultRegistry, ConfBinskstar, ConfBinsMult, ConfBinskT, ConfBinsmT, ConfBins3Dmult, ConfBins3DmT, ConfBinsEta, ConfBinsPhi, ConfIsMC, ConfUse3D); - mixedEventCont.init(&resultRegistry, ConfBinskstar, ConfBinsMult, ConfBinskT, ConfBinsmT, ConfBins3Dmult, ConfBins3DmT, ConfBinsEta, ConfBinsPhi, ConfIsMC, ConfUse3D); + sameEventCont.init(&resultRegistry, confBinskstar, confBinsMult, confBinskT, confBinsmT, confBins3Dmult, confBins3DmT, confBinsEta, confBinsPhi, confIsMC, confUse3D); + mixedEventCont.init(&resultRegistry, confBinskstar, confBinsMult, confBinskT, confBinsmT, confBins3Dmult, confBins3DmT, confBinsEta, confBinsPhi, confIsMC, confUse3D); - sameEventCont.setPDGCodes(333, ConfTrackPDGCode); - mixedEventCont.setPDGCodes(333, ConfTrackPDGCode); + sameEventCont.setPDGCodes(333, confTrackPDGCode); + mixedEventCont.setPDGCodes(333, confTrackPDGCode); pairCleaner.init(&qaRegistry); - if (ConfCPRIsEnabled) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, confDeltaEtaAxis, confDeltaPhiStarAxis, ConfCPRdeltaPhiCutMin, ConfCPRdeltaPhiCutMax, ConfCPRdeltaEtaCutMin, ConfCPRdeltaEtaCutMax, ConfCPRChosenRadii, ConfCPRPlotPerRadii, ConfCPRInvMassCutMin, ConfCPRInvMassCutMax); + if (confCPRIsEnabled) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confDeltaEtaAxis, confDeltaPhiStarAxis, confCPRdeltaPhiCutMin, confCPRdeltaPhiCutMax, confCPRdeltaEtaCutMin, confCPRdeltaEtaCutMax, confCPRChosenRadii, confCPRPlotPerRadii, confCPRInvMassCutMin, confCPRInvMassCutMax); } } template - void doSameEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol, [[maybe_unused]] MCParticles mcParts = nullptr) + void doSameEvent(const PartitionType& groupPartsTrack, const PartitionType& groupPartsPhi, const PartType& parts, float magFieldTesla, int multCol, [[maybe_unused]] const MCParticles& mcParts = nullptr) { for (auto const& phicandidate : groupPartsPhi) { // TODO: add phi meson minv cut here - const auto& posChild = parts.iteratorAt(phicandidate.index() - 2); + const auto& posChild = parts.iteratorAt(phicandidate.index() - kPhiDaughterOffsetPos); float tpcNSigmaKp = trackCuts.getNsigmaTPC(posChild, o2::track::PID::Kaon); float tofNSigmaKp = trackCuts.getNsigmaTOF(posChild, o2::track::PID::Kaon); qaRegistry.fill(HIST("PhiDaugh_pos/nSigmaTPC"), posChild.p(), tpcNSigmaKp); @@ -513,7 +463,7 @@ struct FemtoUniversePairTaskTrackPhi { qaRegistry.fill(HIST("PhiDaugh_pos/eta"), posChild.eta()); qaRegistry.fill(HIST("PhiDaugh_pos/phi"), posChild.phi()); - const auto& negChild = parts.iteratorAt(phicandidate.index() - 1); + const auto& negChild = parts.iteratorAt(phicandidate.index() - kPhiDaughterOffsetNeg); float tpcNSigmaKm = trackCuts.getNsigmaTPC(negChild, o2::track::PID::Kaon); float tofNSigmaKm = trackCuts.getNsigmaTOF(negChild, o2::track::PID::Kaon); qaRegistry.fill(HIST("PhiDaugh_neg/nSigmaTPC"), negChild.p(), tpcNSigmaKm); @@ -526,7 +476,7 @@ struct FemtoUniversePairTaskTrackPhi { trackHistoPartPhi.fillQA(phicandidate); if constexpr (isMC) { // reco - effCorrection.fillRecoHist(phicandidate, 333); + effCorrection.fillRecoHist(phicandidate, o2::constants::physics::Pdg::kPhi); } } @@ -538,11 +488,11 @@ struct FemtoUniversePairTaskTrackPhi { float tpcNSigmaPr = trackCuts.getNsigmaTPC(track, o2::track::PID::Proton); float tofNSigmaPr = trackCuts.getNsigmaTOF(track, o2::track::PID::Proton); - if (ConfTrackIsIdentified) { + if (confTrackIsIdentified) { if (!isParticleNSigmaAccepted(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { continue; } - if (ConfTrackIsRejected) { + if (confTrackIsRejected) { if (isParticleNSigmaRejected(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { continue; } @@ -566,26 +516,26 @@ struct FemtoUniversePairTaskTrackPhi { trackHistoPartTrack.fillQA(track); if constexpr (isMC) { - effCorrection.fillRecoHist(track, ConfTrackPDGCode); + effCorrection.fillRecoHist(track, confTrackPDGCode); } } /// Now build the combinations for (auto const& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { - if (ConfTrackIsIdentified) { + if (confTrackIsIdentified) { if (!isParticleNSigmaAccepted(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } - if (ConfTrackIsRejected) { + if (confTrackIsRejected) { if (isParticleNSigmaRejected(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } // Close Pair Rejection - if (ConfCPRIsEnabled) { + if (confCPRIsEnabled) { if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } @@ -595,8 +545,8 @@ struct FemtoUniversePairTaskTrackPhi { if (!pairCleaner.isCleanPair(track, phicandidate, parts)) { continue; } - weight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); - sameEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + mWeight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); + sameEventCont.setPair(track, phicandidate, multCol, confUse3D, mWeight); } // // Used for better fitting of invariant mass background. @@ -627,27 +577,27 @@ struct FemtoUniversePairTaskTrackPhi { } template - void doMixedEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol, [[maybe_unused]] MCParticles mcParts = nullptr) + void doMixedEvent(const PartitionType& groupPartsTrack, const PartitionType& groupPartsPhi, const PartType& parts, float magFieldTesla, int multCol, [[maybe_unused]] const MCParticles& mcParts = nullptr) { for (auto const& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { - if (ConfTrackIsIdentified) { + if (confTrackIsIdentified) { if (!isParticleNSigmaAccepted(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } - if (ConfTrackIsRejected) { + if (confTrackIsRejected) { if (isParticleNSigmaRejected(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } } - if (ConfCPRIsEnabled) { + if (confCPRIsEnabled) { if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } - weight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); - mixedEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + mWeight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); + mixedEventCont.setPair(track, phicandidate, multCol, confUse3D, mWeight); } } @@ -718,8 +668,9 @@ struct FemtoUniversePairTaskTrackPhi { void processMCTruth(aod::FDParticles const& parts) { for (auto const& part : parts) { - if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { continue; + } int pdgCode = static_cast(part.pidCut()); const auto& pdgParticle = pdgMC->GetParticle(pdgCode); @@ -727,25 +678,26 @@ struct FemtoUniversePairTaskTrackPhi { continue; } - if (pdgCode == ConfTrackPDGCode) { + if (pdgCode == confTrackPDGCode) { effCorrection.fillTruthHist(part); } // charge + if (pdgParticle->Charge() > 0.0) { registryMCtruth.fill(HIST("MCtruthAllPositivePt"), part.pt()); - if (pdgCode == 2212) { + if (pdgCode == kProton) { registryMCtruth.fill(HIST("MCtruthPpos"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthPposPt"), part.pt()); continue; - } else if (pdgCode == 321) { + } + if (pdgCode == kKPlus) { registryMCtruth.fill(HIST("MCtruthKp"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthKpPt"), part.pt()); continue; } } // charge 0 - if (pdgCode == 333) { + if (pdgCode == o2::constants::physics::Pdg::kPhi) { registryMCtruth.fill(HIST("MCtruthPhi"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthPhiPt"), part.pt()); effCorrection.fillTruthHist(part); @@ -756,11 +708,12 @@ struct FemtoUniversePairTaskTrackPhi { if (pdgParticle->Charge() < 0.0) { registryMCtruth.fill(HIST("MCtruthAllNegativePt"), part.pt()); - if (pdgCode == -321) { + if (pdgCode == kKMinus) { registryMCtruth.fill(HIST("MCtruthKm"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthKmPt"), part.pt()); continue; - } else if (pdgCode == -2212) { + } + if (pdgCode == kProtonBar) { registryMCtruth.fill(HIST("MCtruthPneg"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthPnegPt"), part.pt()); continue; @@ -774,36 +727,38 @@ struct FemtoUniversePairTaskTrackPhi { { for (auto const& part : parts) { auto mcPartId = part.fdMCParticleId(); - if (mcPartId == -1) + if (mcPartId == kInvalidMCPartId) { continue; // no MC particle + } const auto& mcpart = mcparts.iteratorAt(mcPartId); - if (mcpart.pdgMCTruth() == ConfTrackPDGCode && (part.pt() > ConfTrackPtLow) && (part.pt() < ConfTrackPtHigh) && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (mcpart.pdgMCTruth() == confTrackPDGCode && (part.pt() > confTrackPtLow) && (part.pt() < confTrackPtHigh) && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { registryMCpT.fill(HIST("MCReco/NC_p_pT"), part.pt()); float weightTrack = effCorrection.getWeight(ParticleNo::TWO, part); registryMCpT.fill(HIST("MCReco/C_p_pT"), part.pt(), weightTrack); } - if ((mcpart.pdgMCTruth() == 333) && (part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (part.pt() > ConfPhiPtLow) && (part.pt() < ConfPhiPtHigh)) { + if ((mcpart.pdgMCTruth() == o2::constants::physics::Pdg::kPhi) && (part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (part.pt() > confPhiPtLow) && (part.pt() < confPhiPtHigh)) { registryMCpT.fill(HIST("MCReco/NC_phi_pT"), part.pt()); float weightPhi = effCorrection.getWeight(ParticleNo::ONE, part); registryMCpT.fill(HIST("MCReco/C_phi_pT"), part.pt(), weightPhi); } - if (isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) + if (isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { hTrackDCA.fillQA(part); - if ((part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (mcpart.pdgMCTruth() == 333) && (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { + } + if ((part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (mcpart.pdgMCTruth() == o2::constants::physics::Pdg::kPhi) && (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { registryMCreco.fill(HIST("MCrecoPhi"), mcpart.pt(), mcpart.eta()); // phi registryMCreco.fill(HIST("MCrecoPhiPt"), mcpart.pt()); } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { if (part.sign() > 0) { registryMCreco.fill(HIST("MCrecoAllPositivePt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == 2212 && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (mcpart.pdgMCTruth() == kProton && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { registryMCreco.fill(HIST("MCrecoPpos"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("MCrecoPposPt"), mcpart.pt()); } } else if (part.sign() < 0) { registryMCreco.fill(HIST("MCrecoAllNegativePt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == -2212 && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (mcpart.pdgMCTruth() == kProtonBar && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { registryMCreco.fill(HIST("MCrecoPneg"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("MCrecoPnegPt"), mcpart.pt()); } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx index 81642eda36d..24cd5ab2610 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx @@ -76,6 +76,9 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { Configurable isNsigmaRectangular{"isNsigmaRectangular", false, "Apply rectangular TPC and TOF nSigma cut, instead of a combined one (TPC confNsigmaCombined{"confNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > confTOFpMin"}; Configurable confNsigmaTPC{"confNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < confTOFpMin"}; + Configurable confNsigmaKaonRejection{"confNsigmaKaonRejection", 0, "In proton selection reject tracks with combined Nsigma confNsigmaPionRejection{"confNsigmaPionRejection", 0, "In proton selection reject tracks with combined Nsigma confTOFpMin{"confTOFpMin", 0.5f, "Min. momentum for which TOF is required for PID."}; Configurable confEtaMax{"confEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; @@ -87,8 +90,8 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { } twotracksconfigs; struct : o2::framework::ConfigurableGroup { - Configurable confTrkTPCnclsMin{"confTrkTPCnclsMin", 0, "Track selection: "}; - Configurable confTrkTPCcRowsMin{"confTrkTPCcRowsMin", 0, "Track selection: "}; + Configurable confTrkTPCnclsMin{"confTrkTPCnclsMin", 0, "Min. TPC clusters"}; + Configurable confTrkTPCcRowsMin{"confTrkTPCcRowsMin", 0, "Min. TPC crossed rows"}; Configurable confDcaXYCustom1FilterCut{"confDcaXYCustom1FilterCut", 10, "Value for [1] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT"}; Configurable confDcaXYCustom2FilterCut{"confDcaXYCustom2FilterCut", 0, "Value for [2] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT"}; } additionalcuts; @@ -280,6 +283,30 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { return std::hypot(nsigmaTOF, nsigmaTPC) < twotracksconfigs.confNsigmaCombined; } + bool isNSigmaProton(float mom, float nsigmaTPC, float nsigmaTOF, float nsigmaTPCkaon, float nsigmaTOFkaon, float nsigmaTPCpion, float nsigmaTOFpion) + { + // with additional nSigma kaon and pion rejection + if (mom < twotracksconfigs.confTOFpMin) { + if (std::abs(nsigmaTPCkaon) < twotracksconfigs.confNsigmaKaonRejection || std::abs(nsigmaTPCpion) < twotracksconfigs.confNsigmaPionRejection) { + return false; + } + } else if (std::hypot(nsigmaTOFkaon, nsigmaTPCkaon) < twotracksconfigs.confNsigmaKaonRejection || std::hypot(nsigmaTOFpion, nsigmaTPCpion) < twotracksconfigs.confNsigmaPionRejection) { + return false; + } + + if (twotracksconfigs.isNsigmaRectangular) { + if (mom < twotracksconfigs.confTOFpMin) { + return std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC; + } + return (std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC && std::abs(nsigmaTOF) < twotracksconfigs.confNsigmaCombined); + } + + if (mom < twotracksconfigs.confTOFpMin) { + return std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC; + } + return std::hypot(nsigmaTOF, nsigmaTPC) < twotracksconfigs.confNsigmaCombined; + } + /// TPC Kaon Sigma selection (stricter cuts for K+ and K-) -- based on Run2 results bool isKaonNsigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { @@ -313,7 +340,7 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { switch (trackonefilter.confPDGCodePartOne) { case kProton: case kProtonBar: - return isNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isNSigmaProton(mom, nsigmaTPCPr, nsigmaTOFPr, nsigmaTPCK, nsigmaTOFK, nsigmaTPCPi, nsigmaTOFPi); case kPiPlus: case kPiMinus: case kPi0: @@ -331,7 +358,7 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { switch (tracktwofilter.confPDGCodePartTwo) { case kProton: case kProtonBar: - return isNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isNSigmaProton(mom, nsigmaTPCPr, nsigmaTOFPr, nsigmaTPCK, nsigmaTOFK, nsigmaTPCPi, nsigmaTOFPi); case kPiPlus: case kPiMinus: case kPi0: diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx index 7db9bd0aae5..a3ec2c9f607 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx @@ -25,8 +25,10 @@ #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include +#include #include #include #include @@ -49,7 +51,6 @@ #include #include -#include #include #include #include @@ -71,9 +72,9 @@ using namespace o2::aod::pidutils; using namespace o2::track; using namespace o2::analysis::femto_universe::efficiency_correction; -struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-type-member-init) +struct FemtoUniversePairTaskTrackV0Extended { - Service pdgMC; + Service pdgMC{}; SliceCache cache; using FemtoFullParticles = soa::Join; @@ -97,21 +98,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty Configurable confChargePart1{"confChargePart1", 0, "sign of particle 1"}; Configurable confHPtPart1{"confHPtPart1", 4.0f, "higher limit for pt of particle 1"}; Configurable confLPtPart1{"confLPtPart1", 0.3f, "lower limit for pt of particle 1"}; + Configurable confTrkTPCnclsMin{"confTrkTPCnclsMin", 0, "Min. TPC clusters (if stricter than in Producer)"}; + Configurable confTrkTPCcRowsMin{"confTrkTPCcRowsMin", 0, "Min. TPC crossed rows (if stricter than in Producer)"}; + Configurable confDcaXYCustom1FilterCut{"confDcaXYCustom1FilterCut", 10, "Value for [1] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT (if stricter than in Producer)"}; + Configurable confDcaXYCustom2FilterCut{"confDcaXYCustom2FilterCut", 0, "Value for [2] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT (if stricter than in Producer)"}; } ConfTrkSelection; - Configurable confmom{"confmom", 0.5, "momentum threshold for particle identification using TOF"}; - Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < confmom"}; - Configurable confNsigmaTPCDaughter{"confNsigmaTPCDaughter", 3.0, "TPC Sigma for daughter"}; - - Configurable confNsigmaTOFParticle{"confNsigmaTOFParticle", 3.0, "TOF Sigma for particle (daugh & bach) momentum > Confmom"}; - Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > confmom"}; + struct : o2::framework::ConfigurableGroup { + Configurable confmom{"confmom", 0.5, "momentum threshold for particle identification using TOF"}; + Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < ConfNSigmaSelection.confmom"}; + Configurable confNsigmaTPCDaughter{"confNsigmaTPCDaughter", 3.0, "TPC Sigma for daughter"}; + Configurable confNsigmaTOFParticle{"confNsigmaTOFParticle", 3.0, "TOF Sigma for particle (daugh & bach) momentum > ConfNSigmaSelection.confmom"}; + Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > ConfNSigmaSelection.confmom"}; + Configurable confNsigmaKaonRejection{"confNsigmaKaonRejection", 0, "In proton selection reject tracks with kaon Nsigma confNsigmaPionRejection{"confNsigmaPionRejection", 0, "In proton selection reject tracks with pion Nsigma ; using FilteredFDCollision = FilteredFDCollisions::iterator; /// Partition for particle 1 using extended table (track) - Partition partsOneFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(ConfTrkSelection.confChargePart1)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1); + Partition partsOneFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(ConfTrkSelection.confChargePart1)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1) && (nabs(aod::track::dcaXY) < (ConfTrkSelection.confDcaXYCustom1FilterCut + ConfTrkSelection.confDcaXYCustom2FilterCut / aod::femtouniverseparticle::pt)) && (aod::femtouniverseparticle::tpcNClsFound) > as(ConfTrkSelection.confTrkTPCnclsMin) && (aod::femtouniverseparticle::tpcNClsCrossedRows) > as(ConfTrkSelection.confTrkTPCcRowsMin); Partition partsOneMCFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1); Partition partsOneMCRecoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(ConfTrkSelection.confChargePart1)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1); @@ -146,8 +154,20 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty Configurable confSeparateInvMassCheck{"confSeparateInvMassCheck", false, "Apply additional cut separate for mLambda and mAntiLambda"}; } ConfV0Selection; + struct : o2::framework::ConfigurableGroup { + Configurable confV0MinCosPA{"confV0MinCosPA", 0, "Min. V0 cosine of piontinh angle (if stricter than in Producer)"}; + Configurable confV0DaughMaxDCA{"confV0DaughMaxDCA", 1000, "Max. DCA of V0 daughters (if stricter than in Producer)"}; + Configurable confV0MinTransRadius{"confV0MinTransRadius", 0, "Min. transverse radius of V0 (if stricter than in Producer)"}; + Configurable confV0MaxRadius{"confV0MaxRadius", 1000, "Max. decay radius of V0 (if stricter than in Producer)"}; + Configurable confV0DaughMinPvDCAxy{"confV0DaughMinPvDCAxy", 0, "Min. DCAxy to primary vertex of V0 daughters (if stricter than in Producer)"}; // to już w córkach, nie da się dać w partycji niestety + Configurable confV0DaughMinTPCCls{"confV0DaughMinTPCCls", 0, "Min. number of TPC clusters for V0 daughters (if stricter than in Producer)"}; + } additionalcutsV0; + /// Partition for particle 2 using extended table - Partition partsTwoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2); + Partition + partsTwoFull = (aod::femtouniverseparticle::decayVtxX < additionalcutsV0.confV0MaxRadius && aod::femtouniverseparticle::decayVtxY < additionalcutsV0.confV0MaxRadius && aod::femtouniverseparticle::decayVtxZ < additionalcutsV0.confV0MaxRadius && + aod::femtouniverseparticle::transRadius > additionalcutsV0.confV0MinTransRadius && aod::femtouniverseparticle::daughDCA < additionalcutsV0.confV0DaughMaxDCA && aod::femtouniverseparticle::tempFitVar > additionalcutsV0.confV0MinCosPA && + aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2)); Partition partsTwoMCFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2); Partition partsTwoMCRecoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2); @@ -213,8 +233,8 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty EffCorConfigurableGroup effCorConfGroup; EfficiencyCorrection effCorrection{&effCorConfGroup}; - static constexpr std::array, 3> V0ChildTable = {{{0, 1}, {1, 0}, {1, 1}}}; // Table to select the V0 children - static constexpr std::array v0InvMass = {1.115, 1.115, 0.497}; // Table to select invariant mass of V0s + static constexpr std::array, 3> V0ChildTable = {{{0, 1}, {1, 0}, {1, 1}}}; // Table to select the V0 children + static constexpr std::array V0InvMass = {o2::constants::physics::MassLambda0, o2::constants::physics::MassLambda0Bar, o2::constants::physics::MassK0}; // Table to select invariant mass of V0s FemtoUniverseContainer sameEventCont; FemtoUniverseContainer mixedEventCont; @@ -233,17 +253,17 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::unique_ptr plocalEffFile; std::unique_ptr pEffHistp1; std::unique_ptr pEffHistp2; - Service ccdb; + Service ccdb{}; TRandom2* randgen = 0; bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle, bool hasTOF) { - if (mom <= confmom) { - return (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle); + if (mom <= ConfNSigmaSelection.confmom) { + return (std::abs(nsigmaTPCParticle) < ConfNSigmaSelection.confNsigmaTPCParticle); } if (hasTOF) { - return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < confNsigmaCombinedParticle); + return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < ConfNSigmaSelection.confNsigmaCombinedParticle); } return false; } @@ -251,7 +271,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty template bool isNSigmaCombinedBitmask(float mom, const T& part) { - if (mom <= confmom) { + if (mom <= ConfNSigmaSelection.confmom) { return ((part.pidCut() & (1u << ConfTrkSelection.confTrackChoicePartOne)) != 0); } if ((part.pidCut() & 512u) != 0) { @@ -277,14 +297,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty bool isNSigmaTPC(float nsigmaTPCParticle) { - return std::abs(nsigmaTPCParticle) < confNsigmaTPCDaughter; + return std::abs(nsigmaTPCParticle) < ConfNSigmaSelection.confNsigmaTPCDaughter; } bool isNSigmaTOF(float mom, float nsigmaTOFParticle, bool hasTOF) { // Cut only on daughter tracks, that have TOF signal - if (mom > confmom && hasTOF) { - return std::abs(nsigmaTOFParticle) < confNsigmaTOFParticle; + if (mom > ConfNSigmaSelection.confmom && hasTOF) { + return std::abs(nsigmaTOFParticle) < ConfNSigmaSelection.confNsigmaTOFParticle; } return true; } @@ -294,7 +314,19 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty { const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + enum particleID { protonId, + pionId, + kaonId }; + if (id == protonId) { + if (part.p() < ConfNSigmaSelection.confmom) { + if (std::abs(tpcNSigmas[kaonId]) < ConfNSigmaSelection.confNsigmaKaonRejection || std::abs(tpcNSigmas[pionId]) < ConfNSigmaSelection.confNsigmaPionRejection) { + return false; + } + } else if (std::hypot(tofNSigmas[kaonId], tpcNSigmas[kaonId]) < ConfNSigmaSelection.confNsigmaKaonRejection || std::hypot(tofNSigmas[pionId], tpcNSigmas[pionId]) < ConfNSigmaSelection.confNsigmaPionRejection) { + return false; + } + } return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id], (part.pidCut() & 512u) != 0); } @@ -430,8 +462,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty if (!ccdbEffLoader.confLocalEfficiency.value.empty()) { plocalEffFile = std::unique_ptr(TFile::Open(ccdbEffLoader.confLocalEfficiency.value.c_str(), "read")); - if (!plocalEffFile || plocalEffFile.get()->IsZombie()) + if (!plocalEffFile || plocalEffFile.get()->IsZombie()) { LOGF(fatal, "Could not load efficiency histogram from %s", ccdbEffLoader.confLocalEfficiency.value.c_str()); + } if (doprocessSameEvent || doprocessSameEventBitmask || doprocessMixedEvent || doprocessMixedEventBitmask) { pEffHistp1 = (ConfTrkSelection.confChargePart1 > 0) ? std::unique_ptr(plocalEffFile.get()->Get("PrPlus")) : std::unique_ptr(plocalEffFile.get()->Get("PrMinus")); // note: works only for protons pEffHistp2 = (ConfV0Selection.confV0Type1 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); @@ -461,8 +494,17 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty effCorrection.init(&qaRegistry, {static_cast(ConfV0Selection.confV0TempFitVarpTBins), {confEtaBins, -2, 2}, confMultBins}); } + template + bool checkDaughter(PartType const& posChild, PartType const& negChild) + { + if (std::abs(posChild.dcaXY()) < additionalcutsV0.confV0DaughMinPvDCAxy || std::abs(negChild.dcaXY()) < additionalcutsV0.confV0DaughMinPvDCAxy) { + return false; + } + return (posChild.tpcNClsFound() > additionalcutsV0.confV0DaughMinTPCCls && negChild.tpcNClsFound() > additionalcutsV0.confV0DaughMinTPCCls); + } + template - using hasSigma = decltype(std::declval().tpcNSigmaStorePr()); + using HasSigma = decltype(std::declval().tpcNSigmaStorePr()); /// This function processes the same event for track - V0 template @@ -473,7 +515,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); @@ -482,8 +524,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty /// Histogramming same event for (const auto& part : groupPartsTwo) { - if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); @@ -492,27 +535,34 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + if (!checkDaughter(posChild, negChild)) { continue; + } trackHistoPartTwo.fillQA(part); posChildHistos.fillQA(posChild); negChildHistos.fillQA(negChild); } else { - if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (part.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (part.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (part.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (part.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (part.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (part.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } trackHistoPartTwo.fillQA(part); posChildHistos.fillQA(posChild); @@ -521,13 +571,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } for (const auto& part : groupPartsOne) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { /// PID plot for particle 1 const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) + if (!isParticleCombined(part, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } if (part.sign() > 0) { qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne]); qaRegistry.fill(HIST("Tracks_pos/nSigmaTOF"), part.p(), tofNSigmas[ConfTrkSelection.confTrackChoicePartOne]); @@ -538,27 +589,33 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty trackHistoPartOneNeg.fillQA(part); } } else { - if (!isNSigmaCombinedBitmask(part.p(), part)) + if (!isNSigmaCombinedBitmask(part.p(), part)) { continue; - if (ConfTrkSelection.confChargePart1 > 0) + } + if (ConfTrkSelection.confChargePart1 > 0) { trackHistoPartOnePos.fillQA(part); - if (ConfTrkSelection.confChargePart1 < 0) + } + if (ConfTrkSelection.confChargePart1 < 0) { trackHistoPartOnePos.fillQA(part); + } } } /// Now build the combinations for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut - if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } /// PID using stored binned nsigma - if constexpr (std::experimental::is_detected::value) { - if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } } else { - if (!isNSigmaCombinedBitmask(p1.p(), p1)) + if (!isNSigmaCombinedBitmask(p1.p(), p1)) { continue; + } } // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { @@ -572,23 +629,32 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } + + if (!checkDaughter(posChild, negChild)) { + continue; + } } else { - if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } } @@ -599,12 +665,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } float weight = 1.0f; - if (pEffHistp1) + if (pEffHistp1) { weight = pEffHistp1.get()->GetBinContent(pEffHistp1->FindBin(p1.pt(), p1.eta())) * pEffHistp2.get()->GetBinContent(pEffHistp2->FindBin(p2.pt(), p2.eta())); - if constexpr (std::is_same::value) + } + if constexpr (std::is_same::value) { sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); - else + } else { sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } } } /// This function processes the same event for V0 - V0 @@ -613,7 +681,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty { const auto& magFieldTesla = col.magField(); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); @@ -632,13 +700,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Check daughters of first V0 particle - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; } if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; } + if (!checkDaughter(posChild, negChild)) { + continue; + } trackHistoV0Type1.fillQABase(part, HIST("V0Type1")); posChildV0Type1.fillQABase(posChild, HIST("posChildV0Type1")); @@ -679,13 +750,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Check daughters of second V0 particle - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; } if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; } + if (!checkDaughter(posChild, negChild)) { + continue; + } trackHistoV0Type2.fillQABase(part, HIST("V0Type2")); posChildV0Type2.fillQABase(posChild, HIST("posChildV0Type2")); @@ -728,7 +802,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { // mark for rejection the v0 that shares a daughter with another v0 and has an invariant mass further from default value. Set confV0DuplCosPA as TRUE to do the same check with cosPA instead. if (!ConfV0Selection.confV0DuplCosPA) { - if (std::abs(p1.mLambda() - v0InvMass[ConfV0Selection.confV0Type1]) < std::abs(p2.mLambda() - v0InvMass[ConfV0Selection.confV0Type2])) { + if (std::abs(p1.mLambda() - V0InvMass[ConfV0Selection.confV0Type1]) < std::abs(p2.mLambda() - V0InvMass[ConfV0Selection.confV0Type2])) { v0Duplicates.insert(p2.globalIndex()); } else { v0Duplicates.insert(p1.globalIndex()); @@ -763,13 +837,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// p1 daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { return false; } if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { return false; } + if (!checkDaughter(posChild1, negChild1)) { + return false; + } } else { if ((posChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { return false; @@ -792,13 +869,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// p2 daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { return false; } if (!isParticleTOF(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { return false; } + if (!checkDaughter(posChild2, negChild2)) { + return false; + } } else { if ((posChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) { return false; @@ -818,12 +898,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty double rand = 0.0; auto part1 = p1; auto part2 = p2; + double randomizationValue = 0.5; if (ConfCPR.confRandomizeCPR) { randgen = new TRandom2(0); rand = randgen->Rndm(); - if (rand > 0.5) { + if (rand > randomizationValue) { part1 = p2; part2 = p1; } @@ -837,10 +918,11 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } } - if constexpr (std::is_same::value) + if constexpr (std::is_same::value) { sameEventCont.setPair(p1, p2, multCol, confUse3D); - else + } else { sameEventCont.setPair(p1, p2, multCol, confUse3D); + } return true; }; @@ -921,22 +1003,24 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty auto groupPartsOne = partsOneMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); /// Histogramming same event for (const auto& part : groupPartsTwo) { int pdgCode = static_cast(part.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode != kLambda0Bar)) { continue; + } trackHistoPartTwo.fillQA(part); } for (const auto& part : groupPartsOne) { int pdgCode = static_cast(part.pidCut()); - if (pdgCode != ConfTrkSelection.confTrkPDGCodePartOne) + if (pdgCode != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } const auto& pdgParticle = pdgMC->GetParticle(pdgCode); if (!pdgParticle) { continue; @@ -951,11 +1035,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty /// Now build the combinations for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) + if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } // track cleaning if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { @@ -972,7 +1058,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty void processMCSameEventV0(FilteredFDCollision const& col, FemtoFullParticles const& parts) { auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); @@ -1037,7 +1123,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::array, 3> v0DaughPtHighTable = {{{ConfV0Selection.confHPtChildProton, ConfV0Selection.confHPtChildPion}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildProton}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildPion}}}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -1051,15 +1137,18 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut - if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } /// PID using stored binned nsigma - if constexpr (std::experimental::is_detected::value) { - if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } } else { - if (!isNSigmaCombinedBitmask(p1.p(), p1)) + if (!isNSigmaCombinedBitmask(p1.p(), p1)) { continue; + } } const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); @@ -1069,20 +1158,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + if (!checkDaughter(posChild, negChild)) { continue; + } } else { - if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } } @@ -1096,13 +1193,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } } float weight = 1.0f; - if (pEffHistp1) + if (pEffHistp1) { weight = pEffHistp1.get()->GetBinContent(pEffHistp1->FindBin(p1.pt(), p1.eta())) * pEffHistp2.get()->GetBinContent(pEffHistp2->FindBin(p2.pt(), p2.eta())); - - if constexpr (std::is_same::value) + } + if constexpr (std::is_same::value) { mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); - else + } else { mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } } }; @@ -1130,7 +1228,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::array, 3> v0DaughPtHighTable = {{{ConfV0Selection.confHPtChildProton, ConfV0Selection.confHPtChildPion}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildProton}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildPion}}}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -1160,20 +1258,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!checkDaughter(posChild1, negChild1)) { continue; + } } else { - if ((posChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (p1.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p1.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p1.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (p1.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p1.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p1.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } } @@ -1184,20 +1290,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; - if (!isParticleTOF(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + } + if (!isParticleTOF(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; + } + if (!checkDaughter(posChild2, negChild2)) { + continue; + } } else { - if ((posChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) + if ((posChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type2 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type2 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type2 == 2) && (p2.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type2 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type2 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type2 == 2) && (p2.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) + if ((posChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) { continue; + } } } @@ -1209,12 +1323,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty double rand = 0.0; auto part1 = p1; auto part2 = p2; + double randomizationValue = 0.5; if (ConfCPR.confRandomizeCPR) { randgen = new TRandom2(0); rand = randgen->Rndm(); - if (rand > 0.5) { + if (rand > randomizationValue) { part1 = p2; part2 = p1; } @@ -1228,10 +1343,11 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } } - if constexpr (std::is_same::value) + if constexpr (std::is_same::value) { mixedEventCont.setPair(p1, p2, multCol, confUse3D); - else + } else { mixedEventCont.setPair(p1, p2, multCol, confUse3D); + } } }; @@ -1291,7 +1407,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsOneMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -1303,11 +1419,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty return; } for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) + if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; @@ -1339,18 +1457,20 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { int pdgCode1 = static_cast(p1.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } mixedEventCont.setPair(p1, p2, multCol, confUse3D); } }; @@ -1376,8 +1496,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty void processMCTruth(aod::FDParticles const& parts) { for (const auto& part : parts) { - if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { continue; + } int pdgCode = static_cast(part.pidCut()); const auto& pdgParticle = pdgMC->GetParticle(pdgCode); @@ -1443,11 +1564,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut - if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } /// PID using stored binned nsigma - if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) + if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); @@ -1456,10 +1579,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { @@ -1473,11 +1598,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("mothersReco/motherParticle"), p1.motherPDG(), p2.motherPDG()); auto mcPartId1 = p1.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } auto mcPartId2 = p2.fdMCParticleId(); - if (mcPartId2 == -1) + if (mcPartId2 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); const auto& mcParticle2 = mcparts.iteratorAt(mcPartId2); if (mcParticle1.pdgMCTruth() == ConfTrkSelection.confTrkPDGCodePartOne && mcParticle2.pdgMCTruth() == ConfV0Selection.confV0PDGCodePartTwo) { @@ -1528,10 +1655,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); @@ -1540,10 +1669,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; - if (!isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } // track cleaning if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { @@ -1553,12 +1684,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty double rand = 0.0; auto part1 = p1; auto part2 = p2; + double randomizationValue = 0.5; if (ConfCPR.confRandomizeCPR) { randgen = new TRandom2(0); rand = randgen->Rndm(); - if (rand > 0.5) { + if (rand > randomizationValue) { part1 = p2; part2 = p1; } @@ -1571,17 +1703,21 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("mothersReco/motherParticle"), p1.motherPDG(), p2.motherPDG()); auto mcPartId1 = p1.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } auto mcPartId2 = p2.fdMCParticleId(); - if (mcPartId2 == -1) + if (mcPartId2 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); const auto& mcParticle2 = mcparts.iteratorAt(mcPartId2); - if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) { continue; - if ((ConfV0Selection.confV0Type2 == 0 && mcParticle2.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && mcParticle2.pdgMCTruth() != kLambda0Bar)) + } + if ((ConfV0Selection.confV0Type2 == 0 && mcParticle2.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && mcParticle2.pdgMCTruth() != kLambda0Bar)) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticlePDGCheck"), p1.motherPDG(), p2.motherPDG()); } @@ -1612,10 +1748,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty int pdgCode1 = static_cast(p1.pidCut()); int pdgCode2 = static_cast(p2.pidCut()); - if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) + if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) { continue; - if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) + } + if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticle"), p1.tempFitVar(), p2.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcess"), p1.cut(), p2.cut()); @@ -1645,11 +1783,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { int pdgCode1 = static_cast(p1.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticle"), p1.tempFitVar(), p2.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcess"), p1.cut(), p2.cut()); @@ -1677,8 +1817,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::array, 3> v0DaughPtHighTable = {{{ConfV0Selection.confHPtChildProton, ConfV0Selection.confHPtChildPion}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildProton}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildPion}}}; for (const auto& part : groupPartsTwo) { - if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); @@ -1686,35 +1827,39 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty continue; } - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleV0"), part.motherPDG()); auto mcPartId1 = part.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); - if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleV0PDGCheck"), part.motherPDG()); } for (const auto& part : groupPartsOne) { - const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; - const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) + if (!isParticleCombined(part, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleTrack"), part.motherPDG()); auto mcPartId1 = part.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); - if (mcParticle1.pdgMCTruth() != ConfTrkSelection.confTrkPDGCodePartOne) + if (mcParticle1.pdgMCTruth() != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleTrackPDGCheck"), part.motherPDG()); } } @@ -1727,15 +1872,17 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty // MC truth for (const auto& part : groupPartsOne) { int pdgCode1 = static_cast(part.pidCut()); - if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) + if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticleTrack"), part.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcessTrack"), part.cut()); } for (const auto& part : groupPartsTwo) { int pdgCode2 = static_cast(part.pidCut()); - if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) + if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticleV0"), part.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcessV0"), part.cut()); } @@ -1759,7 +1906,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { /// Daughters that do not pass this condition are not selected if (!isParticleTPC(posChild, 0) || !isParticleTPC(negChild, 1)) { continue; @@ -1792,7 +1939,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { /// Daughters that do not pass this condition are not selected if (!isParticleTPC(posChild, 1) || !isParticleTPC(negChild, 0)) { continue; @@ -1823,7 +1970,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty if (part.mAntiLambda() > 0) { // mAntiLambda is the sign here registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); if (mcpart.pdgMCTruth() == kPiPlus) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), (part.pidCut() & 512u) != 0)) { continue; } @@ -1839,7 +1986,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("plus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPiPt"), mcpart.pt()); } else if (mcpart.pdgMCTruth() == kProton) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) { continue; } @@ -1854,7 +2001,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } else if (part.mAntiLambda() < 0) { registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); if (mcpart.pdgMCTruth() == kPiMinus) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), (part.pidCut() & 512u) != 0)) { continue; } @@ -1870,7 +2017,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("minus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPiPt"), mcpart.pt()); } else if (mcpart.pdgMCTruth() == kProtonBar) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) { continue; } diff --git a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx index 1257291a825..3fe9e5071d1 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx @@ -73,10 +73,14 @@ struct FemtoPairLambdaAntilambda { colhistmanager::ConfCollisionBinning confCollisionBinning; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + trackhistmanager::ConfV01PosDauBinning confV01PosDauBinning; + trackhistmanager::ConfV01NegDauBinning confV01NegDauBinning; + trackhistmanager::ConfV02PosDauBinning confV02PosDauBinning; + trackhistmanager::ConfV02NegDauBinning confV02NegDauBinning; // setup lambdas + // selection 1 and 2 are sign-separated (lambda / antilambda), so confMixing.sameSpecies + // has to be set to false when running lambda-antilambda v0builder::ConfLambdaSelection1 confLambdaSelection; v0builder::ConfLambdaSelection2 confLambdaSelection2; particlecleaner::ConfLambdaCleaner1 confLambdaCleaner; @@ -156,33 +160,27 @@ struct FemtoPairLambdaAntilambda { void init(o2::framework::InitContext&) { - // TODO: implement lambda-k0short - bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaSameEvent || doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortSameEvent; - bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaSameEventMc || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortSameEventMc; - - if (processData && processMc) { - LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; - } + bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent; - bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; - bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; - - if (processLambdaLambda && processK0shortK0short) { - LOG(fatal) << "Both lambda-lambda and k0short-k0short processing is enabled. Breaking..."; - } + bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; + bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || + doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; // setup histograms std::map> colHistSpec; - std::map> trackHistSpec; - std::map> posDauSpec; - std::map> negDauSpec; + std::map> posDauSpec1; + std::map> negDauSpec1; + std::map> posDauSpec2; + std::map> negDauSpec2; std::map> lambdaHistSpec; std::map> k0shortHistSpec; std::map> pairV0V0HistSpec; @@ -191,62 +189,64 @@ struct FemtoPairLambdaAntilambda { if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + if (processK0shortK0short) { k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + if (processK0shortK0short) { k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } - }; + } void processLambdaLambdaSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) { pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, lambdaPartition2, cache); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-lambda", true); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-antilambda", true); void processLambdaLambdaSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-lambda with mc information", false); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-antilambda with mc information", false); - void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas) + void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/) { - pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdaPartition, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-lambda", true); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-antilambda", true); void processLambdaLambdaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-lambda with mc information", false); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-antilambda with mc information", false); void processK0shortK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) { @@ -260,15 +260,15 @@ struct FemtoPairLambdaAntilambda { } PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortSameEventMc, "Enable processing same event processing for k0short-k0short with mc information", false); - void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) + void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& /*k0shorts*/) { - pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shorts, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortMixedEvent, "Enable processing mixed event processing for k0short-k0short", false); void processK0shortK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortMixedEventMc, "Enable processing mixed event processing for k0short-k0short with mc information", false); }; diff --git a/PWGCF/Flow/TableProducer/zdcQVectors.cxx b/PWGCF/Flow/TableProducer/zdcQVectors.cxx index c646b410b5e..b221a02530f 100644 --- a/PWGCF/Flow/TableProducer/zdcQVectors.cxx +++ b/PWGCF/Flow/TableProducer/zdcQVectors.cxx @@ -20,6 +20,8 @@ #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" #include #include @@ -41,10 +43,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -68,35 +72,22 @@ int counter = 0; // Define histogrm names here to use same names for creating and later uploading and retrieving data from ccdb // Energy calibration: -std::vector namesEcal(10, ""); -std::vector> names(5, std::vector()); //(1x 4d 4x 1d) -std::vector namesTS; // for timestamo recentering -std::vector vnames = {"hvertex_vx", "hvertex_vy"}; +const std::array namesEcal = {{"hZNA_mean_t0_cent", "hZNA_mean_t1_cent", "hZNA_mean_t2_cent", "hZNA_mean_t3_cent", "hZNA_mean_t4_cent", + "hZNC_mean_t0_cent", "hZNC_mean_t1_cent", "hZNC_mean_t2_cent", "hZNC_mean_t3_cent", "hZNC_mean_t4_cent"}}; +const std::array, 5> names = {{{{"hQXA_mean_Cent_V_run", "hQYA_mean_Cent_V_run", "hQXC_mean_Cent_V_run", "hQYC_mean_Cent_V_run"}}, + {{"hQXA_mean_cent_run", "hQYA_mean_cent_run", "hQXC_mean_cent_run", "hQYC_mean_cent_run"}}, + {{"hQXA_mean_vx_run", "hQYA_mean_vx_run", "hQXC_mean_vx_run", "hQYC_mean_vx_run"}}, + {{"hQXA_mean_vy_run", "hQYA_mean_vy_run", "hQXC_mean_vy_run", "hQYC_mean_vy_run"}}, + {{"hQXA_mean_vz_run", "hQYA_mean_vz_run", "hQXC_mean_vz_run", "hQYC_mean_vz_run"}}}}; +const std::array namesTS = {{"hQXA_mean_timestamp_run", "hQYA_mean_timestamp_run", "hQXC_mean_timestamp_run", "hQYC_mean_timestamp_run"}}; // for timestamp recentering +const std::array vnames = {"hvertex_vx", "hvertex_vy"}; // https://alice-notes.web.cern.ch/system/files/notes/analysis/620/017-May-31-analysis_note-ALICE_analysis_note_v2.pdf -std::vector pxZDC = {-1.75, 1.75, -1.75, 1.75}; -std::vector pyZDC = {-1.75, -1.75, 1.75, 1.75}; -double alphaZDC = 0.395; - -// q-vectors before (q) and after (qRec) recentering. -std::vector q(4); // start values of [QxA, QyA, QxC, QyC] -std::vector qNoEq(4); // start values of [QxA, QyA, QxC, QyC] - -// for energy calibration -std::vector eZN(8); // uncalibrated energy for the 2x4 towers (a1, a2, a3, a4, c1, c2, c3, c4) -std::vector meanEZN(10); // mean energies from calibration histos (common A, t1-4 A,common C, t1-4C) -std::vector e(8, 0.); // calibrated energies (a1, a2, a3, a4, c1, c2, c3, c4)) - -// Define variables needed to do the recentring steps. -float centrality = 0; -int runnumber = 0; -int lastRunNumber = 0; -std::vector v(3, 0); // vx, vy, vz -bool isSelected = true; -std::vector cents; // centrality estimaters -uint64_t timestamp = 0; -double rsTimestamp = 0; +const std::array pxZDC = {-1.75, 1.75, -1.75, 1.75}; +const std::array pyZDC = {-1.75, -1.75, 1.75, 1.75}; +const double alphaZDC = 0.395; +const int totalTowers = 10; } // namespace o2::analysis::qvectortask using namespace o2::analysis::qvectortask; @@ -127,11 +118,7 @@ struct ZdcQVectors { } extraTS; ConfigurableAxis axisCent{"axisCent", {90, 0, 90}, "Centrality axis in 1% bins"}; - ConfigurableAxis axisCent10{"axisCent10", {9, 0, 90}, "Centrality axis in 10% bins"}; ConfigurableAxis axisQ{"axisQ", {100, -2, 2}, "Q vector (xy) in ZDC"}; - ConfigurableAxis axisVxBig{"axisVxBig", {3, -0.01, 0.01}, "for Pos X of collision"}; - ConfigurableAxis axisVyBig{"axisVyBig", {3, -0.01, 0.01}, "for Pos Y of collision"}; - ConfigurableAxis axisVzBig{"axisVzBig", {3, -10, 10}, "for Pos Z of collision"}; ConfigurableAxis axisVx{"axisVx", {100, -0.01, 0.01}, "for Pos X of collision"}; ConfigurableAxis axisVy{"axisVy", {100, -0.01, 0.01}, "for Pos Y of collision"}; ConfigurableAxis axisVz{"axisVz", {100, -10, 10}, "for vz of collision"}; @@ -148,19 +135,32 @@ struct ZdcQVectors { O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field; default CCDB will be queried") O2_DEFINE_CONFIGURABLE(cfgEnergyCal, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/Energy", "ccdb path for energy calibration histos") O2_DEFINE_CONFIGURABLE(cfgMeanv, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/vmean", "ccdb path for mean v histos") - O2_DEFINE_CONFIGURABLE(cfgMinEntriesSparseBin, int, 100, "Minimal number of entries allowed in 4D recentering histogram to use for recentering.") + O2_DEFINE_CONFIGURABLE(cfgMinEntriesSparseBin, int, 1000, "Minimal number of entries allowed in 4D recentering histogram to use for recentering.") O2_DEFINE_CONFIGURABLE(cfgRec, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5", "ccdb path for recentering histos"); O2_DEFINE_CONFIGURABLE(cfgFillHistRegistry, bool, true, "Fill common registry with histograms"); O2_DEFINE_CONFIGURABLE(cfgFillCutAnalysis, bool, true, "Fill cut analysis with histograms"); O2_DEFINE_CONFIGURABLE(cfgFillNothing, bool, false, "Disable ALL Histograms -> ONLY use to reduce memory"); - O2_DEFINE_CONFIGURABLE(cfgNoGain, bool, false, "Do not apply gain correction to ZDC energy calibration"); + O2_DEFINE_CONFIGURABLE(cfgNoGain, bool, true, "Do not apply gain correction to ZDC energy calibration"); + + O2_DEFINE_CONFIGURABLE(cfgTrackSelsDCAxy, float, 0.2, "Cut on DCA in the transverse direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsDCAz, float, 0.2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsPtmin, float, 0.2, "minimum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsPtmax, float, 10, "maximum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsEta, float, 0.8, "eta cut"); O2_DEFINE_CONFIGURABLE(cfgCCDBdir_Shift, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/Shift", "CCDB directory for Shift ZDC"); + Configurable> cfgSelVec{"cfgSelVec", std::vector{1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1}, "Put 1 for every event selection from SelectionCriteria that is used in flowSP"}; + Configurable> cfgEvSelsMultPv{"cfgEvSelsMultPv", std::vector{2223.49, -75.1444, 0.963572, -0.00570399, 1.34877e-05, 3790.99, -137.064, 2.13044, -0.017122, 5.82834e-05}, "Multiplicity cuts (PV) first 5 parameters cutLOW last 5 cutHIGH (Default is +-2sigma pass5) "}; + Configurable> cfgEvSelsMult{"cfgEvSelsMult", std::vector{1301.56, -41.4615, 0.478224, -0.00239449, 4.46966e-06, 2967.6, -102.927, 1.47488, -0.0106534, 3.28622e-05}, "Multiplicity cuts (Global) first 5 parameters cutLOW last 5 cutHIGH (Default is +-2sigma pass5) "}; // define my..... // Filter collisionFilter = nabs(aod::collision::posZ) <; - using UsedCollisions = soa::Join; + + using UsedCollisions = soa::Join; using BCsRun3 = soa::Join; + Filter trackFilter = nabs(aod::track::eta) < cfgTrackSelsEta && aod::track::pt > cfgTrackSelsPtmin&& aod::track::pt < cfgTrackSelsPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true)) && nabs(aod::track::dcaXY) < cfgTrackSelsDCAxy&& nabs(aod::track::dcaZ) < cfgTrackSelsDCAz; + using UnfilteredTracks = soa::Join; + using UsedTracks = soa::Filtered; enum SelectionCriteria { evSel_FilteredEvent, @@ -178,6 +178,7 @@ struct ZdcQVectors { evSel_kIsGoodITSLayer0123, evSel_RCTFlagsZDC, evSel_CentCuts, + evSel_MultCut, nEventSelections }; @@ -191,6 +192,15 @@ struct ZdcQVectors { // Define output HistogramRegistry registry{"Registry"}; + // Event selection cuts + std::unique_ptr fPhiCutLow = nullptr; + std::unique_ptr fPhiCutHigh = nullptr; + std::unique_ptr fMultPVCutLow = nullptr; + std::unique_ptr fMultPVCutHigh = nullptr; + std::unique_ptr fMultCutLow = nullptr; + std::unique_ptr fMultCutHigh = nullptr; + std::unique_ptr fMultMultPVCut = nullptr; + Service ccdb; // keep track of calibration histos for each given step and iteration @@ -204,6 +214,13 @@ struct ZdcQVectors { TProfile3D* shiftprofileA = nullptr; bool isShiftProfileFound = false; + int lastRunNumber = 0; + int runnumber = 0; + float centrality = 0; + double rsTimestamp = 0; + uint64_t timestamp = 0; + std::vector v = {0, 0, 0}; + bool isSelected = 0; } cal; enum FillType { @@ -246,30 +263,14 @@ struct ZdcQVectors { registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_CentCuts + 1, "Cenrality range"); registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayer0123 + 1, "kIsGoodITSLayer0123"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_MultCut + 1, "Mult & MultPV"); registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_isSelectedZDC + 1, "isSelected"); - int totalTowers = 10; - int totalTowersPerSide = 5; - for (int tower = 0; tower < totalTowers; tower++) { - namesEcal[tower] = TString::Format("hZN%s_mean_t%i_cent", sides[(tower < totalTowersPerSide) ? 0 : 1], tower % 5); - } - - for (const auto& side : sides) { - for (const auto& coord : capCOORDS) { - names[0].push_back(TString::Format("hQ%s%s_mean_Cent_V_run", coord, side)); - names[1].push_back(TString::Format("hQ%s%s_mean_cent_run", coord, side)); - names[2].push_back(TString::Format("hQ%s%s_mean_vx_run", coord, side)); - names[3].push_back(TString::Format("hQ%s%s_mean_vy_run", coord, side)); - names[4].push_back(TString::Format("hQ%s%s_mean_vz_run", coord, side)); - namesTS.push_back(TString::Format("hQ%s%s_mean_timestamp_run", coord, side)); - } // end of capCOORDS - } - if (!cfgFillNothing) { if (cfgFillHistRegistry) { - registry.add(Form("QA/before/hSPplaneA"), "hSPplaneA", kTH2D, {axisPsiA, axisCent10}); - registry.add(Form("QA/before/hSPplaneC"), "hSPplaneC", kTH2D, {axisPsiC, axisCent10}); - registry.add(Form("QA/before/hSPplaneFull"), "hSPplaneFull", kTH2D, {{100, -PI, PI}, axisCent10}); + registry.add(Form("QA/before/hSPplaneA"), "hSPplaneA", kTH2D, {axisPsiA, axisCent}); + registry.add(Form("QA/before/hSPplaneC"), "hSPplaneC", kTH2D, {axisPsiC, axisCent}); + registry.add(Form("QA/before/hSPplaneFull"), "hSPplaneFull", kTH2D, {{100, -PI, PI}, axisCent}); for (const auto& side : sides) { registry.add(Form("recentering/before/hZN%s_Qx_vs_Qy", side), Form("hZN%s_Qx_vs_Qy", side), kTH2F, {axisQ, axisQ}); } @@ -289,7 +290,7 @@ struct ZdcQVectors { // Sides is {A,C} and capcoords is {X,Y} for (const auto& side : sides) { for (const auto& coord : capCOORDS) { - registry.add(Form("recentering/before/hQ%s%s_vs_cent", coord, side), Form("hQ%s%s_vs_cent", coord, side), {HistType::kTProfile, {axisCent10}}); + registry.add(Form("recentering/before/hQ%s%s_vs_cent", coord, side), Form("hQ%s%s_vs_cent", coord, side), {HistType::kTProfile, {axisCent}}); registry.add(Form("recentering/before/hQ%s%s_vs_vx", coord, side), Form("hQ%s%s_vs_vx", coord, side), {HistType::kTProfile, {axisVx}}); registry.add(Form("recentering/before/hQ%s%s_vs_vy", coord, side), Form("hQ%s%s_vs_vy", coord, side), {HistType::kTProfile, {axisVy}}); registry.add(Form("recentering/before/hQ%s%s_vs_vz", coord, side), Form("hQ%s%s_vs_vz", coord, side), {HistType::kTProfile, {axisVz}}); @@ -380,12 +381,33 @@ struct ZdcQVectors { registry.addClone("recentering/before/", "recentering/after/"); registry.addClone("QA/before/", "QA/after/"); } + + fMultPVCutLow = std::make_unique("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + fMultPVCutHigh = std::make_unique("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + fMultCutLow = std::make_unique("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + fMultCutHigh = std::make_unique("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + + std::vector paramsMultPVCut = cfgEvSelsMultPv; + std::vector paramsMultCut = cfgEvSelsMult; + + uint64_t nParams = 10; + + if (paramsMultPVCut.size() < nParams) { + LOGF(fatal, "cfg.cEvSelsMultPv not set properly.. size = %d (should be 10) --> Check your config files!", paramsMultPVCut.size()); + } else if (paramsMultCut.size() < nParams) { + LOGF(fatal, "cfg.cEvSelsMult not set properly.. size = %d (should be 10) --> Check your config files!", paramsMultCut.size()); + } else { + fMultPVCutLow->SetParameters(paramsMultPVCut[0], paramsMultPVCut[1], paramsMultPVCut[2], paramsMultPVCut[3], paramsMultPVCut[4]); + fMultPVCutHigh->SetParameters(paramsMultPVCut[5], paramsMultPVCut[6], paramsMultPVCut[7], paramsMultPVCut[8], paramsMultPVCut[9]); + fMultCutLow->SetParameters(paramsMultCut[0], paramsMultCut[1], paramsMultCut[2], paramsMultCut[3], paramsMultCut[4]); + fMultCutHigh->SetParameters(paramsMultCut[5], paramsMultCut[6], paramsMultCut[7], paramsMultCut[8], paramsMultCut[9]); + } } double rescaleTimestamp(uint64_t timestamp, int runnumber) { - auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); - auto duration = ccdb.getRunDuration(runnumber); + auto& cc = o2::ccdb::BasicCCDBManager::instance(); + auto duration = cc.getRunDuration(runnumber); double ts = (static_cast(timestamp - duration.first) / static_cast(duration.second - duration.first)) * 100.0; return ts; @@ -401,20 +423,20 @@ struct ZdcQVectors { return; // Add default with different centrality estimators as well // Here we fill the Energy and mean vx, vy vz histograms with an extra dimension for all the event selections used. - registry.get(HIST("CutAnalysis/hvertex_vx"))->Fill(Form("%d", runnumber), evSel, collision.posX()); - registry.get(HIST("CutAnalysis/hvertex_vy"))->Fill(Form("%d", runnumber), evSel, collision.posY()); - registry.get(HIST("CutAnalysis/hvertex_vz"))->Fill(Form("%d", runnumber), evSel, collision.posZ()); - - registry.get(HIST("CutAnalysis/hZNA_mean_t0_cent"))->Fill(centrality, evSel, zdcBC.energyCommonZNA(), 1); - registry.get(HIST("CutAnalysis/hZNA_mean_t1_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[0], 1); - registry.get(HIST("CutAnalysis/hZNA_mean_t2_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[1], 1); - registry.get(HIST("CutAnalysis/hZNA_mean_t3_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[2], 1); - registry.get(HIST("CutAnalysis/hZNA_mean_t4_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[3], 1); - registry.get(HIST("CutAnalysis/hZNC_mean_t0_cent"))->Fill(centrality, evSel, zdcBC.energyCommonZNC(), 1); - registry.get(HIST("CutAnalysis/hZNC_mean_t1_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[0], 1); - registry.get(HIST("CutAnalysis/hZNC_mean_t2_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[1], 1); - registry.get(HIST("CutAnalysis/hZNC_mean_t3_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[2], 1); - registry.get(HIST("CutAnalysis/hZNC_mean_t4_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[3], 1); + registry.get(HIST("CutAnalysis/hvertex_vx"))->Fill(Form("%d", cal.runnumber), evSel, collision.posX()); + registry.get(HIST("CutAnalysis/hvertex_vy"))->Fill(Form("%d", cal.runnumber), evSel, collision.posY()); + registry.get(HIST("CutAnalysis/hvertex_vz"))->Fill(Form("%d", cal.runnumber), evSel, collision.posZ()); + + registry.get(HIST("CutAnalysis/hZNA_mean_t0_cent"))->Fill(cal.centrality, evSel, zdcBC.energyCommonZNA(), 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t1_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNA()[0], 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t2_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNA()[1], 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t3_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNA()[2], 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t4_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNA()[3], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t0_cent"))->Fill(cal.centrality, evSel, zdcBC.energyCommonZNC(), 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t1_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNC()[0], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t2_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNC()[1], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t3_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNC()[2], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t4_cent"))->Fill(cal.centrality, evSel, zdcBC.energySectorZNC()[3], 1); if (evSel == nEventSelections) { int centCounter = 0; @@ -443,7 +465,7 @@ struct ZdcQVectors { } template - uint16_t eventSelected(TCollision collision, TBunchCrossing bunchCrossing) + uint16_t eventSelected(TCollision collision, TBunchCrossing bunchCrossing, bool& isEventSelected, const int& multTrk) { uint16_t selectionBits = 0; bool selected; @@ -457,12 +479,16 @@ struct ZdcQVectors { if (selected) { selectionBits |= static_cast(0x1u << evSel_Zvtx); fillCutAnalysis(collision, bunchCrossing, evSel_Zvtx); + } else if (cfgSelVec.value[evSel_Zvtx]) { + isEventSelected = false; } selected = collision.sel8(); if (selected) { selectionBits |= static_cast(0x1u << evSel_sel8); fillCutAnalysis(collision, bunchCrossing, evSel_sel8); + } else if (cfgSelVec.value[evSel_sel8]) { + isEventSelected = false; } auto occupancy = collision.trackOccupancyInTimeRange(); @@ -470,59 +496,107 @@ struct ZdcQVectors { if (selected) { selectionBits |= static_cast(0x1u << evSel_occupancy); fillCutAnalysis(collision, bunchCrossing, evSel_occupancy); + } else if (cfgSelVec.value[evSel_occupancy]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); if (selected) { selectionBits |= static_cast(0x1u << evSel_kNoSameBunchPileup); fillCutAnalysis(collision, bunchCrossing, evSel_kNoSameBunchPileup); + } else if (cfgSelVec.value[evSel_kNoSameBunchPileup]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); if (selected) { selectionBits |= static_cast(0x1u << evSel_kIsGoodZvtxFT0vsPV); fillCutAnalysis(collision, bunchCrossing, evSel_kIsGoodZvtxFT0vsPV); + } else if (cfgSelVec.value[evSel_kIsGoodZvtxFT0vsPV]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); if (selected) { selectionBits |= static_cast(0x1u << evSel_kNoCollInTimeRangeStandard); fillCutAnalysis(collision, bunchCrossing, evSel_kNoCollInTimeRangeStandard); + } else if (cfgSelVec.value[evSel_kNoCollInTimeRangeStandard]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow); if (selected) { selectionBits |= static_cast(0x1u << evSel_kNoCollInTimeRangeNarrow); fillCutAnalysis(collision, bunchCrossing, evSel_kNoCollInTimeRangeNarrow); + } else if (cfgSelVec.value[evSel_kNoCollInTimeRangeNarrow]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC); if (selected) { selectionBits |= static_cast(0x1u << evSel_kIsVertexITSTPC); fillCutAnalysis(collision, bunchCrossing, evSel_kIsVertexITSTPC); + } else if (cfgSelVec.value[evSel_kIsVertexITSTPC]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); if (selected) { selectionBits |= static_cast(0x1u << evSel_kIsGoodITSLayersAll); fillCutAnalysis(collision, bunchCrossing, evSel_kIsGoodITSLayersAll); + } else if (cfgSelVec.value[evSel_kIsGoodITSLayersAll]) { + isEventSelected = false; } selected = collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); if (selected) { selectionBits |= static_cast(0x1u << evSel_kIsGoodITSLayer0123); fillCutAnalysis(collision, bunchCrossing, evSel_kIsGoodITSLayer0123); + } else if (cfgSelVec.value[evSel_kIsGoodITSLayer0123]) { + isEventSelected = false; } selected = rctChecker(collision); if (selected) { selectionBits |= static_cast(0x1u << evSel_RCTFlagsZDC); fillCutAnalysis(collision, bunchCrossing, evSel_RCTFlagsZDC); + } else if (cfgSelVec.value[evSel_RCTFlagsZDC]) { + isEventSelected = false; + } + + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + float minzRes = 0.25; + int maxNumContrib = 20; + if (zRes > minzRes && collision.numContrib() < maxNumContrib) + vtxz = -999; + } + + auto multNTracksPV = collision.multNTracksPV(); + selected = true; + + if (vtxz > cfgVtxZ || vtxz < -cfgVtxZ) + selected = false; + if (multNTracksPV < fMultPVCutLow->Eval(collision.centFT0C())) + selected = false; + if (multNTracksPV > fMultPVCutHigh->Eval(collision.centFT0C())) + selected = false; + if (multTrk < fMultCutLow->Eval(collision.centFT0C())) + selected = false; + if (multTrk > fMultCutHigh->Eval(collision.centFT0C())) + selected = false; + + if (selected) { + selectionBits |= static_cast(0x1u << evSel_MultCut); + fillCutAnalysis(collision, bunchCrossing, evSel_MultCut); + } else if (cfgSelVec.value[evSel_MultCut]) { + isEventSelected = false; } // Fill for centrality estimators! fillCutAnalysis(collision, bunchCrossing, nEventSelections); - return selectionBits; } @@ -603,7 +677,7 @@ struct ZdcQVectors { } template - void loadCalibrations(std::string ccdb_dir) + void loadCalibrations(std::string ccdb_dir, uint64_t timestamp) { // iteration = 0 (Energy calibration) -> step 0 only // iteration 1,2,3,4,5 = recentering -> 5 steps per iteration (1x 4D + 4x 1D) @@ -633,10 +707,10 @@ struct ZdcQVectors { TList* list = cal.calibList[cm]; hist = reinterpret_cast(list->FindObject(Form("%s", objName))); } else if (cm == kTimestamp) { - TList* list = reinterpret_cast(cal.calibList[cm]->FindObject(Form("it%i_step%i", iteration, step))); + auto list = reinterpret_cast(cal.calibList[cm]->FindObject(Form("it%i_step%i", iteration, step))); hist = reinterpret_cast(list->FindObject(Form("%s", objName))); } else if (cm == kRec) { - TList* list = reinterpret_cast(cal.calibList[cm]->FindObject(Form("it%i_step%i", iteration, step))); + auto list = reinterpret_cast(cal.calibList[cm]->FindObject(Form("it%i_step%i", iteration, step))); if (!list) { LOGF(fatal, "No calibration list for iteration %i and step %i", iteration, step); } @@ -653,53 +727,53 @@ struct ZdcQVectors { if (hist->InheritsFrom("TProfile2D")) { // needed for energy calibration! - TProfile2D* h = reinterpret_cast(hist); + auto h = reinterpret_cast(hist); TString name = h->GetName(); - int binrunnumber = h->GetXaxis()->FindBin(TString::Format("%d", runnumber)); - int bin = h->GetYaxis()->FindBin(centrality); + int binrunnumber = h->GetXaxis()->FindBin(TString::Format("%d", cal.runnumber)); + int bin = h->GetYaxis()->FindBin(cal.centrality); calibConstant = h->GetBinContent(binrunnumber, bin); } else if (hist->InheritsFrom("TProfile")) { - TProfile* h = reinterpret_cast(hist); + auto h = reinterpret_cast(hist); TString name = h->GetName(); int bin{}; if (name.Contains("mean_vx")) { - bin = h->GetXaxis()->FindBin(v[0]); + bin = h->GetXaxis()->FindBin(cal.v[0]); } if (name.Contains("mean_vy")) { - bin = h->GetXaxis()->FindBin(v[1]); + bin = h->GetXaxis()->FindBin(cal.v[1]); } if (name.Contains("mean_vz")) { - bin = h->GetXaxis()->FindBin(v[2]); + bin = h->GetXaxis()->FindBin(cal.v[2]); } if (name.Contains("mean_cent")) { - bin = h->GetXaxis()->FindBin(centrality); + bin = h->GetXaxis()->FindBin(cal.centrality); } if (name.Contains("vertex")) { - bin = h->GetXaxis()->FindBin(TString::Format("%i", runnumber)); + bin = h->GetXaxis()->FindBin(TString::Format("%i", cal.runnumber)); } if (name.Contains("timestamp")) { - bin = h->GetXaxis()->FindBin(rsTimestamp); + bin = h->GetXaxis()->FindBin(cal.timestamp); } calibConstant = h->GetBinContent(bin); } else if (hist->InheritsFrom("THnSparse")) { std::vector sparsePars; - THnSparseD* h = reinterpret_cast(hist); - sparsePars.push_back(h->GetAxis(0)->FindBin(centrality)); - sparsePars.push_back(h->GetAxis(1)->FindBin(v[0])); - sparsePars.push_back(h->GetAxis(2)->FindBin(v[1])); - sparsePars.push_back(h->GetAxis(3)->FindBin(v[2])); + auto h = reinterpret_cast(hist); + sparsePars.push_back(h->GetAxis(0)->FindBin(cal.centrality)); + sparsePars.push_back(h->GetAxis(1)->FindBin(cal.v[0])); + sparsePars.push_back(h->GetAxis(2)->FindBin(cal.v[1])); + sparsePars.push_back(h->GetAxis(3)->FindBin(cal.v[2])); for (std::size_t i = 0; i < sparsePars.size(); i++) { h->GetAxis(i)->SetRange(sparsePars[i], sparsePars[i]); } - TH1D* tempProj = h->Projection(4); + auto tempProj = h->Projection(4); calibConstant = tempProj->GetMean(); if (tempProj->GetEntries() < cfgMinEntriesSparseBin) { LOGF(debug, "1 entry in sparse bin! Not used... (increase binsize)"); calibConstant = 0; - isSelected = false; + cal.isSelected = false; } delete tempProj; @@ -710,7 +784,8 @@ struct ZdcQVectors { void process(UsedCollisions::iterator const& collision, BCsRun3 const& /*bcs*/, - aod::Zdcs const& /*zdcs*/) + aod::Zdcs const& /*zdcs*/, + UsedTracks const& tracks) { // for Q-vector calculation // A[0] & C[1] @@ -718,41 +793,42 @@ struct ZdcQVectors { std::vector xEnZN(2, 0.), xEnZN_noEq(2, 0.); std::vector yEnZN(2, 0.), yEnZN_noEq(2, 0.); - isSelected = true; + cal.isSelected = true; - std::vector centralities; + std::vector cents; auto cent = collision.centFT0C(); - centralities.push_back(collision.centFT0C()); + cents.push_back(collision.centFT0C()); if (cfgFT0Cvariant1) { - centralities.push_back(collision.centFT0CVariant1()); + cents.push_back(collision.centFT0CVariant1()); if (cfgUseSecondCent) cent = collision.centFT0CVariant1(); } if (cfgFT0M) { - centralities.push_back(collision.centFT0M()); + cents.push_back(collision.centFT0M()); if (cfgUseSecondCent) cent = collision.centFT0M(); } if (cfgFV0A) { - centralities.push_back(collision.centFV0A()); + cents.push_back(collision.centFV0A()); if (cfgUseSecondCent) cent = collision.centFV0A(); } if (cfgNGlobal) { - centralities.push_back(collision.centNGlobal()); + cents.push_back(collision.centNGlobal()); if (cfgUseSecondCent) cent = collision.centNGlobal(); } - v = {collision.posX(), collision.posY(), collision.posZ()}; - cents = centralities; - centrality = cent; + std::vector v = {collision.posX(), collision.posY(), collision.posZ()}; + cal.v = v; const auto& foundBC = collision.foundBC_as(); - runnumber = foundBC.runNumber(); + auto runnumber = foundBC.runNumber(); + cal.runnumber = runnumber; + cal.centrality = cent; if (cfgFillHistRegistry && !cfgFillNothing) { registry.fill(HIST("QA/centrality_before"), cent); @@ -760,14 +836,15 @@ struct ZdcQVectors { registry.fill(HIST("hEventCount"), evSel_FilteredEvent); - timestamp = foundBC.timestamp(); - rsTimestamp = rescaleTimestamp(timestamp, runnumber); + uint64_t timestamp = foundBC.timestamp(); + auto rsTimestamp = rescaleTimestamp(timestamp, runnumber); + cal.timestamp = timestamp; + cal.rsTimestamp = rsTimestamp; if (!foundBC.has_zdc()) { - isSelected = false; - spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, 0); - counter++; - lastRunNumber = runnumber; + cal.isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, cal.isSelected, 0); + cal.lastRunNumber = runnumber; return; } registry.fill(HIST("hEventCount"), evSel_BCHasZDC); @@ -778,6 +855,11 @@ struct ZdcQVectors { int nTowers = 8; int nTowersPerSide = 4; + // for energy calibration + std::array eZN; // uncalibrated energy for the 2x4 towers (a1, a2, a3, a4, c1, c2, c3, c4) + std::array meanEZN; // mean energies from calibration histos (common A, t1-4 A,common C, t1-4C) + std::array e; // calibrated energies (a1, a2, a3, a4, c1, c2, c3, c4)) + for (int tower = 0; tower < nTowers; tower++) { eZN[tower] = (tower < nTowersPerSide) ? zdcCol.energySectorZNA()[tower] : zdcCol.energySectorZNC()[tower % nTowersPerSide]; } @@ -799,29 +881,31 @@ struct ZdcQVectors { // if ZNA or ZNC not hit correctly.. do not use event in q-vector calculation if (!isZNAhit || !isZNChit) { - counter++; - isSelected = false; - spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, 0); - lastRunNumber = runnumber; + cal.isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, cal.isSelected, 0); + cal.lastRunNumber = runnumber; return; } registry.fill(HIST("hEventCount"), evSel_isSelectedZDC); - uint16_t eventSelectionFlags = eventSelected(collision, foundBC.zdc()); + // Use this bool to check for given set of event selections of Q-vectors would be selected + // Enable plotting only if event would be selected + bool isEventSelected = true; + + uint16_t eventSelectionFlags = eventSelected(collision, foundBC.zdc(), isEventSelected, tracks.size()); // ALWAYS use these event selections - if (cent < EvSel.cfgCentMin || cent > EvSel.cfgCentMax || !collision.sel8() || std::abs(collision.posZ()) > cfgVtxZ) { + if (cent < EvSel.cfgCentMin || cent > EvSel.cfgCentMax || std::abs(collision.posZ()) > cfgVtxZ || !collision.sel8()) { // event not selected - isSelected = false; - spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, eventSelectionFlags); - counter++; - lastRunNumber = runnumber; + cal.isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, cal.isSelected, eventSelectionFlags); + cal.lastRunNumber = runnumber; return; } registry.fill(HIST("hEventCount"), evSel_CentCuts); // load new calibrations for new runs only - if (runnumber != lastRunNumber) { + if (runnumber != cal.lastRunNumber) { cal.calibfilesLoaded[0] = false; cal.calibList[0] = nullptr; @@ -841,30 +925,29 @@ struct ZdcQVectors { // load the calibration histos for iteration 0 step 0 (Energy Calibration) if (!cfgNoGain) - loadCalibrations(cfgEnergyCal.value); + loadCalibrations(cfgEnergyCal.value, timestamp); + // load the calibrations for the mean v - loadCalibrations(cfgMeanv.value); + loadCalibrations(cfgMeanv.value, timestamp); - if (!cfgFillNothing) { + if (!cfgFillNothing && isEventSelected) { registry.get(HIST("vmean/hvertex_vx"))->Fill(Form("%d", runnumber), v[0]); registry.get(HIST("vmean/hvertex_vy"))->Fill(Form("%d", runnumber), v[1]); registry.get(HIST("vmean/hvertex_vz"))->Fill(Form("%d", runnumber), v[2]); // Fill to get mean energy per tower in 1% centrality bins - if (isZNAhit) { - registry.get(HIST("Energy/hZNA_mean_t0_cent"))->Fill(Form("%d", runnumber), cent, zdcCol.energyCommonZNA(), 1); - registry.get(HIST("Energy/hZNA_mean_t1_cent"))->Fill(Form("%d", runnumber), cent, eZN[0], 1); - registry.get(HIST("Energy/hZNA_mean_t2_cent"))->Fill(Form("%d", runnumber), cent, eZN[1], 1); - registry.get(HIST("Energy/hZNA_mean_t3_cent"))->Fill(Form("%d", runnumber), cent, eZN[2], 1); - registry.get(HIST("Energy/hZNA_mean_t4_cent"))->Fill(Form("%d", runnumber), cent, eZN[3], 1); - } - if (isZNChit) { - registry.get(HIST("Energy/hZNC_mean_t0_cent"))->Fill(Form("%d", runnumber), cent, zdcCol.energyCommonZNC(), 1); - registry.get(HIST("Energy/hZNC_mean_t1_cent"))->Fill(Form("%d", runnumber), cent, eZN[4], 1); - registry.get(HIST("Energy/hZNC_mean_t2_cent"))->Fill(Form("%d", runnumber), cent, eZN[5], 1); - registry.get(HIST("Energy/hZNC_mean_t3_cent"))->Fill(Form("%d", runnumber), cent, eZN[6], 1); - registry.get(HIST("Energy/hZNC_mean_t4_cent"))->Fill(Form("%d", runnumber), cent, eZN[7], 1); - } + + registry.get(HIST("Energy/hZNA_mean_t0_cent"))->Fill(Form("%d", runnumber), cent, zdcCol.energyCommonZNA(), 1); + registry.get(HIST("Energy/hZNA_mean_t1_cent"))->Fill(Form("%d", runnumber), cent, eZN[0], 1); + registry.get(HIST("Energy/hZNA_mean_t2_cent"))->Fill(Form("%d", runnumber), cent, eZN[1], 1); + registry.get(HIST("Energy/hZNA_mean_t3_cent"))->Fill(Form("%d", runnumber), cent, eZN[2], 1); + registry.get(HIST("Energy/hZNA_mean_t4_cent"))->Fill(Form("%d", runnumber), cent, eZN[3], 1); + + registry.get(HIST("Energy/hZNC_mean_t0_cent"))->Fill(Form("%d", runnumber), cent, zdcCol.energyCommonZNC(), 1); + registry.get(HIST("Energy/hZNC_mean_t1_cent"))->Fill(Form("%d", runnumber), cent, eZN[4], 1); + registry.get(HIST("Energy/hZNC_mean_t2_cent"))->Fill(Form("%d", runnumber), cent, eZN[5], 1); + registry.get(HIST("Energy/hZNC_mean_t3_cent"))->Fill(Form("%d", runnumber), cent, eZN[6], 1); + registry.get(HIST("Energy/hZNC_mean_t4_cent"))->Fill(Form("%d", runnumber), cent, eZN[7], 1); } // Now start gain equalisation! @@ -891,7 +974,7 @@ struct ZdcQVectors { calibtower++; } - if (cfgFillHistRegistry && !cfgFillNothing) { + if (cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { for (int i = 0; i < nTowersPerSide; i++) { float bincenter = i + .5; registry.fill(HIST("QA/ZNA_Energy"), bincenter, eZN[i]); @@ -913,21 +996,21 @@ struct ZdcQVectors { double sumZNA = e[0] + e[1] + e[2] + e[3]; double sumZNC = e[4] + e[5] + e[6] + e[7]; - registry.fill(HIST("QA/ZNA_pmC_vs_Centrality"), centrality, zdcCol.energyCommonZNA()); - registry.fill(HIST("QA/ZNA_pmSUM_vs_Centrality"), centrality, sumZNA); + registry.fill(HIST("QA/ZNA_pmC_vs_Centrality"), cent, zdcCol.energyCommonZNA()); + registry.fill(HIST("QA/ZNA_pmSUM_vs_Centrality"), cent, sumZNA); - registry.fill(HIST("QA/ZNC_pmC_vs_Centrality"), centrality, zdcCol.energyCommonZNC()); - registry.fill(HIST("QA/ZNC_pmSUM_vs_Centrality"), centrality, sumZNC); + registry.fill(HIST("QA/ZNC_pmC_vs_Centrality"), cent, zdcCol.energyCommonZNC()); + registry.fill(HIST("QA/ZNC_pmSUM_vs_Centrality"), cent, sumZNC); - registry.fill(HIST("QA/ZNA_pm1_vs_Centrality"), centrality, e[0] / sumZNA); - registry.fill(HIST("QA/ZNA_pm2_vs_Centrality"), centrality, e[1] / sumZNA); - registry.fill(HIST("QA/ZNA_pm3_vs_Centrality"), centrality, e[2] / sumZNA); - registry.fill(HIST("QA/ZNA_pm4_vs_Centrality"), centrality, e[3] / sumZNA); + registry.fill(HIST("QA/ZNA_pm1_vs_Centrality"), cent, e[0] / sumZNA); + registry.fill(HIST("QA/ZNA_pm2_vs_Centrality"), cent, e[1] / sumZNA); + registry.fill(HIST("QA/ZNA_pm3_vs_Centrality"), cent, e[2] / sumZNA); + registry.fill(HIST("QA/ZNA_pm4_vs_Centrality"), cent, e[3] / sumZNA); - registry.fill(HIST("QA/ZNC_pm1_vs_Centrality"), centrality, e[4] / sumZNC); - registry.fill(HIST("QA/ZNC_pm2_vs_Centrality"), centrality, e[5] / sumZNC); - registry.fill(HIST("QA/ZNC_pm3_vs_Centrality"), centrality, e[6] / sumZNC); - registry.fill(HIST("QA/ZNC_pm4_vs_Centrality"), centrality, e[7] / sumZNC); + registry.fill(HIST("QA/ZNC_pm1_vs_Centrality"), cent, e[4] / sumZNC); + registry.fill(HIST("QA/ZNC_pm2_vs_Centrality"), cent, e[5] / sumZNC); + registry.fill(HIST("QA/ZNC_pm3_vs_Centrality"), cent, e[6] / sumZNC); + registry.fill(HIST("QA/ZNC_pm4_vs_Centrality"), cent, e[7] / sumZNC); } } @@ -942,6 +1025,8 @@ struct ZdcQVectors { } // "QXA", "QYA", "QXC", "QYC" + std::array q = {0, 0, 0, 0}; + int sides = 2; for (int i = 0; i < sides; ++i) { if (sumZN[i] > 0) { @@ -950,7 +1035,7 @@ struct ZdcQVectors { } } - if (cfgFillHistRegistry && !cfgFillNothing) { + if (cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { registry.get(HIST("QA/before/ZNA_Qx"))->Fill(Form("%d", runnumber), q[0]); registry.get(HIST("QA/before/ZNA_Qy"))->Fill(Form("%d", runnumber), q[1]); registry.get(HIST("QA/before/ZNC_Qx"))->Fill(Form("%d", runnumber), q[2]); @@ -965,25 +1050,24 @@ struct ZdcQVectors { return; } - loadCalibrations(cfgRec.value); + loadCalibrations(cfgRec.value, timestamp); if (extraTS.cfgRecenterForTimestamp) { - loadCalibrations(extraTS.cfgCCDBdir_Timestamp.value); + loadCalibrations(extraTS.cfgCCDBdir_Timestamp.value, timestamp); } - std::vector qRec(q); + std::array qRec(q); if (cal.atIteration == 0) { - if (isSelected && cfgFillHistRegistry) - fillCommonRegistry(q[0], q[1], q[2], q[3], v, centrality, rsTimestamp); + if (cal.isSelected && cfgFillHistRegistry && isEventSelected) + fillCommonRegistry(q[0], q[1], q[2], q[3], v, cent, rsTimestamp); - spTableZDC(runnumber, cents, v, foundBC.timestamp(), q[0], q[1], q[2], q[3], isSelected, eventSelectionFlags); - counter++; - lastRunNumber = runnumber; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), q[0], q[1], q[2], q[3], cal.isSelected, eventSelectionFlags); + cal.lastRunNumber = runnumber; return; } else { - if (cfgFillHistRegistry) - fillCommonRegistry(q[0], q[1], q[2], q[3], v, centrality, rsTimestamp); + if (cfgFillHistRegistry && isEventSelected) + fillCommonRegistry(q[0], q[1], q[2], q[3], v, cent, rsTimestamp); // vector of 4 std::vector corrQxA; @@ -1002,7 +1086,7 @@ struct ZdcQVectors { corrQxC.push_back(getCorrection(names[0][2].Data(), it, 1)); corrQyC.push_back(getCorrection(names[0][3].Data(), it, 1)); - if (cfgFillHistRegistry && !cfgFillNothing) { + if (cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { registry.get(HIST("recentering/QXA_vs_iteration"))->Fill(pb + 1, q[0] - std::accumulate(corrQxA.begin(), corrQxA.end(), 0.0)); registry.get(HIST("recentering/QYA_vs_iteration"))->Fill(pb + 1, q[1] - std::accumulate(corrQyA.begin(), corrQyA.end(), 0.0)); registry.get(HIST("recentering/QXC_vs_iteration"))->Fill(pb + 1, q[2] - std::accumulate(corrQxC.begin(), corrQxC.end(), 0.0)); @@ -1016,7 +1100,7 @@ struct ZdcQVectors { corrQxC.push_back(getCorrection(names[step - 1][2].Data(), it, step)); corrQyC.push_back(getCorrection(names[step - 1][3].Data(), it, step)); - if (cfgFillHistRegistry && !cfgFillNothing) { + if (cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { registry.get(HIST("recentering/QXA_vs_iteration"))->Fill(pb + 1, q[0] - std::accumulate(corrQxA.begin(), corrQxA.end(), 0.0)); registry.get(HIST("recentering/QYA_vs_iteration"))->Fill(pb + 1, q[1] - std::accumulate(corrQyA.begin(), corrQyA.end(), 0.0)); registry.get(HIST("recentering/QXC_vs_iteration"))->Fill(pb + 1, q[2] - std::accumulate(corrQxC.begin(), corrQxC.end(), 0.0)); @@ -1032,7 +1116,7 @@ struct ZdcQVectors { corrQxC.push_back(getCorrection(namesTS[2].Data(), it, 6)); corrQyC.push_back(getCorrection(namesTS[3].Data(), it, 6)); - if (cfgFillHistRegistry && !cfgFillNothing) { + if (cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { registry.get(HIST("recentering/QXA_vs_iteration"))->Fill(pb + 1, q[0] - std::accumulate(corrQxA.begin(), corrQxA.end(), 0.0)); registry.get(HIST("recentering/QYA_vs_iteration"))->Fill(pb + 1, q[1] - std::accumulate(corrQyA.begin(), corrQyA.end(), 0.0)); registry.get(HIST("recentering/QXC_vs_iteration"))->Fill(pb + 1, q[2] - std::accumulate(corrQxC.begin(), corrQxC.end(), 0.0)); @@ -1079,11 +1163,11 @@ struct ZdcQVectors { } for (int ishift = 1; ishift <= nshift; ishift++) { - if (!cfgFillNothing) { - registry.fill(HIST("shift/ShiftZDCC"), centrality, 0.5, ishift - 0.5, std::sin(ishift * 1.0 * psiZDCC)); - registry.fill(HIST("shift/ShiftZDCC"), centrality, 1.5, ishift - 0.5, std::cos(ishift * 1.0 * psiZDCC)); - registry.fill(HIST("shift/ShiftZDCA"), centrality, 0.5, ishift - 0.5, std::sin(ishift * 1.0 * psiZDCA)); - registry.fill(HIST("shift/ShiftZDCA"), centrality, 1.5, ishift - 0.5, std::cos(ishift * 1.0 * psiZDCA)); + if (!cfgFillNothing && isEventSelected) { + registry.fill(HIST("shift/ShiftZDCC"), cent, 0.5, ishift - 0.5, std::sin(ishift * 1.0 * psiZDCC)); + registry.fill(HIST("shift/ShiftZDCC"), cent, 1.5, ishift - 0.5, std::cos(ishift * 1.0 * psiZDCC)); + registry.fill(HIST("shift/ShiftZDCA"), cent, 0.5, ishift - 0.5, std::sin(ishift * 1.0 * psiZDCA)); + registry.fill(HIST("shift/ShiftZDCA"), cent, 1.5, ishift - 0.5, std::cos(ishift * 1.0 * psiZDCA)); } } @@ -1094,10 +1178,10 @@ struct ZdcQVectors { if (cal.isShiftProfileFound) { for (int ishift = 1; ishift <= nshift; ishift++) { - int binshiftxZDCC = cal.shiftprofileC->FindBin(centrality, 0.5, ishift - 0.5); // bin 0.5 - int binshiftyZDCC = cal.shiftprofileC->FindBin(centrality, 1.5, ishift - 0.5); - int binshiftxZDCA = cal.shiftprofileA->FindBin(centrality, 0.5, ishift - 0.5); - int binshiftyZDCA = cal.shiftprofileA->FindBin(centrality, 1.5, ishift - 0.5); + int binshiftxZDCC = cal.shiftprofileC->FindBin(cent, 0.5, ishift - 0.5); // bin 0.5 + int binshiftyZDCC = cal.shiftprofileC->FindBin(cent, 1.5, ishift - 0.5); + int binshiftxZDCA = cal.shiftprofileA->FindBin(cent, 0.5, ishift - 0.5); + int binshiftyZDCA = cal.shiftprofileA->FindBin(cent, 1.5, ishift - 0.5); if (binshiftxZDCC > 0) coeffshiftxZDCC = cal.shiftprofileC->GetBinContent(binshiftxZDCC); @@ -1120,12 +1204,12 @@ struct ZdcQVectors { psiZDCCshift = std::atan2(std::sin(psiZDCCshift), std::cos(psiZDCCshift)); psiZDCAshift = std::atan2(std::sin(psiZDCAshift), std::cos(psiZDCAshift)); - if (cfgFillHistRegistry && !cfgFillNothing) { - registry.fill(HIST("QA/shift/psiZDCA"), psiZDCA, centrality); - registry.fill(HIST("QA/shift/psiZDCC"), psiZDCC, centrality); + if (cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { + registry.fill(HIST("QA/shift/psiZDCA"), psiZDCA, cent); + registry.fill(HIST("QA/shift/psiZDCC"), psiZDCC, cent); registry.fill(HIST("QA/shift/psiZDCAC"), psiZDCA, psiZDCC); - registry.fill(HIST("QA/shift/psiZDCA_shift"), psiZDCAshift, centrality); - registry.fill(HIST("QA/shift/psiZDCC_shift"), psiZDCCshift, centrality); + registry.fill(HIST("QA/shift/psiZDCA_shift"), psiZDCAshift, cent); + registry.fill(HIST("QA/shift/psiZDCC_shift"), psiZDCCshift, cent); registry.fill(HIST("QA/shift/psiZDCAC_shift"), psiZDCAshift, psiZDCCshift); registry.fill(HIST("QA/shift/DeltaPsiZDCA"), psiZDCAshift, psiZDCA); registry.fill(HIST("QA/shift/DeltaPsiZDCC"), psiZDCCshift, psiZDCC); @@ -1137,24 +1221,23 @@ struct ZdcQVectors { double qXcShift = std::hypot(qRec[2], qRec[3]) * std::cos(psiZDCCshift); double qYcShift = std::hypot(qRec[2], qRec[3]) * std::sin(psiZDCCshift); - if (isSelected && cfgFillHistRegistry && !cfgFillNothing) { - fillCommonRegistry(qXaShift, qYaShift, qXcShift, qYcShift, v, centrality, rsTimestamp); - registry.fill(HIST("QA/centrality_after"), centrality); + if (cal.isSelected && cfgFillHistRegistry && !cfgFillNothing && isEventSelected) { + fillCommonRegistry(qXaShift, qYaShift, qXcShift, qYcShift, v, cent, rsTimestamp); + registry.fill(HIST("QA/centrality_after"), cent); registry.get(HIST("QA/after/ZNA_Qx"))->Fill(Form("%d", runnumber), qXaShift); registry.get(HIST("QA/after/ZNA_Qy"))->Fill(Form("%d", runnumber), qYaShift); registry.get(HIST("QA/after/ZNC_Qx"))->Fill(Form("%d", runnumber), qXcShift); registry.get(HIST("QA/after/ZNC_Qy"))->Fill(Form("%d", runnumber), qYcShift); } - spTableZDC(runnumber, cents, v, foundBC.timestamp(), qXaShift, qYaShift, qXcShift, qYcShift, isSelected, eventSelectionFlags); - qRec.clear(); + spTableZDC(runnumber, cents, v, foundBC.timestamp(), qXaShift, qYaShift, qXcShift, qYcShift, cal.isSelected, eventSelectionFlags); + qRec = {0, 0, 0, 0}; - counter++; - lastRunNumber = runnumber; + cal.lastRunNumber = runnumber; return; } LOGF(warning, "We return without saving table... -> THis is a problem"); - lastRunNumber = runnumber; + cal.lastRunNumber = runnumber; } // end of process }; diff --git a/PWGCF/Flow/Tasks/flowEseTask.cxx b/PWGCF/Flow/Tasks/flowEseTask.cxx index b7c8b5cb96d..e36ad406927 100644 --- a/PWGCF/Flow/Tasks/flowEseTask.cxx +++ b/PWGCF/Flow/Tasks/flowEseTask.cxx @@ -82,7 +82,7 @@ struct FlowEseTask { "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; } cfgCcdbParam; - Service ccdb; + Service ccdb{}; o2::ccdb::CcdbApi ccdbApi; Configurable cfgCentSel{"cfgCentSel", 80., "Centrality selection"}; @@ -204,7 +204,7 @@ struct FlowEseTask { int currentRunNumber = -999; int lastRunNumber = -999; - std::vector shiftprofile{}; + std::vector shiftprofile; TProfile2D* effMap = nullptr; TProfile2D* accMap = nullptr; @@ -213,23 +213,25 @@ struct FlowEseTask { template int getDetId(const T& name) { - if (name.value == "FT0C") { - return 0; - } else if (name.value == "FT0A") { + if (name.value == "FT0A") { return 1; - } else if (name.value == "FT0M") { + } + if (name.value == "FT0M") { return 2; - } else if (name.value == "FV0A") { + } + if (name.value == "FV0A") { return 3; - } else if (name.value == "TPCpos") { + } + if (name.value == "TPCpos") { return 4; - } else if (name.value == "TPCneg") { + } + if (name.value == "TPCneg") { return 5; - } else if (name.value == "TPCall") { + } + if (name.value == "TPCall") { return 6; - } else { - return 0; } + return 0; } int q2CentBin(float cent) const @@ -242,7 +244,7 @@ struct FlowEseTask { const char* q2GroupSuffix(int group) const { - static constexpr const char* Q2GroupSuffixes[] = { + static constexpr std::array Q2GroupSuffixes = { "q2p00_10", "q2p10_20", "q2p20_30", "q2p30_40", "q2p40_50", "q2p50_60", "q2p60_70", "q2p70_80", "q2p80_90", "q2p90_100"}; if (group < 0 || group >= NQ2Groups) { @@ -269,10 +271,10 @@ struct FlowEseTask { template double getQ2(TCollision const& collision) { - if (cfgMultCor) + if (cfgMultCor) { return std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * collision.sumAmplFT0C() / std::sqrt(collision.multFT0C()); - else - return std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()); + } + return std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()); } void init(o2::framework::InitContext&) @@ -300,8 +302,10 @@ struct FlowEseTask { AxisSpec shiftAxis = {10, 0, 10, "shift"}; AxisSpec basisAxis = {20, 0, 20, "basis"}; + AxisSpec q2GroupAxis = {10, 0.0, 10.0, "q_{2} percentile group"}; histos.add("histQvecCent", "", {HistType::kTH2F, {q2QaAxis, centQaAxis}}); + histos.add("histEventCountQ2Group", "", {HistType::kTH2F, {centQaAxis, q2GroupAxis}}); histos.add(Form("histVertex"), "", {HistType::kTHnSparseF, {vertexAxis, vertexAxis, vertexAxis, centAxis}}); for (int iGroup = 0; iGroup < NQ2Groups; ++iGroup) { histos.add(Form("histV2_%s", q2GroupSuffix(iGroup)), "", {HistType::kTHnSparseF, {centAxis, ptAxis, cosAxis}}); @@ -434,6 +438,13 @@ struct FlowEseTask { histos.add(Form("psi%d/QA/EPRes_Det_RefA", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); histos.add(Form("psi%d/QA/EPRes_Det_RefB", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); histos.add(Form("psi%d/QA/EPRes_RefA_RefB", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + if (i == CorrLevel[0]) { + for (int iGroup = 0; iGroup < NQ2Groups; ++iGroup) { + histos.add(Form("psi2/QA/EPRes_Det_RefA_%s", q2GroupSuffix(iGroup)), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi2/QA/EPRes_Det_RefB_%s", q2GroupSuffix(iGroup)), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi2/QA/EPRes_RefA_RefB_%s", q2GroupSuffix(iGroup)), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + } + } histos.add(Form("psi%d/QA/EP_FT0C_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); histos.add(Form("psi%d/QA/EP_FT0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); histos.add(Form("psi%d/QA/EP_FV0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); @@ -490,7 +501,7 @@ struct FlowEseTask { ROOT::Math::PxPyPzMVector protonVec, pionVec, LambdaVec, protonBoostedVec, pionBoostedVec; template - bool eventSelected(TCollision collision) + bool eventSelected(TCollision const& collision) { if (!collision.sel8()) { return 0; @@ -582,14 +593,16 @@ struct FlowEseTask { double safeATan2(double y, double x) { - if (x != 0) + if (x != 0) { return std::atan2(y, x); - if (y == 0) + } + if (y == 0) { return 0; - if (y > 0) + } + if (y > 0) { return o2::constants::math::PIHalf; - else - return -o2::constants::math::PIHalf; + } + return -o2::constants::math::PIHalf; } template @@ -682,6 +695,63 @@ struct FlowEseTask { histos.fill(HIST("psi2/QA/EPRes_Det_RefA"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]))); histos.fill(HIST("psi2/QA/EPRes_Det_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); histos.fill(HIST("psi2/QA/EPRes_RefA_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + const double epResDetRefA = std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd])); + const double epResDetRefB = std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd])); + const double epResRefARefB = std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd])); + switch (q2Group(centrality, getQ2(collision))) { + case 0: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p00_10"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p00_10"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p00_10"), centrality, epResRefARefB); + break; + case 1: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p10_20"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p10_20"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p10_20"), centrality, epResRefARefB); + break; + case 2: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p20_30"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p20_30"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p20_30"), centrality, epResRefARefB); + break; + case 3: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p30_40"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p30_40"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p30_40"), centrality, epResRefARefB); + break; + case 4: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p40_50"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p40_50"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p40_50"), centrality, epResRefARefB); + break; + case 5: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p50_60"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p50_60"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p50_60"), centrality, epResRefARefB); + break; + case 6: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p60_70"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p60_70"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p60_70"), centrality, epResRefARefB); + break; + case 7: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p70_80"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p70_80"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p70_80"), centrality, epResRefARefB); + break; + case 8: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p80_90"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p80_90"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p80_90"), centrality, epResRefARefB); + break; + case 9: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p90_100"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p90_100"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p90_100"), centrality, epResRefARefB); + break; + default: + break; + } } else if (nmode == CorrLevel[1]) { histos.fill(HIST("psi3/QA/EP_Det"), centrality, std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode)); histos.fill(HIST("psi3/QA/EP_RefA"), centrality, std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode)); @@ -1212,6 +1282,10 @@ struct FlowEseTask { histos.fill(HIST("QA/CentDist"), centrality, 1.0); histos.fill(HIST("QA/PVzDist"), collision.posZ(), 1.0); histos.fill(HIST("histQvecCent"), getQ2(collision), centrality); + const int q2PercentileGroup = q2Group(centrality, getQ2(collision)); + if (q2PercentileGroup >= 0) { + histos.fill(HIST("histEventCountQ2Group"), centrality, q2PercentileGroup + 0.5); + } if (cfgShiftCorr) { auto bc = collision.bc_as(); diff --git a/PWGCF/Flow/Tasks/flowSP.cxx b/PWGCF/Flow/Tasks/flowSP.cxx index 3f11c04a52e..33e6969ef60 100644 --- a/PWGCF/Flow/Tasks/flowSP.cxx +++ b/PWGCF/Flow/Tasks/flowSP.cxx @@ -1142,23 +1142,21 @@ struct FlowSP { if (!cfg.cFillEventQA) return; - static constexpr std::string_view Time[] = {"before", "after"}; - - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFT0C"), collision.centFT0C(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentNGlobal"), collision.centNGlobal(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFT0M"), collision.centFT0M(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFV0A"), collision.centFV0A(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_centT0C"), collision.centFT0C(), tracks.size(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_multT0A"), collision.multFT0A(), tracks.size(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_multV0A"), collision.multFV0A(), tracks.size(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/multV0A_multT0A"), collision.multFT0A(), collision.multFV0A(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/multT0C_centT0C"), collision.centFT0C(), collision.multFT0C(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFT0Cvariant1"), collision.centFT0C(), collision.centFT0CVariant1(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFT0M"), collision.centFT0C(), collision.centFT0M(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFV0A"), collision.centFT0C(), collision.centFV0A(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentNGlobal"), collision.centFT0C(), collision.centNGlobal(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("hCentFT0C"), collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("hCentNGlobal"), collision.centNGlobal(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("hCentFT0M"), collision.centFT0M(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("hCentFV0A"), collision.centFV0A(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("globalTracks_centT0C"), collision.centFT0C(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("globalTracks_multT0A"), collision.multFT0A(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("globalTracks_multV0A"), collision.multFV0A(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("CentFT0C_vs_CentFT0Cvariant1"), collision.centFT0C(), collision.centFT0CVariant1(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("CentFT0C_vs_CentFT0M"), collision.centFT0C(), collision.centFT0M(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("CentFT0C_vs_CentFV0A"), collision.centFT0C(), collision.centFV0A(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("CentFT0C_vs_CentNGlobal"), collision.centFT0C(), collision.centNGlobal(), spm.centWeight); if (cfg.cFillEventPlaneQA) { if constexpr (o2::framework::has_type_v) { @@ -1166,18 +1164,18 @@ struct FlowSP { double psiC = 1.0 * std::atan2(collision.qyC(), collision.qxC()); double psiFull = 1.0 * std::atan2(collision.qyA() + collision.qyC(), collision.qxA() + collision.qxC()); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Cent"), psiA, collision.centFT0C(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Cent"), psiC, collision.centFT0C(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Cent"), psiFull, collision.centFT0C(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vx"), psiA, collision.vertex()[0], spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vx"), psiC, collision.vertex()[0], spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vx"), psiFull, collision.vertex()[0], spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vy"), psiA, collision.vertex()[1], spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vy"), psiC, collision.vertex()[1], spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vy"), psiFull, collision.vertex()[1], spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vz"), psiA, collision.posZ(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vz"), psiC, collision.posZ(), spm.centWeight); - histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vz"), psiFull, collision.posZ(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiA_vs_Cent"), psiA, collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiC_vs_Cent"), psiC, collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiFull_vs_Cent"), psiFull, collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiA_vs_Vx"), psiA, collision.vertex()[0], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiC_vs_Vx"), psiC, collision.vertex()[0], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiFull_vs_Vx"), psiFull, collision.vertex()[0], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiA_vs_Vy"), psiA, collision.vertex()[1], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiC_vs_Vy"), psiC, collision.vertex()[1], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiFull_vs_Vy"), psiFull, collision.vertex()[1], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiA_vs_Vz"), psiA, collision.posZ(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiC_vs_Vz"), psiC, collision.posZ(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("PsiFull_vs_Vz"), psiFull, collision.posZ(), spm.centWeight); } } return; @@ -1260,7 +1258,6 @@ struct FlowSP { double weight = spm.wacc[ct][par] * spm.weff[ct][par] * spm.centWeight; - static constexpr std::string_view Time[] = {"before/", "after/"}; // NOTE: species[kUnidentified] = "" (when nocfg.cTrackSelDo) { if (cfg.cTrackSelDoTrackQAvsCent) { histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPt_Eta"), track.pt(), track.eta(), spm.centrality, weight); @@ -1302,7 +1299,6 @@ struct FlowSP { template inline void fillMCPtHistos(TrackObject track, int pdgCode) { - static constexpr std::string_view Time[] = {"before/", "after/"}; static constexpr std::string_view Mode[] = {"Gen/", "Reco/"}; registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_hadron"), track.pt(), track.eta(), spm.centrality); @@ -1339,12 +1335,11 @@ struct FlowSP { template inline void fillPrimaryHistos(McParticleObject mcparticle) { - static constexpr std::string_view Time[] = {"/before", "/after"}; if (!mcparticle.isPhysicalPrimary()) { - registry.fill(HIST("trackMCReco") + HIST(Time[ft]) + HIST("/") + HIST(Charge[ct]) + HIST("hIsPhysicalPrimary"), 0, spm.centrality, mcparticle.pt()); + registry.fill(HIST("trackMCReco/") + HIST(Time[ft]) + HIST(Charge[ct]) + HIST("hIsPhysicalPrimary"), 0, spm.centrality, mcparticle.pt()); } else { - registry.fill(HIST("trackMCReco") + HIST(Time[ft]) + HIST("/") + HIST(Charge[ct]) + HIST("hIsPhysicalPrimary"), 1, spm.centrality, mcparticle.pt()); + registry.fill(HIST("trackMCReco/") + HIST(Time[ft]) + HIST(Charge[ct]) + HIST("hIsPhysicalPrimary"), 1, spm.centrality, mcparticle.pt()); } } diff --git a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx index 0e7d84b607b..54c7912b6ab 100644 --- a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx +++ b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #include #include +#include #include #include #include @@ -85,6 +87,12 @@ struct PidFlowPtCorr { Configurable cfgRangeEta{"cfgRangeEta", 0.4f, "Eta range for mean Pt"}; Configurable cfgCutPtMin{"cfgCutPtMin", 0.2f, "Minimal pT for ref tracks"}; Configurable cfgCutPtMax{"cfgCutPtMax", 10.0f, "Maximal pT for ref tracks"}; + Configurable cfgCutPtMinPi{"cfgCutPtMinPi", 0.2f, "Minimal pT for pion POI"}; + Configurable cfgCutPtMaxPi{"cfgCutPtMaxPi", 10.0f, "Maximal pT for pion POI"}; + Configurable cfgCutPtMinKa{"cfgCutPtMinKa", 0.2f, "Minimal pT for kaon POI"}; + Configurable cfgCutPtMaxKa{"cfgCutPtMaxKa", 10.0f, "Maximal pT for kaon POI"}; + Configurable cfgCutPtMinPr{"cfgCutPtMinPr", 0.2f, "Minimal pT for proton POI"}; + Configurable cfgCutPtMaxPr{"cfgCutPtMaxPr", 10.0f, "Maximal pT for proton POI"}; // track quality selections for daughter track Configurable cfgITSNCls{"cfgITSNCls", 5, "check minimum number of ITS clusters"}; Configurable cfgTPCNCls{"cfgTPCNCls", 50, "check minimum number of TPC hits"}; @@ -108,6 +116,7 @@ struct PidFlowPtCorr { Configurable cfgDoV0AT0Acut{"cfgDoV0AT0Acut", true, "do V0A-T0A cut"}; Configurable cfgCutminIR{"cfgCutminIR", -1, "cut min IR"}; Configurable cfgCutmaxIR{"cfgCutmaxIR", 3000, "cut max IR"}; + Configurable cfgIRSource{"cfgIRSource", "ZNC hadronic", "Interaction-rate source for CTP rate fetcher. Use T0VTX for pp/OO and ZNC hadronic for Pb-Pb; empty disables fetching"}; } evtSeleOpts; struct : ConfigurableGroup { @@ -124,6 +133,8 @@ struct PidFlowPtCorr { std::string prefix = "correctionPathOpts"; Configurable> cfgAcceptancePath{"cfgAcceptancePath", (std::vector{"Users/f/fcui/NUA/NUAREFPartical", "Users/f/fcui/NUA/NUAK0s", "Users/f/fcui/NUA/NUALambda", "Users/f/fcui/NUA/NUAXi", "Users/f/fcui/NUA/NUAOmega"}), "CCDB path to acceptance object"}; + Configurable> cfgAcceptancePathWithPt{"cfgAcceptancePathWithPt", (std::vector{"Users/f/fcui/NUA/NUAREFParticalWithPt"}), "CCDB path to acceptance THnSparse(phi,eta,vz,pt) object, same content as cfgAcceptancePath but with an extra pt axis"}; + Configurable> cfgEfficiencyPath{"cfgEfficiencyPath", (std::vector{"PathtoRef"}), "CCDB path to efficiency object"}; } correctionPathOpts; @@ -143,8 +154,10 @@ struct PidFlowPtCorr { Configurable cfgCheck2MethodDiff{"cfgCheck2MethodDiff", false, "check difference between v2' && v2''"}; Configurable cfgClosureTest{"cfgClosureTest", 0, "choose (val) percent particle from charged to pass Pion PID selection"}; Configurable cfgOutPutMC1D{"cfgOutPutMC1D", true, "Fill MC graphs, note that if the processMCgen is open,this MUST be open"}; + Configurable cfgAddPidResponseMatrixHistograms{"cfgAddPidResponseMatrixHistograms", false, "Add PID response matrix histograms; enable together with processPidResponseMatrix"}; Configurable cfgProcessQAOutput{"cfgProcessQAOutput", false, "QA plots for processQA"}; + Configurable cfgUseNUAWithPt{"cfgUseNUAWithPt", false, "false: use original GFWWeights (phi,eta,vz) NUA; true: use THnSparse (phi,eta,vz,pt) NUA loaded from cfgAcceptancePathWithPt"}; } switchsOpts; /** @@ -274,6 +287,7 @@ struct PidFlowPtCorr { std::vector corrconfigs; std::vector cfgAcceptance; + std::vector cfgAcceptanceWithPt; std::vector cfgMultPVCutPara; std::vector cfgNSigma; @@ -318,12 +332,23 @@ struct PidFlowPtCorr { funcProcessReco, funcProcessSim, funcProcessQA, + funcProcessPidResponseMatrix, funcNumber }; + enum PidResponseBin { + kPidRespPion = 0, + kPidRespKaon, + kPidRespProton, + kPidRespUnidentified, + kPidRespNRecoBins + }; + // graphs for NUE / NUA std::vector mAcceptance; std::vector mEfficiency; + // NUA with extra pt axis: THnSparse(phi, eta, vz, pt), same content as mAcceptance but pt-differential + std::vector mAcceptanceWithPt; bool correctionsLoaded = false; @@ -366,6 +391,7 @@ struct PidFlowPtCorr { ccdb->setCreatedNotAfter(cfgnolaterthan.value); cfgAcceptance = correctionPathOpts.cfgAcceptancePath.value; + cfgAcceptanceWithPt = correctionPathOpts.cfgAcceptancePathWithPt.value; cfgNSigma = cfgNSigmapid; cfgMultPVCutPara = evtSeleOpts.cfgMultPVCut; @@ -387,6 +413,10 @@ struct PidFlowPtCorr { registry.add("hPhicorrKa", "", {HistType::kTH1D, {cfgaxisPhi}}); registry.add("hPhiPr", "", {HistType::kTH1D, {cfgaxisPhi}}); registry.add("hPhicorrPr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUE", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUEPi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUEKa", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUEPr", "", {HistType::kTH1D, {cfgaxisPhi}}); registry.add("hEta", "", {HistType::kTH1D, {cfgaxisEta}}); registry.add("hVtxZ", "", {HistType::kTH1D, {cfgaxisVertex}}); registry.add("hMult", "", {HistType::kTH1D, {cfgaxisNch}}); @@ -485,10 +515,10 @@ struct PidFlowPtCorr { if (switchsOpts.cfgOutputrunbyrun.value) { // hist for NUA - registry.add("correction/hRunNumberPhiEtaVertex", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); - registry.add("correction/hRunNumberPhiEtaVertexPion", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); - registry.add("correction/hRunNumberPhiEtaVertexKaon", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); - registry.add("correction/hRunNumberPhiEtaVertexProton", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); + registry.add("correction/hRunNumberPhiEtaVertex", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); + registry.add("correction/hRunNumberPhiEtaVertexPion", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); + registry.add("correction/hRunNumberPhiEtaVertexKaon", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); + registry.add("correction/hRunNumberPhiEtaVertexProton", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); // set "correction/hRunNumberPhiEtaVertex" axis0 label for (uint64_t idx = 1; idx <= runNumbers.size(); idx++) { @@ -531,10 +561,30 @@ struct PidFlowPtCorr { registry.addClone("hEventCount/processData", "hEventCount/processReco"); // processSim registry.addClone("hEventCount/processData", "hEventCount/processSim"); + // processPidResponseMatrix + registry.addClone("hEventCount/processData", "hEventCount/processPidResponseMatrix"); registry.add("hInteractionRate", "", {HistType::kTH1D, {{1000, 0, 1000}}}); // end set bin label for eventcount + if (switchsOpts.cfgAddPidResponseMatrixHistograms.value) { + registry.add("pidResponseMatrix/hPidResponseMatrix", "PID response matrix;true PID;reconstructed PID", {HistType::kTH2D, {{3, -0.5, 2.5}, {4, -0.5, 3.5}}}); + registry.add("pidResponseMatrix/hPidResponseMatrixRecPtCent", "PID response matrix vs reconstructed pT and centrality;true PID;reconstructed PID;p_{T}^{rec} (GeV/#it{c});Centrality (%)", {HistType::kTHnSparseF, {{3, -0.5, 2.5}, {4, -0.5, 3.5}, cfgaxisPt, axisMultiplicity}}); + + auto setPidResponseLabels = [](TAxis* axis, bool includeUnidentified) { + axis->SetBinLabel(kPidRespPion + 1, "Pion"); + axis->SetBinLabel(kPidRespKaon + 1, "Kaon"); + axis->SetBinLabel(kPidRespProton + 1, "Proton"); + if (includeUnidentified) { + axis->SetBinLabel(kPidRespUnidentified + 1, "Unidentified"); + } + }; + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrix"))->GetXaxis(), false); + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrix"))->GetYaxis(), true); + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrixRecPtCent"))->GetAxis(0), false); + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrixRecPtCent"))->GetAxis(1), true); + } + // flow container setup // cumulant of flow // fill TObjArray for charged @@ -1034,6 +1084,53 @@ struct PidFlowPtCorr { return pid; } + bool isWithinRefPtRange(float pt) + { + return (pt > trkQualityOpts.cfgCutPtMin.value) && (pt < trkQualityOpts.cfgCutPtMax.value); + } + + bool isWithinPOIPtRange(int pid, float pt) + { + switch (pid) { + case MyParticleType::kPion: + return (pt > trkQualityOpts.cfgCutPtMinPi.value) && (pt < trkQualityOpts.cfgCutPtMaxPi.value); + case MyParticleType::kKaon: + return (pt > trkQualityOpts.cfgCutPtMinKa.value) && (pt < trkQualityOpts.cfgCutPtMaxKa.value); + case MyParticleType::kProton: + return (pt > trkQualityOpts.cfgCutPtMinPr.value) && (pt < trkQualityOpts.cfgCutPtMaxPr.value); + default: + return false; + } + } + + int getPidResponseTrueBin(int pdgCode) + { + switch (std::abs(pdgCode)) { + case PDG_t::kPiPlus: + return kPidRespPion; + case PDG_t::kKPlus: + return kPidRespKaon; + case PDG_t::kProton: + return kPidRespProton; + default: + return -1; + } + } + + int getPidResponseRecoBin(int recoPid) + { + switch (recoPid) { + case MyParticleType::kPion: + return kPidRespPion; + case MyParticleType::kKaon: + return kPidRespKaon; + case MyParticleType::kProton: + return kPidRespProton; + default: + return kPidRespUnidentified; + } + } + // pid util function // other utils @@ -1432,6 +1529,33 @@ struct PidFlowPtCorr { // end load NUA + // load NUA with pt axis (THnSparse: phi, eta, vz, pt), only if cfgUseNUAWithPt is enabled + // same convention as the GFWWeights NUA above: 1 path -> charged only, 4 paths -> charged, pi, ka, pr + if (switchsOpts.cfgUseNUAWithPt.value) { + if (cfgAcceptanceWithPt.size() == static_cast(nspecies)) { + for (int i = 0; i < nspecies; i++) { + mAcceptanceWithPt.push_back(ccdb->getForTimeStamp(cfgAcceptanceWithPt[i], timestamp)); + } + if (mAcceptanceWithPt.size() == static_cast(nspecies)) { + LOGF(info, "Loaded acceptance weights with pt axis"); + } else { + LOGF(warning, "Could not load acceptance weights with pt axis"); + } + } + + if (cfgAcceptanceWithPt.size() == static_cast(totalSpecies)) { + for (int i = 0; i <= totalSpecies - 1; i++) { + mAcceptanceWithPt.push_back(ccdb->getForTimeStamp(cfgAcceptanceWithPt[i], timestamp)); + } + if (mAcceptanceWithPt.size() == static_cast(totalSpecies)) { + LOGF(info, "Loaded acceptance weights with pt axis * 4"); + } else { + LOGF(warning, "Could not load acceptance weights with pt axis * 4"); + } + } + } + // end load NUA with pt axis + /// @note dont modify load NUA!, just modify NUE // here needs to load 2 NUE graph selected from 6 ccdb path /// @note when using eff 2D, convert TH1* to (TH2D *) @@ -1466,9 +1590,34 @@ struct PidFlowPtCorr { correctionsLoaded = true; } + /** + * @brief get NUA weight from a THnSparse(phi, eta, vz, pt), same convention as GFWWeights::getNUA + * (bin content is the normalized acceptance, 0-1, so the correction weight is 1/content) + * + * @param hist THnSparse with axes (phi, eta, vz, pt), may be nullptr + */ + float getNUAFromTHn(THnSparse* hist, float phi, float eta, float vz, float pt) + { + if (!hist) { + return 1; + } + std::array bins; + bins[0] = hist->GetAxis(0)->FindBin(phi); + bins[1] = hist->GetAxis(1)->FindBin(eta); + bins[2] = hist->GetAxis(2)->FindBin(vz); + bins[3] = hist->GetAxis(3)->FindBin(pt); + double weight = hist->GetBinContent(bins.data()); + if (weight != 0) { + return 1. / weight; + } + return 1; + } + /** * @brief Set the Particle NUA, note that it works only when macceptance size >= 1, * macceptance size can only be 1 or 4 + * @note controlled by switchsOpts.cfgUseNUAWithPt: false uses the original GFWWeights + * (phi,eta,vz) NUA (mAcceptance); true uses the THnSparse (phi,eta,vz,pt) NUA (mAcceptanceWithPt) * * @tparam TrackObject * @param weight_nua @@ -1480,6 +1629,14 @@ struct PidFlowPtCorr { template bool setParticleNUAWeight(float& weight_nua, TrackObject& track, float vtxz) { + if (switchsOpts.cfgUseNUAWithPt.value) { + if (mAcceptanceWithPt.size() == static_cast(1) || mAcceptanceWithPt.size() == static_cast(4)) { + weight_nua = getNUAFromTHn(mAcceptanceWithPt[0], track.phi(), track.eta(), vtxz, track.pt()); + } else { + weight_nua = 1; + } + return true; + } if (mAcceptance.size() == static_cast(1) || mAcceptance.size() == static_cast(4)) { weight_nua = mAcceptance[0]->getNUA(track.phi(), track.eta(), vtxz); } else { @@ -1491,6 +1648,28 @@ struct PidFlowPtCorr { template bool setParticleNUAWeight(float& weight_nua, TrackObject& track, float vtxz, int pid) { + if (switchsOpts.cfgUseNUAWithPt.value) { + if (mAcceptanceWithPt.size() == static_cast(4)) { + switch (pid) { + case MyParticleType::kPion: + weight_nua = getNUAFromTHn(mAcceptanceWithPt[1], track.phi(), track.eta(), vtxz, track.pt()); + break; + case MyParticleType::kKaon: + weight_nua = getNUAFromTHn(mAcceptanceWithPt[2], track.phi(), track.eta(), vtxz, track.pt()); + break; + case MyParticleType::kProton: + weight_nua = getNUAFromTHn(mAcceptanceWithPt[3], track.phi(), track.eta(), vtxz, track.pt()); + break; + + default: + weight_nua = 1; + break; + } + } else { + weight_nua = 1; + } + return true; + } if (mAcceptance.size() == static_cast(4)) { switch (pid) { @@ -1618,11 +1797,13 @@ struct PidFlowPtCorr { * * @tparam TTrack * @param track + * @param checkPt if false, skip the internal ref-pt cut (cfgCutPtMin/cfgCutPtMax); needed + * so callers can apply an independent POI pt range instead (e.g. processData) * @return true pass selection * @return false reject track */ template - bool trackSelectedGlobal(TTrack& track) + bool trackSelectedGlobal(TTrack& track, bool checkPt = true) { // dca xy cut // note that z cut is in filter @@ -1631,7 +1812,7 @@ struct PidFlowPtCorr { } // pt - if (!((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) { + if (checkPt && !((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) { return false; } @@ -1704,6 +1885,12 @@ struct PidFlowPtCorr { return true; } + template + bool trackSelectedForFlow(TTrack& track) + { + return trackSelectedGlobal(track, false) && track.hasITS() && track.hasTPC() && trackSelected4ITS(track) && trackSelected4TPC(track); + } + // track cut // event selection functions @@ -1732,6 +1919,9 @@ struct PidFlowPtCorr { case MyFunctionName::funcProcessSim: registry.fill(HIST("hEventCount/processSim"), position); break; + case MyFunctionName::funcProcessPidResponseMatrix: + registry.fill(HIST("hEventCount/processPidResponseMatrix"), position); + break; default: // LOGF(warning, "could not find event count graph"); @@ -1884,11 +2074,11 @@ struct PidFlowPtCorr { fillEventCountHelper(funcName, 11.5); registry.fill(HIST("hInteractionRate"), interactionRate); - if (interactionRate > 0 && interactionRate < evtSeleOpts.cfgCutminIR.value) { + if (evtSeleOpts.cfgCutminIR.value >= 0 && interactionRate > 0 && interactionRate < evtSeleOpts.cfgCutminIR.value) { return false; } fillEventCountHelper(funcName, 12.5); - if (interactionRate > evtSeleOpts.cfgCutmaxIR.value) { + if (evtSeleOpts.cfgCutmaxIR.value >= 0 && interactionRate > evtSeleOpts.cfgCutmaxIR.value) { return false; } fillEventCountHelper(funcName, 13.5); @@ -1896,6 +2086,16 @@ struct PidFlowPtCorr { return true; } + double getInteractionRate(uint64_t timestamp, int runNumber) + { + const bool useMinIRCut = evtSeleOpts.cfgCutminIR.value >= 0; + const bool useMaxIRCut = evtSeleOpts.cfgCutmaxIR.value >= 0; + if ((!useMinIRCut && !useMaxIRCut) || evtSeleOpts.cfgIRSource.value.empty()) { + return -1.; + } + return rateFetcher.fetch(ccdb.service, timestamp, runNumber, evtSeleOpts.cfgIRSource.value) * 1.e-3; + } + // event selection // main functions @@ -1909,7 +2109,7 @@ struct PidFlowPtCorr { float nMultTPC = collision.multTPC(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init // collision cut @@ -1952,7 +2152,7 @@ struct PidFlowPtCorr { double q4x = 0, q4y = 0; for (const auto& track : tracks) { // pt cut - bool withinPtRef = (trkQualityOpts.cfgCutPtMin.value < track.pt()) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); // within RF pT rang + bool withinPtRef = isWithinRefPtRange(track.pt()); if (withinPtRef) { q2x += std::cos(2 * track.phi()); q2y += std::sin(2 * track.phi()); @@ -2004,42 +2204,32 @@ struct PidFlowPtCorr { double protonPtSquareSum = 0; // end val for pid particles - /// @note calculate pt - /// use ITS only + // Calculate mean-pT moments and PID-particle sums. for (const auto& track : tracks) { float weff = 1; - // track cut ITS only - if (!trackSelectedGlobal(track)) { - continue; - } - if (!track.hasITS()) { + // The reference and POI pT ranges are applied independently below. + if (!trackSelectedForFlow(track)) { continue; } - if (!trackSelected4ITS(track)) { - continue; - } - if (!track.hasTPC()) { - continue; - } - if (!trackSelected4TPC(track)) { - continue; - } - - // end track cut its only // do nue setParticleNUEWeight(weff, track, cent); // end do nue // calculate ncharged(nch with weight) and pt - if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { + bool withinPtRef = isWithinRefPtRange(track.pt()); + if (withinPtRef && std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { nch += weff; nchSquare += weff * weff; ptSum += weff * track.pt(); ptSumw2 += weff * weff * track.pt(); ptSquareSum += weff * weff * track.pt() * track.pt(); + } + // end calculate nch and pt + // calculate POI (pi/ka/pr) sums, each with its own independent pt range + if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { // ------------------------------ // Unified PID logic (configurable) // ------------------------------ @@ -2049,32 +2239,35 @@ struct PidFlowPtCorr { setParticleNUEWeight(weffPid, track, cent, pid); // end do nue - // Fill PID variables based on unified result - if (pid == MyParticleType::kPion) { - nPionWeighted += weffPid; - nPionSquare += weffPid * weffPid; - pionPtSum += weffPid * track.pt(); - pionPtSumw2 += weffPid * weffPid * track.pt(); - pionPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); - } else if (pid == MyParticleType::kKaon) { - nKaonWeighted += weffPid; - nKaonSquare += weffPid * weffPid; - kaonPtSum += weffPid * track.pt(); - kaonPtSumw2 += weffPid * weffPid * track.pt(); - kaonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); - } else if (pid == MyParticleType::kProton) { - nProtonWeighted += weffPid; - nProtonSquare += weffPid * weffPid; - protonPtSum += weffPid * track.pt(); - protonPtSumw2 += weffPid * weffPid * track.pt(); - protonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + // Apply the species-specific POI pT range before accumulating moments. + if (isWithinPOIPtRange(pid, track.pt())) { + if (pid == MyParticleType::kPion) { + nPionWeighted += weffPid; + nPionSquare += weffPid * weffPid; + pionPtSum += weffPid * track.pt(); + pionPtSumw2 += weffPid * weffPid * track.pt(); + pionPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + } else if (pid == MyParticleType::kKaon) { + nKaonWeighted += weffPid; + nKaonSquare += weffPid * weffPid; + kaonPtSum += weffPid * track.pt(); + kaonPtSumw2 += weffPid * weffPid * track.pt(); + kaonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + } else if (pid == MyParticleType::kProton) { + nProtonWeighted += weffPid; + nProtonSquare += weffPid * weffPid; + protonPtSum += weffPid * track.pt(); + protonPtSumw2 += weffPid * weffPid * track.pt(); + protonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + } } - // else: do nothing (ambiguous or not identified) } - // end calculate nch and pt + // end calculate POI sums - nchCorrectedPassed += weff; - nchPassedSelection += 1; + if (withinPtRef) { + nchCorrectedPassed += weff; + nchPassedSelection += 1; + } } // end pt calculation using ITS only @@ -2096,7 +2289,7 @@ struct PidFlowPtCorr { // end do NUE && NUA if (switchsOpts.cfgDoLocDenCorr.value) { - bool withinPtRef = (trkQualityOpts.cfgCutPtMin.value < track.pt()) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); + bool withinPtRef = isWithinRefPtRange(track.pt()); if (withinPtRef) { double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); fphi = (1 + 2 * fphi); @@ -2111,24 +2304,10 @@ struct PidFlowPtCorr { } } // cfgDoLocDenCorr - // track cut, global + ITS + TPC - if (!trackSelectedGlobal(track)) { - continue; - } - if (!track.hasITS()) { - continue; - } - if (!track.hasTPC()) { - continue; - } - if (!trackSelected4ITS(track)) { + // The reference and POI pT ranges are applied independently below. + if (!trackSelectedForFlow(track)) { continue; } - if (!trackSelected4TPC(track)) { - continue; - } - - // end track cut totalGlobalTrack++; if (switchsOpts.cfgDebugMyCode.value && weff == 1.) { @@ -2139,23 +2318,27 @@ struct PidFlowPtCorr { LOGF(info, "wacc for global track is 1, if NUA is open and this appears alot, check!"); } - // fill QA hist - registry.fill(HIST("hPhi"), track.phi()); - registry.fill(HIST("hPhicorr"), track.phi(), wacc); - registry.fill(HIST("hEta"), track.eta()); - registry.fill(HIST("hPt"), track.pt()); - registry.fill(HIST("hPtCorr"), track.pt(), weff); - // end fill QA hist + bool withinPtRefGlobal = isWithinRefPtRange(track.pt()); + if (withinPtRefGlobal) { + // fill QA hist + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhicorr"), track.phi(), wacc); + registry.fill(HIST("hPhiCorrNUANUE"), track.phi(), wacc * weff); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hPt"), track.pt()); + registry.fill(HIST("hPtCorr"), track.pt(), weff); + // end fill QA hist + + // pt spectra + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hPtCentData"), track.pt(), cent); + } - // pt spectra - if (switchsOpts.cfgOutPutPtSpectra.value) { - registry.fill(HIST("ptSpectra/hPtCentData"), track.pt(), cent); + // fill GFW + // bit mask 1: fill CHARGED PARTICLES + fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) } - // fill GFW - // bit mask 1: fill CHARGED PARTICLES - fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) - // ------------------------------ // Unified PID logic (configurable) // ------------------------------ @@ -2165,37 +2348,40 @@ struct PidFlowPtCorr { this->setParticleNUAWeight(waccPid, track, vtxz, pid); this->setParticleNUEWeight(weffPid, track, cent, pid); - // Fill GFW and counters based on unified result - if (pid == MyParticleType::kPion) { - // bitmask 18: 0010010 - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 2); - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 16, wacc * weff); - registry.fill(HIST("hPhiPi"), track.phi()); - registry.fill(HIST("hPhicorrPi"), track.phi(), waccPid); - registry.fill(HIST("hPtPi"), track.pt()); - registry.fill(HIST("hPtCorrPi"), track.pt(), weffPid); - numOfPi++; - } else if (pid == MyParticleType::kKaon) { - // bitmask 36: 0100100 - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 4); - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 32, wacc * weff); - registry.fill(HIST("hPhiKa"), track.phi()); - registry.fill(HIST("hPhicorrKa"), track.phi(), waccPid); - registry.fill(HIST("hPtKa"), track.pt()); - registry.fill(HIST("hPtCorrKa"), track.pt(), weffPid); - numOfKa++; - } else if (pid == MyParticleType::kProton) { - // bitmask 72: 1001000 - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 8); - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 64, wacc * weff); - registry.fill(HIST("hPhiPr"), track.phi()); - registry.fill(HIST("hPhicorrPr"), track.phi(), waccPid); - registry.fill(HIST("hPtPr"), track.pt()); - registry.fill(HIST("hPtCorrPr"), track.pt(), weffPid); - numOfPr++; - } - // else: do nothing (ambiguous or not identified) - // end fill GFW + // Fill GFW and counters using the same species-specific POI pT range. + if (isWithinPOIPtRange(pid, track.pt())) { + if (pid == MyParticleType::kPion) { + // bitmask 18: 0010010 + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 2); + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 16, wacc * weff); + registry.fill(HIST("hPhiPi"), track.phi()); + registry.fill(HIST("hPhicorrPi"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEPi"), track.phi(), waccPid * weffPid); + registry.fill(HIST("hPtPi"), track.pt()); + registry.fill(HIST("hPtCorrPi"), track.pt(), weffPid); + numOfPi++; + } else if (pid == MyParticleType::kKaon) { + // bitmask 36: 0100100 + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 4); + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 32, wacc * weff); + registry.fill(HIST("hPhiKa"), track.phi()); + registry.fill(HIST("hPhicorrKa"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEKa"), track.phi(), waccPid * weffPid); + registry.fill(HIST("hPtKa"), track.pt()); + registry.fill(HIST("hPtCorrKa"), track.pt(), weffPid); + numOfKa++; + } else if (pid == MyParticleType::kProton) { + // bitmask 72: 1001000 + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 8); + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 64, wacc * weff); + registry.fill(HIST("hPhiPr"), track.phi()); + registry.fill(HIST("hPhicorrPr"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEPr"), track.phi(), waccPid * weffPid); + registry.fill(HIST("hPtPr"), track.pt()); + registry.fill(HIST("hPtCorrPr"), track.pt(), weffPid); + numOfPr++; + } + } } // end track loop for v2 calculation // sub region, fill graphs after 2 loop on all tracks @@ -2448,6 +2634,316 @@ struct PidFlowPtCorr { } PROCESS_SWITCH(PidFlowPtCorr, processData, "", true); + /** + * @brief Run the flow calculation on generated MC particles for a closure test. + * @note Reconstructed collisions are only used to obtain the centrality. The selection is + * deliberately truth-level: MC vertex filter, physical-primary particles, kinematics, + * and PDG PID. No data event, track-quality, detector-PID, NUA, or NUE cuts are applied. + */ + void processMCClosure(FilteredMcCollisions::iterator const& mcCollision, + aod::BCsWithTimestamps const&, + soa::SmallGroups> const& collisions, + FilteredMcParticles const& mcParticles, + FilteredTracksWithMCLabel const&) + { + registry.fill(HIST("hEventCount/processData"), 0.5); + if (collisions.size() <= 0 || mcParticles.size() <= 0) { + return; + } + + for (const auto& collision : collisions) { + const float cent = getCentrality(collision); + const float vtxz = mcCollision.posZ(); + const float rndm = fRndm->Rndm(); + const int nTot = mcParticles.size(); + + fGFW->Clear(); + registry.fill(HIST("hEventCount/processData"), 1.5); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), nTot); + registry.fill(HIST("hCent"), cent); + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hCentEventCountData"), cent); + } + + double ptSum = 0., ptSumw2 = 0., nch = 0., nchSquare = 0., ptSquareSum = 0.; + double pionPtSum = 0., kaonPtSum = 0., protonPtSum = 0.; + double nPionWeighted = 0., nKaonWeighted = 0., nProtonWeighted = 0.; + double pionPtSumw2 = 0., kaonPtSumw2 = 0., protonPtSumw2 = 0.; + double nPionSquare = 0., nKaonSquare = 0., nProtonSquare = 0.; + double pionPtSquareSum = 0., kaonPtSquareSum = 0., protonPtSquareSum = 0.; + int numOfPi = 0, numOfKa = 0, numOfPr = 0; + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || !isStable(mcParticle.pdgCode()) || std::fabs(mcParticle.eta()) > trkQualityOpts.cfgCutEta.value) { + continue; + } + + const float pt = mcParticle.pt(); + const bool withinPtRef = pt > trkQualityOpts.cfgCutPtMin.value && pt < trkQualityOpts.cfgCutPtMax.value; + const bool withinMeanPtEta = std::fabs(mcParticle.eta()) < trkQualityOpts.cfgRangeEta.value; + const int absPdg = std::abs(mcParticle.pdgCode()); + int pid = -1; + if (absPdg == PDG_t::kPiPlus) { + pid = MyParticleType::kPion; + } else if (absPdg == PDG_t::kKPlus) { + pid = MyParticleType::kKaon; + } else if (absPdg == PDG_t::kProton) { + pid = MyParticleType::kProton; + } + + if (withinPtRef && withinMeanPtEta) { + nch += 1.; + nchSquare += 1.; + ptSum += pt; + ptSumw2 += pt; + ptSquareSum += pt * pt; + } + + if (withinMeanPtEta && isWithinPOIPtRange(pid, pt)) { + if (pid == MyParticleType::kPion) { + nPionWeighted += 1.; + nPionSquare += 1.; + pionPtSum += pt; + pionPtSumw2 += pt; + pionPtSquareSum += pt * pt; + } else if (pid == MyParticleType::kKaon) { + nKaonWeighted += 1.; + nKaonSquare += 1.; + kaonPtSum += pt; + kaonPtSumw2 += pt; + kaonPtSquareSum += pt * pt; + } else if (pid == MyParticleType::kProton) { + nProtonWeighted += 1.; + nProtonSquare += 1.; + protonPtSum += pt; + protonPtSumw2 += pt; + protonPtSquareSum += pt * pt; + } + } + + if (withinPtRef) { + registry.fill(HIST("hPhi"), mcParticle.phi()); + registry.fill(HIST("hPhicorr"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUE"), mcParticle.phi()); + registry.fill(HIST("hEta"), mcParticle.eta()); + registry.fill(HIST("hPt"), pt); + registry.fill(HIST("hPtCorr"), pt); + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hPtCentData"), pt, cent); + } + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 1); + } + + if (!isWithinPOIPtRange(pid, pt)) { + continue; + } + if (pid == MyParticleType::kPion) { + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 2); + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 16, 1.); + registry.fill(HIST("hPhiPi"), mcParticle.phi()); + registry.fill(HIST("hPhicorrPi"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUEPi"), mcParticle.phi()); + registry.fill(HIST("hPtPi"), pt); + registry.fill(HIST("hPtCorrPi"), pt); + ++numOfPi; + } else if (pid == MyParticleType::kKaon) { + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 4); + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 32, 1.); + registry.fill(HIST("hPhiKa"), mcParticle.phi()); + registry.fill(HIST("hPhicorrKa"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUEKa"), mcParticle.phi()); + registry.fill(HIST("hPtKa"), pt); + registry.fill(HIST("hPtCorrKa"), pt); + ++numOfKa; + } else if (pid == MyParticleType::kProton) { + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 8); + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 64, 1.); + registry.fill(HIST("hPhiPr"), mcParticle.phi()); + registry.fill(HIST("hPhicorrPr"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUEPr"), mcParticle.phi()); + registry.fill(HIST("hPtPr"), pt); + registry.fill(HIST("hPtCorrPr"), pt); + ++numOfPr; + } + } + + if (particleAbundanceOpts.cfgOutPutAbundanceDis) { + registry.fill(HIST("abundance/hNumOfPiEventCount"), numOfPi); + registry.fill(HIST("abundance/hNumOfKaEventCount"), numOfKa); + registry.fill(HIST("abundance/hNumOfPrEventCount"), numOfPr); + } + registry.fill(HIST("hNchUnCorrectedVSNchCorrected"), nch, nch); + + if (nch <= 0.) { + continue; + } + + fillFC(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, "c22"); + fillFC(MyParticleType::kCharged, corrconfigs.at(1), cent, rndm, "c24"); + fillFC(MyParticleType::kCharged, corrconfigs.at(2), cent, rndm, "c22Full"); + fillFC(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, "c32"); + fillFC(MyParticleType::kCharged, corrconfigs.at(4), cent, rndm, "c34"); + + fillFC(MyParticleType::kPion, corrconfigs.at(35), cent, rndm, "c22Full"); + fillFC(MyParticleType::kPion, corrconfigs.at(36), cent, rndm, "c22Full"); + fillFC(MyParticleType::kKaon, corrconfigs.at(37), cent, rndm, "c22Full"); + fillFC(MyParticleType::kKaon, corrconfigs.at(38), cent, rndm, "c22Full"); + fillFC(MyParticleType::kProton, corrconfigs.at(39), cent, rndm, "c22Full"); + fillFC(MyParticleType::kProton, corrconfigs.at(40), cent, rndm, "c22Full"); + + fillFC(MyParticleType::kPion, corrconfigs.at(11), cent, rndm, "c24"); + fillFC(MyParticleType::kPion, corrconfigs.at(12), cent, rndm, "c24"); + fillFC(MyParticleType::kKaon, corrconfigs.at(13), cent, rndm, "c24"); + fillFC(MyParticleType::kKaon, corrconfigs.at(14), cent, rndm, "c24"); + fillFC(MyParticleType::kProton, corrconfigs.at(15), cent, rndm, "c24"); + fillFC(MyParticleType::kProton, corrconfigs.at(16), cent, rndm, "c24"); + + fillFC(MyParticleType::kPion, corrconfigs.at(17), cent, rndm, "c32"); + fillFC(MyParticleType::kPion, corrconfigs.at(18), cent, rndm, "c32"); + fillFC(MyParticleType::kKaon, corrconfigs.at(19), cent, rndm, "c32"); + fillFC(MyParticleType::kKaon, corrconfigs.at(20), cent, rndm, "c32"); + fillFC(MyParticleType::kProton, corrconfigs.at(21), cent, rndm, "c32"); + fillFC(MyParticleType::kProton, corrconfigs.at(22), cent, rndm, "c32"); + + fillFC(MyParticleType::kPion, corrconfigs.at(23), cent, rndm, "c34"); + fillFC(MyParticleType::kPion, corrconfigs.at(24), cent, rndm, "c34"); + fillFC(MyParticleType::kKaon, corrconfigs.at(25), cent, rndm, "c34"); + fillFC(MyParticleType::kKaon, corrconfigs.at(26), cent, rndm, "c34"); + fillFC(MyParticleType::kProton, corrconfigs.at(27), cent, rndm, "c34"); + fillFC(MyParticleType::kProton, corrconfigs.at(28), cent, rndm, "c34"); + + const bool filledPi = fillFC(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, "c22pure"); + const bool filledKa = fillFC(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, "c22pure"); + const bool filledPr = fillFC(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, "c22pure"); + fillFC(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, "c32pure"); + fillFC(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, "c32pure"); + fillFC(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, "c32pure"); + + if (filledPi || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kPion, corrconfigs.at(5), cent, rndm, "c22"); + fillFC(MyParticleType::kPion, corrconfigs.at(6), cent, rndm, "c22"); + } + if (filledKa || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kKaon, corrconfigs.at(7), cent, rndm, "c22"); + fillFC(MyParticleType::kKaon, corrconfigs.at(8), cent, rndm, "c22"); + } + if (filledPr || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kProton, corrconfigs.at(9), cent, rndm, "c22"); + fillFC(MyParticleType::kProton, corrconfigs.at(10), cent, rndm, "c22"); + } + + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, nch, nch, "c22TrackWeightOne", true); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(1), cent, rndm, nch, nch, "c24TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(2), cent, rndm, nch, nch, "c22FullTrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(4), cent, rndm, nch, nch, "c34TrackWeight"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, ptSum, nch, "covV2PtWeightOne", true); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, ptSum, nch, "covV3Pt"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, ptSum, nch, "covV3Pt"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, ptSum, nch, "covV3Pt"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, ptSum, nch, "covV3Pt"); + + fillProfilePOIvnpt(corrconfigs.at(0), HIST("c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(5), HIST("pi/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(6), HIST("pi/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(7), HIST("ka/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(8), HIST("ka/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(9), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(10), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + + fillFC4PtC22(cent, ptSum, nch, rndm); + if (nPionWeighted > 0.) { + fillFC4PtC22(cent, rndm, MyParticleType::kPion, pionPtSum, nPionWeighted); + } + if (nKaonWeighted > 0.) { + fillFC4PtC22(cent, rndm, MyParticleType::kKaon, kaonPtSum, nKaonWeighted); + } + if (nProtonWeighted > 0.) { + fillFC4PtC22(cent, rndm, MyParticleType::kProton, protonPtSum, nProtonWeighted); + } + + fFCCh->FillProfile("hMeanPt", cent, ptSum / nch, nch, rndm); + fFCCh->FillProfile("hMeanPtWeightOne", cent, ptSum / nch, 1., rndm); + if (nPionWeighted > 0.) { + fFCPi->FillProfile("hMeanPt", cent, pionPtSum / nPionWeighted, nPionWeighted, rndm); + fFCPi->FillProfile("hMeanPtWeightOne", cent, pionPtSum / nPionWeighted, 1., rndm); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, pionPtSum, nPionWeighted, "covV2PtPID"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, nPionWeighted, nPionWeighted, "c22TrackWeightPID"); + } + if (nKaonWeighted > 0.) { + fFCKa->FillProfile("hMeanPt", cent, kaonPtSum / nKaonWeighted, nKaonWeighted, rndm); + fFCKa->FillProfile("hMeanPtWeightOne", cent, kaonPtSum / nKaonWeighted, 1., rndm); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, kaonPtSum, nKaonWeighted, "covV2PtPID"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, nKaonWeighted, nKaonWeighted, "c22TrackWeightPID"); + } + if (nProtonWeighted > 0.) { + fFCPr->FillProfile("hMeanPt", cent, protonPtSum / nProtonWeighted, nProtonWeighted, rndm); + fFCPr->FillProfile("hMeanPtWeightOne", cent, protonPtSum / nProtonWeighted, 1., rndm); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, protonPtSum, nProtonWeighted, "covV2PtPID"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, nProtonWeighted, nProtonWeighted, "c22TrackWeightPID"); + } + + if (switchsOpts.cfgOutPutPtSpectra.value) { + const double nPairCharged = fGFW->Calculate(corrconfigs.at(0), 0, true).real(); + const double chargedC22 = nPairCharged > 0. ? fGFW->Calculate(corrconfigs.at(0), 0, false).real() / nPairCharged : 0.; + const double pidChargedC22Pi = getPidC22InOneEvent(corrconfigs.at(5), corrconfigs.at(6)); + const double pidKaonC22 = getPidC22InOneEvent(corrconfigs.at(7), corrconfigs.at(8)); + const double pidProtonC22 = getPidC22InOneEvent(corrconfigs.at(9), corrconfigs.at(10)); + if (pidChargedC22Pi > 0. && chargedC22 > 0.) { + registry.fill(HIST("c22PrimeVsc22/Pi"), pidChargedC22Pi, chargedC22); + } + if (pidKaonC22 > 0. && chargedC22 > 0.) { + registry.fill(HIST("c22PrimeVsc22/Ka"), pidKaonC22, chargedC22); + } + if (pidProtonC22 > 0. && chargedC22 > 0.) { + registry.fill(HIST("c22PrimeVsc22/Pr"), pidProtonC22, chargedC22); + } + } + + const double nchDiff = nch * nch - nchSquare; + if (nchDiff > minVal4Float) { + fFCCh->FillProfile("ptSquareAve", cent, (ptSum * ptSum - ptSquareSum) / nchDiff, nchDiff, rndm); + fFCCh->FillProfile("ptSquareAveWeightOne", cent, (ptSum * ptSum - ptSquareSum) / nchDiff, 1., rndm); + fFCCh->FillProfile("ptAve", cent, (nch * ptSum - ptSumw2) / nchDiff, nchDiff, rndm); + fFCCh->FillProfile("ptAveWeightOne", cent, (nch * ptSum - ptSumw2) / nchDiff, 1., rndm); + } + const double pionDiff = nPionWeighted * nPionWeighted - nPionSquare; + if (pionDiff > minVal4Float) { + fFCPi->FillProfile("ptSquareAve", cent, (pionPtSum * pionPtSum - pionPtSquareSum) / pionDiff, pionDiff, rndm); + fFCPi->FillProfile("ptSquareAveWeightOne", cent, (pionPtSum * pionPtSum - pionPtSquareSum) / pionDiff, 1., rndm); + fFCPi->FillProfile("ptAve", cent, (nPionWeighted * pionPtSum - pionPtSumw2) / pionDiff, pionDiff, rndm); + fFCPi->FillProfile("ptAveWeightOne", cent, (nPionWeighted * pionPtSum - pionPtSumw2) / pionDiff, 1., rndm); + } + const double kaonDiff = nKaonWeighted * nKaonWeighted - nKaonSquare; + if (kaonDiff > minVal4Float) { + fFCKa->FillProfile("ptSquareAve", cent, (kaonPtSum * kaonPtSum - kaonPtSquareSum) / kaonDiff, kaonDiff, rndm); + fFCKa->FillProfile("ptSquareAveWeightOne", cent, (kaonPtSum * kaonPtSum - kaonPtSquareSum) / kaonDiff, 1., rndm); + fFCKa->FillProfile("ptAve", cent, (nKaonWeighted * kaonPtSum - kaonPtSumw2) / kaonDiff, kaonDiff, rndm); + fFCKa->FillProfile("ptAveWeightOne", cent, (nKaonWeighted * kaonPtSum - kaonPtSumw2) / kaonDiff, 1., rndm); + } + const double protonDiff = nProtonWeighted * nProtonWeighted - nProtonSquare; + if (protonDiff > minVal4Float) { + fFCPr->FillProfile("ptSquareAve", cent, (protonPtSum * protonPtSum - protonPtSquareSum) / protonDiff, protonDiff, rndm); + fFCPr->FillProfile("ptSquareAveWeightOne", cent, (protonPtSum * protonPtSum - protonPtSquareSum) / protonDiff, 1., rndm); + fFCPr->FillProfile("ptAve", cent, (nProtonWeighted * protonPtSum - protonPtSumw2) / protonDiff, protonDiff, rndm); + fFCPr->FillProfile("ptAveWeightOne", cent, (nProtonWeighted * protonPtSum - protonPtSumw2) / protonDiff, 1., rndm); + } + } + } + PROCESS_SWITCH(PidFlowPtCorr, processMCClosure, "Run truth-level MC flow closure", false); + /** * @brief this function is used to fill THn hist for NUA correction and for NUE correction * @details hist THn: (runNumberIDX, phi, eta, Vz), note that different runNumber will be put in the same hist @@ -2461,7 +2957,7 @@ struct PidFlowPtCorr { int nTot = tracks.size(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init // collision cut @@ -2498,7 +2994,7 @@ struct PidFlowPtCorr { // loop all the track for (const auto& track : tracks) { // track cut - if (!trackSelectedGlobal(track)) { + if (!trackSelectedGlobal(track, false)) { continue; } if (!track.hasITS()) { @@ -2516,20 +3012,25 @@ struct PidFlowPtCorr { // end track cut // fill the THn - registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + if (isWithinRefPtRange(track.pt())) { + registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + } int pid = this->getPidConfigurable(track); + if (!isWithinPOIPtRange(pid, track.pt())) { + continue; + } switch (pid) { case MyParticleType::kPion: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); break; case MyParticleType::kKaon: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexKaon"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexKaon"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); break; case MyParticleType::kProton: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexProton"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexProton"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); break; default: @@ -2551,7 +3052,7 @@ struct PidFlowPtCorr { int nTot = tracks.size(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init /// @note collision cut @@ -2619,7 +3120,7 @@ struct PidFlowPtCorr { int nTot = tracks.size(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init // loop the vector, find the place to put @@ -2705,6 +3206,76 @@ struct PidFlowPtCorr { } PROCESS_SWITCH(PidFlowPtCorr, detectorPidQA, "", true); + /** + * @brief Fill PID response matrix with MC truth PID versus reconstructed PID. + * @note The reconstructed PID uses getPidConfigurable(), so it follows the same PID cuts + * as the flow and efficiency parts of this task. Reco bin Unidentified contains + * tracks that pass quality cuts but fail or ambiguously pass PID selection. + */ + void processPidResponseMatrix(FilteredCollisionsWithMCLabel::iterator const& collision, + aod::BCsWithTimestamps const&, + FilteredTracksWithMCLabel const& tracks, + aod::McParticles const&, + aod::McCollisions const&) + { + if (!switchsOpts.cfgAddPidResponseMatrixHistograms.value) { + return; + } + registry.fill(HIST("hEventCount/processPidResponseMatrix"), 0.5); + if (tracks.size() <= 0) { + return; + } + if (!collision.sel8()) { + return; + } + registry.fill(HIST("hEventCount/processPidResponseMatrix"), 1.5); + + const auto cent = getCentrality(collision); + auto bc = collision.bc_as(); + int runNumber = bc.runNumber(); + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); + + if (!eventSelected(collision, cent, interactionRate, MyFunctionName::funcProcessPidResponseMatrix)) { + return; + } + + for (const auto& track : tracks) { + if (!trackSelectedGlobal(track)) { + continue; + } + if (!track.hasITS()) { + continue; + } + if (!track.hasTPC()) { + continue; + } + if (!trackSelected4ITS(track)) { + continue; + } + if (!trackSelected4TPC(track)) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + + auto mcParticle = track.mcParticle(); + if (!mcParticle.isPhysicalPrimary() || !particleSelected(mcParticle)) { + continue; + } + + const int truePidBin = getPidResponseTrueBin(mcParticle.pdgCode()); + if (truePidBin < 0) { + continue; + } + const int recoPidBin = getPidResponseRecoBin(getPidConfigurable(track)); + + registry.fill(HIST("pidResponseMatrix/hPidResponseMatrix"), truePidBin, recoPidBin); + registry.fill(HIST("pidResponseMatrix/hPidResponseMatrixRecPtCent"), truePidBin, recoPidBin, track.pt(), cent); + } + } + PROCESS_SWITCH(PidFlowPtCorr, processPidResponseMatrix, "Fill PID response matrix from MC truth and reconstructed PID", false); + /** * @brief this function is used to fill Reco particles in order to calculate pt eff * @note Efficiency = Efficiency(pt, cent) @@ -2731,7 +3302,7 @@ struct PidFlowPtCorr { const auto cent = getCentrality(collision); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); if (!eventSelected(collision, cent, interactionRate, MyFunctionName::funcProcessReco)) { return; @@ -2810,7 +3381,7 @@ struct PidFlowPtCorr { for (const auto& oneColl : collisions) { auto bc = oneColl.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); double cent = getCentrality(oneColl); auto groupedTracks = tracks.sliceBy(perCollision, oneColl.globalIndex()); diff --git a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx index 4fee24105e0..e7e888b3cdf 100644 --- a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx @@ -399,6 +399,17 @@ struct FlowGenericFramework { V0EfficiencyFilled, V0EfficiencyStageCount }; + enum V0EfficiencyDaughterPdgCategory { + V0EfficiencyDaughterOther = 0, + V0EfficiencyDaughterPiPlus, + V0EfficiencyDaughterPiMinus, + V0EfficiencyDaughterProton, + V0EfficiencyDaughterAntiProton, + V0EfficiencyDaughterElectron, + V0EfficiencyDaughterPositron, + V0EfficiencyDaughterKaon, + V0EfficiencyDaughterPdgCategoryCount + }; enum ResoIDs { K0Sideband1 = 0, K0Signal, @@ -619,6 +630,8 @@ struct FlowGenericFramework { AxisSpec efficiencyParticleAxis = {EfficiencySpeciesCount, -0.5, static_cast(EfficiencySpeciesCount) - 0.5, "particle"}; AxisSpec efficiencyStepAxis = {EfficiencyStepCount, -0.5, static_cast(EfficiencyStepCount) - 0.5, "generated/reconstructed"}; AxisSpec v0EfficiencyStageAxis = {V0EfficiencyStageCount, -0.5, static_cast(V0EfficiencyStageCount) - 0.5, "stage"}; + AxisSpec v0EfficiencyDebugEtaAxis = {160, -4.f, 4.f, "#eta"}; + AxisSpec v0EfficiencyDaughterPdgAxis = {V0EfficiencyDaughterPdgCategoryCount, -0.5, static_cast(V0EfficiencyDaughterPdgCategoryCount) - 0.5, "daughter PDG category"}; ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -642,6 +655,8 @@ struct FlowGenericFramework { if (doprocessEfficiency) { registry.add("Efficiency/efficiencyHist", "; #it{p}_{T}^{MC}; Centrality (%)", {HistType::kTHnSparseF, {{ptAxis, centAxis, efficiencyParticleAxis, efficiencyStepAxis}}}); registry.add("Efficiency/v0RecoDebug", "; #it{p}_{T}; Centrality (%)", {HistType::kTHnSparseF, {{ptAxis, centAxis, efficiencyParticleAxis, v0EfficiencyStageAxis}}}); + registry.add("Efficiency/v0RecoDaughterEtaDebug", "; Centrality (%); particle; #eta^{MC}_{pos}; #eta^{MC}_{neg}; #eta^{reco}_{pos}; #eta^{reco}_{neg}", {HistType::kTHnSparseF, {{centAxis, efficiencyParticleAxis, v0EfficiencyDebugEtaAxis, v0EfficiencyDebugEtaAxis, v0EfficiencyDebugEtaAxis, v0EfficiencyDebugEtaAxis}}}); + registry.add("Efficiency/v0RecoDaughterPdgDebug", "; Centrality (%); particle; PDG^{MC}_{pos}; PDG^{MC}_{neg}", {HistType::kTHnSparseF, {{centAxis, efficiencyParticleAxis, v0EfficiencyDaughterPdgAxis, v0EfficiencyDaughterPdgAxis}}}); } if (doprocessMCReco || doprocessData || doprocessRun2 || doprocessEfficiency) { if (cfgFill.cfgFillQA) { @@ -715,7 +730,7 @@ struct FlowGenericFramework { registryQA.add("K0/PiMinusTOF_K0", "", {HistType::kTH2D, {{ptAxis, axisNsigmaTOF}}}); registryQA.add("K0/hK0Phi", "", {HistType::kTH1D, {phiAxis}}); registryQA.add("K0/hK0Eta", "", {HistType::kTH1D, {etaAxis}}); - registryQA.add("K0/hK0AP", "", {HistType::kTH2D, {{100, -1, 1}, {100, 0, 5.}}}); + registryQA.add("K0/hK0AP", "", {HistType::kTH2D, {{100, -1, 1}, {500, 0, 1.}}}); registryQA.add("K0/hK0Mass_sparse", "", {HistType::kTHnSparseF, {{axisK0Mass, ptAxis, nchAxis}}}); registryQA.add("K0/hK0s", "", {HistType::kTH1D, {singleCount}}); registryQA.add("K0/hK0s_corrected", "", {HistType::kTH1D, {singleCount}}); @@ -2917,17 +2932,38 @@ struct FlowGenericFramework { } template - bool areGeneratedDaughtersWithinEfficiencyEtaAcceptance(const TParticle& particle) + int getV0EfficiencyDaughterPdgCategory(const TParticle& particle) { - if (!particle.has_daughters()) { - return false; + const int pdgCode = particle.pdgCode(); + if (pdgCode == kPiPlus) { + return V0EfficiencyDaughterPiPlus; } - for (const auto& daughter : particle.template daughters_as()) { - if (daughter.eta() <= cfgKinematics.cfgEta->first || daughter.eta() >= cfgKinematics.cfgEta->second) { - return false; - } + if (pdgCode == -kPiPlus) { + return V0EfficiencyDaughterPiMinus; } - return true; + if (pdgCode == kProton) { + return V0EfficiencyDaughterProton; + } + if (pdgCode == -kProton) { + return V0EfficiencyDaughterAntiProton; + } + if (pdgCode == kElectron) { + return V0EfficiencyDaughterElectron; + } + if (pdgCode == -kElectron) { + return V0EfficiencyDaughterPositron; + } + if (std::abs(pdgCode) == kKPlus) { + return V0EfficiencyDaughterKaon; + } + return V0EfficiencyDaughterOther; + } + + template + void fillV0EfficiencyDaughterDebug(int particleIndex, float centrality, const TParticle& posMcParticle, const TParticle& negMcParticle, const TTrack& postrack, const TTrack& negtrack) + { + registry.fill(HIST("Efficiency/v0RecoDaughterEtaDebug"), centrality, particleIndex, posMcParticle.eta(), negMcParticle.eta(), postrack.eta(), negtrack.eta()); + registry.fill(HIST("Efficiency/v0RecoDaughterPdgDebug"), centrality, particleIndex, getV0EfficiencyDaughterPdgCategory(posMcParticle), getV0EfficiencyDaughterPdgCategory(negMcParticle)); } void fillV0EfficiencyRecoDebug(float pt, float centrality, int particleIndex, int stage) @@ -2974,7 +3010,9 @@ struct FlowGenericFramework { void fillEfficiencyRecoV0(const TV0& v0, const TCollision& collision, const TTracks& tracks, float centrality) { using V0TrackTable = std::decay_t; - fillEnabledV0EfficiencyRecoDebug(v0, centrality, V0EfficiencyCandidate); + if (cfgFill.cfgFillV0QA) { + fillEnabledV0EfficiencyRecoDebug(v0, centrality, V0EfficiencyCandidate); + } auto postrack = v0.template posTrack_as(); auto negtrack = v0.template negTrack_as(); @@ -2982,14 +3020,18 @@ struct FlowGenericFramework { if (!postrack.has_mcParticle() || !negtrack.has_mcParticle()) { return; } - fillEnabledV0EfficiencyRecoDebug(v0, centrality, V0EfficiencyDaughterMCLabels); + if (cfgFill.cfgFillV0QA) { + fillEnabledV0EfficiencyRecoDebug(v0, centrality, V0EfficiencyDaughterMCLabels); + } auto posMcParticle = postrack.template mcParticle_as(); auto negMcParticle = negtrack.template mcParticle_as(); if (!posMcParticle.has_mothers() || !negMcParticle.has_mothers()) { return; } - fillEnabledV0EfficiencyRecoDebug(v0, centrality, V0EfficiencyDaughterMothers); + if (cfgFill.cfgFillV0QA) { + fillEnabledV0EfficiencyRecoDebug(v0, centrality, V0EfficiencyDaughterMothers); + } for (const auto& posMother : posMcParticle.template mothers_as()) { for (const auto& negMother : negMcParticle.template mothers_as()) { @@ -2999,52 +3041,78 @@ struct FlowGenericFramework { int pdgCode = std::abs(posMother.pdgCode()); if (pdgCode == PDG_t::kK0Short && resoSwitchVals[UseParticle][K0] != 0) { - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyCommonPrimaryMother); - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyMotherSpecies); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyCommonPrimaryMother); + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyMotherSpecies); + } if (std::abs(posMother.y()) >= resoCutVals[Rapidity][K0]) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyMotherRapidity); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyMotherRapidity); + } auto selection = selectK0(collision, v0, tracks); if (!selection.selected) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencySelection); - if (!areGeneratedDaughtersWithinEfficiencyEtaAcceptance(posMother)) { + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencySelection); + fillV0EfficiencyDaughterDebug(EfficiencyK0, centrality, posMcParticle, negMcParticle, postrack, negtrack); + } + if (!isWithinEfficiencyEtaAcceptance(posMcParticle) || !isWithinEfficiencyEtaAcceptance(negMcParticle)) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyGeneratedDaughterEta); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyGeneratedDaughterEta); + } if (!isWithinEfficiencyEtaAcceptance(postrack) || !isWithinEfficiencyEtaAcceptance(negtrack)) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyRecoDaughterEta); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyRecoDaughterEta); + } registry.fill(HIST("Efficiency/efficiencyHist"), posMother.pt(), centrality, EfficiencyK0, EfficiencyReconstructed); - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyFilled); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyK0, V0EfficiencyFilled); + } return; } if (pdgCode == PDG_t::kLambda0 && resoSwitchVals[UseParticle][Lambda] != 0) { - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyCommonPrimaryMother); - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyMotherSpecies); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyCommonPrimaryMother); + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyMotherSpecies); + } if (std::abs(posMother.y()) >= resoCutVals[Rapidity][Lambda]) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyMotherRapidity); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyMotherRapidity); + } auto selection = selectLambda(collision, v0, tracks); if (!selection.selected) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencySelection); - if (!areGeneratedDaughtersWithinEfficiencyEtaAcceptance(posMother)) { + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencySelection); + fillV0EfficiencyDaughterDebug(EfficiencyLambda, centrality, posMcParticle, negMcParticle, postrack, negtrack); + } + if (!isWithinEfficiencyEtaAcceptance(posMcParticle) || !isWithinEfficiencyEtaAcceptance(negMcParticle)) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyGeneratedDaughterEta); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyGeneratedDaughterEta); + } if (!isWithinEfficiencyEtaAcceptance(postrack) || !isWithinEfficiencyEtaAcceptance(negtrack)) { return; } - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyRecoDaughterEta); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyRecoDaughterEta); + } registry.fill(HIST("Efficiency/efficiencyHist"), posMother.pt(), centrality, EfficiencyLambda, EfficiencyReconstructed); - fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyFilled); + if (cfgFill.cfgFillV0QA) { + fillV0EfficiencyRecoDebug(posMother.pt(), centrality, EfficiencyLambda, V0EfficiencyFilled); + } return; } } diff --git a/PWGCF/GenericFramework/Tasks/flowGfwNonflow.cxx b/PWGCF/GenericFramework/Tasks/flowGfwNonflow.cxx index a721eed9848..991d9870d1a 100644 --- a/PWGCF/GenericFramework/Tasks/flowGfwNonflow.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGfwNonflow.cxx @@ -243,11 +243,11 @@ struct FlowGfwNonflow { // Generic Framework GFW* fGFW = new GFW(); - std::vector corrconfigs{}; + std::vector corrconfigs; TRandom3* fRndm = new TRandom3(0); TAxis* fPtAxis = nullptr; int lastRun = -1; - std::vector multipletKeys{}; + std::vector multipletKeys; // Track selection - DCA functions TF1* fPtDepDCAxy = nullptr; @@ -420,7 +420,7 @@ struct FlowGfwNonflow { delete oba; // Identify unique multiplet setups and populate with identifying keys - identifyUniqueMultipletKeys(multipletKeys, corrconfigs, centAxis); // For now keep centrality axis hardcoded + identifyUniqueMultipletKeys(multipletKeys, corrconfigs, multAxis); LOGF(info, "Unique multiplet keys for current configuration setup"); for (const auto& key : multipletKeys) { LOGF(info, key); @@ -524,7 +524,7 @@ struct FlowGfwNonflow { } } - void identifyUniqueMultipletKeys(std::vector& keys, const std::vector& configs, AxisSpec xAxis) + void identifyUniqueMultipletKeys(std::vector& keys, const std::vector& configs, const AxisSpec& xAxis) { std::set uniqueKeys(keys.begin(), keys.end()); const auto& regionNames = gfwMemberCache.regions.GetNames(); @@ -584,7 +584,7 @@ struct FlowGfwNonflow { if (uniqueKeys.insert(key).second) { keys.push_back(std::move(key)); - MultipletConfig currentMultipletConfig{configIndex, totalOrder, registry.add(Form("%s", keys.back().c_str()), Form("; centrality ; N_{%d}", totalOrder), {HistType::kTProfile, {xAxis}})}; + MultipletConfig currentMultipletConfig{.representativeConfigIndex = configIndex, .order = totalOrder, .profile = registry.add(Form("%s", keys.back().c_str()), Form("; centrality ; N_{%d}", totalOrder), {HistType::kTProfile, {xAxis}})}; effectiveMultiplets[keys.back()] = currentMultipletConfig; } } diff --git a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx index 505f486f2ad..755a723bbc0 100644 --- a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx @@ -67,43 +67,51 @@ #include #include #include -#include #include using namespace o2; using namespace o2::framework; using namespace analysis::genericframework; -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; -static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, (DEFAULT), (HELP)}; // NOLINT(bugprone-macro-parentheses) +static constexpr std::array, 20> LongArrayFloat = {{{{1.1, 2.1, 3.1}}, {{1.2, 2.2, 3.2}}, {{1.3, 2.3, 3.3}}, {{-1.1, -2.1, -3.1}}, {{-1.2, -2.2, -3.2}}, {{-1.3, -2.3, -3.3}}, {{1.1, 1.1, 1.1}}, {{1.2, 1.2, 1.2}}, {{1.3, 1.3, 1.3}}, {{-1.1, -1.1, -1.1}}, {{-1.2, -1.2, -1.2}}, {{-1.3, -1.3, -1.3}}, {{1.1, 1.1, 1.1}}, {{1.2, 1.2, 1.2}}, {{1.3, 1.3, 1.3}}, {{-1.1, -1.1, -1.1}}, {{-1.2, -1.2, -1.2}}, {{-1.3, -1.3, -1.3}}, {{1.1, 1.1, 1.1}}, {{1.2, 1.2, 1.2}}}}; -namespace o2::analysis::gfw +template +auto projectMatrix(Array2D const& mat, std::array& array1, std::array& array2, std::array& array3) { -std::vector ptbinning = {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; -float ptpoilow = 0.2, ptpoiup = 10.0; -float ptreflow = 0.2, ptrefup = 3.0; -float ptlow = 0.2, ptup = 10.0; -int etabins = 16; -float etalow = -0.8, etaup = 0.8; -int vtxZbins = 40; -float vtxZlow = -10.0, vtxZup = 10.0; -int phibins = 72; -float philow = 0.0; -float phiup = o2::constants::math::TwoPI; -int nchbins = 300; -float nchlow = 0; -float nchup = 3000; -std::vector centbinning(90); -int nBootstrap = 10; -std::vector> etagapsPtPt; -GFWRegions regions; -GFWCorrConfigs configs; -std::vector multGlobalCorrCutPars; -std::vector multPVCorrCutPars; -std::vector multGlobalPVCorrCutPars; -} // namespace o2::analysis::gfw + for (auto j = 0; j < static_cast(mat.rows); ++j) { + array1[j] = mat(j, 0); + array2[j] = mat(j, 1); + array3[j] = mat(j, 2); + } +} struct FlowGfwV02 { + + struct GFWMemberCache { + std::vector ptbinning = {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; + float ptpoilow = 0.2, ptpoiup = 10.0; + float ptreflow = 0.2, ptrefup = 3.0; + float ptlow = 0.2, ptup = 10.0; + int etabins = 16; + float etalow = -0.8, etaup = 0.8; + int vtxZbins = 40; + float vtxZlow = -10.0, vtxZup = 10.0; + int phibins = 72; + float philow = 0.0; + float phiup = o2::constants::math::TwoPI; + int nchbins = 300; + float nchlow = 0; + float nchup = 300; + std::vector centbinning{90}; + int nBootstrap = 10; + GFWRegions regions; + GFWCorrConfigs configs; + std::vector multGlobalCorrCutPars; + std::vector multPVCorrCutPars; + std::vector multGlobalPVCorrCutPars; + } gfwMemberCache; + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") O2_DEFINE_CONFIGURABLE(cfgMpar, int, 4, "Highest order of pt-pt correlations") O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") @@ -124,6 +132,7 @@ struct FlowGfwV02 { O2_DEFINE_CONFIGURABLE(cfgNormalizeByCharged, bool, true, "Enable or disable the normalization by charged particles"); O2_DEFINE_CONFIGURABLE(cfgConsistentEventFlag, int, 15, "Flag for consistent event selection"); O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, true, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgUseV0, bool, false, "Use V0 analysis"); // Event selection cuts struct : ConfigurableGroup { @@ -139,6 +148,16 @@ struct FlowGfwV02 { O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "kIsVertexITSTPC - Selects collisions with at least one ITS-TPC track"); } cfgEventCutFlags; + // Event selection cuts + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgEtaSubAMin, float, -0.8, "Minimum eta for subevent A"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubAMax, float, -0.5, "Maximum eta for subevent A"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubBMin, float, 0.5, "Minimum eta for subevent B"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubBMax, float, 0.8, "Maximum eta for subevent B"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubCMin, float, -0.4, "Minimum eta for subevent C"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubCMax, float, 0.4, "Maximum eta for subevent C"); + } cfgSubeventCuts; + struct : ConfigurableGroup { Configurable> cfgMultGlobalCutPars{"cfgMultGlobalCutPars", std::vector{2272.16, -76.6932, 1.01204, -0.00631545, 1.59868e-05, 136.336, -4.97006, 0.121199, -0.0015921, 7.66197e-06}, "Global vs FT0C multiplicity cut parameter values"}; Configurable> cfgMultPVCutPars{"cfgMultPVCutPars", std::vector{3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05}, "PV vs FT0C multiplicity cut parameter values"}; @@ -179,7 +198,7 @@ struct FlowGfwV02 { Configurable cfgRegions{"cfgRegions", {{"refN", "refP", "refFull", "refMid", "piP", "kaP", "prP"}, {-0.8, 0.5, -0.8, -0.4, 0.5, 0.5, 0.5}, {-0.5, 0.8, 0.8, 0.4, 0.8, 0.8, 0.8}, {0, 0, 0, 0, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1}}, "Configurations for GFW regions"}; Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "piP {2} refN {-2}", "kaP {2} refN {-2}", "prP {2} refN {-2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}", "refFull {2 -2}"}, {"ChGap22", "PiGap22", "KaGap22", "PrGap22", "ChFull22", "nchCh", "nchPi", "nchKa", "nchPr", "v02ptCh", "v02ptPi", "v02ptKa", "v02ptPr"}, {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {15, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, "Configurations for each correlation to calculate"}; - Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 6, 3, {"UpCut_pi", "UpCut_ka", "UpCut_pr", "LowCut_pi", "LowCut_ka", "LowCut_pr"}, {"TPC", "TOF", "ITS"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; + Configurable> nSigmas{"nSigmas", {LongArrayFloat.front().data(), 6, 3, {"UpCut_pi", "UpCut_ka", "UpCut_pr", "LowCut_pi", "LowCut_ka", "LowCut_pr"}, {"TPC", "TOF", "ITS"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; struct : ConfigurableGroup { Configurable cfgZvtxMax{"cfgZvtxMax", 10.0f, "Maximum primary vertex cut applied for the events."}; @@ -193,13 +212,13 @@ struct FlowGfwV02 { o2::framework::expressions::Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true)) && (aod::track::itsChi2NCl < cfgTrackCuts.cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgTrackCuts.cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgTrackCuts.cfgDCAz; // Connect to ccdb - Service ccdb; + Service ccdb{}; struct Config { - TH1D* mEfficiency[4] = {nullptr, nullptr, nullptr, nullptr}; - GFWWeights* mAcceptance; + std::array mEfficiency{nullptr, nullptr, nullptr, nullptr}; + GFWWeights* mAcceptance = nullptr; bool correctionsLoaded = false; - } cfg; + } cfg{}; // Define output OutputObj fFC{FlowContainer("FlowContainer")}; @@ -249,10 +268,12 @@ struct FlowGfwV02 { struct PIDState { o2::aod::ITSResponse itsResponse; - std::array tofNsigmaCut; - std::array itsNsigmaCut; - std::array tpcNsigmaCut; + std::array tofNsigmaCut{}; + std::array itsNsigmaCut{}; + std::array tpcNsigmaCut{}; std::array, 4> hPtMid{}; + std::array, 4> hPtForward{}; + std::array, 4> hPtBackward{}; }; PIDState pidStates; @@ -262,10 +283,6 @@ struct FlowGfwV02 { std::unique_ptr fMultCutLow; std::unique_ptr fMultCutHigh; std::unique_ptr fMultPVGlobalCutHigh; - std::unique_ptr fMultGlobalV0ACutLow; - std::unique_ptr fMultGlobalV0ACutHigh; - std::unique_ptr fMultGlobalT0ACutLow; - std::unique_ptr fMultGlobalT0ACutHigh; std::unique_ptr fPtDepDCAxy; @@ -275,7 +292,8 @@ struct FlowGfwV02 { PidCharged = 0, PidPions, PidKaons, - PidProtons + PidProtons, + PidTotal }; enum PiKpArrayIndex { IndPionUp = 0, @@ -285,35 +303,11 @@ struct FlowGfwV02 { IndKaonLow, IndProtonLow }; - enum DetectorType { - kTPC = 0, - kTOF, - kITS - }; void init(InitContext const&) { - pidStates.tpcNsigmaCut[IndPionUp] = nSigmas->getData()[IndPionUp][kTPC]; - pidStates.tpcNsigmaCut[IndKaonUp] = nSigmas->getData()[IndKaonUp][kTPC]; - pidStates.tpcNsigmaCut[IndProtonUp] = nSigmas->getData()[IndProtonUp][kTPC]; - pidStates.tpcNsigmaCut[IndPionLow] = nSigmas->getData()[IndPionLow][kTPC]; - pidStates.tpcNsigmaCut[IndKaonLow] = nSigmas->getData()[IndKaonLow][kTPC]; - pidStates.tpcNsigmaCut[IndProtonLow] = nSigmas->getData()[IndProtonLow][kTPC]; - - pidStates.tofNsigmaCut[IndPionUp] = nSigmas->getData()[IndPionUp][kTOF]; - pidStates.tofNsigmaCut[IndKaonUp] = nSigmas->getData()[IndKaonUp][kTOF]; - pidStates.tofNsigmaCut[IndProtonUp] = nSigmas->getData()[IndProtonUp][kTOF]; - pidStates.tofNsigmaCut[IndPionLow] = nSigmas->getData()[IndPionLow][kTOF]; - pidStates.tofNsigmaCut[IndKaonLow] = nSigmas->getData()[IndKaonLow][kTOF]; - pidStates.tofNsigmaCut[IndProtonLow] = nSigmas->getData()[IndProtonLow][kTOF]; - - pidStates.itsNsigmaCut[IndPionUp] = nSigmas->getData()[IndPionUp][kITS]; - pidStates.itsNsigmaCut[IndKaonUp] = nSigmas->getData()[IndKaonUp][kITS]; - pidStates.itsNsigmaCut[IndProtonUp] = nSigmas->getData()[IndProtonUp][kITS]; - pidStates.itsNsigmaCut[IndPionLow] = nSigmas->getData()[IndPionLow][kITS]; - pidStates.itsNsigmaCut[IndKaonLow] = nSigmas->getData()[IndKaonLow][kITS]; - pidStates.itsNsigmaCut[IndProtonLow] = nSigmas->getData()[IndProtonLow][kITS]; + projectMatrix(nSigmas->getData(), pidStates.tpcNsigmaCut, pidStates.tofNsigmaCut, pidStates.itsNsigmaCut); if (cfgGetNsigmaQA) { if (cfgUseItsPID) { @@ -336,60 +330,79 @@ struct FlowGfwV02 { registry.addClone("QA_PID/before/", "QA_PID/after/"); } - o2::analysis::gfw::regions.SetNames(cfgRegions->GetNames()); - o2::analysis::gfw::regions.SetEtaMin(cfgRegions->GetEtaMin()); - o2::analysis::gfw::regions.SetEtaMax(cfgRegions->GetEtaMax()); - o2::analysis::gfw::regions.SetpTDifs(cfgRegions->GetpTDifs()); - o2::analysis::gfw::regions.SetBitmasks(cfgRegions->GetBitmasks()); - o2::analysis::gfw::configs.SetCorrs(cfgCorrConfig->GetCorrs()); - o2::analysis::gfw::configs.SetHeads(cfgCorrConfig->GetHeads()); - o2::analysis::gfw::configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); - o2::analysis::gfw::configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); - o2::analysis::gfw::regions.Print(); - o2::analysis::gfw::configs.Print(); - o2::analysis::gfw::ptbinning = cfgGFWBinning->GetPtBinning(); - o2::analysis::gfw::ptpoilow = cfgGFWBinning->GetPtPOImin(); - o2::analysis::gfw::ptpoiup = cfgGFWBinning->GetPtPOImax(); - o2::analysis::gfw::ptreflow = cfgGFWBinning->GetPtRefMin(); - o2::analysis::gfw::ptrefup = cfgGFWBinning->GetPtRefMax(); - o2::analysis::gfw::ptlow = cfgTrackCuts.cfgPtMin; - o2::analysis::gfw::ptup = cfgTrackCuts.cfgPtMax; - o2::analysis::gfw::etabins = cfgGFWBinning->GetEtaBins(); - o2::analysis::gfw::vtxZbins = cfgGFWBinning->GetVtxZbins(); - o2::analysis::gfw::phibins = cfgGFWBinning->GetPhiBins(); - o2::analysis::gfw::philow = 0.0f; - o2::analysis::gfw::phiup = o2::constants::math::TwoPI; - o2::analysis::gfw::nchbins = cfgGFWBinning->GetNchBins(); - o2::analysis::gfw::nchlow = cfgGFWBinning->GetNchMin(); - o2::analysis::gfw::nchup = cfgGFWBinning->GetNchMax(); - o2::analysis::gfw::centbinning = cfgGFWBinning->GetCentBinning(); + gfwMemberCache.regions.SetNames(cfgRegions->GetNames()); + gfwMemberCache.regions.SetEtaMin(cfgRegions->GetEtaMin()); + gfwMemberCache.regions.SetEtaMax(cfgRegions->GetEtaMax()); + gfwMemberCache.regions.SetpTDifs(cfgRegions->GetpTDifs()); + gfwMemberCache.regions.SetBitmasks(cfgRegions->GetBitmasks()); + gfwMemberCache.configs.SetCorrs(cfgCorrConfig->GetCorrs()); + gfwMemberCache.configs.SetHeads(cfgCorrConfig->GetHeads()); + gfwMemberCache.configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); + gfwMemberCache.configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); + gfwMemberCache.regions.Print(); + gfwMemberCache.configs.Print(); + gfwMemberCache.ptbinning = cfgGFWBinning->GetPtBinning(); + gfwMemberCache.ptpoilow = cfgGFWBinning->GetPtPOImin(); + gfwMemberCache.ptpoiup = cfgGFWBinning->GetPtPOImax(); + gfwMemberCache.ptreflow = cfgGFWBinning->GetPtRefMin(); + gfwMemberCache.ptrefup = cfgGFWBinning->GetPtRefMax(); + gfwMemberCache.ptlow = cfgTrackCuts.cfgPtMin; + gfwMemberCache.ptup = cfgTrackCuts.cfgPtMax; + gfwMemberCache.etabins = cfgGFWBinning->GetEtaBins(); + gfwMemberCache.vtxZbins = cfgGFWBinning->GetVtxZbins(); + gfwMemberCache.phibins = cfgGFWBinning->GetPhiBins(); + gfwMemberCache.philow = 0.0f; + gfwMemberCache.phiup = o2::constants::math::TwoPI; + gfwMemberCache.nchbins = cfgGFWBinning->GetNchBins(); + gfwMemberCache.nchlow = cfgGFWBinning->GetNchMin(); + gfwMemberCache.nchup = cfgGFWBinning->GetNchMax(); + gfwMemberCache.centbinning = cfgGFWBinning->GetCentBinning(); + gfwMemberCache.nBootstrap = cfgNbootstrap; cfgGFWBinning->Print(); - o2::analysis::gfw::multGlobalCorrCutPars = cfgMultCorrCuts.cfgMultGlobalCutPars; - o2::analysis::gfw::multPVCorrCutPars = cfgMultCorrCuts.cfgMultPVCutPars; - o2::analysis::gfw::multGlobalPVCorrCutPars = cfgMultCorrCuts.cfgMultGlobalPVCutPars; + gfwMemberCache.multGlobalCorrCutPars = cfgMultCorrCuts.cfgMultGlobalCutPars; + gfwMemberCache.multPVCorrCutPars = cfgMultCorrCuts.cfgMultPVCutPars; + gfwMemberCache.multGlobalPVCorrCutPars = cfgMultCorrCuts.cfgMultGlobalPVCutPars; // Initialise pt spectra histograms for different particles - pidStates.hPtMid[PidCharged] = std::make_unique("hPtMid_charged", "hPtMid_charged", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); - pidStates.hPtMid[PidPions] = std::make_unique("hPtMid_pions", "hPtMid_pions", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); - pidStates.hPtMid[PidKaons] = std::make_unique("hPtMid_kaons", "hPtMid_kaons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); - pidStates.hPtMid[PidProtons] = std::make_unique("hPtMid_protons", "hPtMid_protons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtMid[PidCharged] = std::make_unique("hPtMid_charged", "hPtMid_charged", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtMid[PidPions] = std::make_unique("hPtMid_pions", "hPtMid_pions", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtMid[PidKaons] = std::make_unique("hPtMid_kaons", "hPtMid_kaons", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtMid[PidProtons] = std::make_unique("hPtMid_protons", "hPtMid_protons", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); pidStates.hPtMid[PidCharged]->SetDirectory(nullptr); pidStates.hPtMid[PidPions]->SetDirectory(nullptr); pidStates.hPtMid[PidKaons]->SetDirectory(nullptr); pidStates.hPtMid[PidProtons]->SetDirectory(nullptr); - AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; - AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgTrackCuts.cfgEtaMax, cfgTrackCuts.cfgEtaMax, "#eta"}; - AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgEventCuts.cfgZvtxMax, cfgEventCuts.cfgZvtxMax, "Vtx_{z} (cm)"}; - AxisSpec ptAxis = {o2::analysis::gfw::ptbinning, "#it{p}_{T} GeV/#it{c}"}; + pidStates.hPtForward[PidCharged] = std::make_unique("hPtForward_charged", "hPtForward_charged", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtForward[PidPions] = std::make_unique("hPtForward_pions", "hPtForward_pions", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtForward[PidKaons] = std::make_unique("hPtForward_kaons", "hPtForward_kaons", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtForward[PidProtons] = std::make_unique("hPtForward_protons", "hPtForward_protons", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtForward[PidCharged]->SetDirectory(nullptr); + pidStates.hPtForward[PidPions]->SetDirectory(nullptr); + pidStates.hPtForward[PidKaons]->SetDirectory(nullptr); + pidStates.hPtForward[PidProtons]->SetDirectory(nullptr); + + pidStates.hPtBackward[PidCharged] = std::make_unique("hPtBackward_charged", "hPtBackward_charged", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtBackward[PidPions] = std::make_unique("hPtBackward_pions", "hPtBackward_pions", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtBackward[PidKaons] = std::make_unique("hPtBackward_kaons", "hPtBackward_kaons", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtBackward[PidProtons] = std::make_unique("hPtBackward_protons", "hPtBackward_protons", gfwMemberCache.ptbinning.size() - 1, gfwMemberCache.ptbinning.data()); + pidStates.hPtBackward[PidCharged]->SetDirectory(nullptr); + pidStates.hPtBackward[PidPions]->SetDirectory(nullptr); + pidStates.hPtBackward[PidKaons]->SetDirectory(nullptr); + pidStates.hPtBackward[PidProtons]->SetDirectory(nullptr); + + AxisSpec phiAxis = {gfwMemberCache.phibins, gfwMemberCache.philow, gfwMemberCache.phiup, "#phi"}; + AxisSpec etaAxis = {gfwMemberCache.etabins, -cfgTrackCuts.cfgEtaMax, cfgTrackCuts.cfgEtaMax, "#eta"}; + AxisSpec vtxAxis = {gfwMemberCache.vtxZbins, -cfgEventCuts.cfgZvtxMax, cfgEventCuts.cfgZvtxMax, "Vtx_{z} (cm)"}; + AxisSpec ptAxis = {gfwMemberCache.ptbinning, "#it{p}_{T} GeV/#it{c}"}; std::string sCentralityEstimator = "FT0C centrality (%)"; - AxisSpec centAxis = {o2::analysis::gfw::centbinning, sCentralityEstimator.c_str()}; + AxisSpec centAxis = {gfwMemberCache.centbinning, sCentralityEstimator.c_str()}; std::vector nchbinning; - int nchskip = (o2::analysis::gfw::nchup - o2::analysis::gfw::nchlow) / o2::analysis::gfw::nchbins; - for (int i = 0; i <= o2::analysis::gfw::nchbins; ++i) { - nchbinning.push_back(nchskip * i + o2::analysis::gfw::nchlow + 0.5); + const double nchskip = (gfwMemberCache.nchup - gfwMemberCache.nchlow) / static_cast(gfwMemberCache.nchbins); + for (int i = 0; i <= gfwMemberCache.nchbins; ++i) { + nchbinning.push_back(nchskip * i + gfwMemberCache.nchlow + 0.5); } AxisSpec nchAxis = {nchbinning, "N_{ch}"}; AxisSpec t0cAxis = {1000, 0, 10000, "N_{ch} (T0C)"}; @@ -398,9 +411,23 @@ struct FlowGfwV02 { AxisSpec multpvAxis = {600, 0, 600, "N_{ch} (PV)"}; AxisSpec dcaZAxis = {200, -2, 2, "DCA_{z} (cm)"}; AxisSpec dcaXYAxis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; + AxisSpec bsAxis = {gfwMemberCache.nBootstrap, -0.5, gfwMemberCache.nBootstrap - 0.5, "Bootstrap Index"}; + + registry.add("v02pt", "", {HistType::kTProfile3D, {ptAxis, centAxis, nchAxis}}); + registry.add("nchMid", "", {HistType::kTProfile3D, {ptAxis, centAxis, nchAxis}}); + registry.add("v02centmult", "", {HistType::kTProfile2D, {centAxis, nchAxis}}); + + registry.add("analysis/charged/v0AB", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/v0BA", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/nchA", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/nchB", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/ptA", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + registry.add("analysis/charged/ptB", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + registry.add("analysis/charged/ptAB", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); - registry.add("v02pt", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); - registry.add("nchMid", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + registry.addClone("analysis/charged/", "analysis/pion/"); + registry.addClone("analysis/charged/", "analysis/kaon/"); + registry.addClone("analysis/charged/", "analysis/proton/"); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -409,15 +436,15 @@ struct FlowGfwV02 { int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); ccdb->setCreatedNotAfter(now); - int ptbins = o2::analysis::gfw::ptbinning.size() - 1; - fSecondAxis = std::make_unique(ptbins, &o2::analysis::gfw::ptbinning[0]); + int ptbins = gfwMemberCache.ptbinning.size() - 1; + fSecondAxis = std::make_unique(ptbins, gfwMemberCache.ptbinning.data()); // QA histograms registry.add("trackQA/before/phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); registry.add("trackQA/before/pt_dcaXY_dcaZ", "", {HistType::kTH3D, {ptAxis, dcaXYAxis, dcaZAxis}}); registry.add("trackQA/before/nch_pt", "#it{p}_{T} vs multiplicity; N_{ch}; #it{p}_{T}", {HistType::kTH2D, {nchAxis, ptAxis}}); - registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptreflow, o2::analysis::gfw::ptrefup}}}); - registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoiup}}}); + registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, gfwMemberCache.ptreflow, gfwMemberCache.ptrefup}}}); + registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, gfwMemberCache.ptpoilow, gfwMemberCache.ptpoiup}}}); registry.add("trackQA/before/chi2prTPCcls", "#chi^{2}/cluster for the TPC track segment; #chi^{2}/TPC cluster", {HistType::kTH1D, {{100, 0., 5.}}}); registry.add("trackQA/before/chi2prITScls", "#chi^{2}/cluster for the ITS track; #chi^{2}/ITS cluster", {HistType::kTH1D, {{100, 0., 50.}}}); registry.add("trackQA/before/nTPCClusters", "Number of found TPC clusters; TPC N_{cls}; Counts", {HistType::kTH1D, {{100, 40, 180}}}); @@ -462,18 +489,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 (o2::analysis::gfw::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 < o2::analysis::gfw::regions.GetSize(); ++i) { - fGFW->AddRegion(o2::analysis::gfw::regions.GetNames()[i], o2::analysis::gfw::regions.GetEtaMin()[i], o2::analysis::gfw::regions.GetEtaMax()[i], (o2::analysis::gfw::regions.GetpTDifs()[i]) ? ptbins + 1 : 1, o2::analysis::gfw::regions.GetBitmasks()[i]); + 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 < o2::analysis::gfw::configs.GetSize(); ++i) { - corrconfigs.push_back(fGFW->GetCorrelatorConfig(o2::analysis::gfw::configs.GetCorrs()[i], o2::analysis::gfw::configs.GetHeads()[i], o2::analysis::gfw::configs.GetpTDifs()[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()) LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); fGFW->CreateRegions(); - TObjArray* oba = new TObjArray(); + auto* oba = new TObjArray(); oba->SetOwner(kTRUE); addConfigObjectsToObjArray(oba, corrconfigs); LOGF(info, "Number of correlators: %d", oba->GetEntries()); @@ -482,7 +509,7 @@ struct FlowGfwV02 { fFC->Initialize(oba, centAxis, cfgNbootstrap); delete oba; - if (cfgConsistentEventFlag) { + if (cfgConsistentEventFlag != 0) { posRegionIndex = [&]() { auto begin = cfgRegions->GetNames().begin(); auto end = cfgRegions->GetNames().end(); @@ -511,22 +538,22 @@ struct FlowGfwV02 { if (cfgUseAdditionalEventCut) { fMultPVCutLow = std::make_unique("fMultPVCutLow", cfgMultCorrCuts.cfgMultCorrLowCutFunction->c_str(), 0, 100); - fMultPVCutLow->SetParameters(&(o2::analysis::gfw::multPVCorrCutPars[0])); + fMultPVCutLow->SetParameters(gfwMemberCache.multPVCorrCutPars.data()); fMultPVCutHigh = std::make_unique("fMultPVCutHigh", cfgMultCorrCuts.cfgMultCorrHighCutFunction->c_str(), 0, 100); - fMultPVCutHigh->SetParameters(&(o2::analysis::gfw::multPVCorrCutPars[0])); + fMultPVCutHigh->SetParameters(gfwMemberCache.multPVCorrCutPars.data()); fMultCutLow = std::make_unique("fMultCutLow", cfgMultCorrCuts.cfgMultCorrLowCutFunction->c_str(), 0, 100); - fMultCutLow->SetParameters(&(o2::analysis::gfw::multGlobalCorrCutPars[0])); + fMultCutLow->SetParameters(gfwMemberCache.multGlobalCorrCutPars.data()); fMultCutHigh = std::make_unique("fMultCutHigh", cfgMultCorrCuts.cfgMultCorrHighCutFunction->c_str(), 0, 100); - fMultCutHigh->SetParameters(&(o2::analysis::gfw::multGlobalCorrCutPars[0])); + fMultCutHigh->SetParameters(gfwMemberCache.multGlobalCorrCutPars.data()); fMultPVGlobalCutHigh = std::make_unique("fMultPVGlobalCutHigh", cfgMultCorrCuts.cfgMultGlobalPVCorrCutFunction->c_str(), 0, nchbinning.back()); - fMultPVGlobalCutHigh->SetParameters(&(o2::analysis::gfw::multGlobalPVCorrCutPars[0])); + fMultPVGlobalCutHigh->SetParameters(gfwMemberCache.multGlobalPVCorrCutPars.data()); } // Set DCAxy cut fPtDepDCAxy = std::make_unique("ptDepDCAxy", Form("[0]*%s", cfgTrackCuts.cfgDCAxy->c_str()), 0.001, 100); fPtDepDCAxy->SetParameter(0, cfgTrackCuts.cfgDCAxyNSigma); } - static constexpr std::string_view FillTimeName[] = {"before/", "after/"}; + static constexpr std::array FillTimeName = {"before/", "after/"}; enum QAFillTime { kBefore, kAfter @@ -539,7 +566,7 @@ struct FlowGfwV02 { std::string suffix = "_ptDiff"; for (auto i = 0; i < fSecondAxis->GetNbins(); ++i) { std::string index = Form("_pt_%i", i + 1); - oba->Add(new TNamed(it->Head.c_str() + index, it->Head.c_str() + suffix)); + oba->Add(new TNamed(it->Head + index, it->Head + suffix)); } } else { oba->Add(new TNamed(it->Head.c_str(), it->Head.c_str())); @@ -548,7 +575,7 @@ struct FlowGfwV02 { } template - int getNsigmaPID(TTrack track) + int getNsigmaPID(TTrack const& track) { // Computing Nsigma arrays for pion, kaon, and protons std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; @@ -559,7 +586,7 @@ struct FlowGfwV02 { std::array nSigmaToUse = cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS std::array detectorNsigmaCut = cfgUseItsPID ? pidStates.itsNsigmaCut : pidStates.tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS - bool isPion, isKaon, isProton; + bool isPion = false, isKaon = false, isProton = false; bool isDetectedPion = nSigmaToUse[IndPionUp] < detectorNsigmaCut[IndPionUp] && nSigmaToUse[IndPionUp] > detectorNsigmaCut[IndPionLow]; bool isDetectedKaon = nSigmaToUse[IndKaonUp] < detectorNsigmaCut[IndKaonUp] && nSigmaToUse[IndKaonUp] > detectorNsigmaCut[IndKaonLow]; bool isDetectedProton = nSigmaToUse[IndProtonUp] < detectorNsigmaCut[IndProtonUp] && nSigmaToUse[IndProtonUp] > detectorNsigmaCut[IndProtonLow]; @@ -570,7 +597,8 @@ struct FlowGfwV02 { if (track.pt() > cfgTofPtCut && !track.hasTOF()) { return -1; - } else if (track.pt() > cfgTofPtCut && track.hasTOF()) { + } + if (track.pt() > cfgTofPtCut && track.hasTOF()) { isPion = isTofPion && isDetectedPion; isKaon = isTofKaon && isDetectedKaon; isProton = isTofProton && isDetectedProton; @@ -610,17 +638,17 @@ struct FlowGfwV02 { if (cfg.mEfficiency[PidCharged] == nullptr) { LOGF(fatal, "Could not load efficiency histogram from %s", cfgEfficiency.value.c_str()); } - LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency[PidCharged]); + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), static_cast(cfg.mEfficiency[PidCharged])); } if (cfgPIDEfficiency) { const std::array pidStrings = {"ch", "pi", "ka", "pr"}; - for (int i = 1; i < 4; i++) { + for (int i = 1; i < PidTotal; i++) { cfg.mEfficiency[i] = ccdb->getForTimeStamp(cfgEfficiency.value + pidStrings[i], timestamp); if (cfg.mEfficiency[i] == nullptr) { - LOGF(fatal, "Could not load PID efficiency histogram from %s", cfgEfficiency.value + pidStrings[i].c_str()); + LOGF(fatal, "Could not load PID efficiency histogram from %s", (cfgEfficiency.value + pidStrings[i]).c_str()); } - LOGF(info, "Loaded PID efficiency histogram from %s (%p)", cfgEfficiency.value + pidStrings[i].c_str(), (void*)cfg.mEfficiency[i]); + LOGF(info, "Loaded PID efficiency histogram from %s (%p)", (cfgEfficiency.value + pidStrings[i]).c_str(), static_cast(cfg.mEfficiency[i])); } } cfg.correctionsLoaded = true; @@ -640,7 +668,7 @@ struct FlowGfwV02 { } template - double getJTrackAcceptance(TTrack track) + double getJTrackAcceptance(TTrack const& track) { double wacc = 1; if constexpr (requires { track.weightNUA(); }) @@ -649,7 +677,7 @@ struct FlowGfwV02 { } template - double getJTrackEfficiency(TTrack track) + double getJTrackEfficiency(TTrack const& track) { double eff = 1.; if constexpr (requires { track.weightEff(); }) @@ -658,7 +686,7 @@ struct FlowGfwV02 { } template - double getAcceptance(TTrack track, const double& vtxz) + double getAcceptance(TTrack const& track, const double& vtxz) { double wacc = 1; if (cfg.mAcceptance) @@ -667,19 +695,18 @@ struct FlowGfwV02 { } template - double getEfficiency(TTrack track, const int& pid = PidCharged) + double getEfficiency(TTrack const& track, const int& pid = PidCharged) { double eff = 1.; if (cfg.mEfficiency[pid]) eff = cfg.mEfficiency[pid]->GetBinContent(cfg.mEfficiency[pid]->FindBin(track.pt())); if (eff == 0) return -1.; - else - return 1. / eff; + return 1. / eff; } template - bool eventSelected(TCollision collision, const int& multTrk, const float& centrality) + bool eventSelected(TCollision const& collision, const int& multTrk, const float& centrality) { if (cfgEventCutFlags.cfgTVXinTRD) { if (collision.alias_bit(kTVXinTRD)) { @@ -769,7 +796,7 @@ struct FlowGfwV02 { } auto multNTracksPV = collision.multNTracksPV(); - if (vtxz > o2::analysis::gfw::vtxZup || vtxz < o2::analysis::gfw::vtxZlow) + if (vtxz > gfwMemberCache.vtxZup || vtxz < gfwMemberCache.vtxZlow) return 0; if (cfgMultCut) { @@ -796,17 +823,17 @@ struct FlowGfwV02 { int getPIDIndex(const std::string& corrconfig) { - if (boost::ifind_first(corrconfig, "pi")) + if (!boost::ifind_first(corrconfig, "pi").empty()) return PidPions; - if (boost::ifind_first(corrconfig, "ka")) + if (!boost::ifind_first(corrconfig, "ka").empty()) return PidKaons; - if (boost::ifind_first(corrconfig, "pr")) + if (!boost::ifind_first(corrconfig, "pr").empty()) return PidProtons; return PidCharged; } template - void fillOutputContainers(const float& centmult, const double& rndm, const int& /*run*/ = 0) + void fillOutputContainers(const float& centmult, const int& multiplicity, const double& rndm, const int& /*run*/ = 0) { for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { if (!corrconfigs.at(l_ind).pTDif) { @@ -822,7 +849,7 @@ struct FlowGfwV02 { } // Fill pt profiles for different particles - int pidInd = getPIDIndex(corrconfigs.at(l_ind).Head.c_str()); + int pidInd = getPIDIndex(corrconfigs.at(l_ind).Head); auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); if (dnx == 0) @@ -838,14 +865,90 @@ struct FlowGfwV02 { ebyeWeight *= pidStates.hPtMid[PidCharged]->Integral(); } double ptFraction = 0; + double threshold = 1.01; int normIndex = (cfgNormalizeByCharged) ? PidCharged : pidInd; // Configured to normalize by charged particles or the selected particle if (pidStates.hPtMid[normIndex]->Integral() > 0) { ptFraction = pidStates.hPtMid[pidInd]->GetBinContent(i) / pidStates.hPtMid[normIndex]->Integral(); - if (std::abs(val) < 1.01) + if (std::abs(val) < threshold) fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val * ptFraction, ebyeWeight, rndm); } } } + + if (cfgUseV0) { + double v0corrAB = 0; + double v0corrBA = 0; + double ptMeanForward = pidStates.hPtForward[PidCharged]->GetMean(); + double ptMeanBackward = pidStates.hPtBackward[PidCharged]->GetMean(); + double ptFractionForward = 0.; + double ptFractionBackward = 0.; + int bootstrap = fRndm->Integer(gfwMemberCache.nBootstrap); + for (int pid = 0; pid < PidTotal; pid++) { + int normIndex = (cfgNormalizeByCharged) ? PidCharged : pid; + if (!(pidStates.hPtForward[normIndex]->Integral() > 0) || !(pidStates.hPtBackward[normIndex]->Integral() > 0)) { + continue; // Forward or backward pT distribution is not defined + } + for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { + ptFractionForward = pidStates.hPtForward[pid]->GetBinContent(i) / pidStates.hPtForward[normIndex]->Integral(); + ptFractionBackward = pidStates.hPtBackward[pid]->GetBinContent(i) / pidStates.hPtBackward[normIndex]->Integral(); + v0corrAB = ptFractionForward * ptMeanBackward; + v0corrBA = ptFractionBackward * ptMeanForward; + switch (pid) { + case PidCharged: + registry.fill(HIST("analysis/charged/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/charged/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/charged/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/charged/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + case PidPions: + registry.fill(HIST("analysis/pion/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/pion/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/pion/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/pion/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + case PidKaons: + registry.fill(HIST("analysis/kaon/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/kaon/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/kaon/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/kaon/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + case PidProtons: + registry.fill(HIST("analysis/proton/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/proton/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/proton/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/proton/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + default: + break; + } + } + switch (pid) { + case PidCharged: + registry.fill(HIST("analysis/charged/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/charged/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/charged/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + case PidPions: + registry.fill(HIST("analysis/pion/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/pion/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/pion/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + case PidKaons: + registry.fill(HIST("analysis/kaon/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/kaon/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/kaon/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + case PidProtons: + registry.fill(HIST("analysis/proton/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/proton/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/proton/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + default: + break; + } + } + } + // Fill the profiles for each pT bin auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); if (dnx == 0) @@ -855,18 +958,18 @@ struct FlowGfwV02 { double ptFraction = 0; if (pidStates.hPtMid[PidCharged]->Integral() > 0) { ptFraction = pidStates.hPtMid[PidCharged]->GetBinContent(i) / pidStates.hPtMid[PidCharged]->Integral(); - if (std::abs(val) < 1) - registry.fill(HIST("v02pt"), fSecondAxis->GetBinCenter(i), centmult, val * ptFraction, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); - registry.fill(HIST("nchMid"), fSecondAxis->GetBinCenter(i), centmult, ptFraction); + double threshold = 1.01; + if (std::abs(val) < threshold) + registry.fill(HIST("v02pt"), fSecondAxis->GetBinCenter(i), centmult, multiplicity, val * ptFraction, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); + registry.fill(HIST("nchMid"), fSecondAxis->GetBinCenter(i), centmult, multiplicity, ptFraction); } } - return; + registry.fill(HIST("v02centmult"), centmult, multiplicity, val); } struct XAxis { float centrality; int64_t multiplicity; - double time; }; struct AcceptedTracks { @@ -877,12 +980,12 @@ struct FlowGfwV02 { }; template - void processCollision(TCollision collision, TTracks tracks, const XAxis& xaxis, const int& run) + void processCollision(TCollision const& collision, TTracks const& tracks, const XAxis& xaxis, const int& run) { float vtxz = collision.posZ(); if (tracks.size() < 1) return; - if (xaxis.centrality >= 0 && (xaxis.centrality < o2::analysis::gfw::centbinning.front() || xaxis.centrality > o2::analysis::gfw::centbinning.back())) + if (xaxis.centrality >= 0 && (xaxis.centrality < gfwMemberCache.centbinning.front() || xaxis.centrality > gfwMemberCache.centbinning.back())) return; if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) return; @@ -891,23 +994,47 @@ struct FlowGfwV02 { pidStates.hPtMid[PidPions]->Reset(); pidStates.hPtMid[PidKaons]->Reset(); pidStates.hPtMid[PidProtons]->Reset(); + pidStates.hPtBackward[PidCharged]->Reset(); + pidStates.hPtBackward[PidPions]->Reset(); + pidStates.hPtBackward[PidKaons]->Reset(); + pidStates.hPtBackward[PidProtons]->Reset(); + pidStates.hPtForward[PidCharged]->Reset(); + pidStates.hPtForward[PidPions]->Reset(); + pidStates.hPtForward[PidKaons]->Reset(); + pidStates.hPtForward[PidProtons]->Reset(); float lRandom = fRndm->Rndm(); // Loop over tracks and check if they are accepted - AcceptedTracks acceptedTracks{0, 0, 0, 0}; + AcceptedTracks acceptedTracks{.nPos = 0, .nNeg = 0, .nFull = 0, .nMid = 0}; for (const auto& track : tracks) { processTrack(track, vtxz, xaxis.multiplicity, run, acceptedTracks); - if (track.eta() > -0.4 && track.eta() < 0.4) + 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 + pidStates.hPtBackward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); + 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() > -0.4 && track.eta() < 0.4) { + if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) { if (cfgPIDEfficiency) pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); 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) + pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); + 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) + pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); + 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) @@ -922,24 +1049,24 @@ struct FlowGfwV02 { 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, lRandom, run); + fillOutputContainers
(xaxis.centrality, xaxis.multiplicity, lRandom, run); } template - void fillAcceptedTracks(TTrack track, AcceptedTracks& acceptedTracks) + void fillAcceptedTracks(TTrack const& track, AcceptedTracks& acceptedTracks) { - if (posRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[posRegionIndex] && track.eta() < o2::analysis::gfw::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() > o2::analysis::gfw::regions.GetEtaMin()[negRegionIndex] && track.eta() < o2::analysis::gfw::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() > o2::analysis::gfw::regions.GetEtaMin()[fullRegionIndex] && track.eta() < o2::analysis::gfw::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() > o2::analysis::gfw::regions.GetEtaMin()[midRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[midRegionIndex]) + if (midRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[midRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[midRegionIndex]) ++acceptedTracks.nMid; } template - bool trackSelected(TTrack track) + bool trackSelected(TTrack const& track) { if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) return false; @@ -947,7 +1074,7 @@ struct FlowGfwV02 { } template - float getCentrality(TCollision collision) + float getCentrality(TCollision const& collision) { switch (cfgCentEstimator) { case kCentFT0C: @@ -996,12 +1123,12 @@ struct FlowGfwV02 { } template - inline void fillGFW(TTrack track, const double& vtxz) + inline void fillGFW(TTrack const& track, const double& vtxz) { int pidInd = getNsigmaPID(track); - bool withinPtRef = (track.pt() > o2::analysis::gfw::ptreflow && track.pt() < o2::analysis::gfw::ptrefup); - bool withinPtPOI = (track.pt() > o2::analysis::gfw::ptpoilow && track.pt() < o2::analysis::gfw::ptpoiup); + bool withinPtRef = (track.pt() > gfwMemberCache.ptreflow && track.pt() < gfwMemberCache.ptrefup); + bool withinPtPOI = (track.pt() > gfwMemberCache.ptpoilow && track.pt() < gfwMemberCache.ptpoiup); if (!withinPtPOI && !withinPtRef) return; @@ -1021,11 +1148,10 @@ struct FlowGfwV02 { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidKaons + 1); if (withinPtPOI && pidInd == PidProtons) fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidProtons + 1); - return; } template - inline void fillPidQA(TTrack track, const int& pid) + inline void fillPidQA(TTrack const& track, const int& pid) { // Fill Nsigma QA if (!cfgUseItsPID) { @@ -1089,7 +1215,7 @@ struct FlowGfwV02 { } template - inline void fillTrackQA(TTrack track, const float vtxz) + inline void fillTrackQA(TTrack const& track, const float vtxz) { double wacc = getAcceptance(track, vtxz); registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("phi_eta_vtxZ"), track.phi(), track.eta(), vtxz, (ft == kAfter) ? wacc : 1.0); @@ -1106,10 +1232,9 @@ struct FlowGfwV02 { registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_ref"), track.pt()); registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("pt_poi"), track.pt()); } - return; } template - inline void fillEventQA(TCollision collision, XAxis xaxis) + inline void fillEventQA(TCollision const& collision, XAxis xaxis) { if constexpr (framework::has_type_v) { registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_centT0C"), collision.centFT0C(), xaxis.multiplicity); @@ -1125,7 +1250,6 @@ struct FlowGfwV02 { registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multT0A"), collision.multFT0A(), xaxis.multiplicity); registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multV0A"), collision.multFV0A(), xaxis.multiplicity); registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); - return; } double getTimeSinceStartOfFill(uint64_t, int) { return 0.0; } @@ -1146,7 +1270,7 @@ struct FlowGfwV02 { registry.fill(HIST("eventQA/eventSel"), kSel8); registry.fill(HIST("eventQA/eventSel"), kOccupancy); // Add occupancy selection later - const XAxis xaxis{getCentrality(collision), tracks.size(), -1.0}; + const XAxis xaxis{.centrality = getCentrality(collision), .multiplicity = tracks.size()}; if (cfgFillQA) { fillEventQA(collision, xaxis); registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); @@ -1171,7 +1295,7 @@ struct FlowGfwV02 { LOGF(info, "run = %d", run); } loadCorrections(run); - const XAxis xaxis{collision.multiplicity(), tracks.size(), -1.0}; + const XAxis xaxis{.centrality = collision.multiplicity(), .multiplicity = tracks.size()}; registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); @@ -1186,7 +1310,7 @@ struct FlowGfwV02 { lastRun = run; LOGF(info, "run = %d", run); } - const XAxis xaxis{collision.multiplicity(), tracks.size(), -1.0}; + const XAxis xaxis{.centrality = collision.multiplicity(), .multiplicity = tracks.size()}; registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); // processCollision(collision, tracks, xaxis, run); diff --git a/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx index 19e6527b5b1..327877d1112 100644 --- a/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.cxx @@ -154,6 +154,8 @@ struct JEPFlowAnalysis { Configurable cfgSelEvtTwoHP{"cfgSelEvtTwoHP", false, "event selection with two high pT"}; Configurable cfgHighPtSel{"cfgHighPtSel", 5.0, "pT threshold with cfgSelEvtTwoHP"}; + Configurable cfgTwoLPAngle{"cfgTwoLPAngle", 0.5, "azimuthal difference between two LP"}; + Configurable cfgEtaBalancing{"cfgEtaBalancing", 0.5, "pseudorapidity difference between two LP"}; Configurable cfgDetName{"cfgDetName", "FT0C", "The name of detector to be analyzed"}; Configurable cfgRefAName{"cfgRefAName", "TPCPos", "The name of detector for reference A"}; @@ -193,8 +195,14 @@ struct JEPFlowAnalysis { float activity = -1.; float qOvecM = -1.; - float highestPt = -1.; - float hPtPhi = -999.; + + float leadingPt = -1.; + float leadingPhi = -999.; + float leadingEta = -999.; + + float subleadingPt = -1.; + float subleadingPhi = -999.; + float subleadingEta = -999.; std::vector shiftprofile{}; std::string fullCCDBShiftCorrPath; @@ -424,11 +432,33 @@ struct JEPFlowAnalysis { } if (cfgSelEvtTwoHP && i == 0) { + leadingPt = 0.0; + leadingPhi = 0.0; + leadingEta = 0.0; + + subleadingPt = 0.0; + subleadingPhi = 0.0; + subleadingEta = 0.0; + nHighPt = 0; for (const auto& track : tracks) { if (cfgTrkSelFlag && trackSel(track)) continue; + if (leadingPt < track.pt()) { + subleadingPt = leadingPt; + subleadingPhi = leadingPhi; + subleadingEta = leadingEta; + + leadingPt = track.pt(); + leadingPhi = track.phi(); + leadingEta = track.eta(); + } else if (track.pt() > subleadingPt) { + subleadingPt = track.pt(); + subleadingPhi = track.phi(); + subleadingEta = track.eta(); + } + if (track.pt() > cfgHighPtSel) nHighPt++; } @@ -437,6 +467,12 @@ struct JEPFlowAnalysis { if (cfgSelEvtTwoHP && nHighPt < minnHighPt) continue; + if (std::abs(RecoDecay::constrainAngle(leadingPhi - subleadingPhi, 0) - constants::math::PI) > cfgTwoLPAngle) + continue; + + if (std::abs(leadingEta + subleadingEta) > cfgEtaBalancing) + continue; + epFlowHistograms.fill(HIST("EpDet"), i + 2, cent, eps[0]); epFlowHistograms.fill(HIST("EpRefA"), i + 2, cent, eps[1]); epFlowHistograms.fill(HIST("EpRefB"), i + 2, cent, eps[2]); @@ -486,17 +522,13 @@ struct JEPFlowAnalysis { continue; } - highestPt = 0.0; - hPtPhi = 0.0; + leadingPt = 0.0; + leadingPhi = 0.0; + leadingEta = 0.0; for (const auto& track : tracks) { if (cfgTrkSelFlag && trackSel(track)) continue; - if (highestPt < track.pt()) { - highestPt = track.pt(); - hPtPhi = track.phi(); - } - if (cfgEffCor) { weight = getEfficiencyCorrection(effMap, track.eta(), track.pt(), cent, coll.posZ()); } @@ -525,14 +557,14 @@ struct JEPFlowAnalysis { } } if (i == 0) { // second harmonic only - epFlowHistograms.fill(HIST("hQoverM"), cent, highestPt, qOvecM); - epFlowHistograms.fill(HIST("hActivity"), cent, highestPt, activity); + epFlowHistograms.fill(HIST("hQoverM"), cent, leadingPt, qOvecM); + epFlowHistograms.fill(HIST("hActivity"), cent, leadingPt, activity); epFlowHistograms.fill(HIST("hQoverM2M"), cent, coll.qvecAmp()[detId], qOvecM); epFlowHistograms.fill(HIST("hQoverM2Q2"), cent, q2Mag, qOvecM); - epFlowHistograms.fill(HIST("hQoverMdphi"), cent, RecoDecay::constrainAngle(hPtPhi - eps[0], -constants::math::PI), qOvecM); - epFlowHistograms.fill(HIST("hActivitydphi"), cent, RecoDecay::constrainAngle(hPtPhi - eps[0], -constants::math::PI), highestPt, activity); + epFlowHistograms.fill(HIST("hQoverMdphi"), cent, RecoDecay::constrainAngle(leadingPhi - eps[0], -constants::math::PI), qOvecM); + epFlowHistograms.fill(HIST("hActivitydphi"), cent, RecoDecay::constrainAngle(leadingPhi - eps[0], -constants::math::PI), leadingPt, activity); } } } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx index adbd36a53da..f1b3fddd1c5 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx @@ -396,7 +396,7 @@ struct LambdaTableProducer { Configurable cPathCCDB{"cPathCCDB", "Users/y/ypatley/lambda_corr_fact", "Path for ccdb-object"}; // Initialize CCDB Service - Service ccdb; + Service ccdb{}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -413,7 +413,6 @@ struct LambdaTableProducer { // Initialize Global Variables float cent = 0., mult = 0.; - float pt = 0., eta = 0., rap = 0., phi = 0.; void init(InitContext const&) { @@ -555,40 +554,53 @@ struct LambdaTableProducer { template bool selCollision(C const& col) { - if (col.posZ() <= cMinZVtx || col.posZ() >= cMaxZVtx) + if (col.posZ() <= cMinZVtx || col.posZ() >= cMaxZVtx) { return false; + } if constexpr (run == kRun3) { - if (cCentEstimator == kCentFT0M) + if (cCentEstimator == kCentFT0M) { cent = col.centFT0M(); - else if (cCentEstimator == kCentFT0C) + } else if (cCentEstimator == kCentFT0C) { cent = col.centFT0C(); - if (cSel8Trig && !col.sel8()) + } + if (cSel8Trig && !col.sel8()) { return false; + } } else { cent = col.centRun2V0M(); - if (cInt7Trig && !col.alias_bit(kINT7)) + if (cInt7Trig && !col.alias_bit(kINT7)) { return false; - if (cSel7Trig && !col.sel7()) + } + if (cSel7Trig && !col.sel7()) { return false; + } } - if (cent <= cMinMult || cent >= cMaxMult) + if (cent <= cMinMult || cent >= cMaxMult) { return false; - if (cTriggerTvxSel && !col.selection_bit(aod::evsel::kIsTriggerTVX)) + } + if (cTriggerTvxSel && !col.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; - if (cTFBorder && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) + } + if (cTFBorder && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return false; - if (cNoItsROBorder && !col.selection_bit(aod::evsel::kNoITSROFrameBorder)) + } + if (cNoItsROBorder && !col.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; - if (cItsTpcVtx && !col.selection_bit(aod::evsel::kIsVertexITSTPC)) + } + if (cItsTpcVtx && !col.selection_bit(aod::evsel::kIsVertexITSTPC)) { return false; - if (cPileupReject && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) + } + if (cPileupReject && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; - if (cZVtxTimeDiff && !col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + } + if (cZVtxTimeDiff && !col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; - if (cIsGoodITSLayers && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) + } + if (cIsGoodITSLayers && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { return false; + } mult = col.multNTracksPV(); return true; @@ -597,26 +609,28 @@ struct LambdaTableProducer { // Kinematic Selection bool kinCutSelection(float const& pt, float const& rap, float const& ptMin, float const& ptMax, float const& rapMax) { - if (pt <= ptMin || pt >= ptMax || rap >= rapMax) { - return false; - } - return true; + return pt > ptMin && pt < ptMax && rap < rapMax; } // Track Selection template bool selTrack(T const& track) { - if (!kinCutSelection(track.pt(), std::abs(track.eta()), cTrackMinPt, cTrackMaxPt, cTrackEtaCut)) + if (!kinCutSelection(track.pt(), std::abs(track.eta()), cTrackMinPt, cTrackMaxPt, cTrackEtaCut)) { return false; - if (track.tpcNClsCrossedRows() <= cMinTpcCrossedRows) + } + if (track.tpcNClsCrossedRows() <= cMinTpcCrossedRows) { return false; - if (track.tpcCrossedRowsOverFindableCls() < cMinTpcCROverCls) + } + if (track.tpcCrossedRowsOverFindableCls() < cMinTpcCROverCls) { return false; - if (track.tpcNClsShared() > cMaxTpcSharedClusters) + } + if (track.tpcNClsShared() > cMaxTpcSharedClusters) { return false; - if (track.tpcChi2NCl() > cMaxChi2Tpc) + } + if (track.tpcChi2NCl() > cMaxChi2Tpc) { return false; + } return true; } @@ -626,8 +640,9 @@ struct LambdaTableProducer { { auto posTrack = v0.template posTrack_as(); auto negTrack = v0.template negTrack_as(); - if (!selTrack(posTrack) || !selTrack(negTrack)) + if (!selTrack(posTrack) || !selTrack(negTrack)) { return false; + } // Apply DCA Selection on Daughter Tracks Based on Lambda/AntiLambda daughters float dcaProton = 0., dcaPion = 0.; @@ -638,26 +653,32 @@ struct LambdaTableProducer { dcaPion = std::abs(v0.dcapostopv()); dcaProton = std::abs(v0.dcanegtopv()); } - if (dcaProton < cMinDcaProtonToPV || dcaPion < cMinDcaPionToPV) + if (dcaProton < cMinDcaProtonToPV || dcaPion < cMinDcaPionToPV) { return false; + } return true; } template bool topoCutSelection(C const& col, V const& v0, T const&) { - if (v0.dcaV0daughters() <= cMinV0DcaDaughters || v0.dcaV0daughters() >= cMaxV0DcaDaughters) + if (v0.dcaV0daughters() <= cMinV0DcaDaughters || v0.dcaV0daughters() >= cMaxV0DcaDaughters) { return false; - if (v0.dcav0topv() <= cMinDcaV0ToPV || v0.dcav0topv() >= cMaxDcaV0ToPV) + } + if (v0.dcav0topv() <= cMinDcaV0ToPV || v0.dcav0topv() >= cMaxDcaV0ToPV) { return false; - if (v0.v0radius() <= cMinV0TransRadius || v0.v0radius() >= cMaxV0TransRadius) + } + if (v0.v0radius() <= cMinV0TransRadius || v0.v0radius() >= cMaxV0TransRadius) { return false; + } float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; - if (ctau <= cMinV0CTau || ctau >= cMaxV0CTau) + if (ctau <= cMinV0CTau || ctau >= cMaxV0CTau) { return false; - if (v0.v0cosPA() <= cMinV0CosPA) + } + if (v0.v0cosPA() <= cMinV0CosPA) { return false; + } return true; } @@ -716,21 +737,25 @@ struct LambdaTableProducer { template bool selV0Particle(C const& col, V const& v0, T const& tracks, ParticleType& v0Type) { - if (!selLambdaMassWindow(v0, tracks, v0Type)) + if (!selLambdaMassWindow(v0, tracks, v0Type)) { return false; + } histos.fill(HIST("Tracks/h1f_tracks_info"), kV0IsLambdaOrAntiLambda); - if (!selDaughterTracks(v0, tracks, v0Type)) + if (!selDaughterTracks(v0, tracks, v0Type)) { return false; + } histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0DauTrackSel); float rap = cDoEtaAnalysis ? std::abs(v0.eta()) : std::abs(v0.yLambda()); - if (!kinCutSelection(v0.pt(), rap, cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) + if (!kinCutSelection(v0.pt(), rap, cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { return false; + } histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0KinCuts); - if (!topoCutSelection(col, v0, tracks)) + if (!topoCutSelection(col, v0, tracks)) { return false; + } histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0TopoSel); // All Selection Criterion Passed @@ -744,11 +769,13 @@ struct LambdaTableProducer { auto negTrack = v0.template negTrack_as(); auto posCC = posTrack.compatibleCollIds(); auto negCC = negTrack.compatibleCollIds(); - if (posCC.size() > 1 || negCC.size() > 1) + if (posCC.size() > 1 || negCC.size() > 1) { return true; + } if ((posCC.size() != 0 && posCC[0] != posTrack.collisionId()) || - (negCC.size() != 0 && negCC[0] != negTrack.collisionId())) + (negCC.size() != 0 && negCC[0] != negTrack.collisionId())) { return true; + } return false; } @@ -768,8 +795,9 @@ struct LambdaTableProducer { bool selTrueMcRecLambda(V const& v0, T const&) { auto mcpart = v0.template mcParticle_as(); - if (std::abs(mcpart.pdgCode()) != kLambda0) + if (std::abs(mcpart.pdgCode()) != kLambda0) { return false; + } if (cCheckRecoDauFlag) { auto postrack = v0.template posTrack_as(); @@ -798,8 +826,9 @@ struct LambdaTableProducer { template float getCorrectionFactors(V const& v0) { - if (!cCorrectionFlag) + if (!cCorrectionFlag) { return 1.; + } // Get from CCDB auto ccdbObj = ccdb->getForTimeStamp(cPathCCDB.value, 1); @@ -813,8 +842,8 @@ struct LambdaTableProducer { // Get Efficiency Factor if (cGetEffFact) { - TObject* objEff = reinterpret_cast(ccdbObj->FindObject(Form("%s", vCorrFactStrings[cCorrFactHist][part].c_str()))); - TH1F* histEff = reinterpret_cast(objEff->Clone()); + auto* objEff = ccdbObj->FindObject(Form("%s", vCorrFactStrings[cCorrFactHist][part].c_str())); + auto* histEff = dynamic_cast(objEff->Clone()); if (histEff->GetDimension() == TwoDimCorr) { histos.fill(HIST("Tracks/h1f_tracks_info"), kEffCorrPtCent); effCorrFact = histEff->GetBinContent(histEff->FindBin(cent, v0.pt())); @@ -829,8 +858,8 @@ struct LambdaTableProducer { delete histEff; } if (cGetPrimFrac) { - TObject* objPrm = reinterpret_cast(ccdbObj->FindObject(Form("%s", vPrimFracStrings[cPrimFracHist][part].c_str()))); - TH1F* histPrm = reinterpret_cast(objPrm->Clone()); + auto* objPrm = ccdbObj->FindObject(Form("%s", vPrimFracStrings[cPrimFracHist][part].c_str())); + auto* histPrm = dynamic_cast(objPrm->Clone()); if (histPrm->GetDimension() == TwoDimCorr) { histos.fill(HIST("Tracks/h1f_tracks_info"), kPFCorrPtCent); primFrac = histPrm->GetBinContent(histPrm->FindBin(cent, v0.pt())); @@ -858,7 +887,7 @@ struct LambdaTableProducer { template void fillLambdaQAHistos(C const& col, V const& v0, T const&) { - static constexpr std::string_view SubDir[] = {"QA/Lambda/", "QA/AntiLambda/"}; + static constexpr std::array SubDir = {"QA/Lambda/", "QA/AntiLambda/"}; auto postrack = v0.template posTrack_as(); auto negtrack = v0.template negTrack_as(); float mass = (part == kLambda) ? v0.mLambda() : v0.mAntiLambda(); @@ -896,8 +925,8 @@ struct LambdaTableProducer { template void fillKinematicHists(float const& pt, float const& eta, float const& y, float const& phi) { - static constexpr std::string_view SubDirRG[] = {"McRec/", "McGen/"}; - static constexpr std::string_view SubDirPart[] = {"Lambda/", "AntiLambda/"}; + static constexpr std::array SubDirRG = {"McRec/", "McGen/"}; + static constexpr std::array SubDirPart = {"Lambda/", "AntiLambda/"}; histos.fill(HIST(SubDirRG[rg]) + HIST(SubDirPart[part]) + HIST("hPt"), pt); histos.fill(HIST(SubDirRG[rg]) + HIST(SubDirPart[part]) + HIST("hEta"), eta); @@ -911,8 +940,9 @@ struct LambdaTableProducer { histos.fill(HIST("Events/h1f_collisions_info"), kTotCol); if constexpr (dmc == kData) { - if (!selCollision(collision)) + if (!selCollision(collision)) { return; + } } histos.fill(HIST("Events/h1f_collisions_info"), kPassSelCol); @@ -926,27 +956,32 @@ struct LambdaTableProducer { PrmScdType v0PrmScdType = kPrimary; float mass = 0., corr_fact = 1.; float prPx = 0., prPy = 0., prPz = 0.; + float pt = 0., eta = 0., rap = 0., phi = 0.; for (auto const& v0 : v0tracks) { if constexpr (dmc == kMC) { histos.fill(HIST("Tracks/h1f_tracks_info"), kTracksBeforeHasMcParticle); - if (!v0.has_mcParticle()) + if (!v0.has_mcParticle()) { continue; + } } histos.fill(HIST("Tracks/h1f_tracks_info"), kAllV0Tracks); histos.fill(HIST("Tracks/h2f_armpod_before_sel"), v0.alpha(), v0.qtarm()); - if (!selV0Particle(collision, v0, tracks, v0Type)) + if (!selV0Particle(collision, v0, tracks, v0Type)) { continue; - if (cV0TypeSelFlag && v0.v0Type() != cV0TypeSelection) + } + if (cV0TypeSelFlag && v0.v0Type() != cV0TypeSelection) { continue; + } histos.fill(HIST("Tracks/h1f_tracks_info"), kAllSelPassed); if constexpr (run == kRun3) { - if (cRemoveAmbiguousTracks && hasAmbiguousDaughters(v0, tracks)) + if (cRemoveAmbiguousTracks && hasAmbiguousDaughters(v0, tracks)) { continue; + } } mass = (v0Type == kLambda) ? v0.mLambda() : v0.mAntiLambda(); @@ -957,12 +992,15 @@ struct LambdaTableProducer { if constexpr (dmc == kMC) { histos.fill(HIST("Tracks/h2f_tracks_pid_before_sel"), v0.mcParticle().pdgCode(), v0.pt()); - if (cSelMCPSV0) + if (cSelMCPSV0) { v0PrmScdType = isPrimaryV0(v0); - if (cSelectTrueLambda && !selTrueMcRecLambda(v0, tracks)) + } + if (cSelectTrueLambda && !selTrueMcRecLambda(v0, tracks)) { continue; - if (v0PrmScdType == kSecondary) + } + if (v0PrmScdType == kSecondary) { fillLambdaMothers(v0, tracks); + } histos.fill(HIST("Tracks/h1f_tracks_info"), kPassTrueLambdaSel); histos.fill(HIST("Tracks/h2f_tracks_pid_after_sel"), v0.mcParticle().pdgCode(), v0.pt()); if (cRecoMomResoFlag) { @@ -972,8 +1010,9 @@ struct LambdaTableProducer { rap = mc.y(); phi = mc.phi(); float y = cDoEtaAnalysis ? eta : rap; - if (!kinCutSelection(pt, std::abs(y), cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) + if (!kinCutSelection(pt, std::abs(y), cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { continue; + } } } @@ -1015,17 +1054,19 @@ struct LambdaTableProducer { float prPx = 0., prPy = 0., prPz = 0.; for (auto const& mcpart : mcParticles) { - if (mcpart.pdgCode() == kLambda0) + if (mcpart.pdgCode() == kLambda0) { v0Type = kLambda; - else if (mcpart.pdgCode() == kLambda0Bar) + } else if (mcpart.pdgCode() == kLambda0Bar) { v0Type = kAntiLambda; - else + } else { continue; + } v0PrmScdType = mcpart.isPhysicalPrimary() ? kPrimary : kSecondary; rap = cDoEtaAnalysis ? mcpart.eta() : mcpart.y(); - if (!kinCutSelection(mcpart.pt(), std::abs(rap), cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) + if (!kinCutSelection(mcpart.pt(), std::abs(rap), cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { continue; + } histos.fill(HIST("Tracks/h1f_tracks_info"), kGenTotAccLambda); if (!mcpart.has_daughters()) { @@ -1048,10 +1089,12 @@ struct LambdaTableProducer { vDauPz.push_back(dautrack.pz()); } if (cGenDecayChannel) { - if (v0Type == kLambda && (daughterPDGs[0] != kProton || daughterPDGs[1] != kPiMinus)) + if (v0Type == kLambda && (daughterPDGs[0] != kProton || daughterPDGs[1] != kPiMinus)) { continue; - if (v0Type == kAntiLambda && (daughterPDGs[0] != kProtonBar || daughterPDGs[1] != kPiPlus)) + } + if (v0Type == kAntiLambda && (daughterPDGs[0] != kProtonBar || daughterPDGs[1] != kPiPlus)) { continue; + } } histos.fill(HIST("Tracks/h1f_tracks_info"), kGenLambdaToPrPi); @@ -1103,16 +1146,19 @@ struct LambdaTableProducer { void analyzeMcRecoGen(M const& mcCollision, C const& collisions, V const& /*V0s*/, T const& /*tracks*/, P const& mcParticles) { int nRecCols = collisions.size(); - if (nRecCols != 0) + if (nRecCols != 0) { histos.fill(HIST("McGen/h1f_collision_recgen"), nRecCols); - if (nRecCols != 1) + } + if (nRecCols != 1) { return; + } histos.fill(HIST("McGen/h1f_collisions_info"), kTotCol); if (!collisions.begin().has_mcCollision() || !selCollision(collisions.begin()) || - collisions.begin().mcCollisionId() != mcCollision.globalIndex()) + collisions.begin().mcCollisionId() != mcCollision.globalIndex()) { return; + } histos.fill(HIST("McGen/h1f_collisions_info"), kPassSelCol); histos.fill(HIST("McGen/h2f_collision_posZ"), mcCollision.posZ(), collisions.begin().posZ()); fillLambdaMcGenTables(mcCollision, mcParticles); @@ -1198,7 +1244,7 @@ struct LambdaTracksExtProducer { template void fillHistos(T const& track) { - static constexpr std::string_view SubDir[] = {"Reco/", "SharingDau/"}; + static constexpr std::array SubDir = {"Reco/", "SharingDau/"}; if (track.v0Type() == kLambda) { histos.fill(HIST(SubDir[sd]) + HIST("h1f_lambda_invmass"), track.mass()); histos.fill(HIST(SubDir[sd]) + HIST("h1f_lambda_dcadau"), track.dcaDau()); @@ -1220,79 +1266,88 @@ struct LambdaTracksExtProducer { std::vector vSharedDauLambdaIndex; float tLambda = 0., tTrack = 0.; - if (lambda.v0Type() == kLambda) + if (lambda.v0Type() == kLambda) { ++nTotLambda; - else if (lambda.v0Type() == kAntiLambda) + } else if (lambda.v0Type() == kAntiLambda) { ++nTotAntiLambda; + } tLambda = (cA * std::abs(lambda.mass() - MassLambda0)) + (cB * lambda.dcaDau()) + (cC * std::abs(lambda.cosPA() - 1.)); for (auto const& track : tracks) { - if (lambda.index() == track.index()) + if (lambda.index() == track.index()) { continue; + } if (lambda.posTrackId() == track.posTrackId() || lambda.negTrackId() == track.negTrackId()) { vSharedDauLambdaIndex.push_back(track.index()); lambdaSharingDauFlag = true; - if (lambda.v0Type() == kLambda && track.v0Type() == kAntiLambda) + if (lambda.v0Type() == kLambda && track.v0Type() == kAntiLambda) { histos.fill(HIST("h2d_n2_etaphi_LaP_LaM"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); - else if (lambda.v0Type() == kAntiLambda && track.v0Type() == kLambda) + } else if (lambda.v0Type() == kAntiLambda && track.v0Type() == kLambda) { histos.fill(HIST("h2d_n2_etaphi_LaM_LaP"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); - else if (lambda.v0Type() == kLambda && track.v0Type() == kLambda) + } else if (lambda.v0Type() == kLambda && track.v0Type() == kLambda) { histos.fill(HIST("h2d_n2_etaphi_LaP_LaP"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); - else if (lambda.v0Type() == kAntiLambda && track.v0Type() == kAntiLambda) + } else if (lambda.v0Type() == kAntiLambda && track.v0Type() == kAntiLambda) { histos.fill(HIST("h2d_n2_etaphi_LaM_LaM"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); + } - if (std::abs(lambda.mass() - MassLambda0) > std::abs(track.mass() - MassLambda0)) + if (std::abs(lambda.mass() - MassLambda0) > std::abs(track.mass() - MassLambda0)) { lambdaMinDeltaMassFlag = false; + } tTrack = (cA * std::abs(track.mass() - MassLambda0)) + (cB * track.dcaDau()) + (cC * std::abs(track.cosPA() - 1.)); - if (tLambda > tTrack) + if (tLambda > tTrack) { lambdaMinTScoreFlag = false; + } } } - if (lambdaSharingDauFlag) + if (lambdaSharingDauFlag) { fillHistos(lambda); - else + } else { fillHistos(lambda); + } - if (cAcceptAllLambda) - trueLambdaFlag = true; - else if (cRejAllLambdaShaDau && !lambdaSharingDauFlag) - trueLambdaFlag = true; - else if (cSelLambdaMassPdg && lambdaMinDeltaMassFlag) - trueLambdaFlag = true; - else if (cSelLambdaTScore && lambdaMinTScoreFlag) + if (cAcceptAllLambda || + (cRejAllLambdaShaDau && !lambdaSharingDauFlag) || + (cSelLambdaMassPdg && lambdaMinDeltaMassFlag) || + (cSelLambdaTScore && lambdaMinTScoreFlag)) { trueLambdaFlag = true; + } if (trueLambdaFlag) { - if (lambda.v0Type() == kLambda) + if (lambda.v0Type() == kLambda) { ++nSelLambda; - else if (lambda.v0Type() == kAntiLambda) + } else if (lambda.v0Type() == kAntiLambda) { ++nSelAntiLambda; + } } lambdaTrackExtTable(lambdaSharingDauFlag, vSharedDauLambdaIndex, trueLambdaFlag); } - if (nTotLambda != 0) + if (nTotLambda != 0) { histos.fill(HIST("h1i_totlambda_mult"), nTotLambda); - if (nTotAntiLambda != 0) + } + if (nTotAntiLambda != 0) { histos.fill(HIST("h1i_totantilambda_mult"), nTotAntiLambda); - if (nSelLambda != 0) + } + if (nSelLambda != 0) { histos.fill(HIST("h1i_lambda_mult"), nSelLambda); - if (nSelAntiLambda != 0) + } + if (nSelAntiLambda != 0) { histos.fill(HIST("h1i_antilambda_mult"), nSelAntiLambda); + } } }; @@ -1308,7 +1363,7 @@ struct LambdaSpinPolarization { Configurable cMinRap{"cMinRap", -0.5f, "Rapidity min"}; Configurable cMaxRap{"cMaxRap", 0.5f, "Rapidity max"}; Configurable cNPhiBins{"cNPhiBins", 36, "N phi bins"}; - Configurable cNBinsCosTS{"cNBinsCosTS", 20, "N costheta* bins"}; + Configurable cNBinsCosTS{"cNBinsCosTS", 10, "N costheta* bins"}; Configurable cNBinsDeltaR{"cNBinsDeltaR", 20, "N DeltaR bins"}; Configurable cMassHistMin{"cMassHistMin", 1.08f, "Mass histogram min (GeV/c2)"}; @@ -1342,16 +1397,16 @@ struct LambdaSpinPolarization { struct PoolTrack { float _px, _py, _pz, _pt, _rap, _phi, _mass; float _prPx, _prPy, _prPz; - float px() const { return _px; } - float py() const { return _py; } - float pz() const { return _pz; } - float pt() const { return _pt; } - float rap() const { return _rap; } - float phi() const { return _phi; } - float mass() const { return _mass; } - float prPx() const { return _prPx; } - float prPy() const { return _prPy; } - float prPz() const { return _prPz; } + [[nodiscard]] float px() const { return _px; } + [[nodiscard]] float py() const { return _py; } + [[nodiscard]] float pz() const { return _pz; } + [[nodiscard]] float pt() const { return _pt; } + [[nodiscard]] float rap() const { return _rap; } + [[nodiscard]] float phi() const { return _phi; } + [[nodiscard]] float mass() const { return _mass; } + [[nodiscard]] float prPx() const { return _prPx; } + [[nodiscard]] float prPy() const { return _prPy; } + [[nodiscard]] float prPz() const { return _prPz; } }; template @@ -1372,67 +1427,39 @@ struct LambdaSpinPolarization { const AxisSpec axisDRap(2 * cNRapBins, cMinRap - cMaxRap, cMaxRap - cMinRap, "#Deltay"); const AxisSpec axisDPhi(cNPhiBins, -PI, PI, "#Delta#varphi"); const AxisSpec axisCosTS(cNBinsCosTS, -1, 1, "cos(#theta*)"); - const AxisSpec axisDR(cNBinsDeltaR, 0, 4, "#DeltaR"); - const AxisSpec axisPosZ(220, -7, 7, "V_{z} (cm)"); + const AxisSpec axisDR(cNBinsDeltaR, 0, 3.5, "#DeltaR"); + const AxisSpec axisPosZ(200, -10, 10, "V_{z} (cm)"); const AxisSpec axisMult(10, 0, 10, "N_{#Lambda}"); histos.add("QA/ME/hPoolCentVz", "ME pool;cent (%);V_{z}", kTH2F, {axisCentME, axisVtxZME}); histos.add("QA/ME/hLambdaMultVsCent", "ME #Lambda mult;cent;N", kTH2F, {axisCentME, {50, 0, 50}}); histos.add("QA/ME/hAntiLambdaMultVsCent", "ME #bar{#Lambda} mult;cent;N", kTH2F, {axisCentME, {50, 0, 50}}); - histos.add("SE/Reco/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/Reco/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/Reco/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/Reco/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - - histos.add("SE/RecoBkgSigSB/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/RecoBkgSigSB/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/RecoBkgSigSB/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/RecoBkgSigSB/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - - histos.add("SE/RecoBkgSBSB/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/RecoBkgSBSB/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/RecoBkgSBSB/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("SE/RecoBkgSBSB/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - - histos.add("ME/Reco/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/Reco/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/Reco/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/Reco/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} inclusive", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - - histos.add("ME/RecoBkgSigSB/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/RecoBkgSigSB/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/RecoBkgSigSB/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/RecoBkgSigSB/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} Sig#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - - histos.add("ME/RecoBkgSBSB/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/RecoBkgSBSB/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/RecoBkgSBSB/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); - histos.add("ME/RecoBkgSBSB/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} SB#timesSB", - kTHnSparseF, {axisMass, axisMass, axisPt, axisPt, axisDRap, axisDPhi, axisDR}); + const std::vector massSparseAxes = {axisCent, axisMass, axisMass, axisPt, axisPt, + axisDRap, axisDPhi, axisDR, axisCosTS}; + + histos.add("SE/Reco/Star/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} inclusive", kTHnSparseF, massSparseAxes); + histos.add("SE/Reco/Star/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda inclusive", kTHnSparseF, massSparseAxes); + histos.add("SE/Reco/Star/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda inclusive", kTHnSparseF, massSparseAxes); + histos.add("SE/Reco/Star/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} inclusive", kTHnSparseF, massSparseAxes); + + histos.add("SE/RecoBkgSigSB/Star/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} Sig#timesSB", kTHnSparseF, massSparseAxes); + histos.add("SE/RecoBkgSigSB/Star/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda Sig#timesSB", kTHnSparseF, massSparseAxes); + histos.add("SE/RecoBkgSigSB/Star/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda Sig#timesSB", kTHnSparseF, massSparseAxes); + histos.add("SE/RecoBkgSigSB/Star/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} Sig#timesSB", kTHnSparseF, massSparseAxes); + + histos.add("SE/RecoBkgSBSB/Star/h2f_n2_mass_LaPLaM", "M_{inv}: #Lambda#bar{#Lambda} SB#timesSB", kTHnSparseF, massSparseAxes); + histos.add("SE/RecoBkgSBSB/Star/h2f_n2_mass_LaMLaP", "M_{inv}: #bar{#Lambda}#Lambda SB#timesSB", kTHnSparseF, massSparseAxes); + histos.add("SE/RecoBkgSBSB/Star/h2f_n2_mass_LaPLaP", "M_{inv}: #Lambda#Lambda SB#timesSB", kTHnSparseF, massSparseAxes); + histos.add("SE/RecoBkgSBSB/Star/h2f_n2_mass_LaMLaM", "M_{inv}: #bar{#Lambda}#bar{#Lambda} SB#timesSB", kTHnSparseF, massSparseAxes); + + histos.addClone("SE/Reco/Star/", "SE/Reco/Atlas/"); + histos.addClone("SE/RecoBkgSigSB/Star/", "SE/RecoBkgSigSB/Atlas/"); + histos.addClone("SE/RecoBkgSBSB/Star/", "SE/RecoBkgSBSB/Atlas/"); + + histos.addClone("SE/Reco/", "ME/Reco/"); + histos.addClone("SE/RecoBkgSigSB/", "ME/RecoBkgSigSB/"); + histos.addClone("SE/RecoBkgSBSB/", "ME/RecoBkgSBSB/"); histos.add("SE/RecoCorr/Star/h2f_n2_dltaR_LaPLaM", "#rho_{2} #Lambda#bar{#Lambda} [Star]", kTHnSparseF, {axisCent, axisDR, axisCosTS}); histos.add("SE/RecoCorr/Star/h2f_n2_dltaR_LaMLaP", "#rho_{2} #bar{#Lambda}#Lambda [Star]", kTHnSparseF, {axisCent, axisDR, axisCosTS}); @@ -1523,10 +1550,58 @@ struct LambdaSpinPolarization { p[2] = p[2] + gam2 * bp * b[2] + gam * b[2] * e; } + // cos of the opening angle between the two proton three-momenta. + static float cosOpeningAngle(std::array const& a, std::array const& b) + { + std::array n1 = {a[0], a[1], a[2]}, n2 = {b[0], b[1], b[2]}; + return RecoDecay::dotProd(n1, n2) / + (RecoDecay::sqrtSumOfSquares(n1[0], n1[1], n1[2]) * + RecoDecay::sqrtSumOfSquares(n2[0], n2[1], n2[2])); + } + + float cosThetaStarAtlas(std::array const& l1, std::array const& l2, + std::array const& pr1, std::array const& pr2) + { + auto l1a = l1; + auto l2a = l2; + auto pr1a = pr1; + auto pr2a = pr2; + + const float mPair = RecoDecay::m(std::array{std::array{l1a[0], l1a[1], l1a[2]}, + std::array{l2a[0], l2a[1], l2a[2]}}, + std::array{l1a[3], l2a[3]}); + std::array llpair = {l1a[0] + l2a[0], l1a[1] + l2a[1], l1a[2] + l2a[2], mPair}; + std::array vPair{}; + getBoostVector(llpair, vPair, cInvBoostFlag); + boost(l1a, vPair); + boost(l2a, vPair); + boost(pr1a, vPair); + boost(pr2a, vPair); + std::array v1p{}, v2p{}; + getBoostVector(l1a, v1p, cInvBoostFlag); + getBoostVector(l2a, v2p, cInvBoostFlag); + boost(pr1a, v1p); + boost(pr2a, v2p); + return cosOpeningAngle(pr1a, pr2a); + } + + float cosThetaStarStar(std::array const& l1, std::array const& l2, + std::array const& pr1, std::array const& pr2) + { + auto pr1s = pr1; + auto pr2s = pr2; + std::array v1lab{}, v2lab{}; + getBoostVector(l1, v1lab, cInvBoostFlag); + getBoostVector(l2, v2lab, cInvBoostFlag); + boost(pr1s, v1lab); + boost(pr2s, v2lab); + return cosOpeningAngle(pr1s, pr2s); + } + template void fillPairHistos(U const& p1, U const& p2) { - static constexpr std::string_view SubDir[] = {"LaPLaM", "LaMLaP", "LaPLaP", "LaMLaM"}; + static constexpr std::array SubDir = {"LaPLaM", "LaMLaP", "LaPLaP", "LaMLaM"}; constexpr bool IsSigSB = (part_pair == kLambdaSBAntiLambda || part_pair == kAntiLambdaSBLambda || @@ -1545,74 +1620,46 @@ struct LambdaSpinPolarization { float dphi = RecoDecay::constrainAngle(p1.phi() - p2.phi(), -PI); float dR = std::sqrt(drap * drap + dphi * dphi); - if constexpr (!IsSigSB && !IsSBSB) { - histos.fill(HIST("SE/Reco/h2f_n2_mass_") + HIST(SubDir[Idx]), - p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR); - } else if constexpr (IsSigSB) { - histos.fill(HIST("SE/RecoBkgSigSB/h2f_n2_mass_") + HIST(SubDir[Idx]), - p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR); - } else { - histos.fill(HIST("SE/RecoBkgSBSB/h2f_n2_mass_") + HIST(SubDir[Idx]), - p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR); - } - std::array l1 = {p1.px(), p1.py(), p1.pz(), MassLambda0}; std::array l2 = {p2.px(), p2.py(), p2.pz(), MassLambda0}; std::array pr1 = {p1.prPx(), p1.prPy(), p1.prPz(), MassProton}; std::array pr2 = {p2.prPx(), p2.prPy(), p2.prPz(), MassProton}; if (cDoAtlasMethod) { - auto l1a = l1; - auto l2a = l2; - auto pr1a = pr1; - auto pr2a = pr2; - std::array llpair = {l1a[0] + l2a[0], l1a[1] + l2a[1], l1a[2] + l2a[2], l1a[3] + l2a[3]}; - std::array vPair; - getBoostVector(llpair, vPair, cInvBoostFlag); - boost(l1a, vPair); - boost(l2a, vPair); - boost(pr1a, vPair); - boost(pr2a, vPair); - std::array v1p, v2p; - getBoostVector(l1a, v1p, cInvBoostFlag); - getBoostVector(l2a, v2p, cInvBoostFlag); - boost(pr1a, v1p); - boost(pr2a, v2p); - std::array n1 = {pr1a[0], pr1a[1], pr1a[2]}, n2 = {pr2a[0], pr2a[1], pr2a[2]}; - float ctheta = RecoDecay::dotProd(n1, n2) / - (RecoDecay::sqrtSumOfSquares(n1[0], n1[1], n1[2]) * - RecoDecay::sqrtSumOfSquares(n2[0], n2[1], n2[2])); + float ctheta = cosThetaStarAtlas(l1, l2, pr1, pr2); if constexpr (!IsSigSB && !IsSBSB) { + histos.fill(HIST("SE/Reco/Atlas/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta); histos.fill(HIST("SE/RecoCorr/Atlas/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta); histos.fill(HIST("SE/RecoCorr/Atlas/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta); } else if constexpr (IsSigSB) { + histos.fill(HIST("SE/RecoBkgSigSB/Atlas/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta); histos.fill(HIST("SE/RecoCorrBkgSigSB/Atlas/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta); histos.fill(HIST("SE/RecoCorrBkgSigSB/Atlas/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta); } else { + histos.fill(HIST("SE/RecoBkgSBSB/Atlas/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta); histos.fill(HIST("SE/RecoCorrBkgSBSB/Atlas/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta); histos.fill(HIST("SE/RecoCorrBkgSBSB/Atlas/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta); } } if (cDoStarMethod) { - auto pr1s = pr1; - auto pr2s = pr2; - std::array v1lab, v2lab; - getBoostVector(l1, v1lab, cInvBoostFlag); - getBoostVector(l2, v2lab, cInvBoostFlag); - boost(pr1s, v1lab); - boost(pr2s, v2lab); - std::array n1 = {pr1s[0], pr1s[1], pr1s[2]}, n2 = {pr2s[0], pr2s[1], pr2s[2]}; - float ctheta = RecoDecay::dotProd(n1, n2) / - (RecoDecay::sqrtSumOfSquares(n1[0], n1[1], n1[2]) * - RecoDecay::sqrtSumOfSquares(n2[0], n2[1], n2[2])); + float ctheta = cosThetaStarStar(l1, l2, pr1, pr2); if constexpr (!IsSigSB && !IsSBSB) { + histos.fill(HIST("SE/Reco/Star/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta); histos.fill(HIST("SE/RecoCorr/Star/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta); histos.fill(HIST("SE/RecoCorr/Star/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta); } else if constexpr (IsSigSB) { + histos.fill(HIST("SE/RecoBkgSigSB/Star/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta); histos.fill(HIST("SE/RecoCorrBkgSigSB/Star/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta); histos.fill(HIST("SE/RecoCorrBkgSigSB/Star/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta); } else { + histos.fill(HIST("SE/RecoBkgSBSB/Star/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta); histos.fill(HIST("SE/RecoCorrBkgSBSB/Star/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta); histos.fill(HIST("SE/RecoCorrBkgSBSB/Star/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta); } @@ -1622,7 +1669,7 @@ struct LambdaSpinPolarization { template void fillPairHistosWeighted(PoolTrack const& p1, PoolTrack const& p2, float w) { - static constexpr std::string_view SubDir[] = {"LaPLaM", "LaMLaP", "LaPLaP", "LaMLaM"}; + static constexpr std::array SubDir = {"LaPLaM", "LaMLaP", "LaPLaP", "LaMLaM"}; constexpr bool IsSigSB = (part_pair == kLambdaSBAntiLambda || part_pair == kAntiLambdaSBLambda || @@ -1641,57 +1688,31 @@ struct LambdaSpinPolarization { float dphi = RecoDecay::constrainAngle(p1.phi() - p2.phi(), -PI); float dR = std::sqrt(drap * drap + dphi * dphi); - if constexpr (!IsSigSB && !IsSBSB) { - histos.fill(HIST("ME/Reco/h2f_n2_mass_") + HIST(SubDir[Idx]), - p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, w); - } else if constexpr (IsSigSB) { - histos.fill(HIST("ME/RecoBkgSigSB/h2f_n2_mass_") + HIST(SubDir[Idx]), - p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, w); - } else { - histos.fill(HIST("ME/RecoBkgSBSB/h2f_n2_mass_") + HIST(SubDir[Idx]), - p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, w); - } - std::array l1 = {p1.px(), p1.py(), p1.pz(), MassLambda0}; std::array l2 = {p2.px(), p2.py(), p2.pz(), MassLambda0}; std::array pr1 = {p1.prPx(), p1.prPy(), p1.prPz(), MassProton}; std::array pr2 = {p2.prPx(), p2.prPy(), p2.prPz(), MassProton}; if (cDoAtlasMethod) { - auto l1a = l1; - auto l2a = l2; - auto pr1a = pr1; - auto pr2a = pr2; - std::array llpair = {l1a[0] + l2a[0], l1a[1] + l2a[1], - l1a[2] + l2a[2], l1a[3] + l2a[3]}; - std::array vPair; - getBoostVector(llpair, vPair, cInvBoostFlag); - boost(l1a, vPair); - boost(l2a, vPair); - boost(pr1a, vPair); - boost(pr2a, vPair); - std::array v1p, v2p; - getBoostVector(l1a, v1p, cInvBoostFlag); - getBoostVector(l2a, v2p, cInvBoostFlag); - boost(pr1a, v1p); - boost(pr2a, v2p); - std::array n1 = {pr1a[0], pr1a[1], pr1a[2]}, - n2 = {pr2a[0], pr2a[1], pr2a[2]}; - float ctheta = RecoDecay::dotProd(n1, n2) / - (RecoDecay::sqrtSumOfSquares(n1[0], n1[1], n1[2]) * - RecoDecay::sqrtSumOfSquares(n2[0], n2[1], n2[2])); + float ctheta = cosThetaStarAtlas(l1, l2, pr1, pr2); if constexpr (!IsSigSB && !IsSBSB) { + histos.fill(HIST("ME/Reco/Atlas/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta, w); histos.fill(HIST("ME/RecoCorr/Atlas/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta, w); histos.fill(HIST("ME/RecoCorr/Atlas/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta, w); } else if constexpr (IsSigSB) { + histos.fill(HIST("ME/RecoBkgSigSB/Atlas/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSigSB/Atlas/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSigSB/Atlas/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta, w); } else { + histos.fill(HIST("ME/RecoBkgSBSB/Atlas/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSBSB/Atlas/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSBSB/Atlas/h2f_n2_dltaR_") + HIST(SubDir[Idx]), @@ -1700,30 +1721,25 @@ struct LambdaSpinPolarization { } if (cDoStarMethod) { - auto pr1s = pr1; - auto pr2s = pr2; - std::array v1lab, v2lab; - getBoostVector(l1, v1lab, cInvBoostFlag); - getBoostVector(l2, v2lab, cInvBoostFlag); - boost(pr1s, v1lab); - boost(pr2s, v2lab); - std::array n1 = {pr1s[0], pr1s[1], pr1s[2]}, - n2 = {pr2s[0], pr2s[1], pr2s[2]}; - float ctheta = RecoDecay::dotProd(n1, n2) / - (RecoDecay::sqrtSumOfSquares(n1[0], n1[1], n1[2]) * - RecoDecay::sqrtSumOfSquares(n2[0], n2[1], n2[2])); + float ctheta = cosThetaStarStar(l1, l2, pr1, pr2); if constexpr (!IsSigSB && !IsSBSB) { + histos.fill(HIST("ME/Reco/Star/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta, w); histos.fill(HIST("ME/RecoCorr/Star/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta, w); histos.fill(HIST("ME/RecoCorr/Star/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta, w); } else if constexpr (IsSigSB) { + histos.fill(HIST("ME/RecoBkgSigSB/Star/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSigSB/Star/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSigSB/Star/h2f_n2_dltaR_") + HIST(SubDir[Idx]), cent, dR, ctheta, w); } else { + histos.fill(HIST("ME/RecoBkgSBSB/Star/h2f_n2_mass_") + HIST(SubDir[Idx]), + cent, p1.mass(), p2.mass(), p1.pt(), p2.pt(), drap, dphi, dR, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSBSB/Star/h2f_n2_ctheta_") + HIST(SubDir[Idx]), cent, drap, dphi, ctheta, w); histos.fill(HIST("ME/RecoCorrBkgSBSB/Star/h2f_n2_dltaR_") + HIST(SubDir[Idx]), @@ -1739,26 +1755,31 @@ struct LambdaSpinPolarization { void analyzePairsWithMassWindow(T const& trks_1, T const& trks_2) { for (auto const& trk_1 : trks_1) { - if (!isInclusive(trk_1.mass())) + if (!isInclusive(trk_1.mass())) { continue; + } bool t1sig = isSignal(trk_1.mass()); bool t1sb = isSideband(trk_1.mass()); for (auto const& trk_2 : trks_2) { if constexpr (samelambda) { - if (trk_1.index() == trk_2.index()) + if (trk_1.index() == trk_2.index()) { continue; + } } - if (!isInclusive(trk_2.mass())) + if (!isInclusive(trk_2.mass())) { continue; + } bool t2sig = isSignal(trk_2.mass()); bool t2sb = isSideband(trk_2.mass()); fillPairHistos(trk_1, trk_2); - if ((t1sig && t2sb) || (t1sb && t2sig)) + if ((t1sig && t2sb) || (t1sb && t2sig)) { fillPairHistos(trk_1, trk_2); - if (t1sb && t2sb) + } + if (t1sb && t2sb) { fillPairHistos(trk_1, trk_2); + } } } } @@ -1774,30 +1795,35 @@ struct LambdaSpinPolarization { { for (auto const& trk_1 : trks_1) { - if (!isInclusive(trk_1.mass())) + if (!isInclusive(trk_1.mass())) { continue; + } const bool t1sig = isSignal(trk_1.mass()); const bool t1sb = isSideband(trk_1.mass()); PoolTrack p1 = toPoolTrack(trk_1); for (auto const& trk_2 : trks_2) { if constexpr (samelambda) { - if (trk_1.index() == trk_2.index()) + if (trk_1.index() == trk_2.index()) { continue; + } } - if (!isInclusive(trk_2.mass())) + if (!isInclusive(trk_2.mass())) { continue; + } const bool t2sig = isSignal(trk_2.mass()); const bool t2sb = isSideband(trk_2.mass()); PoolTrack p2 = toPoolTrack(trk_2); fillPairHistosWeighted(p1, p2, 1.0f); - if ((t1sig && t2sb) || (t1sb && t2sig)) + if ((t1sig && t2sb) || (t1sb && t2sig)) { fillPairHistosWeighted(p1, p2, 1.0f); + } - if (t1sb && t2sb) + if (t1sb && t2sb) { fillPairHistosWeighted(p1, p2, 1.0f); + } } } } @@ -1812,30 +1838,38 @@ struct LambdaSpinPolarization { std::vector meVec1, meVec2; meVec1.reserve(me_pool_1.size()); meVec2.reserve(me_pool_2.size()); - for (auto const& me : me_pool_1) - if (isInclusive(me.mass())) + for (auto const& me : me_pool_1) { + if (isInclusive(me.mass())) { meVec1.push_back(toPoolTrack(me)); - for (auto const& me : me_pool_2) - if (isInclusive(me.mass())) + } + } + for (auto const& me : me_pool_2) { + if (isInclusive(me.mass())) { meVec2.push_back(toPoolTrack(me)); + } + } - if (meVec1.empty() && meVec2.empty()) + if (meVec1.empty() && meVec2.empty()) { return; + } for (auto const& trk1 : se_trks_1) { - if (!isInclusive(trk1.mass())) + if (!isInclusive(trk1.mass())) { continue; + } const bool se1sig = isSignal(trk1.mass()); const bool se1sb = isSideband(trk1.mass()); PoolTrack p1 = toPoolTrack(trk1); for (auto const& trk2 : se_trks_2) { if constexpr (samelambda) { - if (trk1.index() == trk2.index()) + if (trk1.index() == trk2.index()) { continue; + } } - if (!isInclusive(trk2.mass())) + if (!isInclusive(trk2.mass())) { continue; + } const bool se2sig = isSignal(trk2.mass()); const bool se2sb = isSideband(trk2.mass()); PoolTrack p2 = toPoolTrack(trk2); @@ -1845,8 +1879,9 @@ struct LambdaSpinPolarization { for (auto const& meP : meVec2) { if (std::abs(meP.pt() - p2.pt()) < cMaxDeltaPt && std::abs(meP.rap() - p2.rap()) < cMaxDeltaRap && - std::abs(RecoDecay::constrainAngle(meP.phi() - p2.phi(), -PI)) < cMaxDeltaPhi) + std::abs(RecoDecay::constrainAngle(meP.phi() - p2.phi(), -PI)) < cMaxDeltaPhi) { matchA.push_back(meP); + } } if (!matchA.empty()) { const float wA = 1.0f / static_cast(matchA.size()); @@ -1856,11 +1891,13 @@ struct LambdaSpinPolarization { fillPairHistosWeighted(p1, meP2, wA); - if ((se1sig && me2sb) || (se1sb && me2sig)) + if ((se1sig && me2sb) || (se1sb && me2sig)) { fillPairHistosWeighted(p1, meP2, wA); + } - if (se1sb && me2sb) + if (se1sb && me2sb) { fillPairHistosWeighted(p1, meP2, wA); + } } } } @@ -1870,8 +1907,9 @@ struct LambdaSpinPolarization { for (auto const& meP : meVec1) { if (std::abs(meP.pt() - p1.pt()) < cMaxDeltaPt && std::abs(meP.rap() - p1.rap()) < cMaxDeltaRap && - std::abs(RecoDecay::constrainAngle(meP.phi() - p1.phi(), -PI)) < cMaxDeltaPhi) + std::abs(RecoDecay::constrainAngle(meP.phi() - p1.phi(), -PI)) < cMaxDeltaPhi) { matchB.push_back(meP); + } } if (!matchB.empty()) { const float wB = 1.0f / static_cast(matchB.size()); @@ -1881,11 +1919,13 @@ struct LambdaSpinPolarization { fillPairHistosWeighted(meP1, p2, wB); - if ((me1sig && se2sb) || (me1sb && se2sig)) + if ((me1sig && se2sb) || (me1sb && se2sig)) { fillPairHistosWeighted(meP1, p2, wB); + } - if (me1sb && se2sb) + if (me1sb && se2sb) { fillPairHistosWeighted(meP1, p2, wB); + } } } } @@ -1943,8 +1983,9 @@ struct LambdaSpinPolarization { { for (auto const& [col1, col2] : soa::selfCombinations(binningOnVtxAndMult, mixingParameter, -1, col, col)) { - if (col1.globalIndex() == col2.globalIndex()) + if (col1.globalIndex() == col2.globalIndex()) { continue; + } cent = col1.cent(); histos.fill(HIST("QA/ME/hPoolCentVz"), col1.cent(), col1.posZ()); @@ -1997,22 +2038,25 @@ struct LambdaSpinPolarization { auto alTrks = partAntiLambdaTracks->sliceByCached( aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - if (lTrks.size() == 0 && alTrks.size() == 0) + if (lTrks.size() == 0 && alTrks.size() == 0) { return; + } lambdaMixEvtCol(collision.index(), collision.cent(), collision.posZ(), collision.timeStamp()); - for (auto const& track : lTrks) + for (auto const& track : lTrks) { lambdaMixEvtTrk(collision.index(), track.globalIndex(), track.px(), track.py(), track.pz(), track.mass(), track.prPx(), track.prPy(), track.prPz(), track.v0Type(), collision.timeStamp()); - for (auto const& track : alTrks) + } + for (auto const& track : alTrks) { lambdaMixEvtTrk(collision.index(), track.globalIndex(), track.px(), track.py(), track.pz(), track.mass(), track.prPx(), track.prPy(), track.prPz(), track.v0Type(), collision.timeStamp()); + } } PROCESS_SWITCH(LambdaSpinPolarization, processDataRecoMixEvent, "Mix-event table filling", false); diff --git a/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx b/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx index 8a89826a0ac..abc1a16adc3 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx @@ -44,10 +44,11 @@ #include #include #include -#include #include #include +#include #include +#include #include @@ -86,7 +87,6 @@ struct TwoParticleCorrelationsMpi { Configurable cfgAssociatedCharge{"cfgAssociatedCharge", 0, "Select on charge of associated particle: 0 = all charged; 1 = positive; -1 = negative"}; Configurable cfgPairCharge{"cfgPairCharge", 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"}; Configurable cfgCorrelationMethod{"cfgCorrelationMethod", 0, "Correlation method, 0 = all, 1 = dd, 2 = ddbar"}; - Configurable cfgNuncSeedEstimator{"cfgNuncSeedEstimator", 0, "Estimator for number of uncorrelated seeds, 0 = bin look up, 1 = interpolation"}; Configurable cfgTwoTrackCut{"cfgTwoTrackCut", -1, "Two track cut: -1 = off; >0 otherwise distance value (suggested: 0.02)"}; Configurable cfgTwoTrackCutMinRadius{"cfgTwoTrackCutMinRadius", 0.8f, "Two track cut: radius in m from which two track cuts are applied"}; @@ -99,11 +99,12 @@ struct TwoParticleCorrelationsMpi { Configurable cfgMultCutFormula{"cfgMultCutFormula", "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity, [cFT0M] FT0M centrality"}; // Suggested values: Photon: 0.004; K0 and Lambda: 0.005 - Configurable> cfgPairCut{"cfgPairCut", {CfgPairCutDefaults.front().data(), 5, 1, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; + Configurable> cfgPairCut{"cfgPairCut", {CfgPairCutDefaults.front().data(), 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; Configurable cfgEfficiencyTrigger{"cfgEfficiencyTrigger", "", "CCDB path to efficiency object for trigger particles"}; Configurable cfgEfficiencyAssociated{"cfgEfficiencyAssociated", "", "CCDB path to efficiency object for associated particles"}; - Configurable cfgNuncSeedsCalibration{"cfgNuncSeedsCalibration", "", "CCDB path to calibration object for number of uncorrelated seeds classification"}; + Configurable cfgNuncSeedsTemplateFile{"cfgNuncSeedsTemplateFile", "", "Local ROOT file containing ensembleYieldTemplates"}; + Configurable cfgNuncSeedsTemplate{"cfgNuncSeedsTemplate", "", "CCDB path to the ensemble-yield template ccdb_object"}; Configurable cfgNumMixedEvents{"cfgNumMixedEvents", 5, "Number of mixed events per event"}; @@ -120,7 +121,6 @@ struct TwoParticleCorrelationsMpi { ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}, "pt trigger axis for histograms"}; ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0}, "pt associated axis for histograms"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity / centrality axis for histograms"}; - ConfigurableAxis axisUncSeeds{"axisUncSeeds", {VARIABLE_WIDTH, 0, 0.2, 0.4, 0.6, 0.8, 1}, "uncorrelated seeds axes in quantiles"}; ConfigurableAxis axisVertexEfficiency{"axisVertexEfficiency", {10, -10, 10}, "vertex axis for efficiency histograms"}; ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {20, -1.0, 1.0}, "eta axis for efficiency histograms"}; @@ -162,26 +162,46 @@ struct TwoParticleCorrelationsMpi { bool efficiencyLoaded = false; } cfg; - struct EventClassifier { - std::vector nuncSeedsByMultBin; - std::vector quantileBoundaries; - std::unique_ptr interpolation; - bool isLoaded = false; - int nClasses = 0; + struct YieldTemplate { + int trigBin = -1; + int assocBin = -1; + int multBin = -1; + double nchLow = 0.0; + double nchHigh = 0.0; + double trigPtLow = 0.0; + double trigPtHigh = 0.0; + double assocPtLow = 0.0; + double assocPtHigh = 0.0; + std::array parameters{}; }; - EventClassifier ec; + struct EventSeedEstimate { + int nTriggers = 0; + int nCandidatePairs = 0; + int nPairs = 0; + int nPairsWithoutTemplate = 0; + double nearPairs = 0.0; + double awayPairs = 0.0; + double baselinePairs = 0.0; + + bool isValid() const { return nTriggers > 0; } + double nearYield() const { return isValid() ? nearPairs / nTriggers : 0.0; } + double awayYield() const { return isValid() ? awayPairs / nTriggers : 0.0; } + double nuncSeeds() const + { + const double denominator = 1.0 + nearYield() + awayYield(); + return isValid() && denominator > 0.0 ? nTriggers / denominator : -1.0; + } + }; + + std::vector yieldTemplates; + const TList* loadedCcdbYieldTemplateObject = nullptr; enum CorrelationMethod { All = 0, Dd, Ddbar }; - enum EventClassEstimatorMethod { - BinLookup = 0, - Interpolation - }; - HistogramRegistry registry{"registry"}; PairCuts mPairCuts; @@ -220,10 +240,28 @@ struct TwoParticleCorrelationsMpi { registry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); } registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}}); + registry.add("eventSeedEstimator", "event-level template estimator", {HistType::kTHnSparseF, {{100, 0, 100, "multiplicity"}, {100, -0.5, 99.5, "N_{trig}"}, {200, 0, 20, "Y_{near}"}, {200, 0, 20, "Y_{away}"}, {200, 0, 100, "N_{uncorrelated seeds}"}}}); + registry.add("eventSeedPairProbabilities", "summed pair probabilities", {HistType::kTH3F, {{200, 0, 200, "#Sigma P_{baseline}"}, {200, 0, 200, "#Sigma P_{near}"}, {200, 0, 200, "#Sigma P_{away}"}}}); + registry.add("eventSeedEstimatorStatus", "event-estimator status", {HistType::kTH1F, {{4, -0.5, 3.5, "status"}}}); + registry.add("eventSeedTemplateCoverage", "template coverage vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {102, -0.01, 1.01, "matched/candidate pairs"}}}); + registry.add("eventSeedEstimateVsMultiplicity", "event-level seed estimate vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {200, 0, 100, "N_{uncorrelated seeds}"}}}); + registry.add("eventNearYieldVsMultiplicity", "event-level near yield vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {200, 0, 20, "Y_{near}"}}}); + registry.add("eventAwayYieldVsMultiplicity", "event-level away yield vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {200, 0, 20, "Y_{away}"}}}); + registry.add("profileEventNTriggers", "mean event trigger count", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventNearPairs", "mean summed near-pair probability", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventAwayPairs", "mean summed away-pair probability", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventBaselinePairs", "mean summed baseline-pair probability", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventNearYield", "mean event near yield", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventAwayYield", "mean event away yield", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventNuncSeeds", "mean event uncorrelated-seed estimate", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("profileEventEstimatorValidity", "fraction of events with a valid seed estimate", {HistType::kTProfile, {axisMultiplicity}}); + auto* estimatorStatus = registry.get(HIST("eventSeedEstimatorStatus")).get(); + estimatorStatus->GetXaxis()->SetBinLabel(1, "unused"); + estimatorStatus->GetXaxis()->SetBinLabel(2, "no template-covered triggers"); + estimatorStatus->GetXaxis()->SetBinLabel(3, "no template-covered pairs"); + estimatorStatus->GetXaxis()->SetBinLabel(4, "valid estimate"); registry.add("yvspt", "y vs pT", {HistType::kTH2F, {{100, -1, 1, "y"}, {100, 0, 20, "p_{T}"}}}); // y vs pT for all tracks (control histogram) - const bool useEventClassifier = !cfgNuncSeedsCalibration.value.empty(); - AxisSpec eventClassAxis = useEventClassifier ? AxisSpec(axisUncSeeds) : AxisSpec(axisMultiplicity); const int maxMixBin = AxisSpec(axisMultiplicity).getNbins() * AxisSpec(axisVertex).getNbins(); // The bin numbers for the control histograms (eventcount_*) come from getBin(...) and are the following: #mult_bin * #number_of_z_bins + #zbin registry.add("eventcount_same", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); @@ -268,13 +306,12 @@ struct TwoParticleCorrelationsMpi { } } - std::string eventClassString = useEventClassifier ? "uncorrelated seed quantile" : "multiplicity / centrality"; std::vector corrAxis; corrAxis.reserve(6); corrAxis.emplace_back(axisDeltaEta, "#Delta#eta"); corrAxis.emplace_back(axisPtAssoc, "p_{T} (GeV/c)"); corrAxis.emplace_back(axisPtTrigger, "p_{T} (GeV/c)"); - corrAxis.emplace_back(eventClassAxis.binEdges, eventClassString); + corrAxis.emplace_back(axisMultiplicity, "multiplicity / centrality"); corrAxis.emplace_back(axisDeltaPhi, "#Delta#varphi (rad)"); corrAxis.emplace_back(axisVertex, "z-vtx (cm)"); std::vector effAxis = {{axisEtaEfficiency, "#eta"}, @@ -304,7 +341,10 @@ struct TwoParticleCorrelationsMpi { auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time - loadEventClassifier(now); + if (!cfgNuncSeedsTemplateFile.value.empty() && !cfgNuncSeedsTemplate.value.empty()) { + LOGF(fatal, "Configure only one template source: cfgNuncSeedsTemplateFile or cfgNuncSeedsTemplate"); + } + loadLocalYieldTemplates(); } int getMagneticField(uint64_t timestamp) @@ -481,8 +521,205 @@ struct TwoParticleCorrelationsMpi { return {true, 0.5f * std::log((E + pz) / (E - pz))}; } + void loadYieldTemplatesFromTree(TTree* tree, const TNamed* schemaVersion, const TNamed* correlationStep, const std::string& source) + { + if (!tree) { + LOGF(fatal, "Missing ensembleYieldTemplates in %s", source.c_str()); + return; + } + if (!schemaVersion || TString(schemaVersion->GetTitle()) != "1") { + LOGF(fatal, "Unsupported or missing ensemble-yield template schema version in %s", source.c_str()); + return; + } + if (!correlationStep || TString(correlationStep->GetTitle()) != "kCFStepReconstructed") { + LOGF(fatal, "Ensemble-yield templates must be derived at kCFStepReconstructed"); + return; + } + + YieldTemplate value; + int fitStatus = -1; + double parameters[10] = {}; + tree->SetBranchAddress("trigBin", &value.trigBin); + tree->SetBranchAddress("assocBin", &value.assocBin); + tree->SetBranchAddress("multBin", &value.multBin); + tree->SetBranchAddress("nchLow", &value.nchLow); + tree->SetBranchAddress("nchHigh", &value.nchHigh); + tree->SetBranchAddress("trigPtLow", &value.trigPtLow); + tree->SetBranchAddress("trigPtHigh", &value.trigPtHigh); + tree->SetBranchAddress("assocPtLow", &value.assocPtLow); + tree->SetBranchAddress("assocPtHigh", &value.assocPtHigh); + tree->SetBranchAddress("parameters", parameters); + tree->SetBranchAddress("fitStatus", &fitStatus); + + yieldTemplates.clear(); + yieldTemplates.reserve(tree->GetEntries()); + for (Long64_t iEntry = 0; iEntry < tree->GetEntries(); ++iEntry) { + tree->GetEntry(iEntry); + if (fitStatus != 0) { + LOGF(warning, "Skipping failed yield template (%d, %d, %d), fit status %d", value.trigBin, value.assocBin, value.multBin, fitStatus); + continue; + } + std::copy_n(parameters, value.parameters.size(), value.parameters.begin()); + if (value.parameters[2] <= 0.0 || value.parameters[5] <= 0.0 || value.parameters[8] <= 0.0) { + LOGF(warning, "Skipping yield template (%d, %d, %d) with non-positive Gaussian width", value.trigBin, value.assocBin, value.multBin); + continue; + } + const auto intervalMatchesAxis = [](const AxisSpec& axis, double low, double high) { + constexpr double tolerance = 1e-6; + const auto& edges = axis.binEdges; + return std::any_of(edges.begin(), edges.end() - 1, [&](const auto& edge) { + const auto index = static_cast(&edge - edges.data()); + return std::abs(edge - low) < tolerance && std::abs(edges[index + 1] - high) < tolerance; + }); + }; + if (!intervalMatchesAxis(AxisSpec(axisMultiplicity), value.nchLow, value.nchHigh) || + !intervalMatchesAxis(AxisSpec(axisPtTrigger), value.trigPtLow, value.trigPtHigh) || + !intervalMatchesAxis(AxisSpec(axisPtAssoc), value.assocPtLow, value.assocPtHigh)) { + LOGF(fatal, "Template binning does not match the configured axes for template (%d, %d, %d)", value.trigBin, value.assocBin, value.multBin); + tree->ResetBranchAddresses(); + return; + } + yieldTemplates.push_back(value); + } + tree->ResetBranchAddresses(); + + if (yieldTemplates.empty()) { + LOGF(fatal, "No valid ensemble-yield templates were loaded from %s", source.c_str()); + return; + } + LOGF(info, "Loaded %zu ensemble-yield templates from %s", yieldTemplates.size(), source.c_str()); + } + + void loadLocalYieldTemplates() + { + if (cfgNuncSeedsTemplateFile.value.empty()) { + return; + } + + std::unique_ptr input(TFile::Open(cfgNuncSeedsTemplateFile.value.c_str(), "READ")); + if (!input || input->IsZombie()) { + LOGF(fatal, "Could not open ensemble-yield template file: %s", cfgNuncSeedsTemplateFile.value.c_str()); + return; + } + + TList* calibration = dynamic_cast(input->Get("ccdb_object")); + auto findObject = [&](const char* name) -> TObject* { + if (auto* object = input->Get(name)) { + return object; + } + return calibration ? calibration->FindObject(name) : nullptr; + }; + loadYieldTemplatesFromTree( + dynamic_cast(findObject("ensembleYieldTemplates")), + dynamic_cast(findObject("ensembleYieldTemplateSchemaVersion")), + dynamic_cast(findObject("ensembleYieldTemplateCorrelationStep")), + cfgNuncSeedsTemplateFile.value); + } + + void loadCcdbYieldTemplates(uint64_t timestamp) + { + if (cfgNuncSeedsTemplate.value.empty()) { + return; + } + + auto* calibration = ccdb->getForTimeStamp(cfgNuncSeedsTemplate.value, timestamp); + if (!calibration) { + LOGF(fatal, "Could not load ensemble-yield templates from CCDB path %s at timestamp %llu", cfgNuncSeedsTemplate.value.c_str(), timestamp); + return; + } + if (calibration == loadedCcdbYieldTemplateObject) { + return; + } + + loadYieldTemplatesFromTree( + dynamic_cast(calibration->FindObject("ensembleYieldTemplates")), + dynamic_cast(calibration->FindObject("ensembleYieldTemplateSchemaVersion")), + dynamic_cast(calibration->FindObject("ensembleYieldTemplateCorrelationStep")), + cfgNuncSeedsTemplate.value); + loadedCcdbYieldTemplateObject = calibration; + } + + const YieldTemplate* findYieldTemplate(double multiplicity, double trigPt, double assocPt) const + { + for (const auto& yieldTemplate : yieldTemplates) { + if (multiplicity >= yieldTemplate.nchLow && multiplicity < yieldTemplate.nchHigh && + trigPt >= yieldTemplate.trigPtLow && trigPt < yieldTemplate.trigPtHigh && + assocPt >= yieldTemplate.assocPtLow && assocPt < yieldTemplate.assocPtHigh) { + return &yieldTemplate; + } + } + return nullptr; + } + + bool hasTriggerTemplate(double multiplicity, double trigPt) const + { + return std::any_of(yieldTemplates.begin(), yieldTemplates.end(), [multiplicity, trigPt](const auto& yieldTemplate) { + return multiplicity >= yieldTemplate.nchLow && multiplicity < yieldTemplate.nchHigh && + trigPt >= yieldTemplate.trigPtLow && trigPt < yieldTemplate.trigPtHigh; + }); + } + + bool hasMultiplicityTemplate(double multiplicity) const + { + return std::any_of(yieldTemplates.begin(), yieldTemplates.end(), [multiplicity](const auto& yieldTemplate) { + return multiplicity >= yieldTemplate.nchLow && multiplicity < yieldTemplate.nchHigh; + }); + } + + static double evaluateGaussian(double x, const double* parameters) + { + const double pull = (x - parameters[1]) / parameters[2]; + return parameters[0] * std::exp(-0.5 * pull * pull); + } + + void addPairProbabilities(EventSeedEstimate& estimate, const YieldTemplate& yieldTemplate, double deltaPhi) const + { + const auto& parameters = yieldTemplate.parameters; + const double near = std::max(0.0, evaluateGaussian(deltaPhi, ¶meters[0]) + evaluateGaussian(deltaPhi, ¶meters[3])); + const double away = std::max(0.0, evaluateGaussian(deltaPhi, ¶meters[6])); + const double baseline = std::max(0.0, parameters[9]); + const double total = baseline + near + away; + if (total <= 0.0) { + return; + } + estimate.nearPairs += near / total; + estimate.awayPairs += away / total; + estimate.baselinePairs += baseline / total; + ++estimate.nPairs; + } + + void fillEventSeedEstimatorQA(double multiplicity, const EventSeedEstimate& estimate) + { + if (yieldTemplates.empty()) { + return; + } + if (!hasMultiplicityTemplate(multiplicity)) { + return; + } + registry.fill(HIST("profileEventNTriggers"), multiplicity, estimate.nTriggers); + registry.fill(HIST("profileEventNearPairs"), multiplicity, estimate.nearPairs); + registry.fill(HIST("profileEventAwayPairs"), multiplicity, estimate.awayPairs); + registry.fill(HIST("profileEventBaselinePairs"), multiplicity, estimate.baselinePairs); + registry.fill(HIST("profileEventEstimatorValidity"), multiplicity, estimate.isValid() ? 1.0 : 0.0); + if (!estimate.isValid()) { + registry.fill(HIST("eventSeedEstimatorStatus"), 1.0); + return; + } + registry.fill(HIST("eventSeedEstimatorStatus"), estimate.nPairs > 0 ? 3.0 : 2.0); + const double coverage = estimate.nCandidatePairs > 0 ? static_cast(estimate.nPairs) / estimate.nCandidatePairs : 0.0; + registry.fill(HIST("eventSeedTemplateCoverage"), multiplicity, coverage); + registry.fill(HIST("eventSeedEstimator"), multiplicity, estimate.nTriggers, estimate.nearYield(), estimate.awayYield(), estimate.nuncSeeds()); + registry.fill(HIST("eventSeedPairProbabilities"), estimate.baselinePairs, estimate.nearPairs, estimate.awayPairs); + registry.fill(HIST("eventSeedEstimateVsMultiplicity"), multiplicity, estimate.nuncSeeds()); + registry.fill(HIST("eventNearYieldVsMultiplicity"), multiplicity, estimate.nearYield()); + registry.fill(HIST("eventAwayYieldVsMultiplicity"), multiplicity, estimate.awayYield()); + registry.fill(HIST("profileEventNearYield"), multiplicity, estimate.nearYield()); + registry.fill(HIST("profileEventAwayYield"), multiplicity, estimate.awayYield()); + registry.fill(HIST("profileEventNuncSeeds"), multiplicity, estimate.nuncSeeds()); + } + template - void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight) + void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight, EventSeedEstimate* seedEstimate = nullptr) { const float containerMultiplicity = getCorrelationContainerMultiplicity(multiplicity); if (containerMultiplicity < 0.f) { @@ -572,6 +809,11 @@ struct TwoParticleCorrelationsMpi { target->getTriggerHist()->Fill(step, track1.pt(), containerMultiplicity, posZ, triggerWeight); } + const bool triggerHasTemplate = seedEstimate && hasTriggerTemplate(multiplicity, track1.pt()); + if (triggerHasTemplate) { + ++seedEstimate->nTriggers; + } + for (const auto& track2 : tracks2) { if constexpr (std::is_same::value) { if (track1.globalIndex() == track2.globalIndex()) { @@ -661,6 +903,15 @@ struct TwoParticleCorrelationsMpi { float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -o2::constants::math::PIHalf); + if (triggerHasTemplate) { + ++seedEstimate->nCandidatePairs; + if (const auto* yieldTemplate = findYieldTemplate(multiplicity, track1.pt(), track2.pt())) { + addPairProbabilities(*seedEstimate, *yieldTemplate, deltaPhi); + } else { + ++seedEstimate->nPairsWithoutTemplate; + } + } + // last param is the weight if (cfgMassAxis) { if constexpr (std::experimental::is_detected::value) { @@ -719,149 +970,9 @@ struct TwoParticleCorrelationsMpi { return eff->GetBinContent(effVars.data()); } - void loadEventClassifier(int64_t timestamp) - { - if (cfgNuncSeedsCalibration.value.empty()) { - return; - } - - constexpr int TrigBin = 0; - constexpr int AssocBin = 0; - auto* list = ccdb->getForTimeStamp(cfgNuncSeedsCalibration.value, timestamp); - - if (!list) { - LOGF(fatal, "Could not load event-classifier calibration from CCDB path: %s", cfgNuncSeedsCalibration.value.c_str()); - return; - } - - auto* hNunc = dynamic_cast(list->FindObject(Form("calibNuncSeedsVsNch_%d_%d", TrigBin, AssocBin))); - auto* hQuantiles = dynamic_cast(list->FindObject(Form("calibNuncSeedsQuantileBoundaries_%d_%d", TrigBin, AssocBin))); - - if (!hNunc) { - LOGF(fatal, "Missing CCDB object calibNuncSeedsVsNch_%d_%d", TrigBin, AssocBin); - return; - } - - if (!hQuantiles) { - LOGF(fatal, "Missing CCDB object calibNuncSeedsQuantileBoundaries_%d_%d", TrigBin, AssocBin); - return; - } - - const AxisSpec multAxis(axisMultiplicity); - if (hNunc->GetNbinsX() != multAxis.getNbins()) { - LOGF(fatal, - "Multiplicity axis mismatch for event classifier: calibration has %d bins, axisMultiplicity has %d bins", - hNunc->GetNbinsX(), - multAxis.getNbins()); - return; - } - - ec.nuncSeedsByMultBin.clear(); - ec.quantileBoundaries.clear(); - ec.nuncSeedsByMultBin.reserve(hNunc->GetNbinsX()); - ec.quantileBoundaries.reserve(hQuantiles->GetNbinsX()); - - ec.interpolation = std::make_unique(hNunc->GetNbinsX()); - for (int i = 1; i <= hNunc->GetNbinsX(); ++i) { - ec.nuncSeedsByMultBin.push_back(hNunc->GetBinContent(i)); - ec.interpolation->SetPoint(i - 1, hNunc->GetXaxis()->GetBinCenter(i), hNunc->GetBinContent(i)); - } - - for (int i = 1; i <= hQuantiles->GetNbinsX(); ++i) { - ec.quantileBoundaries.push_back(hQuantiles->GetBinContent(i)); - } - - ec.nClasses = static_cast(ec.quantileBoundaries.size()) - 1; - ec.isLoaded = ec.nClasses > 0; - - if (!ec.isLoaded) { - LOGF(fatal, "Event-classifier calibration has fewer than two quantile boundaries"); - return; - } - - LOGF(info, - "Loaded multiplicity-only event classifier from %s using calibNuncSeedsVsNch_%d_%d and calibNuncSeedsQuantileBoundaries_%d_%d", - cfgNuncSeedsCalibration.value.c_str(), - TrigBin, - AssocBin, - TrigBin, - AssocBin); - } - - int findMultiplicityBin(double multiplicity) const - { - const AxisSpec multAxis(axisMultiplicity); - const auto& edges = multAxis.binEdges; - const int minEdges = 2; - if (edges.size() < minEdges || multiplicity < edges.front() || multiplicity >= edges.back()) { - return -1; - } - - const auto upper = std::upper_bound(edges.begin(), edges.end(), multiplicity); - return static_cast(std::distance(edges.begin(), upper)) - 1; - } - - int classify(double s) const - { - const int minEdges = 2; - if (ec.quantileBoundaries.size() < minEdges) { - return -1; - } - - for (int i = 0; i < static_cast(ec.quantileBoundaries.size()) - 1; ++i) { - if (s >= ec.quantileBoundaries[i] && s < ec.quantileBoundaries[i + 1]) { - return i; - } - } - - return s < ec.quantileBoundaries.front() ? 0 : static_cast(ec.quantileBoundaries.size()) - 2; - } - - int getEventClass(double multiplicity) const - { - if (!ec.isLoaded) { - return -1; - } - - double s = -1.0; - - if (cfgNuncSeedEstimator.value == EventClassEstimatorMethod::BinLookup) { - const int multBin = findMultiplicityBin(multiplicity); - - if (multBin < 0 || multBin >= static_cast(ec.nuncSeedsByMultBin.size())) { - return -1; - } - - s = ec.nuncSeedsByMultBin[multBin]; - } - - if (cfgNuncSeedEstimator.value == EventClassEstimatorMethod::Interpolation) { - if (!ec.interpolation) { - return -1; - } - - s = ec.interpolation->Eval(multiplicity); - } - - if (cfgNuncSeedEstimator.value != EventClassEstimatorMethod::BinLookup && cfgNuncSeedEstimator.value != EventClassEstimatorMethod::Interpolation) { - return -1; - } - - return classify(s); - } - float getCorrelationContainerMultiplicity(float multiplicity) const { - if (!ec.isLoaded) { - return multiplicity; - } - - const int eventClass = getEventClass(multiplicity); - if (eventClass < 0 || ec.nClasses <= 0) { - return -1.f; - } - - return (static_cast(eventClass) + 0.5f) / static_cast(ec.nClasses); + return multiplicity; } // Version with explicit nested loop @@ -876,6 +987,7 @@ struct TwoParticleCorrelationsMpi { // TODO will go to CCDBConfigurable auto bc = collision.bc_as(); loadEfficiency(bc.timestamp()); + loadCcdbYieldTemplates(bc.timestamp()); const auto multiplicity = collision.centRun2V0M(); @@ -884,7 +996,9 @@ struct TwoParticleCorrelationsMpi { } registry.fill(HIST("eventcount_same"), -2); fillQA(collision, multiplicity, tracks); - fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.timestamp()), 1.0f); + EventSeedEstimate seedEstimate; + fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.timestamp()), 1.0f, &seedEstimate); + fillEventSeedEstimatorQA(multiplicity, seedEstimate); } PROCESS_SWITCH(TwoParticleCorrelationsMpi, processSameAOD, "Process same event on AOD", true); @@ -897,6 +1011,7 @@ struct TwoParticleCorrelationsMpi { LOGF(info, "processSameDerivedT: Tracks for collision: %d/%d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks1.size(), tracks2.size(), collision.posZ(), collision.multiplicity()); } loadEfficiency(collision.timestamp()); + loadCcdbYieldTemplates(collision.timestamp()); const auto multiplicity = collision.multiplicity(); @@ -916,15 +1031,17 @@ struct TwoParticleCorrelationsMpi { const bool hasEfficiency = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); const bool fillReco = !(cfgDropStepRECO && hasEfficiency); + EventSeedEstimate seedEstimate; if (fillReco) { fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, &seedEstimate); } if (hasEfficiency) { fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepCorrected); - fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, fillReco ? nullptr : &seedEstimate); } + fillEventSeedEstimatorQA(multiplicity, seedEstimate); } void processSameDerived(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks) diff --git a/PWGDQ/Core/CutsLibrary.cxx b/PWGDQ/Core/CutsLibrary.cxx index 8c069d64920..cea0215d0cd 100644 --- a/PWGDQ/Core/CutsLibrary.cxx +++ b/PWGDQ/Core/CutsLibrary.cxx @@ -4012,9 +4012,7 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) if (nameStr == "alice3DielectronPID") { cut->AddCut(GetAnalysisCut("alice3JpsiKine")); cut->AddCut(GetAnalysisCut("alice3TrackQuality")); - cut->AddCut(GetAnalysisCut("alice3iTOFPIDEl")); - cut->AddCut(GetAnalysisCut("alice3oTOFPIDEl")); - cut->AddCut(GetAnalysisCut("alice3RICHPIDEl")); + cut->AddCut(GetAnalysisCut("alice3CharmoniumPID")); return cut; } @@ -4060,6 +4058,12 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (nameStr == "alice3LambdaCQualityCuts") { + cut->AddCut(GetAnalysisCut("alice3LambdaCKine")); + cut->AddCut(GetAnalysisCut("alice3TrackQuality")); + return cut; + } + delete cut; LOGF(fatal, Form("Did not find cut %s. Returning nullptr", cutName)); return nullptr; @@ -7264,29 +7268,33 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (nameStr == "alice3LambdaCKine") { + cut->AddCut(VarManager::kPt, 0.2, 1000.0); + cut->AddCut(VarManager::kEta, -2.0, 2.0); + return cut; + } + if (nameStr == "alice3JpsiKine") { cut->AddCut(VarManager::kPt, 1.0, 1000.0); - cut->AddCut(VarManager::kEta, -2.5, 2.5); // Total tracker acceptance in v3b geomety + cut->AddCut(VarManager::kEta, -2.5, 2.5); return cut; } if (nameStr == "alice3JpsiKineTOFAcceptance") { cut->AddCut(VarManager::kPt, 1.0, 1000.0); - cut->AddCut(VarManager::kEta, -2.0, 2.0); // TOF acceptance in v3b geomety + cut->AddCut(VarManager::kEta, -2.0, 2.0); return cut; } if (nameStr == "alice3JpsiKineRICHAcceptance") { cut->AddCut(VarManager::kPt, 1.0, 1000.0); - cut->AddCut(VarManager::kEta, -0.8, 0.8); // RICH acceptance in v3b geomety + cut->AddCut(VarManager::kEta, -0.8, 0.8); return cut; } if (nameStr == "alice3TrackQuality") { cut->AddCut(VarManager::kIsReconstructed, 0.5, 1.5); - cut->AddCut(VarManager::kNSiliconHits, 6.0, 12.0); - cut->AddCut(VarManager::kTrackDCAxy, -3.0, 3.0); - cut->AddCut(VarManager::kTrackDCAz, -3.0, 3.0); + cut->AddCut(VarManager::kNSiliconHits, 5.0, 12.0); return cut; } @@ -7343,11 +7351,6 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (nameStr == "alice3oTOFPIDEl") { - cut->AddCut(VarManager::kOuterTOFnSigmaEl, -3.0, 3.0); - return cut; - } - if (nameStr == "alice3oTOFPIDPi") { cut->AddCut(VarManager::kOuterTOFnSigmaPi, -3.0, 3.0); return cut; @@ -7363,27 +7366,29 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (nameStr == "alice3CharmoniumPID") { + cut->AddCut(VarManager::kOuterTOFnSigmaEl, -2.0, 3.0, false, VarManager::kP, 0.0, 1.2); + cut->AddCut(VarManager::kRICHnSigmaEl, -2.0, 3.0, false, VarManager::kHasRICHSigEl, 0.5, 1.5, false, VarManager::kP, 0.7, 1000.0); + return cut; + } + if (nameStr == "alice3RICHPIDEl") { - cut->AddCut(VarManager::kRICHnSigmaEl, -3.0, 3.0); - cut->AddCut(VarManager::kHasRICHSigEl, 0.5, 1.5); + cut->AddCut(VarManager::kRICHnSigmaEl, -3.0, 3.0, false, VarManager::kP, 0.7, 1000.0, false, VarManager::kHasRICHSigEl, 0.5, 1.5); return cut; } if (nameStr == "alice3RICHPIDPi") { - cut->AddCut(VarManager::kRICHnSigmaPi, -3.0, 3.0); - cut->AddCut(VarManager::kHasRICHSigPi, 0.5, 1.5); + cut->AddCut(VarManager::kRICHnSigmaPi, -3.0, 3.0, false, VarManager::kP, 0.57, 1000.0, false, VarManager::kHasRICHSigPi, 0.5, 1.5); return cut; } if (nameStr == "alice3RICHPIDKa") { - cut->AddCut(VarManager::kRICHnSigmaKa, -3.0, 3.0); - cut->AddCut(VarManager::kHasRICHSigKa, 0.5, 1.5); + cut->AddCut(VarManager::kRICHnSigmaKa, -3.0, 3.0, false, VarManager::kP, 2.0, 1000.0, false, VarManager::kHasRICHSigKa, 0.5, 1.5); return cut; } if (nameStr == "alice3RICHPIDPr") { - cut->AddCut(VarManager::kRICHnSigmaPr, -3.0, 3.0); - cut->AddCut(VarManager::kHasRICHSigPr, 0.5, 1.5); + cut->AddCut(VarManager::kRICHnSigmaPr, -3.0, 3.0, false, VarManager::kP, 3.8, 1000.0, false, VarManager::kHasRICHSigPr, 0.5, 1.5); return cut; } diff --git a/PWGDQ/Core/HistogramManager.cxx b/PWGDQ/Core/HistogramManager.cxx index a933ef354fd..74fa3d21b8c 100644 --- a/PWGDQ/Core/HistogramManager.cxx +++ b/PWGDQ/Core/HistogramManager.cxx @@ -812,7 +812,6 @@ void HistogramManager::FillHistClass(const char* className, float* values) bool isProfile = false; bool isTHn = false; int dimension = 0; - bool isSparse = kFALSE; bool isFillLabelx = kFALSE; // TODO: At the moment, maximum 20 dimensions are foreseen for the THn histograms. We should make this more dynamic // But maybe its better to have it like to avoid dynamically allocating this array in the histogram loop @@ -950,18 +949,14 @@ void HistogramManager::FillHistClass(const char* className, float* values) // end if(!isTHn) } else { if (varW > kNothing) { - if (isSparse) { - if (auto* hn = dynamic_cast(h)) { - hn->Fill(fillValues.data(), values[varW]); - } + if (auto* hn = dynamic_cast(h)) { + hn->Fill(fillValues.data(), values[varW]); } else if (auto* hn = dynamic_cast(h)) { hn->Fill(fillValues.data(), values[varW]); } } else { - if (isSparse) { - if (auto* hn = dynamic_cast(h)) { - hn->Fill(fillValues.data()); - } + if (auto* hn = dynamic_cast(h)) { + hn->Fill(fillValues.data()); } else if (auto* hn = dynamic_cast(h)) { hn->Fill(fillValues.data()); } diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 4738a08bdd1..83a75fde02b 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -1257,17 +1257,41 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Coschi", "", false, 25, coschiBins.data(), VarManager::kMCCosChi, 0, nullptr, -1, 0, nullptr, -1, "", "", "", -1, VarManager::kMCWeight); } - if (groupStr.CompareTo("polarization-pseudoproper-gen") == 0) { + if (groupStr.CompareTo("polarization-pseudoproper-midy-he-gen") == 0) { std::array varspTHE = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCVertexingTauxyProjected}; - std::array varspTCS = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCVertexingTauxyProjected}; - std::array varspTRM = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaRM, VarManager::kMCVertexingTauxyProjected}; std::array bins = {50, 20, 20, 1000}; std::array xmin = {2., 0., -1., -0.5}; std::array xmax = {4., 20., 1., 0.5}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaHE_Tauxy", "", 4, varspTHE.data(), bins.data(), xmin.data(), xmax.data(), nullptr, -1, kFALSE); + } + if (groupStr.CompareTo("polarization-pseudoproper-midy-cs-gen") == 0) { + std::array varspTCS = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCVertexingTauxyProjected}; + std::array bins = {50, 20, 20, 1000}; + std::array xmin = {2., 0., -1., -0.5}; + std::array xmax = {4., 20., 1., 0.5}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaCS_Tauxy", "", 4, varspTCS.data(), bins.data(), xmin.data(), xmax.data(), nullptr, -1, kFALSE); + } + if (groupStr.CompareTo("polarization-pseudoproper-midy-rand-gen") == 0) { + std::array varspTRM = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaRM, VarManager::kMCVertexingTauxyProjected}; + std::array bins = {50, 20, 20, 1000}; + std::array xmin = {2., 0., -1., -0.5}; + std::array xmax = {4., 20., 1., 0.5}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaRM_Tauxy", "", 4, varspTRM.data(), bins.data(), xmin.data(), xmax.data(), nullptr, -1, kFALSE); } + if (groupStr.CompareTo("polarization-dielectron-pbpb-midy-he-gen") == 0) { + std::array varspTHE = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCEventCentrFT0C, VarManager::kMCCosThetaHE, VarManager::kMCPhiHE}; + std::array bins = {50, 30, 10, 20, 10}; + std::array xmin = {2., 0., 0, -1., 0.0}; + std::array xmax = {4., 3., 100, 1., 6.28}; + hm->AddHistogram(histClass, "MC_Dielectron_Mass_Pt_Cent_cosThetaHE", "", 5, varspTHE.data(), bins.data(), xmin.data(), xmax.data(), 0, -1, kFALSE); + } + if (groupStr.CompareTo("polarization-dielectron-pbpb-midy-cs-gen") == 0) { + std::array varspTCS = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCEventCentrFT0C, VarManager::kMCCosThetaCS, VarManager::kMCPhiCS}; + std::array bins = {50, 30, 10, 20, 10}; + std::array xmin = {2., 0., 0, -1., 0.0}; + std::array xmax = {4., 3., 100, 1., 6.28}; + hm->AddHistogram(histClass, "MC_Dielectron_Mass_Pt_Cent_cosThetaCS", "", 5, varspTCS.data(), bins.data(), xmin.data(), xmax.data(), 0, -1, kFALSE); + } if (groupStr.CompareTo("pair") == 0) { if (subGroupStr.Contains("cepf")) { hm->AddHistogram(histClass, "Mass", "", false, 300, 0.0, 12.0, VarManager::kMass); diff --git a/PWGDQ/Core/MCSignalLibrary.cxx b/PWGDQ/Core/MCSignalLibrary.cxx index 19dcbbc8aa9..bdd86156c7d 100644 --- a/PWGDQ/Core/MCSignalLibrary.cxx +++ b/PWGDQ/Core/MCSignalLibrary.cxx @@ -1717,6 +1717,13 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Lambda_c", {prong}, {-1}); return signal; } + if (nameStr == "PrKPiFromLambdaC") { + MCProng prongProton(2, {2212, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongKaon(2, {321, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongPion(2, {211, Pdg::kLambdaCPlus}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Proton kaon pion triplet from Lambda_c+/-", {prongProton, prongKaon, prongPion}, {1, 1, 1}); + return signal; + } //-------------------------------------------------------------------------------- diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 69c29570f2e..bf7876ee04c 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -11,9 +11,11 @@ #include "PWGDQ/Core/VarManager.h" +#include "Common/Core/RecoDecay.h" #include "Tools/KFparticle/KFUtilities.h" #include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #include @@ -33,6 +36,7 @@ #include #include +#include #include #include #include @@ -52,6 +56,8 @@ bool VarManager::fgUsedKF = false; bool VarManager::fgPVrecalKF = true; float VarManager::fgMagField = 0.5; float VarManager::fgzMatching = -77.5; +float VarManager::fgxShiftFwd = 0.0; +float VarManager::fgyShiftFwd = 0.0; float VarManager::fgzShiftFwd = 0.0; float VarManager::fgValues[VarManager::kNVars] = {0.0f}; float VarManager::fgTPCInterSectorBoundary = 1.0; // cm @@ -75,7 +81,9 @@ int VarManager::fgCalibrationType = 0; // 0 - no calibration, 1 - bool VarManager::fgUseInterpolatedCalibration = true; // use interpolated calibration histograms (default: true) int VarManager::fgEfficiencyType = 0; // type of efficiency to be applied, default is no efficiency TObject* VarManager::fgEfficiencyHist = nullptr; // histogram for efficiency - +TObject* VarManager::fgPosiPhiMap = nullptr; +TObject* VarManager::fgNegaPhiMap = nullptr; +bool VarManager::fgUsePhiCorrection = false; //__________________________________________________________________ VarManager::VarManager() : TObject() { @@ -453,6 +461,74 @@ void VarManager::FillEfficiency(float* values) } } +void VarManager::SetPhiMap(TObject* hposi, TObject* hnega, bool option) +{ + fgPosiPhiMap = hposi; + fgNegaPhiMap = hnega; + fgUsePhiCorrection = option; +} + +double VarManager::SampleRotationPhi(double pt, double eta, int charge) +{ + // each type only alarm once + static bool warnedEmptyPhi = false; + + if (!fgUsePhiCorrection) { + return gRandom->Uniform(0., o2::constants::math::TwoPI); + } else { + + TH3D* hMap = nullptr; + if (charge > 0) { + hMap = dynamic_cast(fgPosiPhiMap); + } else { + hMap = dynamic_cast(fgNegaPhiMap); + } + + if (!hMap) { + LOGF(fatal, "Phi map is not a TH3D"); + } + // TH3 axes: X=pT, Y=phi, Z=eta + int ptBin = hMap->GetXaxis()->FindBin(pt); + int etaBin = hMap->GetZaxis()->FindBin(eta); + + ptBin = std::clamp(ptBin, 1, hMap->GetNbinsX()); + etaBin = std::clamp(etaBin, 1, hMap->GetNbinsZ()); + + TH1D* hPhi = hMap->ProjectionY( + Form("hTRPhi_tmp_charge%d_ptbin%d_etabin%d", + charge, ptBin, etaBin), + ptBin, + ptBin, + etaBin, + etaBin); + + if (!hPhi || hPhi->Integral(1, hPhi->GetNbinsX()) <= 0.) { + if (!warnedEmptyPhi) { + LOGF(warn, + "Empty phi distribution for " + "pt=%f, eta=%f, charge=%d, ptBin=%d, etaBin=%d. " + "Falling back to uniform phi sampling.", + pt, + eta, + charge, + ptBin, + etaBin); + + warnedEmptyPhi = true; + } + + delete hPhi; + + return gRandom->Uniform(0., o2::constants::math::TwoPI); + } + + const double phi = RecoDecay::constrainAngle(hPhi->GetRandom()); + + delete hPhi; + return phi; + } +} + //__________________________________________________________________ std::tuple VarManager::BimodalityCoefficientUnbinned(const std::vector& data) { @@ -2400,6 +2476,7 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kMCPhi"] = kMCPhi; fgVarNamesMap["kMCEta"] = kMCEta; fgVarNamesMap["kMCY"] = kMCY; + fgVarNamesMap["kMCMass"] = kMCMass; fgVarNamesMap["kMCCosThetaHE"] = kMCCosThetaHE; fgVarNamesMap["kMCPhiHE"] = kMCPhiHE; fgVarNamesMap["kMCPhiTildeHE"] = kMCPhiTildeHE; @@ -2486,6 +2563,7 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kDCATrackVtxProd"] = kDCATrackVtxProd; fgVarNamesMap["kV2SP"] = kV2SP; fgVarNamesMap["kV2EP"] = kV2EP; + fgVarNamesMap["kV2EP_FT0C"] = kV2EP_FT0C; fgVarNamesMap["kA2EP_TPC"] = kA2EP_TPC; fgVarNamesMap["kA2EP_FT0A"] = kA2EP_FT0A; fgVarNamesMap["kA2EP_FT0C"] = kA2EP_FT0C; @@ -2574,6 +2652,18 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kCos2DeltaPhiMu1"] = kCos2DeltaPhiMu1; fgVarNamesMap["kCos2DeltaPhiMu2"] = kCos2DeltaPhiMu2; fgVarNamesMap["kCos3DeltaPhi"] = kCos3DeltaPhi; + fgVarNamesMap["kDeltaPhi_TPC"] = kDeltaPhi_TPC; + fgVarNamesMap["kDeltaPhi_FT0A"] = kDeltaPhi_FT0A; + fgVarNamesMap["kDeltaPhi_FT0C"] = kDeltaPhi_FT0C; + fgVarNamesMap["kCos2DeltaPhi_TPC"] = kCos2DeltaPhi_TPC; + fgVarNamesMap["kCos2DeltaPhi_FT0A"] = kCos2DeltaPhi_FT0A; + fgVarNamesMap["kCos2DeltaPhi_FT0C"] = kCos2DeltaPhi_FT0C; + fgVarNamesMap["kDeltaPhiME_TPC"] = kDeltaPhiME_TPC; + fgVarNamesMap["kDeltaPhiME_FT0A"] = kDeltaPhiME_FT0A; + fgVarNamesMap["kDeltaPhiME_FT0C"] = kDeltaPhiME_FT0C; + fgVarNamesMap["kCos2DeltaPhiME_TPC"] = kCos2DeltaPhiME_TPC; + fgVarNamesMap["kCos2DeltaPhiME_FT0A"] = kCos2DeltaPhiME_FT0A; + fgVarNamesMap["kCos2DeltaPhiME_FT0C"] = kCos2DeltaPhiME_FT0C; fgVarNamesMap["kDeltaPtotTracks"] = kDeltaPtotTracks; fgVarNamesMap["kVertexingLxyOverErr"] = kVertexingLxyOverErr; fgVarNamesMap["kVertexingLzOverErr"] = kVertexingLzOverErr; diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 60d9373e496..db322f84e2e 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -1269,6 +1269,14 @@ class VarManager : public TObject fgzShiftFwd = z; } + // Set x, y and z shifts for forward tracks + static void Set3DShift(float x, float y, float z) + { + fgxShiftFwd = x; + fgyShiftFwd = y; + fgzShiftFwd = z; + } + // Setup the 2 prong KFParticle static void SetupTwoProngKFParticle(float magField) { @@ -1495,6 +1503,10 @@ class VarManager : public TObject static void FillTrackAlice3(T const& track, float* values = nullptr); template static void FillResolutions(M const& mcTrack, T const& track, float* values = nullptr); + template + static void FillPairVertexingAlice3(C const& collision, T const& t1, T const& t2, bool propToSV = false, float* values = nullptr); + template + static void FillTripletVertexingALICE3(C const& collision, T const& t1, T const& t2, T const& t3, VarManager::PairCandidateType tripletType, float* values = nullptr); static void SetCalibrationObject(CalibObjects calib, TObject* obj) { @@ -1530,6 +1542,8 @@ class VarManager : public TObject static void SetEfficiencyObject(int type, TObject* obj); static void FillEfficiency(float* values = nullptr); + static void SetPhiMap(TObject* h1, TObject* h2, bool option); + static double SampleRotationPhi(double pT, double eta, int charge); static TObject* GetCalibrationObject(CalibObjects calib) { auto obj = fgCalibs.find(calib); @@ -1570,6 +1584,8 @@ class VarManager : public TObject static float fgMagField; static float fgzMatching; + static float fgxShiftFwd; + static float fgyShiftFwd; static float fgzShiftFwd; static float fgCenterOfMassEnergy; // collision energy static float fgMassofCollidingParticle; // mass of the colliding particle @@ -1606,14 +1622,18 @@ class VarManager : public TObject static o2::vertexing::FwdDCAFitterN<3> fgFitterThreeProngFwd; static o2::globaltracking::MatchGlobalFwd mMatching; - static std::map fgCalibs; // map of calibration histograms + static std::map fgCalibs; // map of calibration histograms static std::array fgRunTPCPostCalibration; // 0-electron, 1-pion, 2-kaon, 3-proton - static int fgCalibrationType; // 0 - no calibration, 1 - calibration vs (TPCncls,pIN,eta) typically for pp, 2 - calibration vs (eta,nPV,nLong,tLong) typically for PbPb - static bool fgUseInterpolatedCalibration; // use interpolated calibration histograms (default: true) + static int fgCalibrationType; // 0 - no calibration, 1 - calibration vs (TPCncls,pIN,eta) typically for pp, 2 - calibration vs (eta,nPV,nLong,tLong) typically for PbPb + static bool fgUseInterpolatedCalibration; // use interpolated calibration histograms (default: true) static int fgEfficiencyType; // type of efficiency correction to apply static TObject* fgEfficiencyHist; // histogram for efficiency correction + static TObject* fgPosiPhiMap; // phi map to correct track rotation + static TObject* fgNegaPhiMap; + static bool fgUsePhiCorrection; + VarManager& operator=(const VarManager& c); VarManager(const VarManager& c); }; @@ -1745,7 +1765,7 @@ o2::dataformats::VertexBase VarManager::RecalculatePrimaryVertex(T const& track0 template o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C& collision, const int endPoint) { - o2::track::TrackParCovFwd fwdtrack = o2::aod::fwdtrackutils::getTrackParCovFwdShift(muon, fgzShiftFwd, muon); + o2::track::TrackParCovFwd fwdtrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(muon, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd, muon); o2::dataformats::GlobalFwdTrack propmuon; if (static_cast(muon.trackType()) > 2) { o2::dataformats::GlobalFwdTrack track; @@ -1877,7 +1897,7 @@ void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, co double py = propmuon.getP() * std::sin(o2::constants::math::PIHalf - std::atan(mfttrack.tgl())) * std::sin(mfttrack.phi()); double pz = propmuon.getP() * std::cos(o2::constants::math::PIHalf - std::atan(mfttrack.tgl())); double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); - auto mftprop = o2::aod::fwdtrackutils::getTrackParCovFwdShift(mfttrack, fgzShiftFwd); + auto mftprop = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(mfttrack, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd); values[kX] = mftprop.getX(); values[kY] = mftprop.getY(); values[kZ] = mftprop.getZ(); @@ -1898,7 +1918,7 @@ void VarManager::FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, if constexpr ((MuonfillMap & MuonCov) > 0) { if constexpr ((MFTfillMap & MFTCov) > 0) { o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); - auto mft = o2::aod::fwdtrackutils::getTrackParCovFwdShift(mfttrack, fgzShiftFwd, mftcov); + auto mft = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(mfttrack, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd, mftcov); o2::dataformats::GlobalFwdTrack globalRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuon, mft); values[kX] = globalRefit.getX(); @@ -3317,7 +3337,7 @@ void VarManager::FillTrack(T const& track, float* values) values[kMuonC1Pt21Pt2] = track.c1Pt21Pt2(); } if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { - auto muonTrack = o2::aod::fwdtrackutils::getTrackParCovFwdShift(track, fgzShiftFwd, track); + auto muonTrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(track, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd, track); auto muonCov = muonTrack.getCovariances(); values[kX] = muonTrack.getX(); values[kY] = muonTrack.getY(); @@ -3919,6 +3939,11 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); } } + if constexpr ((pairType == kElectronMuon) && ((fillMap & ReducedTrackBarrel) > 0)) { + // DCA of the barrel (electron) leg; not filled in FillPairME since the mixed-event barrel track type has no DCA columns + values[kDCAxy1] = t1.dcaXY(); + values[kDCAz1] = t1.dcaZ(); + } if (fgUsedVars[kPairPhiv]) { values[kPairPhiv] = calculatePhiV(t1, t2); } @@ -3956,8 +3981,7 @@ void VarManager::FillPairRotation(T1 const& t1, T2 const& t2, float* values) m2 = o2::constants::physics::MassMuon; } - double dphi = gRandom->Uniform(0., o2::constants::math::TwoPI); - double rotationphi2 = RecoDecay::constrainAngle(t2.phi() + dphi); + double rotationphi2 = SampleRotationPhi(t2.pt(), t2.eta(), t2.sign()); values[kCharge] = t1.sign() + t2.sign(); values[kCharge1] = t1.sign(); @@ -7327,10 +7351,6 @@ void VarManager::FillPairAlice3(T1 const& t1, T2 const& t2, float* values) m2 = o2::constants::physics::MassPionCharged; } - if constexpr (pairType == kElectronMuon) { - m2 = o2::constants::physics::MassMuon; - } - values[kCharge] = t1.sign() + t2.sign(); values[kCharge1] = t1.sign(); values[kCharge2] = t2.sign(); @@ -7340,7 +7360,6 @@ void VarManager::FillPairAlice3(T1 const& t1, T2 const& t2, float* values) values[kMass] = v12.M(); values[kPt] = v12.Pt(); values[kEta] = v12.Eta(); - // values[kPhi] = v12.Phi(); values[kPhi] = RecoDecay::constrainAngle(v12.Phi()); values[kRap] = -v12.Rapidity(); double Ptot1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); @@ -7514,17 +7533,6 @@ void VarManager::FillPairAlice3(T1 const& t1, T2 const& t2, float* values) } } } - if constexpr ((pairType == kDecayToMuMu) && ((fillMap & Muon) > 0 || (fillMap & ReducedMuon) > 0)) { - if (fgUsedVars[kQuadDCAabsXY]) { - double dca1X = t1.fwdDcaX(); - double dca1Y = t1.fwdDcaY(); - double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); - double dca2X = t2.fwdDcaX(); - double dca2Y = t2.fwdDcaY(); - double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); - values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); - } - } if (fgUsedVars[kPairPhiv]) { values[kPairPhiv] = calculatePhiV(t1, t2); } @@ -7543,4 +7551,298 @@ void VarManager::FillResolutions(M const& mcTrack, T const& track, float* values values[kEtaResolution] = track.eta() - mcTrack.eta(); } +template +void VarManager::FillPairVertexingAlice3(C const& collision, T const& t1, T const& t2, bool propToSV, float* values) +{ + // check at compile time that the event and cov matrix have the cov matrix + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); + + if (!values) { + values = fgValues; + } + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + values[kUsedKF] = static_cast(fgUsedKF); + if (!fgUsedKF) { + int procCode = 0; + + // TODO: use trackUtilities functions to initialize the various matrices to avoid code duplication + // auto pars1 = getTrackParCov(t1); + // auto pars2 = getTrackParCov(t2); + // We need to hide the cov data members from the cases when no cov table is provided + if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { + std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; + std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), + t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), + t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; + std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; + std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), + t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), + t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; + procCode = fgFitterTwoProngBarrel.process(pars1, pars2); + } else { + return; + } + + values[kVertexingProcCode] = procCode; + if (procCode == 0) { + // TODO: set the other variables to appropriate values and return + values[kVertexingChi2PCA] = -999.; + values[kVertexingLxy] = -999.; + values[kVertexingLxyz] = -999.; + values[kVertexingLz] = -999.; + values[kVertexingLxyErr] = -999.; + values[kVertexingLxyzErr] = -999.; + values[kVertexingLzErr] = -999.; + + values[kVertexingTauxy] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauxyErr] = -999.; + values[kVertexingTauzErr] = -999.; + values[kVertexingPz] = -999.; + values[kVertexingSV] = -999.; + return; + } + + Vec3D secondaryVertex; + o2::dataformats::VertexBase primaryVertexNew; + + if constexpr (eventHasVtxCov) { + + std::array covMatrixPCA{}; + // get track impact parameters + // This modifies track momenta! + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {vtxXYZ, vtxCov}; + // auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { + secondaryVertex = fgFitterTwoProngBarrel.getPCACandidate(); + // printf("secVtx (first) %f %f %f \n",secondaryVertex[0],secondaryVertex[1],secondaryVertex[2]); + covMatrixPCA = fgFitterTwoProngBarrel.calcPCACovMatrixFlat(); + auto chi2PCA = fgFitterTwoProngBarrel.getChi2AtPCACandidate(); + auto trackParVar0 = fgFitterTwoProngBarrel.getTrack(0); + auto trackParVar1 = fgFitterTwoProngBarrel.getTrack(1); + values[kVertexingChi2PCA] = chi2PCA; + v1 = {trackParVar0.getPt(), trackParVar0.getEta(), trackParVar0.getPhi(), m1}; + v2 = {trackParVar1.getPt(), trackParVar1.getEta(), trackParVar1.getPhi(), m2}; + v12 = v1 + v2; + } + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + + values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; + values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); + values[kVertexingLz] = std::sqrt(values[kVertexingLz]); + values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingPz] = TMath::Abs(v12.Pz()); + values[kVertexingSV] = secondaryVertex[2]; + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((secondaryVertex[0] - collision.posX()) * v12.Px() + + (secondaryVertex[1] - collision.posY()) * v12.Py() + + (secondaryVertex[2] - collision.posZ()) * v12.Pz()) / + (v12.P() * values[VarManager::kVertexingLxyz]); + // Decay length defined as in Run 2 + values[kVertexingLzProjected] = ((secondaryVertex[2] - collision.posZ()) * v12.Pz()) / TMath::Sqrt(v12.Pz() * v12.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()) + ((secondaryVertex[2] - collision.posZ()) * v12.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py()) + (v12.Pz() * v12.Pz())); + if (fgPVrecalKF) { + values[kVertexingLxyProjectedRecalculatePV] = (secondaryVertex[0] - primaryVertexNew.getX()) * v12.Px() + (secondaryVertex[1] - primaryVertexNew.getY()) * v12.Py(); + values[kVertexingLxyProjectedRecalculatePV] = values[kVertexingLxyProjectedRecalculatePV] / v12.Pt(); + } + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v12.M() / (v12.Pt()); + values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (v12.Pt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + if (fgPVrecalKF) { + values[kVertexingTauxyProjectedPoleJPsiMassRecalculatePV] = values[kVertexingLxyProjectedRecalculatePV] * o2::constants::physics::MassJPsi / (v12.Pt()); + } + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v12.M() / TMath::Abs(v12.Pz()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v12.M() / (v12.P()); + } + } + if (propToSV) { + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + // values[kPhi] = v12.Phi(); + values[kPhi] = RecoDecay::constrainAngle(v12.Phi()); + } else { + values[kPt1] = t1.pt(); + values[kEta1] = t1.eta(); + values[kPhi1] = t1.phi(); + + values[kPt2] = t2.pt(); + values[kEta2] = t2.eta(); + values[kPhi2] = t2.phi(); + } +} + +template +void VarManager::FillTripletVertexingALICE3(C const& collision, T const& t1, T const& t2, T const& t3, VarManager::PairCandidateType tripletType, float* values) +{ + // TODO: Vertexing error variables + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + bool trackHasCov = ((fillMap & ReducedTrackBarrelCov) > 0); + + if (!values) { + values = fgValues; + } + + float m1 = o2::constants::physics::MassKaonCharged; + float m2 = o2::constants::physics::MassPionCharged; + float m3 = o2::constants::physics::MassPionCharged; + + if (tripletType == kTripleCandidateToKPiPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + m3 = o2::constants::physics::MassPionCharged; + } + if (tripletType == kTripleCandidateToPKPi) { + m1 = o2::constants::physics::MassProton; + m2 = o2::constants::physics::MassKaonCharged; + m3 = o2::constants::physics::MassPionCharged; + } + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + + int procCode = 0; + + if (trackHasCov) { + std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; + std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), + t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), + t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; + std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; + std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), + t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), + t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; + std::array t3pars = {t3.y(), t3.z(), t3.snp(), t3.tgl(), t3.signed1Pt()}; + std::array t3covs = {t3.cYY(), t3.cZY(), t3.cZZ(), t3.cSnpY(), t3.cSnpZ(), + t3.cSnpSnp(), t3.cTglY(), t3.cTglZ(), t3.cTglSnp(), t3.cTglTgl(), + t3.c1PtY(), t3.c1PtZ(), t3.c1PtSnp(), t3.c1PtTgl(), t3.c1Pt21Pt2()}; + o2::track::TrackParCov pars3{t3.x(), t3.alpha(), t3pars, t3covs}; + procCode = VarManager::fgFitterThreeProngBarrel.process(pars1, pars2, pars3); + } else { + return; + } + + values[VarManager::kVertexingProcCode] = procCode; + if (procCode == 0) { + // TODO: set the other variables to appropriate values and return + values[kVertexingChi2PCA] = -999.; + values[kVertexingLxy] = -999.; + values[kVertexingLxyz] = -999.; + values[kVertexingLz] = -999.; + values[kVertexingLxyErr] = -999.; + values[kVertexingLxyzErr] = -999.; + values[kVertexingLzErr] = -999.; + + values[kVertexingTauxy] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauxyErr] = -999.; + values[kVertexingTauzErr] = -999.; + + values[kVertexingLzProjected] = -999.; + values[kVertexingLxyProjected] = -999.; + values[kVertexingLxyzProjected] = -999.; + values[kVertexingTauzProjected] = -999.; + values[kVertexingTauxyProjected] = -999.; + values[kVertexingTauxyzProjected] = -999.; + + return; + } + + Vec3D secondaryVertex; + + if constexpr (eventHasVtxCov) { + secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); + + std::array covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); + + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {vtxXYZ, vtxCov}; + auto covMatrixPV = primaryVertex.getCov(); + + if (fgUsedVars[kVertexingChi2PCA]) { + auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); + values[VarManager::kVertexingChi2PCA] = chi2PCA; + } + + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + + values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; + values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); + values[kVertexingLz] = std::sqrt(values[kVertexingLz]); + values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); + + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((secondaryVertex[0] - collision.posX()) * v123.Px() + + (secondaryVertex[1] - collision.posY()) * v123.Py() + + (secondaryVertex[2] - collision.posZ()) * v123.Pz()) / + (v123.P() * values[VarManager::kVertexingLxyz]); + // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v123.Pz(); + values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v123.Pz() * v123.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); + + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / (v123.Pt()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v123.M() / (v123.P()); + } +} + #endif // PWGDQ_CORE_VARMANAGER_H_ diff --git a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx index 32749d294bf..ba0aea373cd 100644 --- a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx @@ -281,8 +281,8 @@ struct TableMaker { Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable fConfigGrpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fZShiftPath{"zShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable fUseRemoteZShift{"cfgUseRemoteZShift", false, "Enable getting Zshift from ccdb"}; + Configurable fFwdShiftPath{"fwdShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for the shift to apply to forward tracks, either 1 value (z) or 3 values (x, y, z)"}; + Configurable fUseRemoteFwdShift{"cfgUseRemoteFwdShift", false, "Enable getting the forward track shift from ccdb"}; Configurable fManualZShift{"cfgManualZShift", 0.f, "Manual value for the Zshift for muons."}; Configurable fConfigGrpMagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; } fConfigCCDB; @@ -1726,12 +1726,16 @@ struct TableMaker { o2::base::Propagator::initFieldFromGRP(fGrpMag); VarManager::SetMagneticField(fGrpMag->getNominalL3Field()); } - if (fConfigCCDB.fUseRemoteZShift) { - auto* fZShift = fCCDB->getForTimeStamp>(fConfigCCDB.fZShiftPath, bcs.begin().timestamp()); - if (fZShift != nullptr && !fZShift->empty()) { - VarManager::SetZShift((*fZShift)[0]); + if (fConfigCCDB.fUseRemoteFwdShift) { + auto* fFwdShift = fCCDB->getForTimeStamp>(fConfigCCDB.fFwdShiftPath, bcs.begin().timestamp()); + if (fFwdShift == nullptr || fFwdShift->empty()) { + LOG(fatal) << "Could not retrieve forward track shift values from CCDB"; + } else if (fFwdShift->size() == 1) { + VarManager::SetZShift((*fFwdShift)[0]); + } else if (fFwdShift->size() == 3) { + VarManager::Set3DShift((*fFwdShift)[0], (*fFwdShift)[1], (*fFwdShift)[2]); } else { - LOG(fatal) << "Could not retrieve Z-shift value from CCDB"; + LOG(fatal) << "Unexpected number of shift values from CCDB: " << fFwdShift->size() << ", expected 1 (z) or 3 (x, y, z)"; } } else { VarManager::SetZShift(fConfigCCDB.fManualZShift.value); diff --git a/PWGDQ/Tasks/DalitzSelection.cxx b/PWGDQ/Tasks/DalitzSelection.cxx index 76b01e073bf..4c3a6a7e581 100644 --- a/PWGDQ/Tasks/DalitzSelection.cxx +++ b/PWGDQ/Tasks/DalitzSelection.cxx @@ -21,6 +21,8 @@ #include "PWGDQ/Core/CutsLibrary.h" #include "PWGDQ/Core/HistogramManager.h" #include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" @@ -32,7 +34,9 @@ #include "Common/DataModel/TrackSelectionTables.h" #include +#include #include +#include #include #include #include @@ -98,11 +102,6 @@ struct DalitzSelection { Configurable fConfigTrackCutsJSON{"cfgTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; Configurable fConfigTrackCutsProbeJSON{"cfgTrackCutsProbeJSON", "", "Additional list of barrel track cuts for the probe in JSON format"}; Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; - Configurable fConfigPtLow{"cfgLowPt", 0.1f, "Low pt cut for Dalitz tracks in the barrel"}; - Configurable fConfigEtaCut{"cfgEtaCut", 0.9f, "Eta cut for Dalitz tracks in the barrel"}; - Configurable fConfigTPCNSigLow{"cfgTPCNSigElLow", -3.f, "Low TPCNSigEl cut for Dalitz tracks in the barrel"}; - Configurable fConfigTPCNSigHigh{"cfgTPCNSigElHigh", 3.f, "High TPCNsigEl cut for Dalitz tracks in the barrel"}; - Configurable fConfigTrackSel{"cfgTrackSel", 0, "track selection requirement: 0: all, 1: reject ITS only, 2: reject TPC only, 3: reject ITS only and TPC only"}; } fConfigCuts; // histograms @@ -118,20 +117,23 @@ struct DalitzSelection { Configurable fQA{"cfgQA", true, "QA histograms"}; Configurable fRemoveDoubleCounting{"cfgRemoveDoubleCounting", true, "If a track/pair is selected for several collisions, we still count it only once"}; // Configurables for TPC post-calibration maps + Configurable fRunEventMixing{"cfgRunEventMixing", false, "Whether or not run event mixing (across TFs)"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; + Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/i/iarsene/Calib/TPCpostCalib", "base path to the ccdb object"}; Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; + Configurable fConfigShiftTPConly{"cfgShiftTPConly", true, "If true, shift the TPC only tracks in z for DCAz"}; Configurable fUseRemoteField{"cfgUseRemoteField", true, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; } fConfigOptions; - Service fCCDB; + Service fCCDB{}; o2::parameters::GRPMagField* grpmag = nullptr; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - - Filter filterBarrelTrack = (o2::aod::track::pt >= fConfigCuts.fConfigPtLow) && (nabs(o2::aod::track::eta) <= fConfigCuts.fConfigEtaCut) && ((o2::aod::pidtpc::tpcNSigmaEl <= fConfigCuts.fConfigTPCNSigHigh && o2::aod::pidtpc::tpcNSigmaEl >= fConfigCuts.fConfigTPCNSigLow) || ((o2::aod::track::v001::detectorMap & 2) == 0)) && ((fConfigCuts.fConfigTrackSel != 1 && fConfigCuts.fConfigTrackSel != 3) || ((o2::aod::track::v001::detectorMap & 2) != 0)) && ((fConfigCuts.fConfigTrackSel != 2 && fConfigCuts.fConfigTrackSel != 3) || ((o2::aod::track::v001::detectorMap & 1) != 0)); + int fCurrentRun = -1; // needed to detect if the run changed and trigger update of calibrations etc. OutputObj fOutputList{"output"}; //! the histogram manager output list OutputObj fStatsList{"Statistics"}; //! skimming statistics @@ -146,16 +148,23 @@ struct DalitzSelection { std::map fDalitzmapProbeAmbiguity; std::map, uint8_t> fAmbiguousPairs; - AnalysisCompositeCut* fEventCut; + AnalysisCompositeCut* fEventCut = nullptr; std::vector fTrackCuts; std::vector fTrackCutsProbe; std::vector fPairCuts; - bool fIsTagAndProbe; // whether we are doing tag and probe, or just symmetric cuts - bool fIsOutputRequested; - bool fSkipEvent; // speed up by skipping next step of event if no track/pair is selected + bool fIsTagAndProbe = false; // whether we are doing tag and probe, or just symmetric cuts + bool fIsOutputRequested = false; + bool fSkipEvent = false; // speed up by skipping next step of event if no track/pair is selected + + MixingHandler fMixingHandler; + MixingHandler::MixingEvent* fMixingEvent = nullptr; + + HistogramManager* fHistMan = nullptr; - HistogramManager* fHistMan; + float fVdrift = -1.; // TPC drift velocity + int64_t fFirstTime = 0; // validity time for the v drift, granularity is smaller than one run + int64_t fLastTime = 0; void init(o2::framework::InitContext& context) { @@ -226,7 +235,7 @@ struct DalitzSelection { } // CCDB configuration - if (fConfigOptions.fConfigComputeTPCpostCalib) { + if (fConfigOptions.fConfigComputeTPCpostCalib || fConfigOptions.fUseRemoteField || fConfigOptions.fConfigShiftTPConly) { fCCDB->setURL(fConfigOptions.fConfigCcdbUrl.value); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); @@ -238,7 +247,7 @@ struct DalitzSelection { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(static_cast(VarManager::fgVariableNames), static_cast(VarManager::fgVariableUnits)); // Create the histogram class names to be added to the histogram manager TString histClasses = ""; @@ -254,36 +263,44 @@ struct DalitzSelection { if (fConfigOptions.fConfigEnableLikeSign) { histClasses += Form("PairLS_%s_%s_%s;", (*trackCut).GetName(), fTrackCutsProbe.at(iCut).GetName(), (*pairCut).GetName()); } + if (fConfigOptions.fRunEventMixing) { + histClasses += Form("PairME_%s_%s_%s;", (*trackCut).GetName(), fTrackCutsProbe.at(iCut).GetName(), (*pairCut).GetName()); + histClasses += Form("PairMELS_%s_%s_%s;", (*trackCut).GetName(), fTrackCutsProbe.at(iCut).GetName(), (*pairCut).GetName()); + } } else { histClasses += Form("TrackBarrel_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); histClasses += Form("Pair_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); if (fConfigOptions.fConfigEnableLikeSign) { histClasses += Form("PairLS_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); } + if (fConfigOptions.fRunEventMixing) { + histClasses += Form("PairME_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); + histClasses += Form("PairMELS_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); + } } } } // Define histograms - std::unique_ptr objArray(histClasses.Tokenize(";")); - for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { - TString classStr = objArray->At(iclass)->GetName(); + std::unique_ptr histArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < histArray->GetEntries(); ++iclass) { + TString classStr = histArray->At(iclass)->GetName(); fHistMan->AddHistClass(classStr.Data()); if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", ""); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "event", ""); } TString histTrackName = fConfigHistograms.fConfigAddTrackHistogram.value; if (classStr.Contains("Track")) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "software-trigger", histTrackName); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "track", histTrackName); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "software-trigger", histTrackName); } TString histPairName = fConfigHistograms.fConfigAddPairHistogram.value; if (classStr.Contains("Pair")) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "pair", histPairName); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "pair", histPairName); } } @@ -297,7 +314,7 @@ struct DalitzSelection { fStatsList->SetOwner(kTRUE); // Dalitz selection statistics: one bin for each (track,pair) selection - TH1I* histTracks = new TH1I("TrackStats", "Dalitz selection statistics", fPairCuts.size() * (1 + fIsTagAndProbe) + 1, -0.5, fPairCuts.size() * (1 + fIsTagAndProbe) + 0.5); + TH1I* histTracks = new TH1I("TrackStats", "Dalitz selection statistics", fPairCuts.size() * (1 + static_cast(fIsTagAndProbe)) + 1, -0.5, fPairCuts.size() * (1 + static_cast(fIsTagAndProbe)) + 0.5); histTracks->GetXaxis()->SetBinLabel(1, "Events selected"); auto trackCut = fTrackCuts.begin(); int icut = 1; @@ -318,7 +335,7 @@ struct DalitzSelection { // autodetect whether the dalitz bits are requested fIsOutputRequested = false; - auto& workflows = context.services().template get(); + const auto& workflows = context.services().template get(); // autodetect this table in other devices for (o2::framework::DeviceSpec const& device : workflows.devices) { // Check if this device subscribed to the dalitz table @@ -332,37 +349,64 @@ struct DalitzSelection { } } } + + // setup mixing handler + if (fConfigOptions.fRunEventMixing) { + TString mixVarsString = fConfigOptions.fConfigMixingVariables.value; + TString mixVarsJsonString = fConfigOptions.fConfigMixingVariablesJson.value; + std::unique_ptr objArray(mixVarsString.Tokenize(",")); + if (objArray->GetEntries() > 0 || mixVarsJsonString != "") { + if (objArray->GetEntries() > 0) { + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(&fMixingHandler, objArray->At(iVar)->GetName()); + } + } + } + if (mixVarsJsonString != "") { + dqmixing::SetUpMixingFromJSON(&fMixingHandler, mixVarsJsonString.Data()); + } + fMixingHandler.SetPoolDepth(fConfigOptions.fConfigMixingDepth); + fMixingHandler.Init(); + } } template void runTrackSelection(TTracks const& tracksBarrel, TEvent const& collision) { - fSkipEvent = true; for (const auto& track1 : tracksBarrel) { - uint8_t filterMap = uint8_t(0); - uint8_t filterMapProbe = uint8_t(0); + auto filterMap = uint8_t(0); + auto filterMapProbe = uint8_t(0); int fullTrackIdx = 0; if constexpr (isReassoc) { auto const& fullTrack = track1.template track_as(); - // Basic filter cuts which cannot be applied directly in case of reassoc - if (fullTrack.pt() < fConfigCuts.fConfigPtLow) { - continue; - } - if (std::fabs(fullTrack.eta()) > fConfigCuts.fConfigEtaCut) { - continue; - } - if (fullTrack.hasTPC() && (fullTrack.tpcNSigmaEl() < fConfigCuts.fConfigTPCNSigLow || fullTrack.tpcNSigmaEl() > fConfigCuts.fConfigTPCNSigHigh)) { - continue; - } - if ((fConfigCuts.fConfigTrackSel == 1 || fConfigCuts.fConfigTrackSel == 3) && !fullTrack.hasTPC()) { - continue; - } - if ((fConfigCuts.fConfigTrackSel == 2 || fConfigCuts.fConfigTrackSel == 3) && !fullTrack.hasITS()) { - continue; - } VarManager::FillTrack(fullTrack); VarManager::FillTrackCollision(fullTrack, collision); + // if the track is TPC only, we shift it in z to be compatible with vertex time + if (!fullTrack.hasITS() && !fullTrack.hasTOF() && !fullTrack.hasTRD() && fVdrift > 0. && fConfigOptions.fConfigShiftTPConly) { + float tTB = 0.; + if (collision.collisionTimeRes() < 0.f || fullTrack.collisionId() < 0) { // use track data + tTB = fullTrack.trackTime(); + } else { + // The TPC track can be associated to a different BC than the one the collision under assumption is; + // we need to calculate the difference and subtract this from the trackTime() + const auto trackBC = fullTrack.template collision_as().template bc_as().globalBC(); + const auto colBC = collision.template foundBC_as().globalBC(); + float sign{1.f}; + uint64_t diffBC{0}; + if (colBC < trackBC) { + sign = -1.f; + diffBC = (trackBC - colBC); + } else { + diffBC = (colBC - trackBC); + } + float diffBCNS = sign * static_cast(diffBC) * static_cast(o2::constants::lhc::LHCBunchSpacingNS); + tTB = collision.collisionTime() + diffBCNS; + } + float dTime = tTB - fullTrack.trackTime(); + float dDrift = dTime * fVdrift; + VarManager::fgValues[VarManager::kTrackDCAz] += ((fullTrack.tgl() < 0.) ? -dDrift : dDrift); + } fullTrackIdx = fullTrack.globalIndex(); } else { VarManager::FillTrack(track1); @@ -370,7 +414,7 @@ struct DalitzSelection { } int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { - if ((*cut).IsSelected(VarManager::fgValues)) { + if ((*cut).IsSelected(static_cast(VarManager::fgValues))) { filterMap |= (uint8_t(1) << i); fSkipEvent = false; } @@ -378,7 +422,7 @@ struct DalitzSelection { if (fIsTagAndProbe) { i = 0; for (auto cut = fTrackCutsProbe.begin(); cut != fTrackCutsProbe.end(); ++cut, ++i) { - if ((*cut).IsSelected(VarManager::fgValues)) { + if ((*cut).IsSelected(static_cast(VarManager::fgValues))) { filterMapProbe |= (uint8_t(1) << i); } } @@ -389,11 +433,39 @@ struct DalitzSelection { if (filterMapProbe) { fTrackmapProbe[fullTrackIdx] = filterMapProbe; } + + if (fConfigOptions.fRunEventMixing && (filterMap || filterMapProbe)) { + // add the track to event mixing, the track1 array is used for the tag and the track2 array is used for the probe + if constexpr (isReassoc) { + auto const& fullTrack = track1.template track_as(); + if (filterMap) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(fullTrack.pt(), fullTrack.eta(), fullTrack.phi(), fullTrack.sign() > 0 ? (static_cast(filterMap) | (static_cast(1) << 8)) : static_cast(filterMap)); + fMixingEvent->AddTrack1(mixingTrack); + } + if (filterMapProbe) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(fullTrack.pt(), fullTrack.eta(), fullTrack.phi(), fullTrack.sign() > 0 ? (static_cast(filterMapProbe) | (static_cast(1) << 8)) : static_cast(filterMapProbe)); + fMixingEvent->AddTrack2(mixingTrack); + } + } else { + if (filterMap) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(track1.pt(), track1.eta(), track1.phi(), track1.sign() > 0 ? (static_cast(filterMap) | (static_cast(1) << 8)) : static_cast(filterMap)); + fMixingEvent->AddTrack1(mixingTrack); + } + if (filterMapProbe) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(track1.pt(), track1.eta(), track1.phi(), track1.sign() > 0 ? (static_cast(filterMapProbe) | (static_cast(1) << 8)) : static_cast(filterMapProbe)); + fMixingEvent->AddTrack2(mixingTrack); + } + } + } } // end loop over tracks } template - void runDalitzPairing(TTracks const& tracks1, TTracks const& tracks2, TEvent collision) + void runDalitzPairing(TTracks const& tracks1, TTracks const& tracks2, TEvent const& collision) { if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { fDalitzmapAmbiguity.clear(); @@ -402,8 +474,8 @@ struct DalitzSelection { fSkipEvent = true; for (const auto& track1 : tracks1) { - int trackIdx1; - bool isTrack1P; + int trackIdx1 = 0; + bool isTrack1P = false; if constexpr (isReassoc) { auto const& fullTrack1 = track1.template track_as(); @@ -419,8 +491,8 @@ struct DalitzSelection { } for (const auto& track2 : tracks2) { - int trackIdx2; - bool isLikeSign; + int trackIdx2 = 0; + bool isLikeSign = false; if constexpr (isReassoc) { auto const& fullTrack2 = track2.template track_as(); trackIdx2 = fullTrack2.globalIndex(); @@ -461,13 +533,13 @@ struct DalitzSelection { if (!(twoTracksFilterMap & (uint8_t(1) << icut))) { continue; } - if ((*pairCut).IsSelected(VarManager::fgValues)) { + if ((*pairCut).IsSelected(static_cast(VarManager::fgValues))) { fSkipEvent = false; bool isPairAlreadySelected = false; if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { // if we remove double counting and the pair is already selected, we don't fill the histograms std::pair iPair(trackIdx1, trackIdx2); - if (fAmbiguousPairs.find(iPair) != fAmbiguousPairs.end()) { + if (fAmbiguousPairs.contains(iPair)) { if (fAmbiguousPairs[iPair] & (static_cast(1) << icut)) { // if this pair is already stored with this cut isPairAlreadySelected = true; } else { @@ -486,26 +558,26 @@ struct DalitzSelection { } if (fIsTagAndProbe) { if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { - fDalitzmapProbeAmbiguity[trackIdx1] |= (uint8_t(1) << icut); + fDalitzmapProbeAmbiguity[trackIdx2] |= (uint8_t(1) << icut); } else { fDalitzmapProbe[trackIdx2] |= (uint8_t(1) << icut); } if (fConfigOptions.fQA && !isPairAlreadySelected) { - fHistMan->FillHistClass(Form("Pair_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("Pair_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } else { if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { - fDalitzmapAmbiguity[trackIdx1] |= (uint8_t(1) << icut); + fDalitzmapAmbiguity[trackIdx2] |= (uint8_t(1) << icut); } else { fDalitzmap[trackIdx2] |= (uint8_t(1) << icut); } if (fConfigOptions.fQA && !isPairAlreadySelected) { - fHistMan->FillHistClass(Form("Pair_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("Pair_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } } else { if (fConfigOptions.fQA && !isPairAlreadySelected) { - fHistMan->FillHistClass(fIsTagAndProbe ? Form("PairLS_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("PairLS_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(fIsTagAndProbe ? Form("PairLS_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("PairLS_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } // end if like-sign } // end if isSelected @@ -516,12 +588,12 @@ struct DalitzSelection { // Fill Hists if (fConfigOptions.fQA && !fSkipEvent) { for (const auto& track : tracks1) { - uint8_t filterMap; - uint8_t filterMapProbe; + auto filterMap = uint8_t(0); + auto filterMapProbe = uint8_t(0); if constexpr (isReassoc) { auto const& fullTrack = track.template track_as(); - filterMap = fDalitzmap[fullTrack.globalIndex()]; - filterMapProbe = fDalitzmapProbe[fullTrack.globalIndex()]; + filterMap = fDalitzmap[fullTrack.globalIndex()]; // cppcheck-suppress redundantInitialization + filterMapProbe = fDalitzmapProbe[fullTrack.globalIndex()]; // cppcheck-suppress redundantInitialization if (fConfigOptions.fRemoveDoubleCounting) { // we remove track selections which were already selected before uint8_t currentFilterMap = fDalitzmapAmbiguity[fullTrack.globalIndex()]; @@ -540,6 +612,31 @@ struct DalitzSelection { VarManager::FillTrack(fullTrack); // The caveat here is that we only fill the DCA to the first selected collision VarManager::FillTrackCollision(fullTrack, collision); + // if the track is TPC only, we shift it in z to be compatible with vertex time + if (!fullTrack.hasITS() && !fullTrack.hasTOF() && !fullTrack.hasTRD() && fVdrift > 0. && fConfigOptions.fConfigShiftTPConly) { + float tTB = 0.; + if (collision.collisionTimeRes() < 0.f || fullTrack.collisionId() < 0) { // use track data + tTB = fullTrack.trackTime(); + } else { + // The TPC track can be associated to a different BC than the one the collision under assumption is; + // we need to calculate the difference and subtract this from the trackTime() + const auto trackBC = fullTrack.template collision_as().template bc_as().globalBC(); + const auto colBC = collision.template foundBC_as().globalBC(); + float sign{1.f}; + uint64_t diffBC{0}; + if (colBC < trackBC) { + sign = -1.f; + diffBC = (trackBC - colBC); + } else { + diffBC = (colBC - trackBC); + } + float diffBCNS = sign * static_cast(diffBC) * static_cast(o2::constants::lhc::LHCBunchSpacingNS); + tTB = collision.collisionTime() + diffBCNS; + } + float dTime = tTB - fullTrack.trackTime(); + float dDrift = dTime * fVdrift; + VarManager::fgValues[VarManager::kTrackDCAz] += ((fullTrack.tgl() < 0.) ? -dDrift : dDrift); + } } else { filterMap = fDalitzmap[track.globalIndex()]; filterMapProbe = fDalitzmapProbe[track.globalIndex()]; @@ -555,18 +652,103 @@ struct DalitzSelection { auto trackCut = fTrackCuts.begin(); for (auto pairCut = fPairCuts.begin(); pairCut != fPairCuts.end(); pairCut++, trackCut++, icut++) { if (filterMap & (uint8_t(1) << icut)) { - reinterpret_cast(fStatsList->At(0))->Fill(fIsTagAndProbe ? 2 * icut + 1 : icut + 1); - fHistMan->FillHistClass(fIsTagAndProbe ? Form("TrackBarrelTag_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("TrackBarrel_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + static_cast(fStatsList->At(0))->Fill(fIsTagAndProbe ? 2 * icut + 1 : icut + 1); + fHistMan->FillHistClass(fIsTagAndProbe ? Form("TrackBarrelTag_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("TrackBarrel_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } if (filterMapProbe & (uint8_t(1) << icut)) { - reinterpret_cast(fStatsList->At(0))->Fill(2 * icut + 2); - fHistMan->FillHistClass(Form("TrackBarrelProbe_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + static_cast(fStatsList->At(0))->Fill(2 * icut + 2); + fHistMan->FillHistClass(Form("TrackBarrelProbe_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } } } } + void runMixing() + { + // run the mixing with the events in the pool corresponding to this event + auto& pool = fMixingHandler.GetPool(fMixingHandler.FindEventCategory(static_cast(VarManager::fgValues))); + + // Bit 8 is a special bit in this case (keeping track sign), so we don't want it to be erased, except when everything else is empty + uint32_t bitMask = (static_cast(1) << 8); + fMixingEvent->ClearFilteringMask(bitMask); + + for (auto& poolEvent : pool.events) { + if ((poolEvent.filteringMask & static_cast(255)) == 0) { + // all other bits have been erased, so we can also mark bit 8 for deletion + poolEvent.filteringMask |= bitMask; + poolEvent.counters[8] = fMixingHandler.GetPoolDepth(); + } + for (auto const& t1 : fMixingEvent->tracks1) { + // tag from event 1 and probe from event 2. If not tag and probe method, all tracks are in tracks1 array + for (auto const& t2 : (fIsTagAndProbe ? poolEvent.tracks2 : poolEvent.tracks1)) { + // check the two-track filter for the mixed pair + auto mixedTwoTrackFilter = static_cast(t1.filteringFlags & t2.filteringFlags & static_cast(255)); // we keep only first 8 bits + if (mixedTwoTrackFilter == 0) { + continue; + } + VarManager::FillPairMEAcrossTFs(t1, t2); + if (fIsTagAndProbe) { + // if we run with tag-and-probe method, we often want quantities as a function of kinematics of the probe, so they need to be filled + // (They are not filled by default in the FillPairMEAcrossTFs) to keep it light + VarManager::fgValues[VarManager::kPt2] = t2.pt; + VarManager::fgValues[VarManager::kEta2] = t2.eta; + VarManager::fgValues[VarManager::kPhi2] = t2.phi; + } + bool isLS = (t1.filteringFlags & (static_cast(1) << 8)) == (t2.filteringFlags & (static_cast(1) << 8)); + for (uint32_t icut = 0; icut < fPairCuts.size(); icut++) { + if (((mixedTwoTrackFilter & (static_cast(1) << icut)) != 0) && fPairCuts.at(icut).IsSelected(static_cast(VarManager::fgValues))) { + if (fIsTagAndProbe) { + if (!isLS) { + fHistMan->FillHistClass(Form("PairME_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } else { + fHistMan->FillHistClass(Form("PairMELS_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } + } else { + if (!isLS) { + fHistMan->FillHistClass(Form("PairME_%s_%s", fTrackCuts.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } else { + fHistMan->FillHistClass(Form("PairMELS_%s_%s", fTrackCuts.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } + } + } + } + } + } + if (fIsTagAndProbe) { + for (auto const& t2 : fMixingEvent->tracks2) { + // tag from event 2 and probe from event 1 + for (auto const& t1 : poolEvent.tracks1) { + auto mixedTwoTrackFilter = static_cast(t1.filteringFlags & t2.filteringFlags & static_cast(255)); // we keep only first 8 bits + if (mixedTwoTrackFilter == 0) { + continue; + } + VarManager::FillPairMEAcrossTFs(t1, t2); + if (fIsTagAndProbe) { + // if we run with tag-and-probe method, we often want quantities as a function of kinematics of the probe, so they need to be filled + // (They are not filled by default in the FillPairMEAcrossTFs to keep it light) + VarManager::fgValues[VarManager::kPt2] = t2.pt; + VarManager::fgValues[VarManager::kEta2] = t2.eta; + VarManager::fgValues[VarManager::kPhi2] = t2.phi; + } + bool isLS = (t1.filteringFlags & (static_cast(1) << 8)) == (t2.filteringFlags & (static_cast(1) << 8)); + for (uint32_t icut = 0; icut < fPairCuts.size(); icut++) { + if (((mixedTwoTrackFilter & (static_cast(1) << icut)) != 0) && fPairCuts.at(icut).IsSelected(static_cast(VarManager::fgValues))) { + if (!isLS) { + fHistMan->FillHistClass(Form("PairME_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } else { + fHistMan->FillHistClass(Form("PairMELS_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } + } + } + } // end loop on tracks of event 1 + } // end loop on tracks of event 2 + } // end if tag and probe + } // end loop on events from the pool + // add the current event to the pool + pool.UpdatePool(*fMixingEvent, fMixingHandler.GetPoolDepth()); + } + void initNewRun(int64_t timestamp) { @@ -601,21 +783,36 @@ struct DalitzSelection { } } + void initNewDF(int64_t timestamp) + { + if (fConfigOptions.fConfigShiftTPConly && (timestamp < fFirstTime || timestamp > fLastTime)) { + std::map headers; + const auto& vd = fCCDB->getForTimeStamp("TPC/Calib/VDriftTgl", timestamp, &headers); + fVdrift = vd->refVDrift * vd->corrFact * 1e-3; + fFirstTime = stol(headers["Valid-From"]); + fLastTime = stol(headers["Valid-Until"]); + headers.clear(); + LOGF(info, "updated v drift with %f cm/ns, valid from %d to %d, current timestamp: %d", fVdrift, fFirstTime, fLastTime, timestamp); + } + } + void processFullTracks(MyEventsWithCent const& collisions, aod::BCsWithTimestamps const&, soa::Filtered const& filteredTracks, MyBarrelTracks const& tracks) { const int pairType = VarManager::kDecayToEE; fDalitzmap.clear(); fDalitzmapProbe.clear(); + bool initDFDone = false; // some quantities might need to be updated for each dataframe + for (const auto& collision : collisions) { fTrackmap.clear(); fTrackmapProbe.clear(); VarManager::ResetValues(VarManager::kNRunWiseVariables, VarManager::kNBarrelTrackVariables); VarManager::FillEvent(collision); - bool isEventSelected = fEventCut->IsSelected(VarManager::fgValues); + bool isEventSelected = fEventCut->IsSelected(static_cast(VarManager::fgValues)); if (isEventSelected) { - reinterpret_cast(fStatsList->At(0))->Fill(0); + static_cast(fStatsList->At(0))->Fill(0); auto bc = collision.template bc_as(); @@ -624,11 +821,28 @@ struct DalitzSelection { fCurrentRun = bc.runNumber(); } + if (!initDFDone) { + initNewDF(bc.timestamp()); + initDFDone = true; + } + + if (fConfigOptions.fRunEventMixing) { + fMixingEvent = new MixingHandler::MixingEvent(); + } + auto groupedFilteredTracks = filteredTracks.sliceBy(perCollision, collision.globalIndex()); runTrackSelection(groupedFilteredTracks, nullptr); if (!fSkipEvent) { runDalitzPairing(groupedFilteredTracks, groupedFilteredTracks, nullptr); } + + if (fConfigOptions.fRunEventMixing) { + if (!fMixingEvent->tracks1.empty()) { + // we require that there is at least one tag track in the event to avoid having the pool full of events with only probe tracks which become useless for mixing + runMixing(); + } + delete fMixingEvent; + } } } @@ -649,16 +863,18 @@ struct DalitzSelection { fDalitzmapProbeAmbiguity.clear(); fAmbiguousPairs.clear(); + bool initDFDone = false; // some quantities might need to be updated for each dataframe + for (const auto& collision : collisions) { fTrackmap.clear(); fTrackmapProbe.clear(); VarManager::ResetValues(VarManager::kNRunWiseVariables, VarManager::kNBarrelTrackVariables); VarManager::FillEvent(collision); - bool isEventSelected = fEventCut->IsSelected(VarManager::fgValues); + bool isEventSelected = fEventCut->IsSelected(static_cast(VarManager::fgValues)); if (isEventSelected) { - reinterpret_cast(fStatsList->At(0))->Fill(0); + static_cast(fStatsList->At(0))->Fill(0); auto bc = collision.template bc_as(); @@ -667,11 +883,28 @@ struct DalitzSelection { fCurrentRun = bc.runNumber(); } + if (!initDFDone) { + initNewDF(bc.timestamp()); + initDFDone = true; + } + + if (fConfigOptions.fRunEventMixing) { + fMixingEvent = new MixingHandler::MixingEvent(); + } + auto groupedTracksAssoc = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); runTrackSelection(groupedTracksAssoc, collision); if (!fSkipEvent) { runDalitzPairing(groupedTracksAssoc, groupedTracksAssoc, collision); } + if (fConfigOptions.fRunEventMixing) { + if (!fMixingEvent->tracks1.empty()) { + // we require that there is at least one tag track in the event to avoid having the pool full of events with only probe tracks which are then useless + // In addition, this allows to avoid mixing events which are too close in time, which could contain tracks from the same event due to track-to-collision reassociation + runMixing(); + } + delete fMixingEvent; + } } } @@ -692,16 +925,18 @@ struct DalitzSelection { fDalitzmapProbeAmbiguity.clear(); fAmbiguousPairs.clear(); + bool initDFDone = false; // some quantities might need to be updated for each dataframe + for (const auto& collision : collisions) { fTrackmap.clear(); fTrackmapProbe.clear(); VarManager::ResetValues(VarManager::kNRunWiseVariables, VarManager::kNBarrelTrackVariables); VarManager::FillEvent(collision); - bool isEventSelected = fEventCut->IsSelected(VarManager::fgValues); + bool isEventSelected = fEventCut->IsSelected(static_cast(VarManager::fgValues)); if (isEventSelected) { - reinterpret_cast(fStatsList->At(0))->Fill(0); + static_cast(fStatsList->At(0))->Fill(0); auto bc = collision.template bc_as(); @@ -710,11 +945,28 @@ struct DalitzSelection { fCurrentRun = bc.runNumber(); } + if (!initDFDone) { + initNewDF(bc.timestamp()); + initDFDone = true; + } + + if (fConfigOptions.fRunEventMixing) { + fMixingEvent = new MixingHandler::MixingEvent(); + } + auto groupedTracksAssoc = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); runTrackSelection(groupedTracksAssoc, collision); if (!fSkipEvent) { runDalitzPairing(groupedTracksAssoc, groupedTracksAssoc, collision); } + if (fConfigOptions.fRunEventMixing) { + if (!fMixingEvent->tracks1.empty()) { + // we require that there is at least one tag track in the event to avoid having the pool full of events with only probe tracks which are then useless + // In addition, this allows to avoid mixing events which are too close in time, which could contain tracks from the same event due to track-to-collision reassociation + runMixing(); + } + delete fMixingEvent; + } } } diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 42c42441774..fea3f19016f 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -1350,6 +1350,223 @@ struct AnalysisPrefilterSelection { PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); }; +// Single-track selection on the barrel tracks after the prefilter decisions (which are not visible in the +// AnalysisTrackSelection histograms): fills track-level histograms separately for surviving and vetoed tracks, +// per track cut and per MC signal. +// NOTE: Histograms are filled per association, regardless of whether the association is the correct one. +struct AnalysisPostPrefilterTrackSelection { + OutputObj fOutputList{"output"}; + + Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of track cuts (among those of analysis-track-selection) for which to fill histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Service fCCDB{}; + + HistogramManager* fHistMan = nullptr; + std::vector fMCSignals; + std::vector fCutBits; // bit positions of the requested cuts in the track-selection task cut list + std::vector fHistNamesSurvived; // [icut] + std::vector fHistNamesVetoed; // [icut] + std::vector fHistNamesMCSurvived; // [icut * nSignals + isig] + std::vector fHistNamesMCVetoed; // [icut * nSignals + isig] + + int fCurrentRun = 0; // current run (needed to detect run changes for loading CCDB parameters) + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fCurrentRun = 0; + TString trackCutsStr = fConfigTrackCuts.value; + std::unique_ptr objArrayCuts(trackCutsStr.Tokenize(",")); + if (objArrayCuts == nullptr || objArrayCuts->GetEntries() == 0) { + LOG(fatal) << " No track cuts specified! Check the cfgTrackCuts configurable"; + } + // get the full list of cuts computed by the track-selection task and resolve the requested cuts to bit positions + std::string trackCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + TString allTrackCutsStr = trackCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + TString addTrackCutsStr = trackCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto const& t : addTrackCuts) { + allTrackCutsStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArrayAllCuts(allTrackCutsStr.Tokenize(",")); + if (objArrayAllCuts == nullptr) { + LOG(fatal) << " Not getting any track cuts from the barrel-track-selection "; + } + std::vector cutNames; + for (int icut = 0; icut < objArrayCuts->GetEntries(); ++icut) { + TString cutName = objArrayCuts->At(icut)->GetName(); + if (objArrayAllCuts->FindObject(cutName.Data()) == nullptr) { + LOG(fatal) << " Track cut " << cutName << " not among the cuts calculated by the track-selection task! "; + } + for (int jcut = 0; jcut < objArrayAllCuts->GetEntries(); ++jcut) { + if (cutName.CompareTo(objArrayAllCuts->At(jcut)->GetName()) == 0) { + fCutBits.push_back(jcut); + } + } + cutNames.push_back(cutName); + } + + // Setting the MC signals + TString configSigNamesStr = fConfigMCSignals.value; + std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(sig); + } + } + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto const& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(mcIt); + } + } + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits()); + + // Configure histogram classes for each track cut, separately for prefilter-surviving and prefilter-vetoed tracks, + // and for each requested MC signal (reconstructed tracks with MC truth) + TString histClasses = ""; + for (auto const& cutName : cutNames) { + TString nameStr = Form("TrackBarrelPostPrefilter_%s", cutName.Data()); + fHistNamesSurvived.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + nameStr = Form("TrackBarrelPrefilterVetoed_%s", cutName.Data()); + fHistNamesVetoed.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + for (auto const& sig : fMCSignals) { + TString nameStr2 = Form("TrackBarrelPostPrefilter_%s_%s", cutName.Data(), sig->GetName()); + fHistNamesMCSurvived.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + nameStr2 = Form("TrackBarrelPrefilterVetoed_%s_%s", cutName.Data(), sig->GetName()); + fHistNamesMCVetoed.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + } + } + + DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data()); + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + } + + template + void runPostPrefilterTrackSelection(soa::Join const& assocs, + TEvents const& events, TTracks const& /*tracks*/, TTracksMC const& tracksMC) + { + // load the magnetic field (needed to recompute the DCA with respect to the associated collision) + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + auto grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + + // Loop over associations + for (auto const& assoc : assocs) { + auto event = assoc.template reducedevent_as(); + if (!event.isEventSelected_bit(0)) { + continue; + } + + // check which of the requested cuts are fulfilled by this association and which of those are prefilter-vetoed + uint32_t selectedMap = 0; + uint32_t vetoMap = 0; + for (std::size_t icut = 0; icut < fCutBits.size(); ++icut) { + if (assoc.isBarrelSelected_bit(fCutBits[icut])) { + selectedMap |= (static_cast(1) << icut); + if (!assoc.isBarrelSelectedPrefilter_bit(fCutBits[icut])) { + vetoMap |= (static_cast(1) << icut); + } + } + } + if (selectedMap == 0) { + continue; + } + + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + // fill event information which might be needed in histograms that combine track and event properties + VarManager::FillEvent(event); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } + + auto track = assoc.template reducedtrack_as(); + VarManager::FillTrack(track); + // compute quantities which depend on the associated collision, such as DCA + VarManager::FillTrackCollision(track, event); + if (track.has_reducedMCTrack()) { + VarManager::FillTrackMC(tracksMC, track.reducedMCTrack()); + } + + for (std::size_t icut = 0; icut < fCutBits.size(); ++icut) { + if (!(selectedMap & (static_cast(1) << icut))) { + continue; + } + bool isVetoed = (vetoMap & (static_cast(1) << icut)) > 0; + fHistMan->FillHistClass((isVetoed ? fHistNamesVetoed[icut] : fHistNamesSurvived[icut]).Data(), dqefficiency_helpers::varValues()); + if (track.has_reducedMCTrack()) { + int isig = 0; + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + fHistMan->FillHistClass((isVetoed ? fHistNamesMCVetoed : fHistNamesMCSurvived)[icut * fMCSignals.size() + isig].Data(), dqefficiency_helpers::varValues()); + } + } + } + } // end loop over cuts + } // end loop over associations + } + + void processSkimmed(soa::Join const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& tracksMC) + { + runPostPrefilterTrackSelection(assocs, events, tracks, tracksMC); + } + void processSkimmedWithCov(soa::Join const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& tracksMC) + { + runPostPrefilterTrackSelection(assocs, events, tracks, tracksMC); + } + void processDummy(MyEvents const&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processSkimmed, "Run barrel track post-prefilter selection on DQ skimmed track associations", false); + PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processSkimmedWithCov, "Run barrel track post-prefilter selection on DQ skimmed track associations w/ cov matrix", false); + PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processDummy, "Dummy function", true); +}; + // Run the same-event pairing // This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) // Runs combinatorics for barrel-barrel, muon-muon and barrel-muon combinations @@ -5183,6 +5400,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx index bfb437c1ef6..d61bf37ea71 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx @@ -331,14 +331,14 @@ struct AnalysisEventSelection { HistogramManager* fHistMan = nullptr; - AnalysisCompositeCut* fEventCut; + AnalysisCompositeCut* fEventCut = nullptr; Service fCCDB; o2::ccdb::CcdbApi fCCDBApi; std::map fSelMap; // key: reduced event global index, value: event selection decision std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices - int fCurrentRun; + int fCurrentRun = 0; void init(o2::framework::InitContext& context) { @@ -595,13 +595,13 @@ struct AnalysisTrackSelection { Service fCCDB; Service fTofResponse; - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; std::vector fTrackCuts; std::vector fMCSignals; // list of signals to be checked std::vector fHistNamesReco; std::vector fHistNamesMCMatched; - int fCurrentRun; // current run (needed to detect run changes for loading CCDB parameters) + int fCurrentRun = 0; // current run (needed to detect run changes for loading CCDB parameters) std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) @@ -938,9 +938,9 @@ struct AnalysisPrefilterSelection { Configurable fPropTrack{"cfgPropTrack", false, "Propagate tracks to associated collision to recalculate DCA and momentum vector"}; std::map fPrefilterMap; - AnalysisCompositeCut* fPairCut; - uint32_t fPrefilterMask; - int fPrefilterCutBit; + AnalysisCompositeCut* fPairCut = nullptr; + uint32_t fPrefilterMask = 0; + int fPrefilterCutBit = 0; Preslice trackAssocsPerCollision = aod::track_association::collisionId; @@ -1140,7 +1140,12 @@ struct AnalysisSameEventPairing { Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigPseudoQA{"cfgPseudoQA", false, "If true, fill QA histograms with pseudo-proper decay length"}; + Configurable fConfigMCtruthQA{"cfgMCtruthQA", false, "If true, fill QA histograms with default"}; + Configurable fConfigPseudoHEQA{"cfgPseudoHEQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization HE"}; + Configurable fConfigPseudoCSQA{"cfgPseudoCSQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization CS"}; + Configurable fConfigPseudoRMQA{"cfgPseudoRMQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization RM"}; + Configurable fConfigTruthPbPbMIDYHE{"cfgTruthPbPbmidyHE", false, "If true, fill QA histograms with dielectron pairs in helicity frame"}; + Configurable fConfigTruthPbPbMIDYCS{"cfgTruthPbPbmidyCS", false, "If true, fill QA histograms with dielectron pairs in collion-soper frame"}; Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; @@ -1201,14 +1206,14 @@ struct AnalysisSameEventPairing { std::vector fMCGenAccCuts; bool fUseMCGenAccCut = false; - uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream - uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream - int fNCutsBarrel; - int fNCutsMuon; - int fNPairCuts; + uint32_t fTrackFilterMask = 0; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream + uint32_t fMuonFilterMask = 0; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream + int fNCutsBarrel = 0; + int fNCutsMuon = 0; + int fNPairCuts = 0; bool fHasTwoProngGenMCsignals = false; - bool fEnableBarrelHistos; + bool fEnableBarrelHistos = false; // bool fEnableMuonHistos; Preslice> trackAssocsPerCollision = aod::track_association::collisionId; @@ -1500,18 +1505,46 @@ struct AnalysisSameEventPairing { histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function histNames += Form("MCTruthGenSel_%s;", sig->GetName()); } else if (sig->GetNProngs() == 2) { - histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); // after event selection - if (fConfigOptions.fConfigPseudoQA.value) { - histNames += Form("MCTruthGenPseudoPolPairSel_%s;", sig->GetName()); + if (fConfigOptions.fConfigMCtruthQA.value) { + histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); // after event selection + } + if (fConfigOptions.fConfigPseudoHEQA.value) { + histNames += Form("MCTruthGenPseudoPolPairHESel_%s;", sig->GetName()); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + histNames += Form("MCTruthGenPseudoPolPairCSSel_%s;", sig->GetName()); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + histNames += Form("MCTruthGenPseudoPolPairRMSel_%s;", sig->GetName()); + } + if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { + histNames += Form("MCTruthGenPoldielectronPbPbPairHESel_%s;", sig->GetName()); + } + if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { + histNames += Form("MCTruthGenPoldielectronPbPbPairCSSel_%s;", sig->GetName()); } fHasTwoProngGenMCsignals = true; } // for these pair level signals, also add histograms for each MCgenAcc cut if specified if (fUseMCGenAccCut) { for (auto& cut : fMCGenAccCuts) { - histNames += Form("MCTruthGenPairSel_%s_%s;", sig->GetName(), cut->GetName()); // after event selection and MCgenAcc cut - if (fConfigOptions.fConfigPseudoQA.value) { - histNames += Form("MCTruthGenPseudoPolPairSel_%s_%s;", sig->GetName(), cut->GetName()); + if (fConfigOptions.fConfigMCtruthQA.value) { + histNames += Form("MCTruthGenPairSel_%s_%s;", sig->GetName(), cut->GetName()); // after event selection and MCgenAcc cut + } + if (fConfigOptions.fConfigPseudoHEQA.value) { + histNames += Form("MCTruthGenPseudoPolPairHESel_%s_%s;", sig->GetName(), cut->GetName()); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + histNames += Form("MCTruthGenPseudoPolPairCSSel_%s_%s;", sig->GetName(), cut->GetName()); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + histNames += Form("MCTruthGenPseudoPolPairRMSel_%s_%s;", sig->GetName(), cut->GetName()); + } + if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { + histNames += Form("MCTruthGenPoldielectronPbPbPairHESel_%s_%s;", sig->GetName(), cut->GetName()); + } + if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { + histNames += Form("MCTruthGenPoldielectronPbPbPairCSSel_%s_%s;", sig->GetName(), cut->GetName()); } } } @@ -2167,16 +2200,46 @@ struct AnalysisSameEventPairing { VarManager::FillTrackCollisionMC(motherMCParticle_t1, collVtxPos, pdgDB->Mass(motherMCParticle_t1.pdgCode())); } } - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); - if (fConfigOptions.fConfigQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairSel_%s", sig->GetName()), VarManager::fgValues); + if (fConfigOptions.fConfigMCtruthQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoHEQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s", sig->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s", sig->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s", sig->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s", sig->GetName()), VarManager::fgValues); } + if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairCSSel_%s", sig->GetName()), VarManager::fgValues); + } + if (fUseMCGenAccCut) { for (auto& cut : fMCGenAccCuts) { if (cut->IsSelected(VarManager::fgValues)) { - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); - if (fConfigOptions.fConfigPseudoQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + if (fConfigOptions.fConfigMCtruthQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoHEQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + + if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairCSSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); } } } @@ -2274,13 +2337,13 @@ struct AnalysisDileptonTrack { Configurable fConfigMCGenSignalHadronJSON{"cfgMCGenSignalHadronJSON", "", "generator level hadron signal (JSON format), used for MC level combinatorics"}; } fConfigMCOptions; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNCuts; - int fNLegCuts; - int fNPairCuts; - int fNCommonTrackCuts; + int fCurrentRun = 0; // needed to detect if the run changed and trigger update of calibrations etc. + int fNCuts = 0; + int fNLegCuts = 0; + int fNPairCuts = 0; + int fNCommonTrackCuts = 0; std::map fCommonTrackCutMap; - uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons + uint32_t fTrackCutBitMap = 0; // track cut bit mask to be used in the selection of tracks associated with dileptons // vector for single-lepton and track cut names for easy access when calling FillHistogramList() std::vector fTrackCutNames; std::vector fLegCutNames; @@ -2297,14 +2360,14 @@ struct AnalysisDileptonTrack { // Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); // use two values array to avoid mixing up the quantities - float* fValuesDilepton; - float* fValuesHadron; - HistogramManager* fHistMan; + float* fValuesDilepton = nullptr; + float* fValuesHadron = nullptr; + HistogramManager* fHistMan = nullptr; std::vector fRecMCSignals; std::vector fGenMCSignals; - MCSignal* fDileptonLegSignal; - MCSignal* fHadronSignal; + MCSignal* fDileptonLegSignal = nullptr; + MCSignal* fHadronSignal = nullptr; void init(o2::framework::InitContext& context) { @@ -2316,7 +2379,7 @@ struct AnalysisDileptonTrack { bool isDummy = context.mOptions.get("processDummy"); if (isDummy) { - if (isBarrel || isMCGen /*|| isBarrelAsymmetric*/ /*|| isMuon*/) { + if (isBarrel || isMCGen) { LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; } else { LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; @@ -2539,13 +2602,13 @@ struct AnalysisDileptonTrack { fNLegCuts = fNCuts; // loop over single lepton cuts - if (isBarrel /*|| isBarrelAsymmetric*/ /* || isMuon*/) { + if (isBarrel) { for (int icut = 0; icut < fNLegCuts; ++icut) { TString pairLegCutName; // here we check that this cut is one of those used for building the dileptons - if (isBarrel /*|| isMuon*/) { + if (isBarrel) { if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { continue; } @@ -3178,10 +3241,22 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("MCTruthGenPair")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); } - if (classStr.Contains("MCTruthGenPseudoPolPair")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-gen", histName); + if (classStr.Contains("MCTruthGenPseudoPolPairHE")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-midy-he-gen", histName); + } + if (classStr.Contains("MCTruthGenPseudoPolPairCS")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-midy-cs-gen", histName); + } + if (classStr.Contains("MCTruthGenPseudoPolPairRM")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-midy-rand-gen", histName); + } + if (classStr.Contains("MCTruthGenPoldielectronPbPbPairHE")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-dielectron-pbpb-midy-he-gen", histName); } + if (classStr.Contains("MCTruthGenPoldielectronPbPbPairCS")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-dielectron-pbpb-midy-cs-gen", histName); + } if (classStr.Contains("MCTruthGenSelBR")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_triple"); } else if (classStr.Contains("MCTruthGen")) { diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index 667c0dfb802..ab91c5cae70 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -83,12 +83,22 @@ namespace globalmuonmatching DECLARE_SOA_COLUMN(IsTagged, isTagged, bool); //! Whether the MCH(-MID) track passes tagging cuts DECLARE_SOA_COLUMN(MatchRanking, matchRanking, int32_t); //! Match candidate ranking (-1 for base MCH entries) DECLARE_SOA_COLUMN(MixedGroupIndex, mixedGroupIndex, int32_t); //! Mixed-event group index (-1 for same-event candidates) +DECLARE_SOA_COLUMN(DeltaBc, deltaBc, int64_t); //! |ΔBC| between mixed collisions (-1 if same-event) +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! |Δφ| between mixed MCH tracks (-1 if same-event) +DECLARE_SOA_COLUMN(DeltaR, deltaR, float); //! ΔR = r2−r1 between mixed MCH tracks (-1 if same-event) +DECLARE_SOA_COLUMN(DeltaAttemptsRel, deltaAttemptsRel, float); //! relative Δ(nMatchAttempts) (-1 if same-event) +DECLARE_SOA_COLUMN(DeltaZ, deltaZ, float); //! |Δvz| between mixed collisions (-1 if same-event) } // namespace globalmuonmatching DECLARE_SOA_TABLE(GmmCandFwdTrkExtras, "AOD", "GMMCANDEXTRA", //! Extra info joinable to FwdTracksReAlign globalmuonmatching::IsTagged, globalmuonmatching::MatchRanking, - globalmuonmatching::MixedGroupIndex); + globalmuonmatching::MixedGroupIndex, + globalmuonmatching::DeltaBc, + globalmuonmatching::DeltaPhi, + globalmuonmatching::DeltaR, + globalmuonmatching::DeltaAttemptsRel, + globalmuonmatching::DeltaZ); } // namespace o2::aod using MyEvents = soa::Join; @@ -128,6 +138,11 @@ struct GlobalMuonMatching { double matchChi2{-1}; int matchRanking{-1}; int32_t mixedGroupIndex{-1}; + int64_t deltaBc{-1}; + float deltaPhi{-1.f}; + float deltaR{-1.f}; + float deltaAttemptsRel{-1.f}; + float deltaZ{-1.f}; }; struct MchTrackInfo { @@ -187,6 +202,9 @@ struct GlobalMuonMatching { Configurable cfgMFTAlignmentCorrYOffsetBottom{"cfgMFTAlignmentCorrYOffsetBottom", 0.f, "MFT Y offset correction - bottom half"}; } configMftAlignmentCorrections; + // Magnetic field position bias + Configurable cfgFieldOriginBiasZ{"cfgFieldOriginBiasZ", 0.0f, "Bias applied to the magnetic field z position"}; + // Variables for CCDB objects access and retrieval struct : ConfigurableGroup { Configurable cfgCcdbUrl{"cfgCcdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -740,6 +758,9 @@ struct GlobalMuonMatching { fCCDBApi.init(configCcdb.cfgCcdbUrl); mRunNumber = 0; + // configure magnetic field position bias + o2::conf::ConfigurableParam::setValue("FieldOriginBias.z", std::to_string(cfgFieldOriginBiasZ.value)); + // Configuration for track fitter const auto& trackerParam = mch::TrackerParam::Instance(); trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); @@ -933,7 +954,7 @@ struct GlobalMuonMatching { track.trackTimeRes()); storeFwdTrackCovariance(trackPar.getCovariances()); - gmCandidateFwdTrackExtras(isTagged, -1, -1); + gmCandidateFwdTrackExtras(isTagged, -1, -1, -1, -1.f, -1.f, -1.f, -1.f); if (hasBcSlice) { gmAmbiguousFwdTracksReAlign(mGmmCandFwdTrackRowIndex, bcSlice.data()); } @@ -1015,7 +1036,14 @@ struct GlobalMuonMatching { mchTrack.trackTimeRes()); storeFwdTrackCovariance(globalMuonRefit.getCovariances()); - gmCandidateFwdTrackExtras(isMchTrackTagged(mchTrack.globalIndex()), candidate.matchRanking, candidate.mixedGroupIndex); + gmCandidateFwdTrackExtras(isMchTrackTagged(mchTrack.globalIndex()), + candidate.matchRanking, + candidate.mixedGroupIndex, + candidate.deltaBc, + candidate.deltaPhi, + candidate.deltaR, + candidate.deltaAttemptsRel, + candidate.deltaZ); if (hasBcSlice) { gmAmbiguousFwdTracksReAlign(mGmmCandFwdTrackRowIndex, bcSlice.data()); } @@ -1357,8 +1385,14 @@ struct GlobalMuonMatching { // add the candidates of MCH track #2 to the list of mixed candidates of track #1 mchTrackInfo1.mixedMatchingCandidates.push_back(mchTrackInfo2.matchingCandidates); // update the muon track index of the mixed candidates to the index of track #1 + // and store the mixing deltas for this group for (auto& candidate : mchTrackInfo1.mixedMatchingCandidates.back()) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) candidate.muonTrackId = mchIndex1; + candidate.deltaBc = deltaBc; + candidate.deltaPhi = deltaPhi; + candidate.deltaR = deltaR; + candidate.deltaAttemptsRel = deltaAttemptsRel; + candidate.deltaZ = deltaZ; } } } @@ -1554,6 +1588,13 @@ struct GlobalMuonMatching { break; } result.mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; + if (useMixedMatchingCandidates && !candidatesGroup.empty()) { + result.deltaBc = candidatesGroup.front().deltaBc; + result.deltaPhi = candidatesGroup.front().deltaPhi; + result.deltaR = candidatesGroup.front().deltaR; + result.deltaAttemptsRel = candidatesGroup.front().deltaAttemptsRel; + result.deltaZ = candidatesGroup.front().deltaZ; + } storedCandidates.push_back(result); ++nStoredThisGroup; } @@ -1647,6 +1688,13 @@ struct GlobalMuonMatching { break; } result.mixedGroupIndex = useMixedMatchingCandidates ? mixedGroupIndex : -1; + if (useMixedMatchingCandidates && !candidatesGroup.empty()) { + result.deltaBc = candidatesGroup.front().deltaBc; + result.deltaPhi = candidatesGroup.front().deltaPhi; + result.deltaR = candidatesGroup.front().deltaR; + result.deltaAttemptsRel = candidatesGroup.front().deltaAttemptsRel; + result.deltaZ = candidatesGroup.front().deltaZ; + } storedCandidates.push_back(result); ++nStoredThisGroup; } diff --git a/PWGDQ/Tasks/jPsiMuonCorrelations.cxx b/PWGDQ/Tasks/jPsiMuonCorrelations.cxx index 8cdbeca1dd0..f53f4229b9f 100644 --- a/PWGDQ/Tasks/jPsiMuonCorrelations.cxx +++ b/PWGDQ/Tasks/jPsiMuonCorrelations.cxx @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -104,13 +106,13 @@ struct DqJPsiMuonCorrelations { // Connect to ccdb Service ccdb{}; Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable ccdbUrl{"ccdbUrl", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; // Define the filter for events Filter eventFilter = aod::dqanalysisflags::isEventSelected == 1; // Define the filter for the dileptons - Filter dileptonFilter = aod::reducedpair::sign == 0; + Filter dileptonFilter = (aod::reducedpair::pt > fConfigDileptonPtMin && aod::reducedpair::pt < fConfigDileptonPtMax) && (aod::reducedpair::eta > fConfigDileptonEtaMin && aod::reducedpair::eta < fConfigDileptonEtaMax); constexpr static uint32_t FgDimuonsFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::Pair; // fill map @@ -139,14 +141,16 @@ struct DqJPsiMuonCorrelations { // Define trigger histograms ConfigurableAxis axisTriggerMass{"axisTriggerMass", {VARIABLE_WIDTH, fConfigBackgroundLowMass, fConfigDileptonLowMass, fConfigDileptonHighMass, fConfigBackgroundHighMass}, "Invariant Mass (GeV/c^{2}) for trigger counting"}; - registry.add("h2dDimuonPtInvVsInvMass", "h2dDimuonPtInvVsInvMass", kTH2D, {axisInvMass, axisPt}); - registry.add("h2dTriggersPtInvVsInvMassRegion", "h2dTriggersPtInvVsInvMassRegion", kTH2D, {axisTriggerMass, axisPt}); - - // Define histograms for the dilepton-muon correlations - registry.add("h2dDimuonMuonDeltaEtaVsMuonPtSignal", "h2dDimuonMuonDeltaEtaVsMuonPtSignal", kTH2D, {axisDeltaEta, axisPt}); - registry.add("h2dDimuonMuonDeltaPhiVsMuonPtSignal", "h2dDimuonMuonDeltaPhiVsMuonPtSignal", kTH2D, {axisDeltaPhi, axisPt}); - registry.add("h2dDimuonMuonDeltaEtaVsMuonPtBackground", "h2dDimuonMuonDeltaEtaVsMuonPtBackground", kTH2D, {axisDeltaEta, axisPt}); - registry.add("h2dDimuonMuonDeltaPhiVsMuonPtBackground", "h2dDimuonMuonDeltaPhiVsMuonPtBackground", kTH2D, {axisDeltaPhi, axisPt}); + for (const auto& signDilepton : {"dileptonOS", "dileptonSS"}) { + registry.add(Form("%s/h2dDimuonPtInvVsInvMass", signDilepton), "h2dDimuonPtInvVsInvMass", kTH2D, {axisInvMass, axisPt}); + registry.add(Form("%s/h2dTriggersPtInvVsInvMassRegion", signDilepton), "h2dTriggersPtInvVsInvMassRegion", kTH2D, {axisTriggerMass, axisPt}); + + // Define histograms for the dilepton-muon correlations + registry.add(Form("%s/h2dDimuonMuonDeltaEtaVsMuonPtSignal", signDilepton), "h2dDimuonMuonDeltaEtaVsMuonPtSignal", kTH2D, {axisDeltaEta, axisPt}); + registry.add(Form("%s/h2dDimuonMuonDeltaPhiVsMuonPtSignal", signDilepton), "h2dDimuonMuonDeltaPhiVsMuonPtSignal", kTH2D, {axisDeltaPhi, axisPt}); + registry.add(Form("%s/h2dDimuonMuonDeltaEtaVsMuonPtBackground", signDilepton), "h2dDimuonMuonDeltaEtaVsMuonPtBackground", kTH2D, {axisDeltaEta, axisPt}); + registry.add(Form("%s/h2dDimuonMuonDeltaPhiVsMuonPtBackground", signDilepton), "h2dDimuonMuonDeltaPhiVsMuonPtBackground", kTH2D, {axisDeltaPhi, axisPt}); + } // QA histograms registry.add("hEventPosZMuon", "hEventPosZMuon", kTH1D, {{50, -25, 25}}); @@ -174,11 +178,6 @@ struct DqJPsiMuonCorrelations { for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesDilepton.data()); - // Dilepton kinematic cuts - if ((dilepton.eta() < fConfigDileptonEtaMin || dilepton.eta() > fConfigDileptonEtaMax) || - (dilepton.pt() < fConfigDileptonPtMin || dilepton.pt() > fConfigDileptonPtMax)) { - continue; - } // Dilepton leg kinematic cuts if ((dilepton.eta1() < fConfigMuonEtaMin || dilepton.eta1() > fConfigMuonEtaMax) || (dilepton.pt1() < axisPt.value[1] || dilepton.pt1() > axisPt.value.back()) || @@ -190,8 +189,13 @@ struct DqJPsiMuonCorrelations { // Fill invariant mass vs pT histogram for the dileptons and for trigger counting double weightDilepton = getWeight(dilepton.pt(), axisPt.value, fConfigBinEffJPsi.value, fConfigDileptonEtaMin, fConfigDileptonEtaMax); - registry.fill(HIST("h2dDimuonPtInvVsInvMass"), dilepton.mass(), dilepton.pt(), weightDilepton); - registry.fill(HIST("h2dTriggersPtInvVsInvMassRegion"), dilepton.mass(), dilepton.pt(), weightDilepton); + if (dilepton.sign() == 0) { + registry.fill(HIST("dileptonOS/h2dDimuonPtInvVsInvMass"), dilepton.mass(), dilepton.pt(), weightDilepton); + registry.fill(HIST("dileptonOS/h2dTriggersPtInvVsInvMassRegion"), dilepton.mass(), dilepton.pt(), weightDilepton); + } else { + registry.fill(HIST("dileptonSS/h2dDimuonPtInvVsInvMass"), dilepton.mass(), dilepton.pt(), weightDilepton); + registry.fill(HIST("dileptonSS/h2dTriggersPtInvVsInvMassRegion"), dilepton.mass(), dilepton.pt(), weightDilepton); + } for (const auto& assoc : assocs) { // Check selection bit @@ -221,11 +225,21 @@ struct DqJPsiMuonCorrelations { double weightMuon = getWeight(track.pt(), axisPt.value, fConfigBinEffMuon.value, fConfigMuonEtaMin, fConfigMuonEtaMax); if (dilepton.mass() > fConfigDileptonLowMass && dilepton.mass() < fConfigDileptonHighMass) { - registry.fill(HIST("h2dDimuonMuonDeltaEtaVsMuonPtSignal"), deltaEta, track.pt(), weightDilepton * weightMuon); - registry.fill(HIST("h2dDimuonMuonDeltaPhiVsMuonPtSignal"), deltaPhi, track.pt(), weightDilepton * weightMuon); + if (dilepton.sign() == 0) { + registry.fill(HIST("dileptonOS/h2dDimuonMuonDeltaEtaVsMuonPtSignal"), deltaEta, track.pt(), weightDilepton * weightMuon); + registry.fill(HIST("dileptonOS/h2dDimuonMuonDeltaPhiVsMuonPtSignal"), deltaPhi, track.pt(), weightDilepton * weightMuon); + } else { + registry.fill(HIST("dileptonSS/h2dDimuonMuonDeltaEtaVsMuonPtSignal"), deltaEta, track.pt(), weightDilepton * weightMuon); + registry.fill(HIST("dileptonSS/h2dDimuonMuonDeltaPhiVsMuonPtSignal"), deltaPhi, track.pt(), weightDilepton * weightMuon); + } } else if (dilepton.mass() > fConfigBackgroundLowMass && dilepton.mass() < fConfigBackgroundHighMass) { - registry.fill(HIST("h2dDimuonMuonDeltaEtaVsMuonPtBackground"), deltaEta, track.pt(), weightDilepton * weightMuon); - registry.fill(HIST("h2dDimuonMuonDeltaPhiVsMuonPtBackground"), deltaPhi, track.pt(), weightDilepton * weightMuon); + if (dilepton.sign() == 0) { + registry.fill(HIST("dileptonOS/h2dDimuonMuonDeltaEtaVsMuonPtBackground"), deltaEta, track.pt(), weightDilepton * weightMuon); + registry.fill(HIST("dileptonOS/h2dDimuonMuonDeltaPhiVsMuonPtBackground"), deltaPhi, track.pt(), weightDilepton * weightMuon); + } else { + registry.fill(HIST("dileptonSS/h2dDimuonMuonDeltaEtaVsMuonPtBackground"), deltaEta, track.pt(), weightDilepton * weightMuon); + registry.fill(HIST("dileptonSS/h2dDimuonMuonDeltaPhiVsMuonPtBackground"), deltaPhi, track.pt(), weightDilepton * weightMuon); + } } } } diff --git a/PWGDQ/Tasks/mftMchMatcher.cxx b/PWGDQ/Tasks/mftMchMatcher.cxx index 165488fcf7c..825e320f369 100644 --- a/PWGDQ/Tasks/mftMchMatcher.cxx +++ b/PWGDQ/Tasks/mftMchMatcher.cxx @@ -48,6 +48,7 @@ #include #include +#include #include #include #include @@ -143,6 +144,7 @@ DECLARE_SOA_COLUMN(Chi2Glob, chi2Glob, float); DECLARE_SOA_COLUMN(Chi2Match, chi2Match, float); DECLARE_SOA_COLUMN(IsAmbig, isAmbig, bool); DECLARE_SOA_COLUMN(MFTMult, mftMult, int); +DECLARE_SOA_COLUMN(MatchAttempts, matchAttempts, int); DECLARE_SOA_COLUMN(DCAX, dcaX, float); DECLARE_SOA_COLUMN(DCAY, dcaY, float); DECLARE_SOA_COLUMN(McMaskGlob, mcMaskGlob, int); @@ -207,6 +209,7 @@ DECLARE_SOA_TABLE(FwdMatchMLCandidates, "AOD", "FWDMLCAND", fwdmatchcandidates::DCAY, fwdmatchcandidates::IsAmbig, fwdmatchcandidates::MFTMult, + fwdmatchcandidates::MatchAttempts, fwdmatchcandidates::McMaskMCH, fwdmatchcandidates::McMaskMFT, fwdmatchcandidates::McMaskGlob, @@ -265,14 +268,13 @@ struct mftMchMatcher { kMatchTypeWrongNonLeading = 5, kMatchTypeDecayNonLeading = 6, kMatchTypeFakeNonLeading = 7, - kMatchTypeUndefined + kMatchTypeUndefined = 8 }; - double mBzAtMftCenter{0}; o2::globaltracking::MatchGlobalFwd mExtrap; int mRunNumber{0}; // needed to detect if the run changed and trigger update of magnetic field - Service ccdbManager; + Service ccdbManager{}; o2::ccdb::CcdbApi fCCDBApi; o2::parameters::GRPMagField* fGrpMag = nullptr; @@ -288,6 +290,22 @@ struct mftMchMatcher { HistogramRegistry registry{"registry", {}}; + template + o2::dataformats::GlobalFwdTrack trackToGlobalFwd(const T& track, const C& cov) + { + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack fwdtrack; + fwdtrack.setParameters(trackparCov.getParameters()); + fwdtrack.setCovariances(trackparCov.getCovariances()); + return fwdtrack; + } + template bool pDCACut(const T& mchTrack, const C& collision, double nSigmaPDCA) { @@ -316,11 +334,8 @@ struct mftMchMatcher { double pResEffect = sigmaPDCA / (1. - nrp / (1. + nrp)); double slopeResEffect = 535. * slopeRes * p; double sigmaPDCAWithRes = TMath::Sqrt(pResEffect * pResEffect + slopeResEffect * slopeResEffect); - if (pDCA > nSigmaPDCA * sigmaPDCAWithRes) { - return false; - } - return true; + return (pDCA <= nSigmaPDCA * sigmaPDCAWithRes); } template @@ -333,8 +348,9 @@ struct mftMchMatcher { double nSigmaPdcaCut) { // chi2 cut - if (mchTrack.chi2() > chi2Cut) + if (mchTrack.chi2() > chi2Cut) { return false; + } // momentum cut if (mchTrack.p() < pCut) { @@ -373,8 +389,9 @@ struct mftMchMatcher { std::array etaCut) { // chi2 cut - if (mftTrack.chi2() > chi2Cut) + if (mftTrack.chi2() > chi2Cut) { return false; + } // transverse momentum cut if (mftTrack.pt() < pTCut) { @@ -393,8 +410,9 @@ struct mftMchMatcher { template void initCCDB(BC const& bc) { - if (mRunNumber == bc.runNumber()) + if (mRunNumber == bc.runNumber()) { return; + } fGrpMag = ccdbManager->getForTimeStamp(grpmagPath, bc.timestamp()); @@ -470,7 +488,7 @@ struct mftMchMatcher { } } } - for (auto& pairCand : mCandidates) { + for (const auto& pairCand : mCandidates) { fBestMatch[pairCand.second.second] = true; } } @@ -522,8 +540,9 @@ struct mftMchMatcher { bool isPairedMuon(int64_t muonTrackId, const std::vector>& matchablePairs) { for (const auto& [id1, id2] : matchablePairs) { - if (muonTrackId == id1) + if (muonTrackId == id1) { return true; + } } return false; } @@ -542,8 +561,9 @@ struct mftMchMatcher { // search for an MFT track that is associated to the MCH mother particle for (const auto& mftTrack : mftTracks) { // skip tracks that do not have an associated MC particle - if (!mftTrack.has_mcParticle()) + if (!mftTrack.has_mcParticle()) { continue; + } if (mftTrack.mcParticle().globalIndex() == mchMotherParticle.globalIndex()) { return true; @@ -593,14 +613,50 @@ struct mftMchMatcher { return result; } + template + int getMftMchMatchAttempts(EVT const& collisions, + BC const& bcs, + TMUON const& mchTrack, + TMFTS const& mftTracks) + { + if (!mchTrack.has_collision()) { + return 0; + } + const auto& collMch = collisions.rawIteratorAt(mchTrack.collisionId()); + const auto& bcMch = bcs.rawIteratorAt(collMch.bcId()); + + int attempts{0}; + for (const auto& mftTrack : mftTracks) { + if (!mftTrack.has_collision()) { + continue; + } + + const auto& collMft = collisions.rawIteratorAt(mftTrack.collisionId()); + const auto& bcMft = bcs.rawIteratorAt(collMft.bcId()); + + int64_t deltaBc = static_cast(bcMft.globalBC()) - static_cast(bcMch.globalBC()); + double deltaBcNS = o2::constants::lhc::LHCBunchSpacingNS * deltaBc; + double deltaTrackTime = mftTrack.trackTime() - mchTrack.trackTime() + deltaBcNS; + double trackTimeResTot = mftTrack.trackTimeRes() + mchTrack.trackTimeRes(); + + if (std::fabs(deltaTrackTime) > trackTimeResTot) { + continue; + } + attempts += 1; + } + + return attempts; + } template void fillTable(TCOLLS const& collisions, - TBCS const& /*bcs*/, + TBCS const& bcs, TMUONS const& muonTracks, TMFTS const& mftTracks, TCOVS const& mftCovs) { + std::unordered_map matchAttemptsMap; + registry.get(HIST("acceptedEvents"))->Fill(0); // reject a randomly selected fraction of events if (fSamplingFraction < 1.0) { @@ -619,11 +675,11 @@ struct mftMchMatcher { } mftCovIndexes.clear(); - for (auto& mftTrackCov : mftCovs) { + for (const auto& mftTrackCov : mftCovs) { mftCovIndexes[mftTrackCov.matchMFTTrackId()] = mftTrackCov.globalIndex(); } - for (auto muon : muonTracks) { + for (const auto& muon : muonTracks) { // only consider global MFT-MCH-MID matches if (static_cast(muon.trackType()) != 0) { continue; @@ -650,7 +706,7 @@ struct mftMchMatcher { auto mftTime = mfttrack.trackTime() + bc_coll.globalBC() * o2::constants::lhc::LHCBunchSpacingNS; o2::track::TrackParCovFwd mftprop = VarManager::FwdToTrackPar(mfttrack, mfttrackcov); - o2::track::TrackParCovFwd muonprop = VarManager::FwdToTrackPar(muontrack, muontrack); + o2::dataformats::GlobalFwdTrack muonprop = trackToGlobalFwd(muontrack, muontrack); if (fzMatching.value < 0.) { mftprop = VarManager::PropagateFwd(mfttrack, mfttrackcov, fzMatching.value); muonprop = VarManager::PropagateMuon(muontrack, collision, VarManager::kToMatching); @@ -670,6 +726,14 @@ struct mftMchMatcher { bool IsAmbig = (muon.compatibleCollIds().size() != 1); int MFTMult = collision.mftNtracks(); + int matchAttempts = 0; + auto matchAttemptsIt = matchAttemptsMap.find(muontrack.globalIndex()); + if (matchAttemptsIt == matchAttemptsMap.end()) { + matchAttempts = getMftMchMatchAttempts(collisions, bcs, muontrack, mftTracks); + matchAttemptsMap.insert(std::make_pair(static_cast(muontrack.globalIndex()), matchAttempts)); + } else { + matchAttempts = matchAttemptsIt->second; + } auto matchType = kMatchTypeUndefined; if constexpr (isMc) { @@ -789,6 +853,7 @@ struct mftMchMatcher { muon.fwdDcaY(), IsAmbig, MFTMult, + matchAttempts, mcMaskMuon, mcMaskMft, ncMaskGlob, @@ -833,8 +898,8 @@ struct mftMchMatcher { PROCESS_SWITCH(mftMchMatcher, processRD, "process_RD", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(context)}; }; diff --git a/PWGDQ/Tasks/muonGlobalAlignment.cxx b/PWGDQ/Tasks/muonGlobalAlignment.cxx index bdd60ef5717..7014a0ea0c7 100644 --- a/PWGDQ/Tasks/muonGlobalAlignment.cxx +++ b/PWGDQ/Tasks/muonGlobalAlignment.cxx @@ -148,6 +148,8 @@ struct muonGlobalAlignment { Configurable fMftTracksMultiplicityMax{"cfgMftTracksMultiplicityMax", 0, "Maximum number of MFT tracks to be processed per event (zero means no limit)"}; + // Magnetic field position bias + Configurable cfgFieldOriginBiasZ{"cfgFieldOriginBiasZ", 0.0f, "Bias applied to the magnetic field z position"}; Configurable fVertexZshift{"cfgVertexZshift", 0.0f, "Correction to the vertex z position"}; Configurable fDipoleZshift{"cfgDipoleZshift", 0.0f, "Correction to the dipole z position"}; @@ -418,10 +420,8 @@ struct muonGlobalAlignment { ccdbApi.init(configCCDB.ccdburl); mRunNumber = 0; - if (!o2::base::GeometryManager::isGeometryLoaded()) { - LOGF(info, "Load geometry from CCDB"); - ccdbManager->get(configCCDB.geoPath); - } + // configure magnetic field position bias + o2::conf::ConfigurableParam::setValue("FieldOriginBias.z", std::to_string(cfgFieldOriginBiasZ.value)); // Configuration for track fitter const auto& trackerParam = TrackerParam::Instance(); @@ -431,6 +431,9 @@ struct muonGlobalAlignment { trackFitter.useChamberResolution(); mImproveCutChi2 = 2. * configRealign.fSigmaCutImprove * configRealign.fSigmaCutImprove; + // use the Runge-Kutta extrapolation v2 + TrackExtrap::useExtrapV2(); + // Fill table of MCH alignment corrections rapidjson::Document document; // Check that the json is parsed correctly diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.cxx index aba3686f2e8..fa4de63004d 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -1362,6 +1363,7 @@ struct AnalysisSameEventPairing { Configurable GrpLhcIfPath{"grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; Configurable efficiencyPath{"effHistPath", "Users/z/zhxiong/efficiency", "Path on the CCDB for the efficiency histograms"}; Configurable flowPath{"flowPath", "Users/y/yiping/FlowResolution", "Path to the flow resolution object"}; + Configurable phiPath{"phiPath", "Users/h/hxiaoyu/TrackPhi/LHC23", "Path to load phi distribution for track rotation"}; } fConfigCCDB; struct : ConfigurableGroup { @@ -1381,6 +1383,7 @@ struct AnalysisSameEventPairing { Configurable useEfficiencyWeighting{"cfgUseEfficiencyWeighting", false, "Apply efficiency weighting to the pairs from CCDB"}; Configurable efficiencyType{"cfgEfficiencyType", 0, "Type of efficiency to apply from CCDB: 0 no efficiency, 1 pt-cent-costhetastar"}; Configurable useFlowReso{"cfgUseFlowReso", false, "Use remote flow information from CCDB"}; + Configurable usePhiDistribution{"cfgUsePhiDistribution", false, "Use phi distribution to correct track rotation"}; } fConfigOptions; struct : ConfigurableGroup { Configurable applyBDT{"applyBDT", false, "Flag to apply ML selections"}; @@ -1855,6 +1858,18 @@ struct AnalysisSameEventPairing { LOGF(fatal, "Flow resolution histograms not available in CCDB at timestamp=%llu", timestamp); } } + + if (fConfigOptions.usePhiDistribution) { + TString PathPhi = fConfigCCDB.phiPath.value; + TString ccdbPathPhiPosi = Form("%s/hPtPhiPositive", PathPhi.Data()); + TString ccdbPathPhiNega = Form("%s/hPtPhiNegative", PathPhi.Data()); + auto phiPosi = fCCDB->getForTimeStamp(ccdbPathPhiPosi.Data(), timestamp); + auto phiNega = fCCDB->getForTimeStamp(ccdbPathPhiNega.Data(), timestamp); + if (phiPosi == nullptr || phiNega == nullptr) { + LOGF(fatal, "Phi distribution histograms not available in CCDB at timestamp=%llu", timestamp); + } + VarManager::SetPhiMap(phiPosi, phiNega, fConfigOptions.usePhiDistribution.value); + } } // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) diff --git a/PWGEM/Dilepton/Core/DileptonHadronMPC.h b/PWGEM/Dilepton/Core/DileptonHadronMPC.h index ea1740e3ff6..38b45983fb5 100644 --- a/PWGEM/Dilepton/Core/DileptonHadronMPC.h +++ b/PWGEM/Dilepton/Core/DileptonHadronMPC.h @@ -58,7 +58,6 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include -#include #include #include diff --git a/PWGEM/Dilepton/Core/DileptonSV.h b/PWGEM/Dilepton/Core/DileptonSV.h index 4acaf0f6028..8e34fe9f1c6 100644 --- a/PWGEM/Dilepton/Core/DileptonSV.h +++ b/PWGEM/Dilepton/Core/DileptonSV.h @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/PWGEM/Dilepton/Core/DileptonSVMC.h b/PWGEM/Dilepton/Core/DileptonSVMC.h index 863cd3ca7d8..37c58fe8d53 100644 --- a/PWGEM/Dilepton/Core/DileptonSVMC.h +++ b/PWGEM/Dilepton/Core/DileptonSVMC.h @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/PWGEM/Dilepton/Core/SingleTrackQC.h b/PWGEM/Dilepton/Core/SingleTrackQC.h index 0f0fe143a4b..15289d398f2 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQC.h @@ -349,6 +349,7 @@ struct SingleTrackQC { fRegistry.add("Track/positive/hChi2MatchMCHMFT_Pt", "chi2 match MCH-MFT;p_{T,#mu} (GeV/c);chi2/ndf", o2::framework::HistType::kTH2F, {{200, 0, 10}, {200, 0.0f, 100}}, false); fRegistry.add("Track/positive/hMFTClusterMap", "MFT cluster map", o2::framework::HistType::kTH1F, {{1024, -0.5, 1023.5}}, false); fRegistry.add("Track/positive/hdR_Chi2MatchMCHMFT", "dr vs. matching chi2 MCH-MFT;chi2 match MCH-MFT;#DeltaR;", o2::framework::HistType::kTH2F, {{200, 0.0f, 100}, {200, 0, 0.5}}, false); + fRegistry.add("Track/positive/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", o2::framework::HistType::kTH1F, {{100, -5, 5}}, false); fRegistry.addClone("Track/positive/", "Track/negative/"); } } @@ -681,6 +682,7 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/positive/hChi2MatchMCHMFT_Pt"), track.pt(), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/positive/hMFTClusterMap"), track.mftClusterMap()); fRegistry.fill(HIST("Track/positive/hdR_Chi2MatchMCHMFT"), track.chi2MatchMCHMFT(), std::sqrt(deta * deta + dphi * dphi)); + fRegistry.fill(HIST("Track/positive/hLog10Chi2IP"), std::log10(track.chi2IP())); } else { fRegistry.fill(HIST("Track/negative/hs"), track.pt(), track.eta(), track.phi(), dca_xy, weight); fRegistry.fill(HIST("Track/negative/hEtaPhi_MatchMCHMID"), track.phiMatchedMCHMID(), track.etaMatchedMCHMID(), weight); @@ -705,6 +707,7 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/negative/hChi2MatchMCHMFT_Pt"), track.pt(), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/negative/hMFTClusterMap"), track.mftClusterMap()); fRegistry.fill(HIST("Track/negative/hdR_Chi2MatchMCHMFT"), track.chi2MatchMCHMFT(), std::sqrt(deta * deta + dphi * dphi)); + fRegistry.fill(HIST("Track/negative/hLog10Chi2IP"), std::log10(track.chi2IP())); } } diff --git a/PWGEM/Dilepton/Core/SingleTrackQCMC.h b/PWGEM/Dilepton/Core/SingleTrackQCMC.h index b2d1243df6d..222f863e71f 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQCMC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQCMC.h @@ -397,6 +397,7 @@ struct SingleTrackQCMC { fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaEta", "muon #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", o2::framework::HistType::kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaPhi", "muon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); fRegistry.add("Track/PromptLF/positive/hdR_Chi2MatchMCHMFT", "dr vs. matching chi2 MCH-MFT;chi2 match MCH-MFT;#DeltaR;", o2::framework::HistType::kTH2F, {{200, 0.0f, 100}, {200, 0, 0.5}}, false); + fRegistry.add("Track/PromptLF/positive/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", o2::framework::HistType::kTH1F, {{100, -5, 5}}, false); } fRegistry.addClone("Track/PromptLF/positive/", "Track/PromptLF/negative/"); fRegistry.addClone("Track/PromptLF/", "Track/NonPromptLF/"); @@ -793,6 +794,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2MatchMCHMFT_Pt"), track.pt(), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hMFTClusterMap"), track.mftClusterMap()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hdR_Chi2MatchMCHMFT"), track.chi2MatchMCHMFT(), std::sqrt(deta * deta + dphi * dphi)); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hLog10Chi2IP"), std::log10(track.chi2IP())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); @@ -826,6 +828,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2MatchMCHMFT_Pt"), track.pt(), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hMFTClusterMap"), track.mftClusterMap()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hdR_Chi2MatchMCHMFT"), track.chi2MatchMCHMFT(), std::sqrt(deta * deta + dphi * dphi)); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hLog10Chi2IP"), std::log10(track.chi2IP())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPhi"), mctrack.pt(), track.phi() - mctrack.phi()); diff --git a/PWGEM/Dilepton/DataModel/dileptonTables.h b/PWGEM/Dilepton/DataModel/dileptonTables.h index 5c34d437ff9..4178d0c7b89 100644 --- a/PWGEM/Dilepton/DataModel/dileptonTables.h +++ b/PWGEM/Dilepton/DataModel/dileptonTables.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #ifndef PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ diff --git a/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx b/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx index 98035efe8e9..a2917c791e5 100644 --- a/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx +++ b/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx @@ -16,8 +16,10 @@ #include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include #include #include +#include #include using namespace o2; diff --git a/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx index e483a9a7404..19e42b98774 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx @@ -30,6 +30,8 @@ #include +#include + #include #include #include diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx index 210e41414cd..8706432f69d 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -54,6 +54,8 @@ #include #include +#include + using namespace o2; using namespace o2::soa; using namespace o2::framework; diff --git a/PWGEM/Dilepton/Tasks/dimuonV1.cxx b/PWGEM/Dilepton/Tasks/dimuonV1.cxx index db6d97d01ec..747f4e54cd0 100644 --- a/PWGEM/Dilepton/Tasks/dimuonV1.cxx +++ b/PWGEM/Dilepton/Tasks/dimuonV1.cxx @@ -54,6 +54,8 @@ #include #include +#include + struct dimuonV1 { // // Configurables @@ -72,13 +74,14 @@ struct dimuonV1 { o2::framework::ConfigurableAxis ConfMllBins{"ConfMllBins", {o2::framework::VARIABLE_WIDTH, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.3, 1.4, 1.5, 2.00, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, 2.61, 2.62, 2.63, 2.64, 2.65, 2.66, 2.67, 2.68, 2.69, 2.7, 2.71, 2.72, 2.73, 2.74, 2.75, 2.76, 2.77, 2.78, 2.79, 2.8, 2.81, 2.82, 2.83, 2.84, 2.85, 2.86, 2.87, 2.88, 2.89, 2.9, 2.91, 2.92, 2.93, 2.94, 2.95, 2.96, 2.97, 2.98, 2.99, 3., 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6, 3.61, 3.62, 3.63, 3.64, 3.65, 3.66, 3.67, 3.68, 3.69, 3.7, 3.71, 3.72, 3.73, 3.74, 3.75, 3.76, 3.77, 3.78, 3.79, 3.8, 3.81, 3.82, 3.83, 3.84, 3.85, 3.86, 3.87, 3.88, 3.89, 3.9, 3.91, 3.92, 3.93, 3.94, 3.95, 3.96, 3.97, 3.98, 3.99, 4.0, 6.00, 6.10, 6.20, 6.30, 6.40, 6.50, 6.60, 6.70, 6.80, 6.90, 7.00, 7.10, 7.20, 7.30, 7.40, 7.50, 7.60, 7.70, 7.80, 7.90, 8.00, 8.10, 8.20, 8.30, 8.40, 8.50, 8.60, 8.70, 8.80, 8.90, 9.00, 9.10, 9.20, 9.30, 9.40, 9.50, 9.60, 9.70, 9.80, 9.90, 10.00, 10.10, 10.20, 10.30, 10.40, 10.50, 10.60, 10.70, 10.80, 10.90, 11.00, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0}, "mmumu bins for output histograms"}; o2::framework::ConfigurableAxis ConfPtllBins{"ConfPtllBins", {10, 0, 10}, "pTll bins for output histograms"}; - o2::framework::ConfigurableAxis ConfEtallBins{"ConfEtallBins", {30, -5, -2}, "etall bins for output histograms"}; + o2::framework::ConfigurableAxis ConfYllBins{"ConfYllBins", {30, -5, -2}, "yll or etall bins for output histograms"}; o2::framework::ConfigurableAxis ConfUQBins{"ConfUQBins", {400, -1, 1}, "uQ bins for output histograms"}; o2::framework::ConfigurableAxis ConfCentBins{"ConfCentBins", {20, 10, 30}, "centrality bins for output histograms"}; o2::framework::Configurable cfgNrotation{"cfgNrotation", 1, "number of rotation bkg"}; o2::framework::Configurable cfgRandomSeed{"cfgRandomSeed", 1, "randam seed for rotation bkg"}; o2::framework::Configurable cfgRotationMin{"cfgRotationMin", -M_PI / 4, "min. rotation angle for rotation bkg"}; o2::framework::Configurable cfgRotationMax{"cfgRotationMax", +M_PI / 4, "max. rotation angle for rotation bkg"}; + o2::framework::Configurable cfgUseRapidity{"cfgUseRapidity", true, "flag to use rapidity. if false, pseudorapidity"}; EMEventCut fEMEventCut; struct : o2::framework::ConfigurableGroup { @@ -222,7 +225,9 @@ struct dimuonV1 { // pair info const o2::framework::AxisSpec axis_mass{ConfMllBins, "m_{#mu#mu} (GeV/c^{2})"}; const o2::framework::AxisSpec axis_pt{ConfPtllBins, "p_{T,#mu#mu} (GeV/c)"}; - const o2::framework::AxisSpec axis_eta{ConfEtallBins, "#eta_{#mu#mu}"}; + const o2::framework::AxisSpec axis_y{ConfYllBins, "y_{#mu#mu}"}; + const o2::framework::AxisSpec axis_eta{ConfYllBins, "#eta_{#mu#mu}"}; + // const o2::framework::AxisSpec axis_uxQxt{ConfUQBins, "u_{x}Q_{x}^{t}"}; // const o2::framework::AxisSpec axis_uxQxp{ConfUQBins, "u_{x}Q_{x}^{p}"}; // const o2::framework::AxisSpec axis_uyQyt{ConfUQBins, "u_{y}Q_{y}^{t}"}; @@ -235,8 +240,13 @@ struct dimuonV1 { fRegistry.add("Track/hs", "single muon;p_{T} (GeV/c);#eta;#varphi (rad.);sign;", o2::framework::HistType::kTHnSparseD, {{100, 0, 10}, {30, -5, -2}, {36, 0, 2 * M_PI}, {3, -1.5, +1.5}}, true); - fRegistry.add("Pair/same/uls/hs", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_eta, axis_uxQx, axis_uyQy, axis_centrality}, true); - fRegistry.add("Pair/same/uls/hsRotBkg", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_eta}, true); + if (cfgUseRapidity) { + fRegistry.add("Pair/same/uls/hs", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_uxQx, axis_uyQy, axis_centrality}, true); + fRegistry.add("Pair/same/uls/hsRotBkg", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_y}, true); + } else { + fRegistry.add("Pair/same/uls/hs", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_eta, axis_uxQx, axis_uyQy, axis_centrality}, true); + fRegistry.add("Pair/same/uls/hsRotBkg", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_eta}, true); + } // fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); // fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); @@ -326,13 +336,21 @@ struct dimuonV1 { float uyQyp = std::sin(1.f * phi) * collision.qyZDCA(); if (t1.sign() * t2.sign() < 0) { // ULS - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), v12.Eta(), uxQxp - uxQxt, uyQyp - uyQyt, centrality, weight); + if (cfgUseRapidity) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), uxQxp - uxQxt, uyQyp - uyQyt, centrality, weight); + } else { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), v12.Eta(), uxQxp - uxQxt, uyQyp - uyQyt, centrality, weight); + } for (int i = 0; i < cfgNrotation; i++) { float dphi = distDPhi(engine); ROOT::Math::PtEtaPhiMVector v2rot(t2.pt(), t2.eta(), RecoDecay::constrainAngle(t2.phi() + M_PI + dphi, 0, 1U), o2::constants::physics::MassMuon); ROOT::Math::PtEtaPhiMVector v12bkg = v1 + v2rot; - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hsRotBkg"), v12bkg.M(), v12bkg.Pt(), v12bkg.Eta(), weight * 1.f / static_cast(cfgNrotation)); + if (cfgUseRapidity) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hsRotBkg"), v12bkg.M(), v12bkg.Pt(), v12bkg.Rapidity(), weight * 1.f / static_cast(cfgNrotation)); + } else { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hsRotBkg"), v12bkg.M(), v12bkg.Pt(), v12bkg.Eta(), weight * 1.f / static_cast(cfgNrotation)); + } } // } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ diff --git a/PWGEM/PhotonMeson/Core/DalitzEECut.h b/PWGEM/PhotonMeson/Core/DalitzEECut.h index 49e0397b661..09df413654a 100644 --- a/PWGEM/PhotonMeson/Core/DalitzEECut.h +++ b/PWGEM/PhotonMeson/Core/DalitzEECut.h @@ -21,6 +21,7 @@ #include #include +#include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h index 37d1810ca92..86227bfe02c 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h b/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h index 32f1b59d133..db448562f61 100644 --- a/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_CORE_PHOSPHOTONCUT_H_ #include +#include #include diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h index 9964f1d0333..5da73b42f97 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h index f8ee7db2af0..a8270f7abc6 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.h b/PWGEM/PhotonMeson/Core/V0PhotonCut.h index d5c8e30e236..369d3a55521 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/DataModel/ConversionMl.h b/PWGEM/PhotonMeson/DataModel/ConversionMl.h new file mode 100644 index 00000000000..656a597829f --- /dev/null +++ b/PWGEM/PhotonMeson/DataModel/ConversionMl.h @@ -0,0 +1,64 @@ +// 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 ConversionMl.h +/// \brief This header provides the table definitions to store cluster pairs to analyze and potentially tag late conversions +/// \author Marvin Hemmer (marvin.hemmer@cern.ch) - Goethe University Frankfurt + +#ifndef PWGEM_PHOTONMESON_DATAMODEL_CONVERSIONML_H_ +#define PWGEM_PHOTONMESON_DATAMODEL_CONVERSIONML_H_ + +#include + +#include + +namespace o2::aod +{ + +namespace convtag +{ +DECLARE_SOA_COLUMN(PMEvent, pmevent, int); //! index column to the pmevent +DECLARE_SOA_COLUMN(Minv, minv, float); //! invariant mass of the pair +DECLARE_SOA_COLUMN(HarmonicET, harmonicET, float); //! ET1 * ET2 / (ET1 + ET2) in GeV +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! difference in eta of the two clusters +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! difference in phi of the two clusters in rad +DECLARE_SOA_COLUMN(Phiv, phiv, float); //! angle between plane spanned by the two clusters and the plane between the B-field direction the their combined momentum +DECLARE_SOA_COLUMN(E1, e1, float); //! energy of first cluster in GeV +DECLARE_SOA_COLUMN(E2, e2, float); //! energy of second cluster in GeV +DECLARE_SOA_COLUMN(M021, m021, float); //! M02 of first cluster +DECLARE_SOA_COLUMN(M022, m022, float); //! M02 of second cluster +DECLARE_SOA_COLUMN(Time1, time1, float); //! time of first cluster in ns +DECLARE_SOA_COLUMN(Time2, time2, float); //! time of second cluster in ns +DECLARE_SOA_COLUMN(NCells1, nCells1, uint8_t); //! NCells of first cluster +DECLARE_SOA_COLUMN(NCells2, nCells2, uint8_t); //! NCells of second cluster +DECLARE_SOA_COLUMN(TruthLabel, truthLabel, int8_t); //! truth label for ML training -- see TruthClass enum for the mapping +DECLARE_SOA_COLUMN(CentOrMult, centOrMult, float); //! centrality or multiplicity value of the collision +DECLARE_SOA_COLUMN(Purity1, purity1, float); // leading-contributor amplitude fraction, cluster 1 +DECLARE_SOA_COLUMN(Purity2, purity2, float); // leading-contributor amplitude fraction, cluster 2 + +} // namespace convtag +DECLARE_SOA_TABLE(ConvTagCandidates, "AOD", "CONVTAGCAND", + convtag::PMEvent, + convtag::Minv, convtag::HarmonicET, convtag::DeltaEta, convtag::DeltaPhi, convtag::Phiv, + convtag::E1, convtag::E2, convtag::M021, convtag::M022, + convtag::Time1, convtag::Time2, convtag::NCells1, convtag::NCells2, + convtag::TruthLabel, convtag::CentOrMult); + +DECLARE_SOA_TABLE_VERSIONED(ConvTagCandidates_001, "AOD", "CONVTAGCAND", 1, + convtag::PMEvent, + convtag::Minv, convtag::HarmonicET, convtag::DeltaEta, convtag::DeltaPhi, convtag::Phiv, + convtag::E1, convtag::E2, convtag::M021, convtag::M022, + convtag::Time1, convtag::Time2, convtag::NCells1, convtag::NCells2, convtag::Purity1, convtag::Purity2, + convtag::TruthLabel, convtag::CentOrMult); + +} // namespace o2::aod + +#endif // PWGEM_PHOTONMESON_DATAMODEL_CONVERSIONML_H_ diff --git a/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h b/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h index 79219f35fa4..d9d2485206d 100644 --- a/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h +++ b/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -46,7 +47,7 @@ enum Observable { }; // Values in tables are stored in downscaled format to save disk space -const float downscalingFactors[nObservables]{ +constexpr std::array downscalingFactors{ 1E0, // Cluster definition 1E3, // Cluster energy 1E4, // Cluster eta diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index 9ef4b45727b..ca46c23329f 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -102,23 +102,31 @@ using V0LegMCLabel = V0LegMCLabels::iterator; // 3. EMEMCClusterMCLabels: Vector of EM MC particle ID of largest contributor to cluster namespace emcclustermclabel { -DECLARE_SOA_ARRAY_INDEX_COLUMN(McParticle, emmcparticle) //! +DECLARE_SOA_ARRAY_INDEX_COLUMN(McParticle, mcParticle) //! Array of indice of McParticles +DECLARE_SOA_COLUMN(Amplitude, amplitude, std::vector); //! vector of aplitudes stored in cluster. Ordering is identical to the ordering of EMMCParticleId } // namespace emcclustermclabel // NOTE: MC labels. This table has one vector of global mc particle ids for each reconstructed emc cluster (joinable with emccluster table) DECLARE_SOA_TABLE(EMCClusterMCLabels, "AOD", "EMCClsMCLABEL", //! emcclustermclabel::McParticleIds); -using EMCClusterMCLabel = EMCClusterMCLabels::iterator; + +DECLARE_SOA_TABLE_VERSIONED(EMCClusterMCLabels_001, "AOD", "EMCClsMCLABEL", 1, //! + emcclustermclabel::McParticleIds, emcclustermclabel::Amplitude); +using EMCClusterMCLabel = EMCClusterMCLabels_001::iterator; namespace ememcclustermclabel { -DECLARE_SOA_ARRAY_INDEX_COLUMN(EMMCParticle, emmcparticle); //! +DECLARE_SOA_ARRAY_INDEX_COLUMN(EMMCParticle, emmcparticle); //! Array of indice of EmMcParticles +DECLARE_SOA_COLUMN(Amplitude, amplitude, std::vector); //! vector of aplitudes stored in cluster. Ordering is identical to the ordering of EMMCParticleId } // namespace ememcclustermclabel // NOTE: MC labels. This table has a vector of entries for each reconstructed emc cluster (joinable with emccluster table) DECLARE_SOA_TABLE(EMEMCClusterMCLabels, "AOD", "EMEMCClsMCLABEL", //! ememcclustermclabel::EMMCParticleIds); -using EMEMCClusterMCLabel = EMEMCClusterMCLabels::iterator; + +DECLARE_SOA_TABLE_VERSIONED(EMEMCClusterMCLabels_001, "AOD", "EMEMCClsMCLABEL", 1, //! + ememcclustermclabel::EMMCParticleIds, ememcclustermclabel::Amplitude); +using EMEMCClusterMCLabel = EMEMCClusterMCLabels_001::iterator; namespace v0leg { @@ -146,9 +154,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t i } if (nl > 0) { return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; } + return 0; }); DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32_t itsClusterSizes) -> float { int total_cluster_size = 0, nl = 0; @@ -161,9 +168,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32 } if (nl > 0) { return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; } + return 0; }); DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32_t itsClusterSizes) -> float { int total_cluster_size = 0, nl = 0; @@ -176,9 +182,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32 } if (nl > 0) { return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; } + return 0; }); } // namespace v0leg DECLARE_SOA_TABLE(V0Legs_000, "AOD", "V0LEG", //! diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx index 26d2f62bf6c..7eb9d556d85 100644 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -10,8 +10,8 @@ // or submit itself to any jurisdiction. /// \file associateMCinfoPhoton.cxx -/// \brief This code produces reduced events for photon analyses -/// \author Daiki Sekihata (daiki.sekihata@cern.ch) +/// \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/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include +#include #include #include #include @@ -56,7 +58,7 @@ using namespace o2::constants::physics; using MyCollisionsMC = soa::Join; using TracksMC = soa::Join; using FwdTracksMC = soa::Join; -using MyEMCClusters = soa::Join; +using MyEMCClusters = soa::Join; struct Counter { int particles{0}; @@ -76,7 +78,7 @@ struct AssociateMCInfoPhoton { Produces emmcparticles; Produces v0legmclabels; Produces emprimaryelectronmclabels; - Produces ememcclustermclabels; + Produces ememcclustermclabels; Produces binnedGenPt; @@ -99,6 +101,7 @@ struct AssociateMCInfoPhoton { // !!Don't change pt,eta,y binning. These binnings have to be consistent with binned data at analysis.!! std::vector ptbins; + ptbins.reserve(72); for (int i = 0; i < 2; i++) { // o2-linter: disable=magic-number (just numbers for binning) ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c } @@ -115,7 +118,7 @@ struct AssociateMCInfoPhoton { const AxisSpec axisRapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; static constexpr uint NParticleNames = 9; - static constexpr std::string_view ParticleNames[NParticleNames] = { + static constexpr std::array ParticleNames = { "Gamma", "Pi0", "Eta", "Omega", "Phi", "ChargedPion", "ChargedKaon", "K0S", "Lambda"}; @@ -266,8 +269,9 @@ struct AssociateMCInfoPhoton { genGamma[binNumber]++; break; case PDG_t::kPi0: - if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) { continue; + } registry.fill(HIST("Generated/h2PtY_Pi0"), mcParticle.pt(), std::fabs(mcParticle.y())); genPi0[binNumber]++; if (isMesonAccepted) { @@ -275,8 +279,9 @@ struct AssociateMCInfoPhoton { } break; case Pdg::kEta: - if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) { continue; + } registry.fill(HIST("Generated/h2PtY_Eta"), mcParticle.pt(), std::fabs(mcParticle.y())); genEta[binNumber]++; if (isMesonAccepted) { @@ -290,7 +295,7 @@ struct AssociateMCInfoPhoton { } // end of mc track loop // make an entry for this MC event only if it was not already added to the table - if (!(fEventLabels.find(mcCollisionIter.globalIndex()) != fEventLabels.end())) { + if (!fEventLabels.contains(mcCollisionIter.globalIndex())) { mcevents(mcCollisionIter.globalIndex(), mcCollisionIter.generatorsID(), mcCollisionIter.posX(), mcCollisionIter.posY(), mcCollisionIter.posZ(), mcCollisionIter.impactParameter(), mcCollisionIter.eventPlaneAngle()); fEventLabels[mcCollisionIter.globalIndex()] = fCounter.events; fCounter.events++; @@ -437,15 +442,17 @@ struct AssociateMCInfoPhoton { mcCollisionIter.setCursor(collisionIter.mcCollisionId()); // TODO: test - if (emccluster.emmcparticleIds().size() <= 0) { + if (emccluster.mcParticleIds().size() <= 0) { continue; } std::vector vEmcMcParticleIds; + std::vector vAmplitudes; - vEmcMcParticleIds.reserve(emccluster.emmcparticleIds().size()); + vEmcMcParticleIds.reserve(emccluster.mcParticleIds().size()); + vAmplitudes.reserve(emccluster.mcParticleIds().size()); - for (const auto& emcParticleId : emccluster.emmcparticleIds()) { - mcPhoton.setCursor(emcParticleId); + for (size_t iCont = 0; iCont < emccluster.mcParticleIds().size(); iCont++) { + mcPhoton.setCursor(emccluster.mcParticleIds()[iCont]); // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack auto [iter, isNew] = fNewLabels.try_emplace(mcPhoton.globalIndex(), fCounter.particles); @@ -455,6 +462,7 @@ struct AssociateMCInfoPhoton { fCounter.particles++; } vEmcMcParticleIds.emplace_back(iter->second); + vAmplitudes.emplace_back(emccluster.amplitude()[iCont]); // ememcclustermclabels(fNewLabels.find(mcPhoton.index())->second); // Next, store mother-chain of this reconstructed track. @@ -464,7 +472,7 @@ struct AssociateMCInfoPhoton { } selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter, fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter); } // end of loop over mc particles of the current emc cluster - ememcclustermclabels(vEmcMcParticleIds); + ememcclustermclabels(vEmcMcParticleIds, vAmplitudes); } // end of em emc cluster loop } @@ -624,8 +632,8 @@ struct AssociateMCInfoPhoton { PROCESS_SWITCH(AssociateMCInfoPhoton, processDummy, "processDummy", true); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"associate-mc-info-photon"})}; + adaptAnalysisTask(context, TaskName{"associate-mc-info-photon"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx index 75838125d69..d8eae0d3617 100644 --- a/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx +++ b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/TableProducer/createPCM.cxx b/PWGEM/PhotonMeson/TableProducer/createPCM.cxx index 70457782ae6..539ea496a5e 100644 --- a/PWGEM/PhotonMeson/TableProducer/createPCM.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createPCM.cxx @@ -12,6 +12,7 @@ /// \file createPCM.cxx /// \brief This code produces photon data tables. /// \author Daiki Sekihata , Tokyo +/// \note legacy code, please use the photonconversionbuilder tasks. #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -113,9 +115,9 @@ struct createPCM { Configurable max_r_req_its{"max_r_req_its", 16.0, "min Rxy for V0 with ITS hits"}; Configurable min_r_tpconly{"min_r_tpconly", 32.0, "min Rxy for V0 with TPConly tracks"}; - int mRunNumber; - float d_bz; - Service ccdb; + int mRunNumber = 0; + float d_bz = 0; + Service ccdb{}; o2::base::MatLayerCylSet* lut = nullptr; o2::vertexing::DCAFitterN<2> fitter; // Material correction in the DCA fitter @@ -213,7 +215,7 @@ struct createPCM { } } - template + template bool reconstructV0(TTrack const& ele, TTrack const& pos) { bool isITSonly_pos = pos.hasITS() && !pos.hasTPC(); @@ -257,7 +259,7 @@ struct createPCM { return false; } - float xyz[3] = {0.f, 0.f, 0.f}; + std::array xyz = {0.f, 0.f, 0.f}; Vtx_recalculation(o2::base::Propagator::Instance(), pos, ele, xyz, matCorr); float recalculatedVtxR = std::sqrt(std::pow(xyz[0], 2) + std::pow(xyz[1], 2)); // LOGF(info, "recalculated vtx : x = %f , y = %f , z = %f", xyz[0], xyz[1], xyz[2]); @@ -275,7 +277,7 @@ struct createPCM { return true; } - template + template void fillV0Table(TCollision const& collision, TTrack const& ele, TTrack const& pos, const bool filltable) { std::array pVtx = {collision.posX(), collision.posY(), collision.posZ()}; @@ -323,7 +325,7 @@ struct createPCM { } registry.fill(HIST("hV0xy"), svpos[0], svpos[1]); // this should have worst resolution - float xyz_tmp[3] = {0.f, 0.f, 0.f}; + std::array xyz_tmp = {0.f, 0.f, 0.f}; Vtx_recalculation(o2::base::Propagator::Instance(), pos, ele, xyz_tmp, matCorr); registry.fill(HIST("hV0xy_recalculated"), xyz_tmp[0], xyz_tmp[1]); // this should have good resolution @@ -343,7 +345,7 @@ struct createPCM { } std::pair> its_ib_Requirement = {0, {0, 1, 2}}; // no hit on 3 ITS ib layers. - template + template bool isSelected(TTrack const& track) { if (track.pt() < minpt || std::abs(track.eta()) > maxeta) { @@ -420,7 +422,7 @@ struct createPCM { // registry.fill(HIST("hEventCounter"), 1); int32_t min_sw = std::max(static_cast(0), collision.globalIndex()); - int32_t max_sw = std::min(static_cast(min_sw + nsw), static_cast(collisions.size())); + int32_t max_sw = std::min(static_cast(min_sw + nsw), collisions.size()); // LOGF(info, "orphan_posTracks.size() = %d, orphan_negTracks.size() = %d", orphan_posTracks.size(), orphan_negTracks.size()); negTracks_sw.reserve(max_sw - min_sw); @@ -477,7 +479,7 @@ struct createPCM { vec_cospa.reserve(max_sw - min_sw); for (int32_t isw = min_sw; isw < max_sw; isw++) { auto collision_in_sw = collisions.rawIteratorAt(isw); - if (cospa_map.find(std::make_tuple(pos.globalIndex(), ele.globalIndex(), collision_in_sw.globalIndex())) != cospa_map.end()) { + if (cospa_map.contains(std::make_tuple(pos.globalIndex(), ele.globalIndex(), collision_in_sw.globalIndex()))) { vec_cospa.emplace_back(cospa_map[std::make_tuple(pos.globalIndex(), ele.globalIndex(), collision_in_sw.globalIndex())]); } else { vec_cospa.emplace_back(-999.f); @@ -516,7 +518,7 @@ struct createPCM { } } // end of pca_map loop - if (is_closest_v0 && used_pair_map.find(std::make_pair(pos.globalIndex(), ele.globalIndex())) == used_pair_map.end()) { + if (is_closest_v0 && !used_pair_map.contains(std::make_pair(pos.globalIndex(), ele.globalIndex()))) { // LOGF(info, "store : pos.globalIndex() = %d , ele.globalIndex() = %d , collision.globalIndex() = %d , cospa = %f , pca = %f", std::get<0>(key), std::get<1>(key), std::get<2>(key), value, pca_map[key]); fillV0Table(collision_most_prob, ele, pos, true); used_pair_map[std::make_pair(pos.globalIndex(), ele.globalIndex())] = true; @@ -563,7 +565,7 @@ struct createPCM { if (ele.sign() < 0) { fillV0Table(collision, ele, pos, true); } else { - fillV0Table(collision, pos, ele, true); + fillV0Table(collision, pos, ele, true); // NOLINT(readability-suspicious-call-argument) in case the ele is actually positivley charged } } } // end of collision loop @@ -571,8 +573,8 @@ struct createPCM { PROCESS_SWITCH(createPCM, processTrkCollAsso, "create V0s with track-to-collision associator", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"v0-finder"})}; + adaptAnalysisTask(context, TaskName{"v0-finder"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx b/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx index 57a551a40c1..05695b42850 100644 --- a/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx +++ b/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index 9a0ae99daa4..f91611d3c93 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -52,6 +52,7 @@ #include #include #include +#include #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) @@ -62,6 +63,8 @@ #include #include +#include + #include #include #include @@ -69,7 +72,9 @@ #include #include #include +#include #include +#include #include #include @@ -94,6 +99,50 @@ enum MatCorrType { LUT = 2 }; +enum TrackPropMode { + kProper = 0, + kFast = 1, + kBoth = 2 +}; + +enum V0DeduplicationMode { + Pairwise = 0, // old algorithm + GreedyMatching = 1 // new algorithm +}; + +// Struct needed for deduplication mode 1. Used to keep track of v0 properties and a score based on pca and cosPA +struct V0CandidateHelper { + int v0ID = -1; + int colID = -1; + int posID = -1; + int eleID = -1; + float cosPA = -1.f; + float pca = -1.f; + float score = -1.f; + + V0CandidateHelper() = default; + + V0CandidateHelper(int v0, int col, int pos, int ele, float cpa, float p, float s) + : v0ID(v0), colID(col), posID(pos), eleID(ele), cosPA(cpa), pca(p), score(s) + { + } + + bool operator==(const V0CandidateHelper& other) const + { + return score == other.score; + } + + bool operator<(const V0CandidateHelper& other) const + { + return score < other.score; + } + + bool operator>(const V0CandidateHelper& other) const + { + return score > other.score; + } +}; + struct PhotonConversionBuilder { Produces v0photonskf; Produces v0legs; @@ -114,6 +163,9 @@ struct PhotonConversionBuilder { // Operation and minimisation criteria Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + Configurable modeTrackPropagation{"modeTrackPropagation", 0, "0: use real track propagation, including material, 1: use fast approximation using only geometry, 2: Use real track propagation and make comparison to fast propagation (only for debugging and testing)"}; + Configurable deduplicationMode{"deduplicationMode", 0, "0: Pairwise deduplication, 1: Based on Greedy matching (best score wins)"}; + Configurable deduplicationScoreWeight{"deduplicationScoreWeight", 0.5f, "0.:only pca goes into the score, 1: only cosPA goes itno score, any number in between is a mix of pca and cosPA"}; // single track cuts Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; @@ -325,6 +377,22 @@ struct PhotonConversionBuilder { registry.add("V0/hBDTScoreAfterCutVsPt", "BDT score after cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); } } + + // Compare proper propagation and fast geometrical propagation + if (modeTrackPropagation == TrackPropMode::kBoth) { + registry.add("V0Leg/hDCAxyPropagationCompare", "Comparison of DCA_{xy} propagation;DCA_{xy} (cm) proper propagation; DCA_{xy} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}}); + registry.add("V0Leg/hDCAzPropagationCompare", "Comparison of DCA_{z} propagation;DCA_{z} (cm) proper propagation; DCA_{z} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}}); + registry.add("V0/hPhivPropagationCompare", "Comparison of #phi_{v};#phi_{v} proper propagation; #phi_{v} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}}); + registry.add("V0/hPsiPairPropagationCompare", "Comparison of #Psi_{pair};#Psi_{pair} proper propagation; #Psi_{pair} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}}); + } + + // Make sure the deduplicationScoreWeight is between 0 and 1 + if (deduplicationScoreWeight > 1.f) { // o2-linter: disable=magic-number (score has to be below unity) + LOG(warning) << "deduplicationScoreWeight is larger than unity which is not allowed"; + } + if (deduplicationScoreWeight < 0.f) { // o2-linter: disable=magic-number (score has to be above zero) + LOG(warning) << "deduplicationScoreWeight is smaller than zero which is not allowed"; + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -555,8 +623,23 @@ struct PhotonConversionBuilder { return; } auto pTrackC = pTrack; + o2::math_utils::Point3D vtxPrim{ + collision.posX(), + collision.posY(), + collision.posZ()}; + if (modeTrackPropagation != TrackPropMode::kProper) { + dcaInfo = CalculateDCAFast(pTrackC, vtxPrim, d_bz); + } pTrackC.setPID(o2::track::PID::Electron); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo); + + std::array dcaInfoFast = dcaInfo; + if (modeTrackPropagation != TrackPropMode::kFast) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo); + if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { + registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]); + registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]); + } + } auto posdcaXY = dcaInfo[0]; auto posdcaZ = dcaInfo[1]; @@ -566,8 +649,19 @@ struct PhotonConversionBuilder { return; } auto nTrackC = nTrack; + if (modeTrackPropagation != TrackPropMode::kProper) { + dcaInfo = CalculateDCAFast(nTrackC, vtxPrim, d_bz); + } nTrackC.setPID(o2::track::PID::Electron); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo); + + dcaInfoFast = dcaInfo; + if (modeTrackPropagation != TrackPropMode::kFast) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo); + if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { + registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]); + registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]); + } + } auto eledcaXY = dcaInfo[0]; auto eledcaZ = dcaInfo[1]; @@ -576,7 +670,7 @@ struct PhotonConversionBuilder { } std::array xyz = {0.f, 0.f, 0.f}; - Vtx_recalculationParCov(o2::base::Propagator::Instance(), pTrack, nTrack, xyz.data(), matCorr); + Vtx_recalculationParCov(o2::base::Propagator::Instance(), pTrack, nTrack, xyz, matCorr); float rxy_tmp = RecoDecay::sqrtSumOfSquares(xyz[0], xyz[1]); if (rxy_tmp > maxX + margin_r_tpc) { return; @@ -587,30 +681,68 @@ struct PhotonConversionBuilder { float phiv = 999.f; float psipair = 999.f; + float phivFast = 999.f; + float psipairFast = 999.f; float baseR = std::hypot(xyz[0], xyz[1]); - std::array offsetsR = {propV0LegsRadius, 30.f, 10.f}; - bool pPropagatedSuccess = false; - bool nPropagatedSuccess = false; - auto pTrackProp = pTrack; - auto nTrackProp = nTrack; - for (const float& offsetR : offsetsR) { - pTrackProp = pTrack; - pTrackProp.setPID(o2::track::PID::Electron); - nTrackProp = nTrack; - nTrackProp.setPID(o2::track::PID::Electron); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo); - pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR); - nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR); - if (pPropagatedSuccess && nPropagatedSuccess) { - KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); - KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); - phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz); - psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz()); - break; + // This method uses the track Helix instead of the full propagation. + // Hence, it is only an approximation but much faster + if (modeTrackPropagation != TrackPropMode::kProper) { + + o2::track::TrackAuxPar helixPosEle(nTrack, d_bz); + o2::track::TrackAuxPar helixPosPos(pTrack, d_bz); + + float diffX = helixPosEle.xC - helixPosPos.xC; + float diffY = helixPosEle.yC - helixPosPos.yC; + auto phiHelix = RecoDecay::constrainAngle(std::atan2(diffY, diffX) - o2::constants::math::PI / 2.); + + // Electron + float arcLenghtEle = helixPosEle.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosEle.rC) * helixPosEle.rC : o2::constants::math::PI / 2.2 * helixPosEle.rC; // This assumes that the photon momentum vector is a tangent of the circle + auto propTrackEle = getPropMomentumFromTrackHelix(arcLenghtEle, ele, helixPosEle, d_bz / 10., phiHelix - ele.phi()); + // Positron + float arcLenghtPos = helixPosPos.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosPos.rC) * helixPosPos.rC : o2::constants::math::PI / 2.2 * helixPosPos.rC; // This assumes that the photon momentum vector is a tangent of the circle + auto propTrackPos = getPropMomentumFromTrackHelix(arcLenghtPos, pos, helixPosPos, d_bz / 10., phiHelix - pos.phi()); + + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2], pos.sign(), ele.sign(), d_bz); + psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2]); + + // Store values for later comparison + phivFast = phiv; + psipairFast = psipair; + } + // This uses the full propagation including material effects + if (modeTrackPropagation != TrackPropMode::kFast) { + std::array offsetsR = {propV0LegsRadius, 30.f, 10.f}; + bool pPropagatedSuccess = false; + bool nPropagatedSuccess = false; + auto pTrackProp = pTrack; + auto nTrackProp = nTrack; + for (const auto& offsetR : offsetsR) { + pTrackProp = pTrack; + pTrackProp.setPID(o2::track::PID::Electron); + nTrackProp = nTrack; + nTrackProp.setPID(o2::track::PID::Electron); + + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo); + + pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR); + nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR); + + if (pPropagatedSuccess && nPropagatedSuccess) { + KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); + KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz); + psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz()); + break; + } + LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset."; + } + if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { + registry.fill(HIST("V0/hPhivPropagationCompare"), phiv, phivFast); + registry.fill(HIST("V0/hPsiPairPropagationCompare"), psipair, psipairFast); } - LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset."; } + if (phiv == 999.f || psipair == 999.f) { LOG(debug) << "Propagation failed for all radii (" << propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f)."; } @@ -774,6 +906,10 @@ struct PhotonConversionBuilder { pca_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = v0photoncandidate.getPCA(); cospa_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = v0photoncandidate.getCosPA(); + const auto score = getScoreV0(v0photoncandidate.getCosPA(), v0photoncandidate.getPCA(), deduplicationScoreWeight); + V0CandidateHelper v0Helper(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex(), v0photoncandidate.getCosPA(), v0photoncandidate.getPCA(), score); + vecV0Dedup.emplace_back(v0Helper); + if (applyPCMMl) { bool isSelectedML = false; std::vector mlInputFeatures = emMlResponse.getInputFeatures(v0photoncandidate, pos, ele); @@ -871,12 +1007,13 @@ struct PhotonConversionBuilder { Preslice perCollision = o2::aod::v0::collisionId; std::map, float> pca_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca std::map, float> cospa_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa + std::vector vecV0Dedup; // vector with all V0Candidates that is used to sort them by score (see struct V0CandidateHelper for more details of content) std::vector> stored_v0Ids; // (pos.globalIndex(), ele.globalIndex()) std::vector> stored_fullv0Ids; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) std::unordered_map nv0_map; // map collisionId -> nv0 template - void build(TCollisions const& collisions, TV0s const& v0s, TTracks const&, TBCs const&) + void build(TCollisions const& collisions, TV0s const& v0s, TTracks const& tracks, TBCs const&) { for (const auto& collision : collisions) { if constexpr (isMC) { @@ -903,6 +1040,7 @@ struct PhotonConversionBuilder { updateCCDB(bc); // delay update until is needed + vecV0Dedup.reserve(30000); // rough estimate for number of V0s per DF const auto& v0s_per_coll = v0s.sliceBy(perCollision, collision.globalIndex()); // LOGF(info, "n v0 = %d", v0s_per_coll.size()); for (const auto& v0 : v0s_per_coll) { @@ -915,56 +1053,99 @@ struct PhotonConversionBuilder { stored_fullv0Ids.reserve(pca_map.size()); // number of photon candidates per DF // find minimal pca - for (const auto& [key, value] : pca_map) { - auto v0Id = std::get<0>(key); - auto collisionId = std::get<1>(key); - auto posId = std::get<2>(key); - auto eleId = std::get<3>(key); - float v0pca = value; - float cospa = cospa_map[key]; - bool is_closest_v0 = true; - bool is_most_aligned_v0 = true; - - for (const auto& [key_tmp, value_tmp] : pca_map) { - auto v0Id_tmp = std::get<0>(key_tmp); - auto collisionId_tmp = std::get<1>(key_tmp); - auto posId_tmp = std::get<2>(key_tmp); - auto eleId_tmp = std::get<3>(key_tmp); - float v0pca_tmp = value_tmp; - float cospa_tmp = cospa_map[key_tmp]; - - if (v0Id == v0Id_tmp) { // skip exactly the same v0 + if (deduplicationMode == V0DeduplicationMode::Pairwise) { + for (const auto& [key, value] : pca_map) { + auto v0Id = std::get<0>(key); + auto collisionId = std::get<1>(key); + auto posId = std::get<2>(key); + auto eleId = std::get<3>(key); + float v0pca = value; + float cospa = cospa_map[key]; + bool is_closest_v0 = true; + bool is_most_aligned_v0 = true; + + for (const auto& [key_tmp, value_tmp] : pca_map) { + auto v0Id_tmp = std::get<0>(key_tmp); + auto collisionId_tmp = std::get<1>(key_tmp); + auto posId_tmp = std::get<2>(key_tmp); + auto eleId_tmp = std::get<3>(key_tmp); + float v0pca_tmp = value_tmp; + float cospa_tmp = cospa_map[key_tmp]; + + if (v0Id == v0Id_tmp) { // skip exactly the same v0 + continue; + } + + if (collisionId != collisionId_tmp && eleId == eleId_tmp && posId == posId_tmp && cospa < cospa_tmp) { // same ele and pos, but attached to different collision + // LOGF(info, "!reject! | collision id = %d | posid1 = %d , eleid1 = %d , posid2 = %d , eleid2 = %d , cospa1 = %f , cospa2 = %f", collisionId, posId, eleId, posId_tmp, eleId_tmp, cospa, cospa_tmp); + is_most_aligned_v0 = false; + break; + } + + if ((eleId == eleId_tmp || posId == posId_tmp) && v0pca > v0pca_tmp) { + // LOGF(info, "!reject! | collision id = %d | posid1 = %d , eleid1 = %d , posid2 = %d , eleid2 = %d , pca1 = %f , pca2 = %f", collisionId, posId, eleId, posId_tmp, eleId_tmp, v0pca, v0pca_tmp); + is_closest_v0 = false; + break; + } + } // end of pca_map tmp loop + + bool is_stored = std::find(stored_v0Ids.begin(), stored_v0Ids.end(), std::make_pair(posId, eleId)) != stored_v0Ids.end(); + if (is_closest_v0 && is_most_aligned_v0 && !is_stored) { + // auto v0 = v0s.rawIteratorAt(v0Id); + // auto collision = collisions.rawIteratorAt(collisionId); + // auto pos = tracks.rawIteratorAt(posId); + // auto ele = tracks.rawIteratorAt(eleId); + // LOGF(info, "!accept! | collision id = %d | v0id1 = %d , posid1 = %d , eleid1 = %d , pca1 = %f , cospa = %f", collisionId, v0Id, posId, eleId, v0pca, cospa); + + // fillV0Table(v0, true); + stored_v0Ids.emplace_back(std::make_pair(posId, eleId)); + stored_fullv0Ids.emplace_back(std::make_tuple(v0Id, collisionId, posId, eleId)); + nv0_map[collisionId]++; + } + } // end of pca_map loop + // LOGF(info, "pca_map.size() = %d", pca_map.size()); + } else { + // Sort best candidates first, depending on score + std::sort(vecV0Dedup.begin(), vecV0Dedup.end()); + // container to keep track of which electron and positron tracks have already been used + std::vector usedLegs(tracks.size(), false); + + // clear output containers + stored_v0Ids.clear(); + stored_fullv0Ids.clear(); + nv0_map.clear(); + + // Loop over all v0s, starting with the one with the best score + // If a v0 contains a track that is already in another (better) V0 candidate, skip V0 + for (const auto& v0Cand : vecV0Dedup) { + // Skip if one of the tracks is already used + if (usedLegs[v0Cand.posID] || usedLegs[v0Cand.eleID]) { continue; } - if (collisionId != collisionId_tmp && eleId == eleId_tmp && posId == posId_tmp && cospa < cospa_tmp) { // same ele and pos, but attached to different collision - // LOGF(info, "!reject! | collision id = %d | posid1 = %d , eleid1 = %d , posid2 = %d , eleid2 = %d , cospa1 = %f , cospa2 = %f", collisionId, posId, eleId, posId_tmp, eleId_tmp, cospa, cospa_tmp); - is_most_aligned_v0 = false; - break; - } + // Accept candidate + usedLegs[v0Cand.posID] = true; + usedLegs[v0Cand.eleID] = true; - if ((eleId == eleId_tmp || posId == posId_tmp) && v0pca > v0pca_tmp) { - // LOGF(info, "!reject! | collision id = %d | posid1 = %d , eleid1 = %d , posid2 = %d , eleid2 = %d , pca1 = %f , pca2 = %f", collisionId, posId, eleId, posId_tmp, eleId_tmp, v0pca, v0pca_tmp); - is_closest_v0 = false; - break; - } - } // end of pca_map tmp loop - - bool is_stored = std::find(stored_v0Ids.begin(), stored_v0Ids.end(), std::make_pair(posId, eleId)) != stored_v0Ids.end(); - if (is_closest_v0 && is_most_aligned_v0 && !is_stored) { - // auto v0 = v0s.rawIteratorAt(v0Id); - // auto collision = collisions.rawIteratorAt(collisionId); - // auto pos = tracks.rawIteratorAt(posId); - // auto ele = tracks.rawIteratorAt(eleId); - // LOGF(info, "!accept! | collision id = %d | v0id1 = %d , posid1 = %d , eleid1 = %d , pca1 = %f , cospa = %f", collisionId, v0Id, posId, eleId, v0pca, cospa); - - // fillV0Table(v0, true); - stored_v0Ids.emplace_back(std::make_pair(posId, eleId)); - stored_fullv0Ids.emplace_back(std::make_tuple(v0Id, collisionId, posId, eleId)); - nv0_map[collisionId]++; + stored_v0Ids.emplace_back(v0Cand.posID, v0Cand.eleID); + + stored_fullv0Ids.emplace_back( + v0Cand.v0ID, + v0Cand.colID, + v0Cand.posID, + v0Cand.eleID); + + nv0_map[v0Cand.colID]++; } - } // end of pca_map loop - // LOGF(info, "pca_map.size() = %d", pca_map.size()); + + // sort accepted candidates by collision ID to be compatible with table + std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), + [](const auto& a, const auto& b) { + return std::get<1>(a) < std::get<1>(b); + }); + + // End of deduplication + } for (const auto& fullv0Id : stored_fullv0Ids) { auto v0Id = std::get<0>(fullv0Id); @@ -985,14 +1166,14 @@ struct PhotonConversionBuilder { fillV0Table(v0, true); } // end of fullv0Id loop - for (const auto& collision : collisions) { - if constexpr (isMC) { - if (!collision.has_mcCollision()) { - continue; - } - } - // events_ngpcm(nv0_map[collision.globalIndex()]); - } // end of collision loop + // for (const auto& collision : collisions) { + // if constexpr (isMC) { + // if (!collision.has_mcCollision()) { + // continue; + // } + // } + // // events_ngpcm(nv0_map[collision.globalIndex()]); + // } // end of collision loop pca_map.clear(); cospa_map.clear(); @@ -1001,6 +1182,7 @@ struct PhotonConversionBuilder { stored_v0Ids.shrink_to_fit(); stored_fullv0Ids.clear(); stored_fullv0Ids.shrink_to_fit(); + vecV0Dedup.clear(); } // end of build //! type of V0. 0: built solely for cascades (does not pass standard V0 cuts), 1: standard 2, 3: photon-like with TPC-only use. Regular analysis should always use type 1 or 3. diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx index 3c54a08a4bb..872df52551c 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx @@ -53,7 +53,7 @@ struct SkimmerGammaCalo { Preslice psMSperCluster = o2::aod::emcalclustercell::emcalclusterId; Produces tableGammaEMCReco; - Produces tableEMCClusterMCLabels; + Produces tableEMCClusterMCLabels; Produces tableCellEMCReco; Produces tableEmEmcClusters; @@ -331,15 +331,16 @@ struct SkimmerGammaCalo { continue; } std::vector mcLabels; + std::vector amplitudes; + mcLabels.reserve(emccluster.amplitudeA().size()); + amplitudes.reserve(emccluster.amplitudeA().size()); for (size_t iCont = 0; iCont < emccluster.amplitudeA().size(); iCont++) { mcLabels.push_back(emccluster.mcParticleIds()[iCont]); + amplitudes.push_back(emccluster.amplitudeA()[iCont]); } - // LOGF(info, "---- New Cluster ---"); - // for (unsigned long int iCont = 0; iCont < mcLabels.size(); iCont++) { - // LOGF(info, "iCont = %d, mcParticle = %d, amplitudeA = %.5f", iCont, mcLabels.at(iCont), emccluster.amplitudeA()[iCont]); - // } - tableEMCClusterMCLabels(mcLabels); + tableEMCClusterMCLabels(mcLabels, amplitudes); mcLabels.clear(); + amplitudes.clear(); } } PROCESS_SWITCH(SkimmerGammaCalo, processMC, "process MC info", false); // Run this in addition to processRec for MCs to copy the cluster mc labels from the EMCALMCClusters to the skimmed EMCClusterMCLabels table diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx index c0b14051d74..6b2f9d20e13 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #include #include +#include #include #include #include @@ -104,7 +106,7 @@ struct skimmerGammaConversion { }; // declare this here in order to be able to access it from a lambda - std::shared_ptr fMotherSizesHisto{}; + std::shared_ptr fMotherSizesHisto; enum eV0Confirmation { kV0In, @@ -131,7 +133,7 @@ struct skimmerGammaConversion { Produces fFuncTableMCTrackInformation; Produces fIndexTableMCTrackIndex; - Service ccdb; + Service ccdb{}; int runNumber = -1; o2::base::MatLayerCylSet* lut = nullptr; @@ -166,7 +168,7 @@ struct skimmerGammaConversion { } auto run3grp_timestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(ccdbPath, run3grp_timestamp); + auto* grpo = ccdb->getForTimeStamp(ccdbPath, run3grp_timestamp); o2::parameters::GRPMagField* grpmag = nullptr; if (grpo) { @@ -189,7 +191,7 @@ struct skimmerGammaConversion { KFParticle::SetField(magneticField); } - template + template void fillTrackTable(TTRACK const& theTrack, TKFP const& kfp) { v0legs(theTrack.collisionId(), @@ -201,8 +203,8 @@ struct skimmerGammaConversion { theTrack.itsClusterSizes(), theTrack.itsChi2NCl(), theTrack.detectorMap()); } - template - void fillfFuncTableMCTrackInformation(TTRACK theTrack, bool sameMother) + template + void fillfFuncTableMCTrackInformation(TTRACK const& theTrack, bool sameMother) { fFuncTableMCTrackInformation( theTrack.mcParticle().pdgCode(), @@ -212,7 +214,7 @@ struct skimmerGammaConversion { sameMother); } - template + template bool checkV0leg(TTrack const& track) { if (track.pt() < minpt || abs(track.eta()) > maxeta) { @@ -236,24 +238,24 @@ struct skimmerGammaConversion { return true; } - template + template void fillV0KF(TCollision const& collision, TV0 const& v0) { auto pos = v0.template posTrack_as(); // positive daughter auto ele = v0.template negTrack_as(); // negative daughter - float xyz[3] = {0.f, 0.f, 0.f}; + std::array xyz = {0.f, 0.f, 0.f}; Vtx_recalculation(o2::base::Propagator::Instance(), pos, ele, xyz); KFPTrack kfp_track_pos = createKFPTrackFromTrack(pos); KFPTrack kfp_track_ele = createKFPTrackFromTrack(ele); KFParticle kfp_pos(kfp_track_pos, -11); KFParticle kfp_ele(kfp_track_ele, 11); - const KFParticle* GammaDaughters[2] = {&kfp_pos, &kfp_ele}; + std::array GammaDaughters = {&kfp_pos, &kfp_ele}; KFParticle gammaKF; gammaKF.SetConstructMethod(2); - gammaKF.Construct(GammaDaughters, 2); + gammaKF.Construct(GammaDaughters.data(), 2); if (kfMassConstrain > -0.1) { gammaKF.SetNonlinearMassConstraint(kfMassConstrain); } @@ -265,7 +267,7 @@ struct skimmerGammaConversion { // Transport the gamma to the recalculated decay vertex KFParticle gammaKF_DecayVtx = gammaKF; // with respect to (0,0,0) - gammaKF_DecayVtx.TransportToPoint(xyz); + gammaKF_DecayVtx.TransportToPoint(xyz.data()); //// Apply a topological constraint of the gamma to the PV. Parameters will be given at the primary vertex. // KFParticle gammaKF_PV = gammaKF_DecayVtx; @@ -278,8 +280,8 @@ struct skimmerGammaConversion { KFParticle kfp_pos_DecayVtx = kfp_pos; KFParticle kfp_ele_DecayVtx = kfp_ele; - kfp_pos_DecayVtx.TransportToPoint(xyz); - kfp_ele_DecayVtx.TransportToPoint(xyz); + kfp_pos_DecayVtx.TransportToPoint(xyz.data()); + kfp_ele_DecayVtx.TransportToPoint(xyz.data()); // KFParticle kfp_pos_PV = kfp_pos_DecayVtx; // KFParticle kfp_ele_PV = kfp_ele_DecayVtx; @@ -407,7 +409,7 @@ struct skimmerGammaConversion { } PROCESS_SWITCH(skimmerGammaConversion, processMc, "process reconstructed and mc info ", false); - template + template eV0Confirmation isTrueV0(TV0 const& /*theV0*/, TTRACK const& theTrackPos, TTRACK const& theTrackNeg) @@ -516,7 +518,7 @@ struct skimmerGammaConversion { } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-gamma-conversion"})}; + return WorkflowSpec{adaptAnalysisTask(context, TaskName{"skimmer-gamma-conversion"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversionTruthOnlyMc.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversionTruthOnlyMc.cxx index e44600aafaa..a9eb488775b 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversionTruthOnlyMc.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversionTruthOnlyMc.cxx @@ -111,7 +111,7 @@ struct skimmerGammaConversionTruthOnlyMc { } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-gamma-conversion-truthonlymc"})}; + return WorkflowSpec{adaptAnalysisTask(context, TaskName{"skimmer-gamma-conversion-truthonlymc"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx index 9c0c52b24de..fb843adc325 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx @@ -16,6 +16,7 @@ #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -31,13 +32,16 @@ #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 @@ -45,8 +49,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -60,17 +66,40 @@ using MyCollisions = soa::Join; using MyCollisionsWithSWT = soa::Join; using MyCollisionsMC = soa::Join; -using MyTracks = soa::Join; +using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; using MyTracksMC = soa::Join; using MyTrackMC = MyTracksMC::iterator; -struct SkimmerPrimaryElectronFromDalitzEE { +namespace o2::aod +{ +namespace pwgem::pm::recalculatedtofpid +{ +DECLARE_SOA_COLUMN(BetaRecalculated, betaRecalculated, float); +DECLARE_SOA_COLUMN(TOFNSigmaElRecalculated, tofNSigmaElRecalculated, float); +} // namespace pwgem::pm::recalculatedtofpid + +DECLARE_SOA_TABLE(EMTOFNSigmas, "AOD", "EMTOFNSIGMA", // make std::map in your tasks later. // Don't store this table in the derived data. + o2::aod::emprimaryelectron::CollisionId, o2::aod::emprimaryelectron::TrackId, + o2::aod::pwgem::pm::recalculatedtofpid::BetaRecalculated, o2::aod::pwgem::pm::recalculatedtofpid::TOFNSigmaElRecalculated); + +using EMTOFNSigma = EMTOFNSigmas::iterator; +} // namespace o2::aod + +struct skimmerPrimaryElectronFromDalitzEE { SliceCache cache; Preslice perCol = o2::aod::track::collisionId; - Preslice perColPcm = o2::aod::v0photonkf::collisionId; + PresliceOptional perTracksCollision = aod::track::collisionId; + Preslice perCol_pcm = o2::aod::v0photonkf::collisionId; + Preslice trackIndicesPerCollision = aod::track_association::collisionId; Produces emprimaryelectrons; Produces emprimaryelectronsDeDxMC; + Service mTOFResponse{}; + + Produces emtofs; // Configurables Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -82,11 +111,13 @@ struct SkimmerPrimaryElectronFromDalitzEE { Configurable dBzInput{"dBzInput", -999, "bz field in kG, -999 is automatic"}; Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; - Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable minchi2tpc{"minchi2tpc", 0.0, "min. chi2/NclsTPC"}; Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable minchi2its{"minchi2its", 0.0, "min. chi2/NclsITS"}; Configurable maxchi2its{"maxchi2its", 36.0, "max. chi2/NclsITS"}; Configurable minpt{"minpt", 0.05, "min pt for ITS-TPC track"}; Configurable maxeta{"maxeta", 2.0, "max eta acceptance"}; @@ -99,13 +130,23 @@ struct SkimmerPrimaryElectronFromDalitzEE { Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; Configurable minTOFNsigmaEl{"minTOFNsigmaEl", -3.5, "min. TOF n sigma for electron inclusion"}; Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", +3.5, "max. TOF n sigma for electron inclusion"}; + Configurable minTPCNsigmaKa{"minTPCNsigmaKa", -2.5, "min. TPC n sigma for kaon exclusion"}; + Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 2.5, "max. TPC n sigma for kaon exclusion"}; + Configurable minTPCNsigmaPr{"minTPCNsigmaPr", -2.5, "min. TPC n sigma for proton exclusion"}; + Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 2.5, "max. TPC n sigma for proton exclusion"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + Configurable min_pin_for_pion_rejection{"min_pin_for_pion_rejection", 0.0, "pion rejection is applied above this pin"}; // this is used only in TOFreq + Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 0.5, "pion rejection is applied below this pin"}; Configurable maxMee{"maxMee", 0.04, "max. mee to store dalitz ee pairs"}; Configurable fillLS{"fillLS", true, "flag to fill LS histograms for QA"}; + Configurable fillWithPairs{"fillWithPairs", false, "flag to fill table based on pair information"}; Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; Configurable intercept{"intercept", -0.0380, "intercept for m vs. phiv"}; + Configurable useTOFNSigmaDeltaBC{"useTOFNSigmaDeltaBC", false, "Flag to shift delta BC for TOF n sigma (only with TTCA)"}; + Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; static constexpr std::array DileptonSigns = {"uls/", "lspp/", "lsmm/"}; @@ -114,8 +155,9 @@ struct SkimmerPrimaryElectronFromDalitzEE { float dBz = 0.; Service ccdb{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::dataformats::VertexBase mVtx; - void init(InitContext&) + void init(InitContext& initContext) { // if (doprocessRec && doprocessRec_SWT) { // LOGF(fatal, "Cannot enable doprocessRec and doprocessRec_SWT at the same time. Please choose one."); @@ -129,6 +171,10 @@ struct SkimmerPrimaryElectronFromDalitzEE { ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + LOGF(info, "before TOF initSetup"); + mTOFResponse->initSetup(ccdb, initContext); + LOGF(info, "after TOF initSetup"); + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, o2::constants::math::TwoPI}, {400, -2.0f, 2.0f}}, false); fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); @@ -167,8 +213,18 @@ struct SkimmerPrimaryElectronFromDalitzEE { fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); // pair + fRegistry.add("Pair/uls/hTrackMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hCheckEMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); fRegistry.add("Pair/uls/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hMCutMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hMPhiCutMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + + fRegistry.add("Pair/uls/hTrackMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hCheckEMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); fRegistry.add("Pair/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hMCutMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hMPhiCutMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.addClone("Pair/uls/", "Pair/lspp/"); fRegistry.addClone("Pair/uls/", "Pair/lsmm/"); } @@ -215,20 +271,105 @@ struct SkimmerPrimaryElectronFromDalitzEE { mRunNumber = bc.runNumber(); } - template - bool checkTrack(TCollision const&, TTrack const& track) + template + void calculateTOFNSigmaWithReassociation(TCollisions const& collisions, TBCs const&, TTracks const& tracks, TTrackAssoc const& trackIndices) + { + if (useTOFNSigmaDeltaBC) { + if constexpr (withTTCA) { + for (const auto& collision : collisions) { + if (mapCollisionTime.find(collision.globalIndex()) == mapCollisionTime.end()) { + continue; + } + auto bcCollision = collision.template bc_as(); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + + if (track.hasTOF() && track.has_collision()) { // TTCA may use orphan tracks. + auto bcTrack = track.template collision_as().template bc_as(); + float tofNSigmaEl = mTOFResponse->nSigma(track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()), track.tofExpMom(), track.length(), track.p(), track.eta(), mapCollisionTime[collision.globalIndex()], mapCollisionTimeError[collision.globalIndex()]); + float beta = track.length() / (track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()) - mapCollisionTime[collision.globalIndex()]) / (o2::constants::physics::LightSpeedCm2S * 1e-12); + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = tofNSigmaEl; + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = beta; + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } else { + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } // end of track loop + } // end of collision loop + } else { + for (const auto& collision : collisions) { + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } // end of track loop + } // end of collision loop + } else { + if constexpr (withTTCA) { + for (const auto& collision : collisions) { + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } // end of track loop + } // end of collision loop + } else { + for (const auto& collision : collisions) { + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } // end of track loop + } // end of collision loop + } + } + + template + bool checkTrack(TCollision const& collision, TTrack const& track) { if constexpr (isMC) { if (!track.has_mcParticle()) { return false; } + if (storeOnlyTrueElectronMC) { + const auto& mcParticle = track.template mcParticle_as(); + if (std::abs(mcParticle.pdgCode()) != 11) { + return false; + } + } + } + + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + if (requireTOF && !(track.hasTOF() && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl)) { + return false; } if (!track.hasITS()) { return false; } - if (track.itsChi2NCl() < 0.f || maxchi2its < track.itsChi2NCl()) { + if (track.itsChi2NCl() < minchi2its || maxchi2its < track.itsChi2NCl()) { return false; } @@ -244,7 +385,7 @@ struct SkimmerPrimaryElectronFromDalitzEE { } if (track.hasTPC()) { - if (track.tpcChi2NCl() < 0.f || maxchi2tpc < track.tpcChi2NCl()) { + if (track.tpcChi2NCl() < minchi2tpc || maxchi2tpc < track.tpcChi2NCl()) { return false; } @@ -265,80 +406,213 @@ struct SkimmerPrimaryElectronFromDalitzEE { } } - if (std::fabs(track.dcaXY()) > dca_xy_max || std::fabs(track.dcaZ()) > dca_z_max) { + o2::dataformats::DCA mDcaInfoCov; // for Track association + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { return false; } float dca3D = 999.f; - float det = track.cYY() * track.cZZ() - track.cZY() * track.cZY(); + float det = trackParCov.getSigmaY2() * trackParCov.getSigmaZ2() - trackParCov.getSigmaZY() * trackParCov.getSigmaZY(); if (det < 0) { dca3D = 999.f; } else { - float chi2 = (track.dcaXY() * track.dcaXY() * track.cZZ() + track.dcaZ() * track.dcaZ() * track.cYY() - 2. * track.dcaXY() * track.dcaZ() * track.cZY()) / det; + float chi2 = (dcaXY * dcaXY * trackParCov.getSigmaZ2() + dcaZ * dcaZ * trackParCov.getSigmaY2() - 2. * dcaXY * dcaZ * trackParCov.getSigmaZY()) / det; dca3D = std::sqrt(std::fabs(chi2) / 2.); } if (dca3D > dca_3d_sigma_max) { return false; } - if (std::fabs(track.eta()) > maxeta) { + if (trackParCov.getPt() < minpt || std::fabs(trackParCov.getEta()) > maxeta) { return false; } - if ((track.hasITS() && track.hasTPC()) && track.pt() < minpt) { + + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + if (maxMeanITSClusterSize < static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))) { return false; } + if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { return false; } + // if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { + // return false; + // } + return true; } - template - bool isElectron(TTrack const& track) + template + bool isElectron(TCollision const& collision, TTrack const& track) { - if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { - int totalClusterSize = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { // o2-linter: disable=magic-number (number of its layers) - int clusterSizePerLayer = track.itsClsSizeInLayer(layer); - if (clusterSizePerLayer > 0) { + if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) [[unlikely]] { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { nl++; } - totalClusterSize += clusterSizePerLayer; + total_cluster_size += cluster_size_per_layer; } - return (maxMeanITSClusterSize > static_cast(totalClusterSize) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + return (maxMeanITSClusterSize > static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); } + return isElectron_TPChadrej(collision, track) || isElectron_TOFreq(collision, track); + } + + template + bool isElectron_TPChadrej(TCollision const& collision, TTrack const& track) + { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { return false; } - if (track.hasTOF() && (track.tofNSigmaEl() < minTOFNsigmaEl || maxTOFNsigmaEl < track.tofNSigmaEl())) { // TOFif + if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { + return false; + } + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(tofNSigmaEl))) { return false; } return true; } - template - void fillTrackTable(TCollision const& collision, TTrack const& track) + template + bool isElectron_TOFreq(TCollision const& collision, TTrack const& track) { - emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), - track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), track.cYY(), track.cZY(), track.cZZ(), - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), - track.beta(), track.tofNSigmaEl(), - track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap()); + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; - if constexpr (isMC) { - emprimaryelectronsDeDxMC(track.mcTunedTPCSignal()); + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && (min_pin_for_pion_rejection < track.tpcInnerParam() && track.tpcInnerParam() < max_pin_for_pion_rejection)) { + return false; + } + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl; + } + + template + void fillTrackInfo(TCollision const& collision, TTracks const& tracks) + { + + for (const auto& track : tracks) { + if (!checkTrack(collision, track)) { + continue; + } + + if (!isElectron(collision, track)) { + continue; + } + + fillTrackHistograms(track); + fillTrackTable(collision, track); } } - template + template + void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) + { + if constexpr (pairtype == 0) { // ULS + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { + continue; + } + + if (!isElectron(collision, t1) || !isElectron(collision, t2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); + + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); + + if (v12.M() > maxMee) { // don't store + continue; + } + + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMCutMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMCutMvsPhiV"), phiv, v12.M()); + + if (v12.M() < slope * phiv + intercept) { + continue; + } + + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMPhiCutMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMPhiCutMvsPhiV"), phiv, v12.M()); + + if (t1.sign() > 0) { // for positron + if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t1.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { + fillTrackHistograms(t1); + acceptedPosTrackIds_per_collision.emplace_back(t1.globalIndex()); + } + } else { // for electron + if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t1.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { + fillTrackHistograms(t1); + acceptedNegTrackIds_per_collision.emplace_back(t1.globalIndex()); + } + } + + if (t2.sign() > 0) { // for positron + if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t2.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { + fillTrackHistograms(t2); + acceptedPosTrackIds_per_collision.emplace_back(t2.globalIndex()); + } + } else { // for electron + if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t2.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { + fillTrackHistograms(t2); + acceptedNegTrackIds_per_collision.emplace_back(t2.globalIndex()); + } + } + } // end of ULS pairing + } else { // LS + for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { + if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { + continue; + } + if (!isElectron(collision, t1) || !isElectron(collision, t2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); + } // end of LS pairing + } + } + + template void fillTrackHistograms(TTrack const& track) { float mcTunedTPCSignal = 0.f; @@ -408,235 +682,227 @@ struct SkimmerPrimaryElectronFromDalitzEE { fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), track.p(), static_cast(totalClusterSizeOb) / static_cast(nlOb) * std::cos(std::atan(track.tgl()))); } - template - void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) + template + void fillTrackTable(TCollision const& collision, TTrack const& track) { - if constexpr (pairtype == 0) { // ULS - for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { - continue; - } - if (!isElectron(t1) || !isElectron(t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); - - if (v12.M() > maxMee) { // don't store - continue; - } - - if (v12.M() < slope * phiv + intercept) { - continue; - } - - if (t1.sign() > 0) { // for positron - if (std::find(acceptedPosTrackIdsPerCollision.begin(), acceptedPosTrackIdsPerCollision.end(), t1.globalIndex()) == acceptedPosTrackIdsPerCollision.end()) { - fillTrackHistograms(t1); - acceptedPosTrackIdsPerCollision.emplace_back(t1.globalIndex()); - } - } else { // for electron - if (std::find(acceptedNegTrackIdsPerCollision.begin(), acceptedNegTrackIdsPerCollision.end(), t1.globalIndex()) == acceptedNegTrackIdsPerCollision.end()) { - fillTrackHistograms(t1); - acceptedNegTrackIdsPerCollision.emplace_back(t1.globalIndex()); - } - } - - if (t2.sign() > 0) { // for positron - if (std::find(acceptedPosTrackIdsPerCollision.begin(), acceptedPosTrackIdsPerCollision.end(), t2.globalIndex()) == acceptedPosTrackIdsPerCollision.end()) { - fillTrackHistograms(t2); - acceptedPosTrackIdsPerCollision.emplace_back(t2.globalIndex()); - } - } else { // for electron - if (std::find(acceptedNegTrackIdsPerCollision.begin(), acceptedNegTrackIdsPerCollision.end(), t2.globalIndex()) == acceptedNegTrackIdsPerCollision.end()) { - fillTrackHistograms(t2); - acceptedNegTrackIdsPerCollision.emplace_back(t2.globalIndex()); - } - } - } // end of ULS pairing - } else { // LS - for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { - continue; - } - if (!isElectron(t1) || !isElectron(t2)) { - continue; - } + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), track.cYY(), track.cZY(), track.cZZ(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), + track.beta(), track.tofNSigmaEl(), + track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap()); - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); - } // end of LS pairing + if constexpr (isMC) { + emprimaryelectronsDeDxMC(track.mcTunedTPCSignal()); } } - std::vector acceptedPosTrackIdsPerCollision; - std::vector acceptedNegTrackIdsPerCollision; - std::vector> storedTrackIds; - Filter trackFilter = minpt < o2::aod::track::pt && nabs(o2::aod::track::eta) < maxeta && o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max && nabs(o2::aod::track::dcaZ) < dca_z_max; - using MyFilteredTracks = soa::Filtered; - Partition posTracks = o2::aod::track::signed1Pt > 0.f; - Partition negTracks = o2::aod::track::signed1Pt < 0.f; + std::vector acceptedPosTrackIds_per_collision; + std::vector acceptedNegTrackIds_per_collision; + std::vector acceptedTrackIds_per_collision; + // Filter trackFilter = minpt < o2::aod::track::pt && nabs(o2::aod::track::eta) < maxeta && o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max && nabs(o2::aod::track::dcaZ) < dca_z_max; + // Filter trackFilter + // using MyFilteredTracks = soa::Filtered; + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + std::unordered_map mapCollisionTime; + std::unordered_map mapCollisionTimeError; + + std::map, float> mapTOFNsigmaReassociated; // map pair(collisionId, trackId) -> tof n sigma + std::map, float> mapTOFBetaReassociated; // map pair(collisionId, trackId) -> tof beta // ---------- for data ---------- - void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks, aod::V0PhotonsKF const& v0photons) + void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const& bcs, MyTracks const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) { - storedTrackIds.reserve(tracks.size()); + initCCDB(bcs.iteratorAt(0)); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + + for (const auto& track : tracks) { + mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); + mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); for (const auto& collision : collisions) { - auto bc = collision.template foundBC_as(); - initCCDB(bc); if (!collision.isSelected()) { continue; } - const auto& v0photonsPerColl = v0photons.sliceBy(perColPcm, collision.globalIndex()); - const auto& posTracksPerColl = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - const auto& negTracksPerColl = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - acceptedPosTrackIdsPerCollision.reserve(posTracksPerColl.size()); - acceptedNegTrackIdsPerCollision.reserve(negTracksPerColl.size()); - - fillPairInfo(collision, posTracksPerColl, negTracksPerColl); // ULS - if (fillLS) { - fillPairInfo(collision, posTracksPerColl, posTracksPerColl); // LS++ - fillPairInfo(collision, negTracksPerColl, negTracksPerColl); // LS-- - } - - if ((v0photonsPerColl.size() >= 1 && !acceptedPosTrackIdsPerCollision.empty() && !acceptedNegTrackIdsPerCollision.empty()) || (acceptedPosTrackIdsPerCollision.size() >= 2 && acceptedNegTrackIdsPerCollision.size() >= 2)) { // o2-linter: disable=magic-number (check to see if we have enough particles that it make sense to fill the tables) - // LOGF(info, "v0photonsPerColl.size() = %d, acceptedPosTrackIdsPerCollision.size() = %d, acceptedNegTrackIdsPerCollision.size() = %d", v0photonsPerColl.size(), acceptedPosTrackIdsPerCollision.size(), acceptedNegTrackIdsPerCollision.size()); - for (const auto& posId : acceptedPosTrackIdsPerCollision) { - const auto& pos = tracks.rawIteratorAt(posId); - fillTrackTable(collision, pos); + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + if (!fillWithPairs) { + fillTrackInfo(collision, slicedTracks); + } else { + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- } - for (const auto& eleId : acceptedNegTrackIdsPerCollision) { - const auto& ele = tracks.rawIteratorAt(eleId); - fillTrackTable(collision, ele); + + if ((v0photons_per_coll.size() >= 1 && !acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + const auto& pos = tracks.rawIteratorAt(posId); + fillTrackTable(collision, pos); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + const auto& ele = tracks.rawIteratorAt(eleId); + fillTrackTable(collision, ele); + } } } - acceptedPosTrackIdsPerCollision.clear(); - acceptedPosTrackIdsPerCollision.shrink_to_fit(); - acceptedNegTrackIdsPerCollision.clear(); - acceptedNegTrackIdsPerCollision.shrink_to_fit(); - } // end of collision loop + acceptedPosTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.clear(); - storedTrackIds.clear(); - storedTrackIds.shrink_to_fit(); + } // end of collision loop } - PROCESS_SWITCH(SkimmerPrimaryElectronFromDalitzEE, processRec, "process reconstructed info only", true); // standalone + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec, "process reconstructed info only", false); // standalone - // void processRec_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks, aod::V0PhotonsKF const& v0photons) + // void processRec_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const& bcs, MyTracks const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) // { - // storedTrackIds.reserve(tracks.size()); + // initCCDB(bcs.iteratorAt(0)); + + // mTOFResponse->processSetup(bcs.iteratorAt(0)); + // for (const auto& track : tracks) { + // mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); + // mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); + // } + // calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); // for (const auto& collision : collisions) { - // auto bc = collision.template foundBC_as(); - // initCCDB(bc); // if (!collision.isSelected()) { // continue; // } - // if (collision.triggerMask_raw() == 0) { + // if (collision.swtaliastmp_raw() == 0) { // continue; // } - // const auto& v0photonsPerColl = v0photons.sliceBy(perColPcm, collision.globalIndex()); - // const auto& posTracksPerColl = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - // const auto& negTracksPerColl = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - // acceptedPosTrackIdsPerCollision.reserve(posTracksPerColl.size()); - // acceptedNegTrackIdsPerCollision.reserve(negTracksPerColl.size()); - - // fillPairInfo(collision, posTracksPerColl, negTracksPerColl); // ULS - // if (fillLS) { - // fillPairInfo(collision, posTracksPerColl, posTracksPerColl); // LS++ - // fillPairInfo(collision, negTracksPerColl, negTracksPerColl); // LS-- - // } - - // if ((v0photonsPerColl.size() >= 1 && acceptedPosTrackIdsPerCollision.size() >= 1 && acceptedNegTrackIdsPerCollision.size() >= 1) || (acceptedPosTrackIdsPerCollision.size() >= 2 && acceptedNegTrackIdsPerCollision.size() >= 2)) { - // // LOGF(info, "v0photonsPerColl.size() = %d, acceptedPosTrackIdsPerCollision.size() = %d, acceptedNegTrackIdsPerCollision.size() = %d", v0photonsPerColl.size(), acceptedPosTrackIdsPerCollision.size(), acceptedNegTrackIdsPerCollision.size()); - // for (const auto& posId : acceptedPosTrackIdsPerCollision) { - // const auto& pos = tracks.rawIteratorAt(posId); - // fillTrackTable(collision, pos); + // const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + // const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + // const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + // const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); + // acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + // acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + // if(!fillWithPairs){ + // fillTrackInfo(collision, slicedTracks); + // }else{ + // fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + // if (fillLS) { + // fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + // fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- // } - // for (const auto& eleId : acceptedNegTrackIdsPerCollision) { - // const auto& ele = tracks.rawIteratorAt(eleId); - // fillTrackTable(collision, ele); + + // if ((v0photons_per_coll.size() >= 1 && !acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { + // // LOGF(info, "v0photons_per_coll.size() = %d, acceptedPosTrackIds_per_collision.size() = %d, acceptedNegTrackIds_per_collision.size() = %d", v0photons_per_coll.size(), acceptedPosTrackIds_per_collision.size(), acceptedNegTrackIds_per_collision.size()); + // for (const auto& posId : acceptedPosTrackIds_per_collision) { + // const auto& pos = tracks.rawIteratorAt(posId); + // fillTrackTable(collision, pos); + // } + // for (const auto& eleId : acceptedNegTrackIds_per_collision) { + // const auto& ele = tracks.rawIteratorAt(eleId); + // fillTrackTable(collision, ele); + // } // } // } - // acceptedPosTrackIdsPerCollision.clear(); - // acceptedPosTrackIdsPerCollision.shrink_to_fit(); - // acceptedNegTrackIdsPerCollision.clear(); - // acceptedNegTrackIdsPerCollision.shrink_to_fit(); - // } // end of collision loop + // acceptedPosTrackIds_per_collision.clear(); + // acceptedNegTrackIds_per_collision.clear(); - // storedTrackIds.clear(); - // storedTrackIds.shrink_to_fit(); + // } // end of collision loop // } - // PROCESS_SWITCH(SkimmerPrimaryElectronFromDalitzEE, processRec_SWT, "process reconstructed info with CEFP", false); // with cefp + // PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec_SWT, "process reconstructed info with CEFP", false); // with cefp - using MyFilteredTracksMC = soa::Filtered; - Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; - Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + // using MyFilteredTracksMC = soa::Filtered; + Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; // ---------- for MC ---------- - void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::V0PhotonsKF const& v0photons) + void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const& bcs, MyTracksMC const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) { - storedTrackIds.reserve(tracks.size()); + uint64_t nCollisSel = 0; + uint64_t nNoMcColl = 0; + uint64_t nProcessedCollisions = 0; + uint64_t nCheckTrack = 0; + + initCCDB(bcs.iteratorAt(0)); + + mTOFResponse->processSetup(bcs.iteratorAt(0)); + for (const auto& track : tracks) { + mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); + mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); for (const auto& collision : collisions) { - auto bc = collision.template foundBC_as(); - initCCDB(bc); if (!collision.has_mcCollision()) { + nNoMcColl++; continue; } + if (!collision.isSelected()) { + nCollisSel++; continue; } - - const auto& v0photonsPerColl = v0photons.sliceBy(perColPcm, collision.globalIndex()); - const auto& posTracksPerColl = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - const auto& negTracksPerColl = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - acceptedPosTrackIdsPerCollision.reserve(posTracksPerColl.size()); - acceptedNegTrackIdsPerCollision.reserve(negTracksPerColl.size()); - - fillPairInfo(collision, posTracksPerColl, negTracksPerColl); // ULS - if (fillLS) { - fillPairInfo(collision, posTracksPerColl, posTracksPerColl); // LS++ - fillPairInfo(collision, negTracksPerColl, negTracksPerColl); // LS-- - } - if ((v0photonsPerColl.size() >= 1 && !acceptedPosTrackIdsPerCollision.empty() && !acceptedNegTrackIdsPerCollision.empty()) || (acceptedPosTrackIdsPerCollision.size() >= 2 && acceptedNegTrackIdsPerCollision.size() >= 2)) { // o2-linter: disable=magic-number (check to see if we have enough particles that it make sense to fill the tables) - // LOGF(info, "v0photonsPerColl.size() = %d, acceptedPosTrackIdsPerCollision.size() = %d, acceptedNegTrackIdsPerCollision.size() = %d", v0photonsPerColl.size(), acceptedPosTrackIdsPerCollision.size(), acceptedNegTrackIdsPerCollision.size()); - for (const auto& posId : acceptedPosTrackIdsPerCollision) { - const auto& pos = tracks.rawIteratorAt(posId); - fillTrackTable(collision, pos); + nProcessedCollisions++; + + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + acceptedTrackIds_per_collision.reserve(2 * (negTracks_per_coll.size())); + + if (!fillWithPairs) { + fillTrackInfo(collision, slicedTracks); + } else { + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- } - for (const auto& eleId : acceptedNegTrackIdsPerCollision) { - const auto& ele = tracks.rawIteratorAt(eleId); - fillTrackTable(collision, ele); + if ((acceptedPosTrackIds_per_collision.empty() && acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { // v0photons_per_coll.size() >= 1 && + for (const auto& posId : acceptedPosTrackIds_per_collision) { + const auto& pos = tracks.rawIteratorAt(posId); + fillTrackTable(collision, pos); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + const auto& ele = tracks.rawIteratorAt(eleId); + fillTrackTable(collision, ele); + } } - } + } // end of fill loop + + acceptedPosTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.clear(); - acceptedPosTrackIdsPerCollision.clear(); - acceptedPosTrackIdsPerCollision.shrink_to_fit(); - acceptedNegTrackIdsPerCollision.clear(); - acceptedNegTrackIdsPerCollision.shrink_to_fit(); } // end of collision loop - storedTrackIds.clear(); - storedTrackIds.shrink_to_fit(); + LOG(info) << "Total collisions: " << collisions.size(); + LOG(info) << "No MC collision: " << nNoMcColl; + LOG(info) << "Rejected by selection: " << nCollisSel; + LOG(info) << "Processed collisions: " << nProcessedCollisions; + LOG(info) << "Invalid track: " << nCheckTrack; } - PROCESS_SWITCH(SkimmerPrimaryElectronFromDalitzEE, processMC, "process reconstructed and MC info ", false); + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processMC, "process reconstructed and MC info ", true); }; +// WorkflowSpec defineDataProcessing(ConfigContext const& context) +// { +// return WorkflowSpec{adaptAnalysisTask(context, TaskName{"skimmer-primary-electron-from-dalitzee"})}; +// } WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(context, TaskName{"skimmer-primary-electron-from-dalitzee"})}; + o2::pid::tof::TOFResponseImpl::metadataInfo.initMetadata(context); + + return WorkflowSpec{ + adaptAnalysisTask(context, TaskName{"skimmer-primary-electron-from-dalitzee"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index fe155e91fe1..9a7baf84587 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt @@ -200,3 +200,8 @@ o2physics_add_dpl_workflow(photonhbt SOURCES photonhbt.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(emcal-photon-mc-task + SOURCES emcalPhotonMcTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx b/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx index 3caa5e5b5aa..b0ad9fea148 100644 --- a/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx +++ b/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx @@ -169,7 +169,7 @@ struct CheckMCV0 { Configurable mLUTPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; Configurable mCCDBUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Service mCCDB; + Service mCCDB{}; int mRunNumber{-1}; o2::base::MatLayerCylSet* mLUT{nullptr}; o2::parameters::GRPMagField* mGRPMagField{nullptr}; @@ -177,7 +177,6 @@ struct CheckMCV0 { // params std::array mcPosXYZEtaTglPtProp{}; std::array mcEleXYZEtaTglPtProp{}; - std::array mcMotherXYZEtaTglPtProp{}; // Track Types static constexpr std::array v0Types{"ITSTPC_ITSTPC/", "TPConly_TPConly/", "ITSonly_ITSonly/", "ITSTPC_TPConly/", "ITSTPC_ITSonly/", "TPConly_ITSonly/"}; @@ -515,7 +514,7 @@ struct CheckMCV0 { } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"check-mc-v0"})}; + return WorkflowSpec{adaptAnalysisTask(context, TaskName{"check-mc-v0"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx index 4d096927d6e..f6a6bad2c2e 100644 --- a/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx +++ b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx b/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx index d7046d8832f..f1e3d11878a 100644 --- a/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx +++ b/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -83,11 +84,11 @@ struct Compconvbuilder { EMOnly = 2, LFOnly = 3, Common = 4, - NConversionBuilder + NConversionBuilder = 5 }; - static constexpr std::string_view kConversionBuilder[NConversionBuilder] = {"EMBuilder/", "LFBuilder/", "EMOnly/", "LFOnly/", "Common/"}; - static constexpr std::string_view kEventTypes[2] = {"before/", "after/"}; + static constexpr std::array kConversionBuilder = {"EMBuilder/", "LFBuilder/", "EMOnly/", "LFOnly/", "Common/"}; + static constexpr std::array kEventTypes = {"before/", "after/"}; EMPhotonEventCut fEMEventCut; struct : ConfigurableGroup { @@ -765,9 +766,7 @@ struct Compconvbuilder { registry.fill(HIST("truePhotons/Sparse_Converted"), d1.vx(), mc.y(), d1.vz(), r, mc.phi(), mc.eta(), mc.pt()); - int id1 = mc2trk.count(d1.globalIndex()) ? mc2trk[d1.globalIndex()] : -1; - int id2 = mc2trk.count(d2.globalIndex()) ? mc2trk[d2.globalIndex()] : -1; - if (id1 < 0 || id2 < 0) { + if (!mc2trk.contains(d1.globalIndex()) || !mc2trk.contains(d2.globalIndex())) { continue; } } @@ -795,8 +794,9 @@ struct Compconvbuilder { } for (const auto& collision : collisions) { - if (!fEMEventCut.IsSelected(collision)) + if (!fEMEventCut.IsSelected(collision)) { continue; + } fillEventInfo<1, EMBuilder>(collision); @@ -818,22 +818,25 @@ struct Compconvbuilder { .emmcparticle_as(); int pid = FindCommonMotherFrom2Prongs(posmc, negmc, kPositron, kElectron, kGamma, mcparticles); - if (pid >= 0) + if (pid >= 0) { table[pid].emIt = it; + } } for (LFIt it = lfSlice.begin(); it != lfSlice.end(); ++it) { int posTrackIndex = it.posTrackId(); auto negTrackIndex = it.negTrackId(); - if (!trackToMcLabel.count(posTrackIndex) || !trackToMcLabel.count(negTrackIndex)) + if (!trackToMcLabel.contains(posTrackIndex) || !trackToMcLabel.contains(negTrackIndex)) { continue; + } auto posmc = mcparticles.iteratorAt(trackToMcLabel[posTrackIndex]); auto negmc = mcparticles.iteratorAt(trackToMcLabel[negTrackIndex]); int pid = FindCommonMotherFrom2Prongs(posmc, negmc, kPositron, kElectron, kGamma, mcparticles); - if (pid >= 0) + if (pid >= 0) { table[pid].lfIt = it; + } } for (auto const& [pid, entry] : table) { @@ -872,7 +875,7 @@ struct Compconvbuilder { PROCESS_SWITCH(Compconvbuilder, processConvV0s, "Process generated converted V0s", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfg)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx index c3f41633d9b..f33e70e1b86 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx @@ -8,11 +8,10 @@ // 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 runs loop over dalitz ee table for dalitz QC. -// Please write to: daiki.sekihata@cern.ch + +/// \file dalitzEEQC.cxx +/// \brief This code runs loop over dalitz ee table for dalitz QC +/// \author Daiki Sekihata, daiki.sekihata@cern.ch #include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" @@ -27,6 +26,7 @@ #include #include +#include #include #include #include @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -53,8 +54,6 @@ #include #include -#include - using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -131,12 +130,12 @@ struct DalitzEEQC { } dileptoncuts; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; - int mRunNumber; - float d_bz; + Service ccdb{}; + int mRunNumber = 0; + float d_bz = 0; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; + static constexpr std::array event_cut_types = {"before/", "after/"}; void init(InitContext& /*context*/) { @@ -153,7 +152,7 @@ struct DalitzEEQC { ccdb->setFatalWhenNull(false); } - template + template void initCCDB(TCollision const& collision) { if (mRunNumber == collision.runNumber()) { @@ -172,10 +171,11 @@ struct DalitzEEQC { } auto run3grp_timestamp = collision.timestamp(); - o2::parameters::GRPObject* grpo = 0x0; - o2::parameters::GRPMagField* grpmag = 0x0; - if (!skipGRPOquery) + o2::parameters::GRPObject* grpo = nullptr; + o2::parameters::GRPMagField* grpmag = nullptr; + if (!skipGRPOquery) { grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + } if (grpo) { // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); @@ -192,7 +192,7 @@ struct DalitzEEQC { mRunNumber = collision.runNumber(); } - ~DalitzEEQC() {} + ~DalitzEEQC() = default; void addhistograms() { @@ -204,11 +204,11 @@ struct DalitzEEQC { const AxisSpec axis_pt{200, 0, 2, "p_{T,ee} (GeV/c)"}; fRegistry.add("Pair/same/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {axis_mass, axis_pt}, true); - fRegistry.add("Pair/same/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 0.1f}}, true); + fRegistry.add("Pair/same/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, o2::constants::math::PI}, {100, 0.0f, 0.1f}}, true); fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); - fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, o2::constants::math::TwoPI}, {40, -2.0f, 2.0f}}, false); fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -0.1f, 0.1f}, {200, -0.1f, 0.1f}}, false); fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); @@ -280,7 +280,7 @@ struct DalitzEEQC { fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); } - template + template bool fillPairInfo(TCollision const&, TTrack1 const& t1, TTrack2 const& t2) { if (t1.trackId() == t2.trackId()) { // this is protection against pairing identical 2 tracks. This happens, when TTCA is used. TTCA can assign a track to several possible collisions. @@ -319,7 +319,7 @@ struct DalitzEEQC { return true; } - template + template void fillTrackInfo(TTrack const& track) { fRegistry.fill(HIST("Track/hPt"), track.pt()); @@ -363,7 +363,7 @@ struct DalitzEEQC { { for (auto& collision : collisions) { initCCDB(collision); - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + const std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -372,7 +372,7 @@ struct DalitzEEQC { if (!fEMEventCut.IsSelected(collision)) { continue; } - if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange()) || !(collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { continue; } o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision); @@ -398,8 +398,8 @@ struct DalitzEEQC { PROCESS_SWITCH(DalitzEEQC, processDummy, "Dummy function", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"dalitz-ee-qc"})}; + adaptAnalysisTask(context, TaskName{"dalitz-ee-qc"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx index 084b866da50..c0dd75f3545 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx @@ -9,10 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// ======================== -// -// This code runs loop over dalitz ee table for dalitz QC. -// Please write to: daiki.sekihata@cern.ch + +/// \file dalitzEEQC.cxx +/// \brief This code runs loop over dalitz ee table for dalitz QC in MC +/// \author Daiki Sekihata, daiki.sekihata@cern.ch #include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -48,14 +50,15 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include +#include +#include #include #include +#include #include #include #include -#include - using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -134,9 +137,9 @@ struct DalitzEEQCMC { } dileptoncuts; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; - int mRunNumber; - float d_bz; + Service ccdb{}; + int mRunNumber = 0; + float d_bz = 0; struct : ConfigurableGroup { std::string prefix = "mctrackcut_group"; @@ -146,10 +149,10 @@ struct DalitzEEQCMC { } mctrackcuts; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - static constexpr std::string_view event_cut_types[2] = {"before/", "after/"}; - static constexpr std::string_view track_types[2] = {"primary/", "secondary/"}; + static constexpr std::array event_cut_types = {"before/", "after/"}; + static constexpr std::array track_types = {"primary/", "secondary/"}; - ~DalitzEEQCMC() {} + ~DalitzEEQCMC() = default; void addhistograms() { @@ -169,7 +172,7 @@ struct DalitzEEQCMC { // reconstructed pair info fRegistry.add("Pair/sm/Photon/hMvsPt", "m_{ee} vs. p_{T,ee} ULS", kTH2F, {axis_mass, axis_pt}, true); - fRegistry.add("Pair/sm/Photon/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, M_PI}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("Pair/sm/Photon/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0, o2::constants::math::PI}, {100, 0.0f, 0.1f}}, false); fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Pi0/"); fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Eta/"); fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/EtaPrime/"); @@ -180,7 +183,7 @@ struct DalitzEEQCMC { // track info fRegistry.add("Track/primary/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); fRegistry.add("Track/primary/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); - fRegistry.add("Track/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, false); + fRegistry.add("Track/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, o2::constants::math::TwoPI}, {40, -2.0f, 2.0f}}, false); fRegistry.add("Track/primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -0.1f, 0.1f}, {200, -0.1f, 0.1f}}, false); fRegistry.add("Track/primary/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); fRegistry.add("Track/primary/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); @@ -225,7 +228,7 @@ struct DalitzEEQCMC { ccdb->setFatalWhenNull(false); } - template + template void initCCDB(TCollision const& collision) { if (mRunNumber == collision.runNumber()) { @@ -244,10 +247,11 @@ struct DalitzEEQCMC { } auto run3grp_timestamp = collision.timestamp(); - o2::parameters::GRPObject* grpo = 0x0; - o2::parameters::GRPMagField* grpmag = 0x0; - if (!skipGRPOquery) + o2::parameters::GRPObject* grpo = nullptr; + o2::parameters::GRPMagField* grpmag = nullptr; + if (!skipGRPOquery) { grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + } if (grpo) { // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); @@ -310,10 +314,10 @@ struct DalitzEEQCMC { fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfg_min_TOFNsigmaEl, dileptoncuts.cfg_max_TOFNsigmaEl); } - template + template int FindLF(TTrack const& posmc, TTrack const& elemc, TMCParticles const& mcparticles) { - int arr[] = { + std::array arr = { FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles), @@ -323,22 +327,16 @@ struct DalitzEEQCMC { FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 333, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 443, mcparticles), FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 100443, mcparticles)}; - int size = sizeof(arr) / sizeof(*arr); - int max = *std::max_element(arr, arr + size); - return max; + return *std::ranges::max_element(arr); } - template + template bool isInAcceptance(T const& t1) { - if ((mctrackcuts.min_mcPt < t1.pt() && t1.pt() < mctrackcuts.max_mcPt) && std::fabs(t1.eta()) < mctrackcuts.max_mcEta) { - return true; - } else { - return false; - } + return ((mctrackcuts.min_mcPt < t1.pt() && t1.pt() < mctrackcuts.max_mcPt) && std::fabs(t1.eta()) < mctrackcuts.max_mcEta); } - template + template bool fillTruePairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TMCParticles const& mcparticles) { if (!fDileptonCut.IsSelectedTrack(t1) || !fDileptonCut.IsSelectedTrack(t2)) { @@ -471,7 +469,7 @@ struct DalitzEEQCMC { return true; } - template + template void fillTrackInfo(TTrack const& track) { auto mctrack = track.template emmcparticle_as(); @@ -521,7 +519,7 @@ struct DalitzEEQCMC { for (auto& collision : collisions) { initCCDB(collision); - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -530,7 +528,7 @@ struct DalitzEEQCMC { if (!fEMEventCut.IsSelected(collision)) { continue; } - if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange()) || !(collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { continue; } o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision); @@ -561,7 +559,7 @@ struct DalitzEEQCMC { // all MC tracks which belong to the MC event corresponding to the current reconstructed event for (auto& collision : collisions) { - float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -569,7 +567,7 @@ struct DalitzEEQCMC { if (!fEMEventCut.IsSelected(collision)) { continue; } - if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { + if (!(eventcuts.cfgOccupancyMin <= collision.trackOccupancyInTimeRange()) || !(collision.trackOccupancyInTimeRange() < eventcuts.cfgOccupancyMax)) { continue; } auto mccollision = collision.emmcevent_as(); @@ -640,8 +638,8 @@ struct DalitzEEQCMC { PROCESS_SWITCH(DalitzEEQCMC, processDummy, "Dummy function", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"dalitz-ee-qc-mc"})}; + adaptAnalysisTask(context, TaskName{"dalitz-ee-qc-mc"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx b/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx index 1bc980ed4bc..0db7a6cc899 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx @@ -8,12 +8,10 @@ // 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 emcalBcWiseGammaGamma.cxx /// \brief Task that extracts pi0s and eta mesons from BC wise derived data of EMCal clusters /// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) Goethe University Frankfurt -/// #include "PWGEM/PhotonMeson/DataModel/bcWiseTables.h" @@ -35,11 +33,11 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include #include -#include #include #include #include +#include using namespace o2; using namespace o2::framework; @@ -78,7 +76,7 @@ struct EmcalBcWiseGammaGamma { Filter m02Filter = (aod::bcwisecluster::storedNCells == 1 || (aod::bcwisecluster::storedM02 > cfgMinM02 && aod::bcwisecluster::storedM02 < cfgMaxM02)); Filter timeFilter = (aod::bcwisecluster::storedTime > cfgMinTime && aod::bcwisecluster::storedTime < cfgMaxTime); - emcal::Geometry* emcalGeom; + emcal::Geometry* emcalGeom = nullptr; void init(InitContext const&) { @@ -86,10 +84,10 @@ struct EmcalBcWiseGammaGamma { const int nEventBins = 6; mHistManager.add("Event/nBCs", "Number of BCs;;#bf{FT0M centrality (%)};#bf{#it{N}_{BC}}", HistType::kTH2F, {{nEventBins, -0.5, 5.5}, cfgCentralityBinning}); mHistManager.add("Event/nCollisions", "Number of Collisions (BCs x P(mu));;#bf{FT0M centrality (%)};#bf{#it{N}_{coll}}", HistType::kTH2F, {{nEventBins, -0.5, 5.5}, cfgCentralityBinning}); - const TString binLabels[nEventBins] = {"All", "FT0", "TVX", "kTVXinEMC", "Cell", "Cluster"}; + const std::array binLabels = {"All", "FT0", "TVX", "kTVXinEMC", "Cell", "Cluster"}; for (int iBin = 0; iBin < nEventBins; iBin++) { - mHistManager.get(HIST("Event/nBCs"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); - mHistManager.get(HIST("Event/nCollisions"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); + mHistManager.get(HIST("Event/nBCs"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin].data()); + mHistManager.get(HIST("Event/nCollisions"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin].data()); } mHistManager.add("Event/nCollPerBC", "Number of collisions per BC;#bf{#it{N}_{coll}};#bf{FT0M centrality (%)};#bf{#it{N}_{BC}}", HistType::kTH2F, {{5, -0.5, 4.5}, cfgCentralityBinning}); @@ -137,21 +135,24 @@ struct EmcalBcWiseGammaGamma { float getCentrality(const auto& bc) { - if (cfgCentralityEstimator == 0) + if (cfgCentralityEstimator == 0) { return bc.ft0cCentrality(); - else if (cfgCentralityEstimator == 1) + } + if (cfgCentralityEstimator == 1) { return bc.ft0mCentrality(); - else - throw std::runtime_error("Unknown centrality estimator selected"); + } + throw std::runtime_error("Unknown centrality estimator selected"); } /// \brief returns if cluster is too close to edge of EMCal bool isTooCloseToEdge(const int cellID, const int DistanceToBorder = 1) { - if (DistanceToBorder <= 0) + if (DistanceToBorder <= 0) { return false; - if (cellID < 0) + } + if (cellID < 0) { return true; + } // check distance to border in case the cell is okay auto [iSupMod, iMod, iPhi, iEta] = emcalGeom->GetCellIndex(cellID); @@ -218,20 +219,24 @@ struct EmcalBcWiseGammaGamma { ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (std::fabs(v12.Rapidity()) > cfgRapidityCut) + if (std::fabs(v12.Rapidity()) > cfgRapidityCut) { continue; + } float openingAngle12 = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); - if (openingAngle12 < cfgMinOpenAngle) + if (openingAngle12 < cfgMinOpenAngle) { continue; + } mHistManager.fill(HIST("GG/invMassVsPt"), v12.M(), v12.Pt(), getCentrality(bc)); - if (clusters.size() < 3) + if (clusters.size() < 3) { continue; + } - if (bc.globalIndex() % cfgBGEventDownsampling != 0) + if (bc.globalIndex() % cfgBGEventDownsampling != 0) { continue; + } // "else: Calculate background" @@ -243,21 +248,24 @@ struct EmcalBcWiseGammaGamma { try { int iCellID = emcalGeom->GetAbsCellIdFromEtaPhi(vi.Eta(), vi.Phi()); - if (isTooCloseToEdge(iCellID, cfgDistanceToEdge)) + if (isTooCloseToEdge(iCellID, cfgDistanceToEdge)) { continue; - } catch (o2::emcal::InvalidPositionException& e) { + } + } catch (o2::emcal::InvalidPositionException const& e) { continue; } for (const auto& g3 : clusters) { - if (g3.globalIndex() == g1.globalIndex() || g3.globalIndex() == g2.globalIndex()) + if (g3.globalIndex() == g1.globalIndex() || g3.globalIndex() == g2.globalIndex()) { continue; + } ROOT::Math::PtEtaPhiMVector v3(g3.pt(), g3.eta(), g3.phi(), 0.); float openingAnglei3 = std::acos(vi.Vect().Dot(v3.Vect()) / (vi.P() * v3.P())); - if (openingAnglei3 < cfgMinOpenAngle) + if (openingAnglei3 < cfgMinOpenAngle) { continue; + } ROOT::Math::PtEtaPhiMVector vBG = v3 + vi; @@ -269,57 +277,67 @@ struct EmcalBcWiseGammaGamma { void reconstructTrueMesons(const auto& clusters, const auto& mcPi0s, const auto& mcEtas, const auto& bc) { for (const auto& [g1, g2] : soa::combinations(soa::CombinationsStrictlyUpperIndexPolicy(clusters, clusters))) { - if (g1.mesonID() != g2.mesonID() || g1.mesonID() == -1) + if (g1.mesonID() != g2.mesonID() || g1.mesonID() == -1) { continue; + } ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (std::fabs(v12.Rapidity()) > cfgRapidityCut) + if (std::fabs(v12.Rapidity()) > cfgRapidityCut) { continue; + } float openingAngle12 = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); - if (openingAngle12 < cfgMinOpenAngle) + if (openingAngle12 < cfgMinOpenAngle) { continue; + } if (!g1.isEta()) { const auto& mcPi0 = mcPi0s.iteratorAt(g1.mesonID() - mcPi0s.offset()); mHistManager.fill(HIST("True/pi0_PtRecVsPtTrue"), v12.Pt(), mcPi0.pt(), getCentrality(bc)); - if (mcPi0.isPrimary()) + if (mcPi0.isPrimary()) { mHistManager.fill(HIST("True/pi0_invMassVsPt_Primary"), v12.M(), v12.Pt(), getCentrality(bc)); - else if (mcPi0.isFromWD()) + } else if (mcPi0.isFromWD()) { mHistManager.fill(HIST("True/pi0_invMassVsPt_Secondary"), v12.M(), v12.Pt(), getCentrality(bc)); - else + } else { mHistManager.fill(HIST("True/pi0_invMassVsPt_HadronicShower"), v12.M(), v12.Pt(), getCentrality(bc)); + } } else { const auto& mcEta = mcEtas.iteratorAt(g1.mesonID() - mcEtas.offset()); mHistManager.fill(HIST("True/eta_PtRecVsPtTrue"), v12.Pt(), mcEta.pt(), getCentrality(bc)); - if (mcEta.isPrimary()) + if (mcEta.isPrimary()) { mHistManager.fill(HIST("True/eta_invMassVsPt_Primary"), v12.M(), v12.Pt(), getCentrality(bc)); - else if (mcEta.isFromWD()) + } else if (mcEta.isFromWD()) { mHistManager.fill(HIST("True/eta_invMassVsPt_Secondary"), v12.M(), v12.Pt(), getCentrality(bc)); - else + } else { mHistManager.fill(HIST("True/eta_invMassVsPt_HadronicShower"), v12.M(), v12.Pt(), getCentrality(bc)); + } } } } bool isBCSelected(const auto& bc, const auto& collisions) { - if (cfgRequirekTVXinEMC && !bc.haskTVXinEMC()) + if (cfgRequirekTVXinEMC && !bc.haskTVXinEMC()) { return false; - if (cfgRequireEMCCell && !bc.hasEMCCell()) + } + if (cfgRequireEMCCell && !bc.hasEMCCell()) { return false; - if (cfgSelectOnlyUniqueAmbiguous == 1 && collisions.size() != 1) + } + if (cfgSelectOnlyUniqueAmbiguous == 1 && collisions.size() != 1) { return false; - if (cfgSelectOnlyUniqueAmbiguous == 2 && collisions.size() == 1) + } + if (cfgSelectOnlyUniqueAmbiguous == 2 && collisions.size() == 1) { return false; - if (cfgMinTimeSinceSOF > bc.timeSinceSOF() / 60 || cfgMaxTimeSinceSOF < bc.timeSinceSOF() / 60) + } + if (cfgMinTimeSinceSOF > bc.timeSinceSOF() / 60 || cfgMaxTimeSinceSOF < bc.timeSinceSOF() / 60) { return false; + } return true; } @@ -328,35 +346,44 @@ struct EmcalBcWiseGammaGamma { for (const auto& mcPi0 : mcPi0s) { if (mcPi0.isPrimary()) { mHistManager.fill(HIST("Generated/pi0_AllBCs"), mcPi0.pt(), getCentrality(bc)); - if (bc.hasFT0()) + if (bc.hasFT0()) { mHistManager.fill(HIST("Generated/pi0_FT0"), mcPi0.pt(), getCentrality(bc)); - if (bc.hasTVX()) + } + if (bc.hasTVX()) { mHistManager.fill(HIST("Generated/pi0_TVX"), mcPi0.pt(), getCentrality(bc)); - if (bc.haskTVXinEMC()) + } + if (bc.haskTVXinEMC()) { mHistManager.fill(HIST("Generated/pi0_kTVXinEMC"), mcPi0.pt(), getCentrality(bc)); - if (mcPi0.isAccepted() && bc.haskTVXinEMC()) + } + if (mcPi0.isAccepted() && bc.haskTVXinEMC()) { mHistManager.fill(HIST("Accepted/pi0_kTVXinEMC"), mcPi0.pt(), getCentrality(bc)); + } } } for (const auto& mcEta : mcEtas) { if (mcEta.isPrimary()) { mHistManager.fill(HIST("Generated/eta_AllBCs"), mcEta.pt(), getCentrality(bc)); - if (bc.hasFT0()) + if (bc.hasFT0()) { mHistManager.fill(HIST("Generated/eta_FT0"), mcEta.pt(), getCentrality(bc)); - if (bc.hasTVX()) + } + if (bc.hasTVX()) { mHistManager.fill(HIST("Generated/eta_TVX"), mcEta.pt(), getCentrality(bc)); - if (bc.haskTVXinEMC()) + } + if (bc.haskTVXinEMC()) { mHistManager.fill(HIST("Generated/eta_kTVXinEMC"), mcEta.pt(), getCentrality(bc)); - if (mcEta.isAccepted() && bc.haskTVXinEMC()) + } + if (mcEta.isAccepted() && bc.haskTVXinEMC()) { mHistManager.fill(HIST("Accepted/eta_kTVXinEMC"), mcEta.pt(), getCentrality(bc)); + } } } } void process(aod::BCWiseBCs::iterator const& bc, aod::BCWiseCollisions const& collisions, SelectedClusters const& clusters) { - if (!isBCSelected(bc, collisions)) + if (!isBCSelected(bc, collisions)) { return; + } fillEventHists(bc, collisions, clusters); @@ -367,20 +394,23 @@ struct EmcalBcWiseGammaGamma { void processMCInfo(aod::BCWiseBCs::iterator const& bc, aod::BCWiseCollisions const& collisions, SelectedMCClusters const& clusters, aod::BCWiseMCPi0s const& mcPi0s, aod::BCWiseMCEtas const& mcEtas) { - if (!cfgIsMC) + if (!cfgIsMC) { LOG(fatal) << "MC processing is not enabled, but the task is running on MC data. Please set cfgIsMC to true."; + } fillGeneratedMesonHists(mcPi0s, mcEtas, bc); // Fill before BC selection to also store pi0s and eta mesons in BCs that were not triggered - if (!isBCSelected(bc, collisions)) + if (!isBCSelected(bc, collisions)) { return; + } - for (const auto& cluster : clusters) + for (const auto& cluster : clusters) { mHistManager.fill(HIST("True/clusterERecVsETrue"), cluster.e(), cluster.trueE(), getCentrality(bc)); + } reconstructTrueMesons(clusters, mcPi0s, mcEtas, bc); } PROCESS_SWITCH(EmcalBcWiseGammaGamma, processMCInfo, "Run true and gen", false); }; -WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) { return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx new file mode 100644 index 00000000000..21c9c55f980 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx @@ -0,0 +1,786 @@ +// 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 emcalPhotonMcTask.cxx +/// \brief Analysis task for to analyse photon clusters and differences to conversion clusters in MC +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "PWGEM/PhotonMeson/Core/EMBitFlags.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/ConversionMl.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#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/Vector3Dfwd.h) +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photon; +using namespace o2::constants::physics; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; + +constexpr float MinAmpThreshold = 0.2f; // Minimum cluster amplitude threshold to count as significant +constexpr float MaxAmpDiff = 0.1f; // Maximum cluster amplitude difference to leading cluster contribution to count as significant + +enum CentralityEstimator { + None = 0, + CFT0A, + CFT0C, + CFT0M, + NCentralityEstimators +}; + +enum class TruthClass { + Conversion = 0, // 0: true e+/e- pair from the same conversion + + PhotonPairSamePi0, // 1: two photon clusters, same Pi0 + PhotonPairDiffPi0, // 2: two photon clusters, different Pi0s + PhotonPairOnePi0, // 3: two photon clusters, only one from a Pi0 + + PhotonElectronSamePi0, // 4: photon + electron cluster, same Pi0 + PhotonElectronDiffPi0, // 5: photon + electron cluster, different Pi0s + PhotonElectronOnePi0, // 6: photon + electron cluster, only one from a Pi0 + BSPhotonElectron, // 7: photon + electron cluster, from Bremsstrahlung + + ElectronPairSamePi0, // 8: e+e cluster pair, same Pi0 (conversion and/or Dalitz) + ElectronPairDiffPi0, // 9: e+e cluster pair, different Pi0s + ElectronPairOnePi0, // 10: e+e cluster pair, only one from a Pi0 + + SplitPhotonCluster, // 11: one photon producing two clusters + SplitLeptonCluster, // 12: one lepton producing two clusters + PhotonBSPhotonPair, // 13: photon + photon from Bremsstrahlung + ElectronBSPhotonPair, // 14: one cluster from Bremsstrahlung and one electron cluster except case BSPhotonElectron + BSPhotonPair, // 15: both photons from Bremsstrahlung + + Background, // 16: else / uncorrelated + + NClasses +}; + +enum class ClusterTruthClass { + Photon = 0, // cluster is a true, unconverted photon + Conversion, // cluster is a leg of a true conversion + Pi0Conversion, // ...and that conversion's photon itself came from pi0/eta (excludes same-gamma-pair case) + Pi0, // cluster comes from the pi0/eta decay chain (not via the conversion-leg path above) + Background, // cluster is flagged as both meson-chain AND conversion -- ambiguous/contradictory + NClasses +}; + +enum class TagDecision { + NotTagged = 0, + Tagged, + NTags +}; + +struct ClusterMcInfo { + bool isLepton = false; + bool isPhoton = false; + bool isFromConv = false; + bool isMergedConv = false; + bool isFromPi0 = false; + bool isFromBremsstrahlung = false; + int convMotherId = -1; + int photonId = -1; + float purity = 0; +}; + +template +ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcClusterLooper, TIter& mcClusterLooper2, McParticles const& mcParticles) +{ + ClusterMcInfo info; + mcCluster.setCursor(g.emmcparticleIds()[0]); + info.isFromBremsstrahlung = isFromBremsstrahlung(mcCluster, mcClusterLooper); // particle has to be a photon and it has to have a e+ or e- as mother! + float leadingAmplitude = g.amplitude()[0]; + info.purity = leadingAmplitude; + if (std::abs(mcCluster.pdgCode()) == PDG_t::kElectron) { + info.isLepton = true; + info.convMotherId = getMotherIndexFromChain(mcCluster, mcClusterLooper, PDG_t::kGamma); + info.isFromConv = info.convMotherId >= 0; + + if (mcCluster.mothersIds().size() > 0 && info.isFromConv) { + for (size_t i = 1; i < g.emmcparticleIds().size(); ++i) { + mcClusterLooper.setCursor(g.emmcparticleIds()[i]); + if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron && mcClusterLooper.pdgCode() == -1 * mcCluster.pdgCode()) { + int32_t otherConvMotherId = getMotherIndexFromChain(mcClusterLooper, mcClusterLooper2, PDG_t::kGamma); + if (otherConvMotherId == info.convMotherId) { + if (g.amplitude()[i] >= leadingAmplitude - MaxAmpDiff && g.amplitude()[i] > MinAmpThreshold) { + info.isMergedConv = true; + } + break; + } + } + } + } + } + if (std::abs(mcCluster.pdgCode()) == PDG_t::kGamma) { + info.isPhoton = true; + } + + info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); + info.isFromPi0 = info.photonId >= 0; + + return info; +} + +struct EmcalPhotonMcTask { + static constexpr float EMCALRadius = 440.f; + static constexpr float PhiVUndefined = -999.f; + static constexpr float Epsilon = 1.e-6f; + + static constexpr std::array(TruthClass::NClasses)> kTruthClassNames = { + "Conversion", "PhotonPairSamePi0", "PhotonPairDiffPi0", "PhotonPairOnePi0", + "PhotonElectronSamePi0", "PhotonElectronDiffPi0", "PhotonElectronOnePi0", "BSPhotonElectron", + "ElectronPairSamePi0", "ElectronPairDiffPi0", "ElectronPairOnePi0", + "SplitPhotonCluster", "SplitLeptonCluster", "Background"}; + + Produces convTagCandidates; + + 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 skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable writeTable{"writeTable", true, "write table for ML."}; + Configurable> classPrescale{"classPrescale", {1, 1, 700, 25, 1, 350, 15, 1, 1, 35, 2, 1, 1, 1, 1, 1, 1000}, "prescale factor per TruthClass, indexed 0..10 matching the enum order"}; + Configurable bkgPrescaleSeed{"bkgPrescaleSeed", 42, "seed for the background-prescale RNG"}; + + // configurable axis + ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {400, 0.0, 0.8}, "invariant mass axis for the neutral meson"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {400, 0., 20.}, "pT axis for the neutral meson"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, "centrality axis for the current event"}; + ConfigurableAxis thnConfigAxisMult{"thnConfigAxisMult", {60, 0., 60000.}, "multiplicity axis for the current event"}; + ConfigurableAxis thnConfigAxisDeltaEta{"thnConfigAxisDeltaEta", {100, -1, 1}, "delta eta axis"}; + ConfigurableAxis thnConfigAxisDeltaPhi{"thnConfigAxisDeltaPhi", {100, -1, 1}, "delta phi axis"}; + Configurable useCent{"useCent", false, "flag to enable usage of centrality instead of multiplicity as axis."}; + + struct : ConfigurableGroup { + std::string prefix = "conversiontagging"; + Configurable maxMinv{"maxMinv", 0.1f, "maximum invariant mass for tagging conversions."}; + Configurable maxDeltaEta{"maxDeltaEta", 0.05f, "maximum delta eta between two clusters for tagging them as conversions."}; + Configurable maxDeltaPhi{"maxDeltaPhi", 0.1f, "maximum delta phi between two clusters for tagging them as conversions."}; + Configurable minrConv{"minrConv", 370.f, "minimum conversion Radius of two clusters for tagging them as conversions."}; + Configurable maxrConv{"maxrConv", 430.f, "maximum conversion Radius of two clusters for tagging them as conversions."}; + } conversiontaggingcuts; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcuts"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", true, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -1, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgMinCent{"cfgMinCent", 0, "min. centrality (%)"}; + Configurable cfgMaxCent{"cfgMaxCent", 90, "max. centrality (%)"}; + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccuts"; + Configurable clusterDefinition{"clusterDefinition", "kV3MostSplitSmallestTimeDiff", "Clusterizer to be selected, e.g. V3Default"}; + Configurable cfgEMCminTime{"cfgEMCminTime", -25., "Minimum cluster time for EMCal time cut"}; + Configurable cfgEMCmaxTime{"cfgEMCmaxTime", +30., "Maximum cluster time for EMCal time cut"}; + Configurable cfgEMCminM02{"cfgEMCminM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable cfgEMCmaxM02{"cfgEMCmaxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable cfgEMCminE{"cfgEMCminE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable cfgEMCminNCell{"cfgEMCminNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> cfgEMCTMEta{"cfgEMCTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> cfgEMCTMPhi{"cfgEMCTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMEta{"emcSecTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMPhi{"emcSecTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable cfgEMCEoverp{"cfgEMCEoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable cfgEMCUseExoticCut{"cfgEMCUseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; + Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + } emccuts; + + struct : ConfigurableGroup { + std::string prefix = "mesonConfig"; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + } mesonConfig; + + SliceCache cache; + + using EMCalPhotons = soa::Join; + + using Colls = soa::Join; + + using McColls = o2::soa::Join; + using McParticles = EMMCParticles; + + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; + PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + int8_t bTruthLabel{}; + + Service ccdb{}; + int mRunNumber{0}; + float dBz{0.f}; + + std::mt19937 mRandGen; + std::uniform_int_distribution mPrescaleDist; + + void defineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void defineEMCCut() + { + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetTrackMatchingEtaParams(emccuts.cfgEMCTMEta->at(0), emccuts.cfgEMCTMEta->at(1), emccuts.cfgEMCTMEta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.cfgEMCTMPhi->at(0), emccuts.cfgEMCTMPhi->at(1), emccuts.cfgEMCTMPhi->at(2)); + + fEMCCut.SetSecTrackMatchingEtaParams(emccuts.emcSecTMEta->at(0), emccuts.emcSecTMEta->at(1), emccuts.emcSecTMEta->at(2)); + fEMCCut.SetSecTrackMatchingPhiParams(emccuts.emcSecTMPhi->at(0), emccuts.emcSecTMPhi->at(1), emccuts.emcSecTMPhi->at(2)); + fEMCCut.SetMinEoverP(emccuts.cfgEMCEoverp); + + fEMCCut.SetMinE(emccuts.cfgEMCminE); + fEMCCut.SetMinNCell(emccuts.cfgEMCminNCell); + fEMCCut.SetM02Range(emccuts.cfgEMCminM02, emccuts.cfgEMCmaxM02); + fEMCCut.SetTimeRange(emccuts.cfgEMCminTime, emccuts.cfgEMCmaxTime); + fEMCCut.SetUseExoticCut(emccuts.cfgEMCUseExoticCut); + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetUseTM(emccuts.cfgEMCUseTM.value); // disables or enables TM + fEMCCut.SetUseSecondaryTM(emccuts.emcUseSecondaryTM.value); // disables or enables secondary TM + fEMCCut.SetDoQA(emccuts.cfgEnableQA.value); + } + + void init(InitContext&) + { + mRunNumber = 0; + dBz = 0; + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + defineEMEventCut(); + defineEMCCut(); + fEMCCut.addQAHistograms(®istry); + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(®istry); + + const AxisSpec thnAxisERec{thnConfigAxisPt, "#it{E}_{Rec} (GeV)"}; + const AxisSpec thnAxisPtRec{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisInvMass{thnConfigAxisInvMass, "#it{M}_{#gamma#gamma} (GeV/#it{c}^{2})"}; + + const AxisSpec thnAxisrConvRec{100, 0, 500, "#it{R}_{rec}"}; + const AxisSpec thnAxisrConvGen{100, 0, 500, "#it{R}_{gen}"}; + + const AxisSpec thnAxisDeltaEta{thnConfigAxisDeltaEta, "#Delta#it{eta}"}; + const AxisSpec thnAxisDeltaPhi{thnConfigAxisDeltaPhi, "#Delta#it{#varphi} (rad)"}; + + const AxisSpec thnAxisTagging{static_cast(TagDecision::NTags), -0.5, static_cast(TagDecision::NTags) - 0.5, ""}; + const AxisSpec thnAxisClasses{static_cast(TruthClass::NClasses), -0.5, static_cast(TruthClass::NClasses) - 0.5, ""}; + + AxisSpec thnAxisCentOrMult{1, 0., 1., "Centrality/Multiplicity"}; // placeholder, overwritten in init + if (useCent.value) { + // PbPb: use centrality + thnAxisCentOrMult = {thnConfigAxisCent, "Centrality (%)"}; + } else { + // pp: use multiplicity + thnAxisCentOrMult = {thnConfigAxisMult, "FT0C Multiplicity"}; + } + + auto hTruthLabel = registry.add("hTruthLabel", "Truth label distribution;;Counts", HistType::kTH2D, {{static_cast(TruthClass::NClasses), -0.5, static_cast(TruthClass::NClasses) - 0.5}, thnAxisPtRec}); + + // set bin labels once at init, so histogram is human-readable without decoding the enum + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Conversion) + 1, "Conversion"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairSamePi0) + 1, "PhotonPairSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairDiffPi0) + 1, "PhotonPairDiffPi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairOnePi0) + 1, "PhotonPairOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronSamePi0) + 1, "PhotonElectronSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronDiffPi0) + 1, "PhotonElectronDiffPi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronOnePi0) + 1, "PhotonElectronOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::BSPhotonElectron) + 1, "BSPhotonElectron"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairSamePi0) + 1, "ElectronPairSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairDiffPi0) + 1, "ElectronPairDiffPi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairOnePi0) + 1, "ElectronPairOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SplitPhotonCluster) + 1, "SplitPhotonCluster"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SplitLeptonCluster) + 1, "SplitLeptonCluster"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonBSPhotonPair) + 1, "PhotonBSPhotonPair"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronBSPhotonPair) + 1, "ElectronBSPhotonPair"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::BSPhotonPair) + 1, "BSPhotonPair"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Background) + 1, "Background"); + + auto hPi0BothResolvedLost = registry.add("EMCal/hPi0BothResolvedLost", "Confusion matrix for conversion tagging", HistType::kTH1D, {{2, -0.5, 1.5}}); + hPi0BothResolvedLost->GetXaxis()->SetBinLabel(1, "both resolved (denominator)"); + hPi0BothResolvedLost->GetXaxis()->SetBinLabel(2, "lost to tagging"); + + auto hConfusionMatrixConversionTagging = registry.add("EMCal/ConfusionMatrixConversionTagging", "Confusion matrix for conversion tagging", HistType::kTH2D, {thnAxisTagging, thnAxisClasses}); + hConfusionMatrixConversionTagging->GetXaxis()->SetBinLabel(1, "not tagged"); + hConfusionMatrixConversionTagging->GetXaxis()->SetBinLabel(2, "tagged"); + + hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(1, "true conv."); + hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(2, "true #pi^{0}"); + hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(3, "true #pi^{0} conv."); + hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(4, "background"); + hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(5, "#gamma"); + + mRandGen.seed(bkgPrescaleSeed.value); + + if (classPrescale.value.size() != kTruthClassNames.size()) { + LOG(fatal) << "classPrescale has " << classPrescale.value.size() << " entries, " + << "but TruthClass has " << kTruthClassNames.size() << " members -- update classPrescale!"; + } + + LOG(info) << "=== classPrescale configuration ==="; + for (size_t i = 0; i < kTruthClassNames.size(); ++i) { + LOG(info) << " [" << i << "] " << kTruthClassNames[i] << " -> prescale = " << classPrescale.value[i]; + } + }; // end init + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + auto run3GrpTimestamp = collision.timestamp(); + o2::parameters::GRPObject* grpo = nullptr; + o2::parameters::GRPMagField* grpmag = nullptr; + if (!skipGRPOquery) { + grpo = ccdb->getForTimeStamp(grpPath, run3GrpTimestamp); + } + if (grpo) { + // Fetch magnetic field from ccdb for current collision + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + grpmag = ccdb->getForTimeStamp(grpmagPath, run3GrpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3GrpTimestamp; + } + // Fetch magnetic field from ccdb for current collision + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << dBz << " kZG"; + } + mRunNumber = collision.runNumber(); + } + + template + float getCentralityOrMultiplicity(TCollision const& collision) + { + if (useCent.value) { + return getCentrality(collision); + } + // pp: use raw FT0C multiplicity + return collision.multFT0C(); + } + + /// Get the centrality + /// \param collision is the collision with the centrality information + template + float getCentrality(TCollision const& collision) + { + float cent = -999.; + switch (eventcuts.centEstimator) { + case CentralityEstimator::CFT0M: + cent = collision.centFT0M(); + break; + case CentralityEstimator::CFT0A: + cent = collision.centFT0A(); + break; + case CentralityEstimator::CFT0C: + cent = collision.centFT0C(); + break; + default: + LOG(warning) << "Centrality estimator not valid. Possible values are T0M, T0A, T0C. Fallback to T0C"; + cent = collision.centFT0C(); + break; + } + return cent; + } + + /// \brief check if standard event cuts + FT0 occupancy + centrality + QVec good is + /// \param collision collision that will be checked + /// \param fillHisto flag to enable filling of histograms + /// \return true if collision survives all checks, otherwise false + template + bool isFullEventSelected(TCollision const& collision, bool fillHisto = false) + { + if (fillHisto) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + } + if (!(fEMEventCut.IsSelected(collision))) { + // general event selection + return false; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + return false; + } + float centOrMult = getCentralityOrMultiplicity(collision); + if (useCent && (centOrMult < eventcuts.cfgMinCent || centOrMult > eventcuts.cfgMaxCent)) { + // event selection + return false; + } + if (fillHisto) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + } + return true; + } + + // EMCal same event + void processEmcal(Colls const& collisions, McColls const&, EMCalPhotons const& clusters, MinMTracks const& matchedPrims, MinMSTracks const& matchedSeconds, EMMCParticles const& mcParticles) + { + if (clusters.size() <= 0) { + LOG(info) << "Skipping DF because there are not photons!"; + return; + } + if (collisions.size() <= 0) { + return; + } + std::vector wasMeassured(mcParticles.size(), false); + EMBitFlags emcFlagsFromTrueMeson(clusters.size()); + EMBitFlags emcFlagsFromTrueMesonSameGamma(clusters.size()); + EMBitFlags emcFlagsFromTrueConversion(clusters.size()); + EMBitFlags emcFlagsTagging(clusters.size()); + EMBitFlags emcFlags(clusters.size()); + if (clusters.size() > 0) { + fEMCCut.AreSelectedRunning(emcFlags, clusters, matchedPrims, matchedSeconds, ®istry); + } + auto mcCluster1 = mcParticles.begin(); // iterator of MC particle of highest contributor for first cluster + auto mcCluster2 = mcParticles.begin(); // iterator of MC particle of highest contributor for second cluster + auto mcClusterLooper = mcParticles.begin(); // iterator of MC particle of other contributor for both clusters + auto mcClusterLooper2 = mcParticles.begin(); // iterator of MC particle of other contributor for both clusters + auto mcPhoton1 = mcParticles.begin(); // iterator of MC particle of highest contributor for first cluster that is photon + auto mcPhoton2 = mcParticles.begin(); // iterator of MC particle of highest contributor for second cluster that is photon + auto mcMother = mcParticles.begin(); // iterator of MC particle of combined mother of both clusters + + for (const auto& collision : collisions) { + initCCDB(collision); + isFullEventSelected(collision, true); + + float centOrMult = getCentralityOrMultiplicity(collision); + + auto photonsEMCPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photonsEMCPerCollision, photonsEMCPerCollision))) { + if (!(emcFlags.test(g1.globalIndex())) || !(emcFlags.test(g2.globalIndex()))) { + continue; + } + + if (g1.emmcparticleIds().empty() || g2.emmcparticleIds().empty()) { + // there is a cluster which is just noise, skip + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; + + // z-axis unit vector (beam/field direction) + ROOT::Math::XYZVector p1 = v1.Vect(); + ROOT::Math::XYZVector p2 = v2.Vect(); + ROOT::Math::XYZVector pSum = p1 + p2; + ROOT::Math::XYZVector zAxis(0, 0, 1); + + ROOT::Math::XYZVector u = pSum.Unit(); + ROOT::Math::XYZVector nDecay = p1.Cross(p2); // normal to the plane containing p1, p2 + ROOT::Math::XYZVector nRef = u.Cross(zAxis); // normal to the plane containing u and z + + float phiV = PhiVUndefined; // sentinel for degenerate geometry + if (nDecay.R() > Epsilon && nRef.R() > Epsilon) { + float cosPhiV = static_cast(nDecay.Unit().Dot(nRef.Unit())); + cosPhiV = std::clamp(cosPhiV, -1.f, 1.f); + phiV = std::acos(cosPhiV); + } + + const float deltaPhi = RecoDecay::constrainAngle(v1.Phi() - v2.Phi(), -o2::constants::math::PI); + const float deltaEta = v1.Eta() - v2.Eta(); + const float eT1 = v1.Et(); + const float eT2 = v2.Et(); + const float harmonicET = (eT1 * eT2) / (eT1 + eT2); + + // calculate the conversion radius in cm. The formula expects radii in m, B field in T and energies in GeV + const float rConv = 100.f * (EMCALRadius / 100.f - std::fabs(deltaPhi) / (0.15f * (std::fabs(dBz) / 10.f)) * harmonicET); + + // tag conversion pairs + if (conversiontaggingcuts.maxMinv >= vMeson.M() && conversiontaggingcuts.maxDeltaEta >= std::fabs(deltaEta) && conversiontaggingcuts.minrConv <= rConv && rConv <= conversiontaggingcuts.maxrConv && conversiontaggingcuts.maxDeltaPhi >= std::fabs(deltaPhi)) { + emcFlagsTagging.set(g1.globalIndex()); + emcFlagsTagging.set(g2.globalIndex()); + } + + // set MC particle cursors to the largest cluster contributor + mcCluster1.setCursor(g1.emmcparticleIds()[0]); + mcCluster2.setCursor(g2.emmcparticleIds()[0]); + + bool areFromSamePi0 = false; + bool areConversionLegs = false; + bool areSplitPhotonCluster = false; + bool areSplitLeptonCluster = false; + bool areBSPhotonElectron = false; + + auto c1 = classifyCluster(g1, mcCluster1, mcClusterLooper, mcClusterLooper2, mcParticles); + auto c2 = classifyCluster(g2, mcCluster2, mcClusterLooper, mcClusterLooper2, mcParticles); + + // split-cluster check MUST run first and take priority over everything else -- + // if both clusters share the same dominant MC particle, this is one physical + // shower reconstructed as two clusters, not a genuine pair of anything. + const bool isSameDominantParticle = (g1.emmcparticleIds()[0] == g2.emmcparticleIds()[0]); + if (isSameDominantParticle) { + if (c1.isPhoton) { + areSplitPhotonCluster = true; + } else if (c1.isLepton) { + areSplitLeptonCluster = true; + } + } + + const bool isAnyBSPhoton = c1.isFromBremsstrahlung || c2.isFromBremsstrahlung; + const bool areBSPhotons = c1.isFromBremsstrahlung && c2.isFromBremsstrahlung; + + // if they are not a split cluster check for proper conversion pair + if (!isSameDominantParticle && c1.isFromConv && c2.isFromConv && c1.convMotherId == c2.convMotherId) { + emcFlagsFromTrueConversion.set(g1.globalIndex()); + emcFlagsFromTrueConversion.set(g2.globalIndex()); + areConversionLegs = true; + } + + // if they are not a split cluster check for neutral meson connection + if (!isSameDominantParticle && c1.isFromPi0 && c2.isFromPi0) { + mcPhoton1.setCursor(c1.photonId); + mcPhoton2.setCursor(c2.photonId); + mcMother.setCursor(mcPhoton1.mothersIds()[0]); + if (mcMother.producedByGenerator()) { + if (c1.photonId == c2.photonId) { + // bremsstrahlung: one side is a photon born from the other side's lepton lineage + const bool photonIsBS = (c1.isPhoton && c1.isFromBremsstrahlung) || (c2.isPhoton && c2.isFromBremsstrahlung); + if (photonIsBS && ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton))) { + areBSPhotonElectron = true; + } else { + areFromSamePi0 = true; + emcFlagsFromTrueMesonSameGamma.set(g1.globalIndex()); + emcFlagsFromTrueMesonSameGamma.set(g2.globalIndex()); + } + } else if (mcPhoton1.mothersIds()[0] == mcPhoton2.mothersIds()[0]) { + areFromSamePi0 = true; + emcFlagsFromTrueMeson.set(g1.globalIndex()); + emcFlagsFromTrueMeson.set(g2.globalIndex()); + } + } + } + + bTruthLabel = static_cast(TruthClass::Background); + if (areSplitPhotonCluster) { + bTruthLabel = static_cast(TruthClass::SplitPhotonCluster); + } else if (areSplitLeptonCluster) { + bTruthLabel = static_cast(TruthClass::SplitLeptonCluster); + } else if (areConversionLegs) { + bTruthLabel = static_cast(TruthClass::Conversion); + } else if (areBSPhotonElectron) { + bTruthLabel = static_cast(TruthClass::BSPhotonElectron); + } else if (areBSPhotons && (c1.isFromPi0 || c2.isFromPi0)) { + bTruthLabel = static_cast(TruthClass::BSPhotonPair); + } else if (isAnyBSPhoton && (c1.isFromPi0 || c2.isFromPi0) && ((c1.isPhoton && c2.isLepton) || (c2.isPhoton && c1.isLepton))) { + bTruthLabel = static_cast(TruthClass::ElectronBSPhotonPair); + } else if (isAnyBSPhoton && (c1.isFromPi0 || c2.isFromPi0) && (c1.isPhoton && c2.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonBSPhotonPair); + } else if (areFromSamePi0) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronSamePi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairSamePi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairSamePi0); + } + } else if (c1.isFromPi0 && c2.isFromPi0) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronDiffPi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairDiffPi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairDiffPi0); + } + } else if ((c1.isFromPi0 && !c2.isFromPi0) || (!c1.isFromPi0 && c2.isFromPi0)) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronOnePi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairOnePi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairOnePi0); + } + } + + registry.fill(HIST("hTruthLabel"), bTruthLabel, vMeson.Pt()); + + // final tree values plus filling + const int prescale = classPrescale.value[static_cast(bTruthLabel)]; + const bool keepThisRow = (prescale <= 1) || (std::uniform_int_distribution(0, prescale - 1)(mRandGen) == 0); + if (writeTable.value && keepThisRow) { + convTagCandidates(collision.globalIndex(), vMeson.M(), harmonicET, deltaEta, deltaPhi, phiV, g1.e(), g2.e(), g1.m02(), g2.m02(), g1.time(), g2.time(), g1.nCells(), g2.nCells(), c1.purity, c2.purity, bTruthLabel, centOrMult); + } + } // pair loop + } // collision loop + + std::vector photonSeen(mcParticles.size(), false); // this decay photon has >=1 resolved cluster + std::vector photonTagged(mcParticles.size(), false); // >=1 of those clusters got conversion-tagged + auto collision = collisions.begin(); + for (const auto& cluster : clusters) { + if (!(emcFlags.test(cluster.globalIndex()))) { + continue; + } + if (cluster.emmcparticleIds().empty()) { + // there is a cluster which is just noise, skip + continue; + } + if (cluster.pmeventId() > collision.globalIndex()) { + collision.setCursor(cluster.pmeventId()); + } + + mcCluster1.setCursor(cluster.emmcparticleIds()[0]); + int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); + int motherId = -1; + if (photonid1 >= 0) { + mcPhoton1.setCursor(photonid1); + motherId = mcPhoton1.mothersIds()[0]; + + photonSeen[static_cast(photonid1)] = true; + const bool isTagged = !emcFlagsTagging.test(cluster.globalIndex()); + if (isTagged) { + photonTagged[static_cast(photonid1)] = true; + } + } + + const bool alreadyCountedForMeson = (motherId > -1 && wasMeassured[static_cast(motherId)]); + + if (mcCluster1.pdgCode() == PDG_t::kGamma) { + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Photon)); + } + if (!emcFlagsFromTrueConversion.test(cluster.globalIndex())) { + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Conversion)); + if (!emcFlagsFromTrueMesonSameGamma.test(cluster.globalIndex()) && !alreadyCountedForMeson) { + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Pi0Conversion)); + } + } + if (!emcFlagsFromTrueMeson.test(cluster.globalIndex()) && !alreadyCountedForMeson) { + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Pi0)); + } + if (emcFlagsFromTrueMeson.test(cluster.globalIndex()) && emcFlagsFromTrueConversion.test(cluster.globalIndex())) { + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Background)); + } + if (motherId > -1 && !wasMeassured[static_cast(motherId)]) { + wasMeassured[static_cast(motherId)] = true; + } + } // end of loop over cluster + + for (const auto& mcPart : mcParticles) { + if (mcPart.pdgCode() != PDG_t::kPi0 && mcPart.pdgCode() != Pdg::kEta) { + continue; + } + if (!mcPart.producedByGenerator()) { + continue; + } + if (mcPart.daughtersIds().size() != 2) { // o2-linter: disable=magic-number (self explanatory and does not need extra named variable) + continue; + } + + const int d0 = mcPart.daughtersIds()[0]; + const int d1 = mcPart.daughtersIds()[1]; + mcPhoton1.setCursor(d0); + mcPhoton2.setCursor(d1); + if (mcPhoton1.pdgCode() != PDG_t::kGamma || mcPhoton2.pdgCode() != PDG_t::kGamma) { + continue; // skip anything that is not pi0/eta -> γγ. + } + + const bool bothResolved = photonSeen[static_cast(d0)] && photonSeen[static_cast(d1)]; + if (!bothResolved) { + continue; // not in the denominator -- ceiling case, not attributable to the cut + } + + const bool lost = photonTagged[static_cast(d0)] || photonTagged[static_cast(d1)]; + registry.fill(HIST("EMCal/hPi0BothResolvedLost"), 0.0); // "denominator" bin, once per bothResolved pi0 + if (lost) { + registry.fill(HIST("EMCal/hPi0BothResolvedLost"), 1.0); // "lost" bin + } + } + } + PROCESS_SWITCH(EmcalPhotonMcTask, processEmcal, "Process for pcm and emcal photons", true); + +}; // End struct EmcalPhotonMcTask + +WorkflowSpec defineDataProcessing(ConfigContext const& context) +{ + return WorkflowSpec{adaptAnalysisTask(context)}; +} diff --git a/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx b/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx index 04f1f09b6e7..98bcc1533fd 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx index 411e46c9712..5a793f86aa9 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx @@ -27,6 +27,7 @@ #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx b/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx index 7c436bf018c..5f51e8914bd 100644 --- a/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx +++ b/PWGEM/PhotonMeson/Tasks/gammaConversions.cxx @@ -12,6 +12,7 @@ /// \file gammaConversions.cxx /// \brief perform photon conversion analysis on V0 candidates from aod::StoredV0Datas /// \author stephan.friedrich.stiefelmaier@cern.ch +/// \note legacy code, please use the Pi0EtaToGammaGamma tasks for the standard neutral meson analysis. /// dependencies: o2-analysis-lf-lambdakzerobuilder #include "PWGEM/PhotonMeson/Tasks/gammaConversions.h" @@ -36,10 +37,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -133,6 +136,7 @@ struct GammaConversions { void init(InitContext const&) { + o2::framework::AxisSpec gAxis_pT_log{800, 0.01f, 25.f}; // make axis logarithmic gAxis_pT_log.makeLogarithmic(); @@ -337,9 +341,9 @@ struct GammaConversions { TMCGAMMA const& theMcPhoton, TV0 const& theV0, float const& theV0CosinePA, - int PDGCode[], + std::span PDGCode, bool const& sameMother, - float McTrackmomentum[]) + std::span McTrackmomentum) { fillV0Histograms( fMyRegistry.mV0.mRejectedByMc[theRejReason].mBeforeAfterRecCuts[theBefAftRec].mV0Kind[kRec].mContainer, @@ -365,7 +369,7 @@ struct GammaConversions { } template - bool v0IsGoodValidatedMcPhoton(TMCGAMMA const& theMcPhoton, TV0 const& theV0, float const& theV0CosinePA, bool theV0PassesRecCuts, int PDGCode[], bool const& sameMother, float McTrackmomentum[]) + bool v0IsGoodValidatedMcPhoton(TMCGAMMA const& theMcPhoton, TV0 const& theV0, float const& theV0CosinePA, bool theV0PassesRecCuts, std::span PDGCode, bool const& sameMother, std::span McTrackmomentum) { auto fillRejectedV0HistosI = [&](eMcRejectedSaved theRejReason) { fillAllV0HistogramsForRejectedByMc(static_cast(theRejReason), @@ -417,9 +421,9 @@ struct GammaConversions { TV0 const& theV0, float const& theV0CosinePA, bool theV0PassesRecCuts, - int PDGCode[], + std::span PDGCode, bool const& sameMother, - float McTrackmomentum[]) + std::span McTrackmomentum) { fillV0McValidationHisto(eV0McValidation::kV0in); @@ -456,10 +460,10 @@ struct GammaConversions { } } - void processPDGHistos(int const PDGCode[], - bool const& sameMother, - float const McTrackmomentum[], - int const& theV0PassesRecCuts) + void processPDGHistos(std::span PDGCode, + bool const sameMother, + std::span McTrackmomentum, + bool const theV0PassesRecCuts) { lfillPDGHist(fMyRegistry.mV0.mBeforeAfterRecCuts[kBeforeRecCuts].mV0Kind[kRec].mContainer, PDGCode); @@ -478,17 +482,17 @@ struct GammaConversions { } } - void lfillPDGHist(mapStringHistPtr& theContainer, - int const PDGCode[]) + void lfillPDGHist(mapStringHistPtr const& theContainer, + std::span const PDGCode) { fillTH1(theContainer, "hPDGCode", PDGCode[0]); fillTH1(theContainer, "hPDGCode", PDGCode[1]); } - void lfillDecaysHist(mapStringHistPtr& theContainer, - int const PDGCode[], - int const& sameMother, - float const McTrackmomentum[]) + void lfillDecaysHist(mapStringHistPtr const& theContainer, + std::span PDGCode, + const bool sameMother, + std::span McTrackmomentum) { float MCV0p = RecoDecay::sqrtSumOfSquares(McTrackmomentum[0] + McTrackmomentum[3], McTrackmomentum[1] + McTrackmomentum[4]); @@ -539,7 +543,7 @@ struct GammaConversions { } template - void fillTruePhotonHistograms(int theBefAftRec, TMCGAMMA const& theMcPhoton, TV0 const& theV0, float const& theV0CosinePA, float McTrackmomentum[]) + void fillTruePhotonHistograms(int theBefAftRec, TMCGAMMA const& theMcPhoton, TV0 const& theV0, float const& theV0CosinePA, std::span McTrackmomentum) { fillV0HistogramsMcGamma( fMyRegistry.mV0.mBeforeAfterRecCuts[theBefAftRec].mV0Kind[kMCTrue].mContainer, @@ -567,7 +571,7 @@ struct GammaConversions { TMCGAMMA const& theMcPhoton, TV0 const& theV0, float const& theV0CosinePA, - float McTrackmomentum[]) + std::span McTrackmomentum) { fillV0HistogramsMcGamma( fMyRegistry.mV0.mRejectedByMc[theRejReason].mBeforeAfterRecCuts[theBefAftRec].mV0Kind[kMCTrue].mContainer, @@ -590,9 +594,9 @@ struct GammaConversions { } template - void fillV0MCDaughterParticlesArrays(TTRACKS ele, TTRACKS pos, - int PDGCode[], - float McParticleMomentum[], + void fillV0MCDaughterParticlesArrays(TTRACKS const& ele, TTRACKS const& pos, + std::span PDGCode, + std::span McParticleMomentum, bool& sameMother) { if ((ele.has_v0DaughterMcParticle()) && (pos.has_v0DaughterMcParticle())) { @@ -666,9 +670,9 @@ struct GammaConversions { // check if V0 passes rec cuts and fill beforeRecCuts,afterRecCuts [kRec] bool lV0PassesRecCuts = processV0(lV0, lV0CosinePA, ele, pos); - int PDGCode[2]; // Pos, then Neg - float McParticleMomentum[6]; // Mc momentum of the two daughter tracks, 0-2 = one 3-5 = two, no need to check the charges - bool sameMother; + std::array PDGCode{}; + std::array McParticleMomentum{}; + bool sameMother{}; fillV0MCDaughterParticlesArrays(ele, pos, PDGCode, McParticleMomentum, sameMother); // pointers are passed so they can be later on used here // this process function has to exist seperatly because it is only for MC Rec @@ -772,7 +776,7 @@ struct GammaConversions { // SFS todo: combine fillV0Histograms and fillV0HistogramsMcGamma template - void fillV0HistogramsMcGamma(mapStringHistPtr& theContainer, TMCGAMMA const& theMcGamma, float McTrackmomentum[]) + void fillV0HistogramsMcGamma(mapStringHistPtr& theContainer, TMCGAMMA const& theMcGamma, std::span McTrackmomentum) { fillTH1(theContainer, "hEta", theMcGamma.eta()); fillTH1(theContainer, "hPhi", theMcGamma.phi()); @@ -821,10 +825,7 @@ struct GammaConversions { bool pass_ele = trackPassesCuts(ele); bool pass_pos = trackPassesCuts(pos); - if (pass_ele && pass_pos) - return true; - else - return false; + return (pass_ele && pass_pos); } template @@ -923,7 +924,7 @@ struct GammaConversions { } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 47052298f51..4f2740fed70 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -41,6 +41,7 @@ #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index e7c1ce2a34b..bdcd338d4aa 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -45,6 +45,7 @@ #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx index 3ae919f990c..f7c80f9b6d1 100644 --- a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index b621516b429..7ea2cfab560 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -29,10 +29,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -47,6 +50,8 @@ #include #include // IWYU pragma: keep #include +#include +#include #include #include @@ -98,21 +103,100 @@ static constexpr float kMinMagnitude = 1e-12f; static constexpr float kMinCosine = 1e-12f; static constexpr float kMinSigma = 1e-9f; -static constexpr std::array kPhiStarRadiiM = {0.85f, 1.05f, 1.25f, 1.45f, 1.65f, - 1.85f, 2.05f, 2.25f, 2.45f}; +static constexpr std::array kPhiStarRadiiM = { + 0.85f, 0.95f, 1.05f, 1.15f, 1.25f, 1.35f, 1.45f, 1.55f, 1.65f, + 1.75f, 1.85f, 1.95f, 2.05f, 2.15f, 2.25f, 2.35f, 2.45f}; static constexpr float kPhiStarInvalid = -999.f; static constexpr float kCmPerM = 100.f; -[[nodiscard]] static float legPhiStar(float phi, float pt, int charge, float bzT, float radiusM) +struct LegHelix { + float phiStar = kPhiStarInvalid; // azimuth of the track at that radius + float sxy = -1.f; + int status = 3; // 0 ok, 1 below R_conv, 2 out of reach,3 bad input +}; + +[[nodiscard]] static LegHelix legHelixAt(float vxM, float vyM, float phiMom, float pt, int charge, float bzT, float radiusM) { - if (pt < kMinSigma) { - return kPhiStarInvalid; + LegHelix out; + if (pt < kMinSigma || std::fabs(bzT) < kMinSigma) { + out.status = 3; // o2-linter: disable=magic-number (status code) + return out; + } + const float rStart = std::hypot(vxM, vyM); + if (rStart < kMinSigma) { + out.status = 3; // o2-linter: disable=magic-number (status code) + return out; + } + if (radiusM < rStart) { + out.status = 1; + return out; + } + const float rho = pt / (0.3f * std::fabs(bzT)); // curvature radius, m + const float sgn = (bzT >= 0.f ? 1.f : -1.f) * static_cast(charge); + const float cx = vxM + sgn * rho * std::sin(phiMom); + const float cy = vyM - sgn * rho * std::cos(phiMom); + const float d = std::hypot(cx, cy); + if (d < kMinSigma) { + out.status = 3; // o2-linter: disable=magic-number (status code) + return out; } - const float arg = -0.3f * bzT * static_cast(charge) * radiusM / (2.f * pt); - if (std::fabs(arg) >= 1.f) { - return kPhiStarInvalid; // leg curls up before + if (radiusM > d + rho || radiusM < std::fabs(d - rho)) { + out.status = 2; // o2-linter: disable=magic-number (status code) + return out; } - return RecoDecay::constrainAngle(phi + std::asin(arg), 0.f); + const float phiC = std::atan2(cy, cx); + auto clamp1 = [](float x) { return std::max(-1.f, std::min(1.f, x)); }; + auto alphaAt = [&](float r) { return std::acos(clamp1((r * r + d * d - rho * rho) / (2.f * r * d))); }; + auto betaAt = [&](float r) { return std::acos(clamp1((d * d + rho * rho - r * r) / (2.f * d * rho))); }; + + const float phiVtx = std::atan2(vyM, vxM); + const float a0 = alphaAt(rStart); + const float resPlus = std::fabs(RecoDecay::constrainAngle(phiC + a0 - phiVtx, -o2::constants::math::PI)); + const float resMinus = std::fabs(RecoDecay::constrainAngle(phiC - a0 - phiVtx, -o2::constants::math::PI)); + const float branch = (resPlus < resMinus) ? 1.f : -1.f; + + out.phiStar = RecoDecay::constrainAngle(phiC + branch * alphaAt(radiusM), 0.f); + out.sxy = rho * std::fabs(betaAt(radiusM) - betaAt(rStart)); + out.status = 0; + return out; +} + +[[nodiscard]] inline float selfTestLegHelix() +{ + float worst = 0.f; + constexpr float eps = 1.e-5f; + + for (const auto& bz : {0.5f, -0.5f}) { + for (const auto& q : {+1, -1}) { + for (const auto& pt : {0.1f, 0.2f, 0.5f}) { + for (const auto& r : {0.85f, 1.45f, 2.45f}) { + for (const auto& phi : {0.f, 1.f, -2.f}) { + const auto h = legHelixAt(eps * std::cos(phi), eps * std::sin(phi), phi, pt, q, bz, r); + + if (h.status != 0) { + continue; + } + const float arg = + -0.3f * bz * static_cast(q) * r / (2.f * pt); + + if (std::fabs(arg) >= 1.f) { + continue; + } + const float referencePhi = + RecoDecay::constrainAngle(phi + std::asin(arg), 0.f); + + worst = std::max( + worst, + std::fabs(RecoDecay::constrainAngle( + h.phiStar - referencePhi, + -o2::constants::math::PI))); + } + } + } + } + } + + return worst; } struct Photonhbt { @@ -145,8 +229,42 @@ struct Photonhbt { }; struct PairSep { - float dEtaPP{0}, dPhiPP{0}, dEtaNN{0}, dPhiNN{0}; - float u{999.f}; + float dMin3D{999.f}, dRPhiAtMin3D{999.f}, dZAtMin3D{999.f}; + float dMinRPhi{999.f}, dZAtMinRPhi{999.f}; + std::array fCloseRPhiThr{}; + std::array nCloseRPhiThr{}; + float fCloseRPhi{0.f}; // == fCloseRPhiThr[3] + int nCommon{0}; + int nSameSide{0}; // usable radii on the SAME TPC side + int criticalCharge{-1}; // 0 = e+e+, 1 = e-e-, chosen by d_3D + int rphiCharge{-1}; // chosen by d_rphi alone + std::array dMin3DPerCharge{999.f, 999.f}; + std::array fCloseRPhiPerCharge{0.f, 0.f}; + std::array dMinRPhiPerCharge{999.f, 999.f}; + std::array nSameSidePerCharge{}; + std::array, 2> nCloseRPhiThrPerCharge{}; + std::array, 2> fCloseRPhiThrPerCharge{}; + float dMinRPhiAll{999.f}, dPairMinAll{999.f}; + float dPairMin{999.f}; + float dRPhiAtDPairMin{999.f}, dZAtDPairMin{999.f}; + float rAtDPairMin{-1.f}, absZAtDPairMin{-1.f}, driftLen{-1.f}; + int nCloseScaled{0}; + std::array dPairMinPerCharge{999.f, 999.f}; + float dZGlobalAtDPairMin{999.f}; + float dZSignedLocalAtDPairMin{999.f}, dZSignedGlobalAtDPairMin{999.f}; + float dVtxZ{0.f}; + float fCloseScaled{0.f}; + float driftOldAtDPairMin{-1.f}; // kept only to show the difference + bool sameSideAtDPairMin{true}; + int nLegsITSTPC{0}; + std::array nPoints{}; + std::array, 2> ptDRPhi{}, ptDZ{}, ptDZSgnLocal{}, ptR{}, ptDrift{}, ptSameSide{}; + }; + + struct CrossObs { + // m(e+e-) of the two leg-swapped combinations + std::array mee{999.f, 999.f}; + float meeOverQ{999.f}; }; struct TruthGamma { @@ -163,8 +281,10 @@ struct Photonhbt { struct PhotonWithLegs { float fPt{0}, fEta{0}, fPhi{0}; float fVx{0}, fVy{0}, fVz{0}; + float fVtxZ{0}; std::array fLegPt{}, fLegEta{}, fLegPhi{}; std::array, 2> fLegPhiStar{}; + std::array, 2> fLegSxy{}; // transverse arc length since conversion (m) [[nodiscard]] float pt() const { return fPt; } [[nodiscard]] float eta() const { return fEta; } [[nodiscard]] float phi() const { return fPhi; } @@ -174,6 +294,7 @@ 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]; } + int fNITSTPC{0}; pairutil::V0PhotonLegCounts fLegCounts{}; [[nodiscard]] pairutil::V0PhotonLegCounts const& legCounts() const { return fLegCounts; } }; @@ -206,7 +327,8 @@ struct Photonhbt { Service ccdb{}; Configurable cfgCcdbUrl{"cfgCcdbUrl", "http://alice-ccdb.cern.ch", "CCDB url"}; Configurable cfgBzOverrideT{"cfgBzOverrideT", -999.f, "Bz in Tesla; used instead of CCDB if > -100"}; - float mBzT{0.f}; // signed, Tesla + float mBzT{0.f}; // signed, Tesla + float mVDriftCmPerNs{0.f}; // TPC drift velocity from CCDB; 0 = unavailable // ─── Configurables: QA flags ─────────────────────────────────────────────── struct : ConfigurableGroup { @@ -217,6 +339,11 @@ struct Photonhbt { Configurable cfgMaxQinvForQA{"cfgMaxQinvForQA", 0.1f, "fill per-step pair QA histograms only when q_inv < this value"}; Configurable cfgMaxQinvForFullRange{"cfgMaxQinvForFullRange", 0.3f, "fill full-range histograms only when q_inv < this value"}; Configurable cfgMaxQinvForMCQA{"cfgMaxQinvForMCQA", 0.3f, "fill MC truth 1D histograms only when q_inv < this value"}; + Configurable cfgQaLevel{"cfgQaLevel", 2, "QA: 0 no QA, 1 standard, 2 full diagnostics with leg information etc."}; + Configurable cfgFillDRDZSparse{"cfgFillDRDZSparse", true, "book/fill the FullRange |R1-R2|-Deltaz-qinv sparse (large; needs cfgQaLevel>=2)"}; + 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 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; // ─── HBT analysis mode ─────────────────────────────────────────────────────────── @@ -229,8 +356,7 @@ struct Photonhbt { // ----- Photon Leg Classification - Configurable cfgDoPhotonClassPairCut{"cfgDoPhotonClassPairCut", false, - "apply photon-class pair selection A x B (leg track composition)"}; + Configurable cfgDoPhotonClassPairCut{"cfgDoPhotonClassPairCut", false, "apply photon-class pair selection A x B (leg track composition)"}; struct : ConfigurableGroup { std::string prefix = "photonclassA_group"; @@ -328,14 +454,32 @@ struct Photonhbt { struct : ConfigurableGroup { std::string prefix = "pairsep_group"; Configurable cfgDoPairSepQA{"cfgDoPairSepQA", true, "fill SE/ME same-sign leg separation histograms"}; - Configurable cfgUSigEta{"cfgUSigEta", 0.02f, "eta scale defining u (axis units only, NOT a cut)"}; - Configurable cfgUSigPhi{"cfgUSigPhi", 0.02f, "phi(*) scale defining u (axis units only, NOT a cut)"}; Configurable cfgPairSepMaxQinv{"cfgPairSepMaxQinv", 0.5f, "fill PairSep histograms only for qinv < this value (<=0: no gate)"}; - Configurable cfgUsePhiStar{"cfgUsePhiStar", true, "compute u from phi* at TPC radii instead of vertex phi"}; - Configurable cfgDoLegSepCut{"cfgDoLegSepCut", false, "apply symmetric leg-separation cut u > cfgUCut to SE and ME"}; - Configurable cfgUCut{"cfgUCut", 0.f, "min u (sigma units); pairs with u < cut rejected in SE AND ME"}; + Configurable cfgSigRPhi{"cfgSigRPhi", 1.f, "rphi scale of the pair-merging metric (cm)"}; + Configurable cfgSigZ{"cfgSigZ", 1.f, "z scale of the pair-merging metric (cm)"}; + Configurable cfgSigZNs{"cfgSigZNs", -1.f, "z scale in ns of drift time; <=0 keeps cfgSigZ in cm"}; + Configurable cfgDPairClose{"cfgDPairClose", 1.f, "a sampled radius counts as close when D_pair < this"}; + Configurable> cfgCloseThrCm{"cfgCloseThrCm", {0.5f, 1.0f, 1.5f, 2.0f}, "four d_rphi thresholds (cm) for N_close/f_close"}; + Configurable cfgDoPairMergeCut{"cfgDoPairMergeCut", false, "apply the pair-merging cut to SE AND ME"}; + Configurable cfgDPairCut{"cfgDPairCut", 1.f, "reject pairs with min D_pair below this (needs cfgDoPairMergeCut)"}; + Configurable cfgNCloseCut{"cfgNCloseCut", 0, "reject pairs with at least this many close radii; 0 disables"}; + Configurable cfgTpcHalfLengthCm{"cfgTpcHalfLengthCm", 250.f, "TPC half length, used for drift length = halfLength - |z|"}; + Configurable cfgRegionEdge1{"cfgRegionEdge1", 132.f, "radius (cm) separating region 0 from 1 (approx. IROC / OROC1)"}; + Configurable cfgRegionEdge2{"cfgRegionEdge2", 171.f, "radius (cm) separating region 1 from 2"}; + Configurable cfgRegionEdge3{"cfgRegionEdge3", 208.f, "radius (cm) separating region 2 from 3"}; + Configurable cfgCondQinvMin{"cfgCondQinvMin", 0.10f, "control window for the (d_rphi, d_z) calibration map: min qinv"}; + Configurable cfgCondQinvMax{"cfgCondQinvMax", 0.30f, "control window for the (d_rphi, d_z) calibration map: max qinv"}; + Configurable cfgFillCalibSparse{"cfgFillCalibSparse", true, "fill the per-radius calibration sparse (d_rphi, d_z, region, drift, qinv)"}; } pairsep; + struct : ConfigurableGroup { + std::string prefix = "crosspair_group"; + Configurable cfgDoCrossPairQA{"cfgDoCrossPairQA", false, "fill crossed-hypothesis QA (mee_cross, dist_cross vs qinv) for pairs passing all other pair cuts; SE and ME"}; + Configurable cfgDoCrossPairCut{"cfgDoCrossPairCut", false, "reject pairs with a photon-like crossed combination; applied to SE AND ME"}; + Configurable cfgCrossMaxMeeRatio{"cfgCrossMaxMeeRatio", 0.2f, "veto: min(m_ee^cross)/q_inv below this; genuine pairs sit near 0.5, leg swaps near 0"}; + Configurable cfgCrossMaxQinvQA{"cfgCrossMaxQinvQA", 0.3f, "fill crossed QA sparses only below this qinv"}; + } crosspair; + struct : ConfigurableGroup { std::string prefix = "eventcut_group"; Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; @@ -493,9 +637,44 @@ struct Photonhbt { // INITS /*************************************************/ + struct QaGates { + bool pairQa{true}; + bool singlePhotonQa{true}; + bool legPairQa{true}; + bool pairSepQa{true}; + bool fillDRDZSparse{true}; + bool fillR1R2Sparse{true}; + bool pairSepAfterCut{true}; + } mQa; + void init(InitContext& context) { isMC = context.mOptions.get("processMC"); + + if (pairsep.cfgCloseThrCm.value.size() != 4) { // o2-linter: disable=magic-number (four thresholds) + LOGF(fatal, "cfgCloseThrCm must contain exactly four thresholds, got %zu", + pairsep.cfgCloseThrCm.value.size()); + } + if (pairsep.cfgCloseThrCm.value.front() <= 0.f || + !std::is_sorted(pairsep.cfgCloseThrCm.value.begin(), pairsep.cfgCloseThrCm.value.end())) { + LOGF(fatal, "cfgCloseThrCm must be positive and sorted in ascending order"); + } + const int qaLevel = qaflags.cfgQaLevel.value; + mQa.pairQa = qaflags.doPairQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) + mQa.singlePhotonQa = qaflags.doSinglePhotonQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) + mQa.legPairQa = qaflags.doLegPairQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mQa.pairSepQa = pairsep.cfgDoPairSepQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mQa.fillDRDZSparse = qaflags.cfgFillDRDZSparse.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mQa.fillR1R2Sparse = qaflags.cfgFillR1R2Sparse.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + // an AfterCut copy only differs from Before when a pair cut is active + mQa.pairSepAfterCut = + mQa.pairSepQa && + (ggpaircuts.cfgDoEllipseCut.value || ggpaircuts.cfgDoRCut.value || + ggpaircuts.cfgDoZCut.value || ggpaircuts.cfgMinDRCosOA.value > 0.f || + ggpaircuts.cfgMaxAsymmetry.value >= 0.f || pairsep.cfgDoPairMergeCut.value || + crosspair.cfgDoCrossPairCut.value || cfgDoPhotonClassPairCut.value); + LOGF(info, "photonhbt QA level %d -> pairQA %d, singlePhotonQA %d, legPairQA %d, pairSep %d, dRdZ sparse %d, R1R2 sparse %d, pairSep afterCut %d", + qaLevel, mQa.pairQa, mQa.singlePhotonQa, mQa.legPairQa, mQa.pairSepQa, mQa.fillDRDZSparse, mQa.fillR1R2Sparse, mQa.pairSepAfterCut); mRunNumber = 0; parseBins(mixing.confVtxBins, ztxBinEdges); parseBins(mixing.confCentBins, centBinEdges); @@ -514,6 +693,46 @@ struct Photonhbt { ccdb->setURL(cfgCcdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + + const float worst = selfTestLegHelix(); + constexpr float kSelfTestTol = 1.e-4f; + if (worst < kSelfTestTol) { + LOGF(info, "photonhbt: leg-helix origin-limit self test PASSED (max |dphi| = %.2e rad)", worst); + } else { + LOGF(fatal, + "photonhbt: leg-helix origin-limit self test FAILED, max |dphi| = %.3e rad. " + "The helix-centre sign convention or the branch choice is wrong; every " + "leg-separation variable would be mirrored. Refusing to run.", + worst); + } + LOGF(info, "photonhbt: leg propagation sampled at %zu radii, %.0f-%.0f cm in %.0f cm steps", + kPhiStarRadiiM.size(), kPhiStarRadiiM.front() * kCmPerM, kPhiStarRadiiM.back() * kCmPerM, + (kPhiStarRadiiM.size() > 1) ? (kPhiStarRadiiM[1] - kPhiStarRadiiM[0]) * kCmPerM : 0.f); + LOGF(info, "photonhbt: PairSep QA %s", pairsep.cfgDoPairSepQA.value ? "on" : "off"); + LOGF(info, "photonhbt r-phi closeness thresholds: %.2f, %.2f, %.2f, %.2f cm", + pairsep.cfgCloseThrCm.value[0], pairsep.cfgCloseThrCm.value[1], + pairsep.cfgCloseThrCm.value[2], pairsep.cfgCloseThrCm.value[3]); + LOGF(info, "photonhbt pair merging: metric sigma_rphi = %.2f cm, sigma_z = %.2f cm (or %.1f ns if > 0), close at D_pair < %.2f", + pairsep.cfgSigRPhi.value, pairsep.cfgSigZ.value, pairsep.cfgSigZNs.value, pairsep.cfgDPairClose.value); + LOGF(info, + "photonhbt pair separation: all merging observables (d_rphi^min, D_pair^min, " + "N_close, f_close) use SAME-SIDE radii only; the pure r-phi quantities are " + "selected by d_rphi, not by d_3D"); + LOGF(info, + "photonhbt pair separation: d_z is vertex-LOCAL (each leg relative to its own primary vertex); " + "drift length uses global z. Check PairSep/mix/hDzLocal_vs_dVtxZ -- it must NOT be diagonal."); + LOGF(info, "photonhbt pair merging cut: %s, D_pair > %.2f, N_close < %d (0 = off); control window %.2f < q_inv < %.2f", + pairsep.cfgDoPairMergeCut.value ? "ON" : "off", pairsep.cfgDPairCut.value, + pairsep.cfgNCloseCut.value, pairsep.cfgCondQinvMin.value, pairsep.cfgCondQinvMax.value); + LOGF(info, "photonhbt: crossed-pair QA %s, cut %s (min(m_ee)/q_inv > %.2f)", + crosspair.cfgDoCrossPairQA.value ? "on" : "off", + crosspair.cfgDoCrossPairCut.value ? "ON" : "off", crosspair.cfgCrossMaxMeeRatio.value); + LOGF(info, "photonhbt: q_inv gates -- QA < %.3f, FullRange < %.3f, PairSep < %.3f", + qaflags.cfgMaxQinvForQA.value, qaflags.cfgMaxQinvForFullRange.value, + pairsep.cfgPairSepMaxQinv.value); + LOGF(info, + "photonhbt: check PairSep/hLegPropStatus after the run -- if 'propagated' is " + "not the dominant bin, the separation variables rest on a minority of legs"); } template @@ -523,6 +742,18 @@ struct Photonhbt { return; } mRunNumber = collision.runNumber(); + + auto vd = ccdb->getForRun("TPC/Calib/VDriftTgl", mRunNumber); + if (vd != nullptr) { + mVDriftCmPerNs = vd->refVDrift * vd->corrFact * 1e-3f; // o2-linter: disable=magic-number (cm/us -> cm/ns) + LOGF(info, "photonhbt: run %d, TPC vdrift = %.6f cm/ns (%.4f cm/us); 1 cm in z = %.0f ns", + mRunNumber, mVDriftCmPerNs, 1e3f * mVDriftCmPerNs, + (mVDriftCmPerNs > 0.f) ? 1.f / mVDriftCmPerNs : -1.f); + } else { + mVDriftCmPerNs = 0.f; + LOGF(warn, "photonhbt: no TPC VDrift object for run %d -- the z scale stays in cm", mRunNumber); + } + if (cfgBzOverrideT.value > -100.f) { // o2-linter: disable=magic-number (number in case B-field is overridden in case not fetched from CCDB) mBzT = cfgBzOverrideT.value; return; @@ -656,12 +887,13 @@ struct Photonhbt { addEventHistograms(); addPairCFHistograms(); addPairSepHistograms(); + addCrossPairHistograms(); addSinglePhotonQAHistograms(); addPairQAHistograms(); if (isMC) { addPairMCHistograms(); - if (qaflags.doLegPairQA) { + if (mQa.legPairQa) { addLegPairMCHistograms(); } addTruthMCHistograms(); @@ -696,7 +928,7 @@ struct Photonhbt { fRegistryCF.add("Pair/same/hSparse_DEtaDPhi_qinv_kT", "pair (#Delta#eta,#Delta#phi,q_{inv},k_{T}) for efficiency reweighting;" "#Delta#eta;#Delta#phi (rad);q_{inv} (GeV/c);k_{T} (GeV/c)", - kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisQinv, axisKt}, true); + kTHnSparseF, {axisDeltaEta, axisDeltaPhi, axisQinv, axisKt}, true); fRegistryCF.add("Pair/same/hPhi_lowerPtV0", "azimuthal angle of lower-p_{T} V0 in pair;#phi (rad);counts", kTH1D, {axisPhi}, true); addFullRangeHistograms("Pair/same/FullRange/"); @@ -704,16 +936,111 @@ struct Photonhbt { fRegistryCF.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current}-BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); } - - // ─── CF: PairSep ──────────────────────── // ─── CF: PairSep ──────────────────────── void addPairSepHistograms() { - for (const auto& sm : {std::string("PairSep/same/"), std::string("PairSep/mix/"), std::string("PairSep/sameAfterCut/"), std::string("PairSep/mixAfterCut/")}) { - fRegistryCF.add((sm + "hDEtaDPhiKt_PP").c_str(), "e^{+}e^{+};#Delta#eta;#Delta#phi (rad);k_{T} (GeV/c)", kTHnSparseF, {{160, -0.4f, 0.4f}, {160, -0.4f, 0.4f}, axisKt}, true); - fRegistryCF.add((sm + "hDEtaDPhiKt_NN").c_str(), "e^{-}e^{-};#Delta#eta;#Delta#phi (rad);k_{T} (GeV/c)", kTHnSparseF, {{160, -0.4f, 0.4f}, {160, -0.4f, 0.4f}, axisKt}, true); - fRegistryCF.add((sm + "hU_Qinv_Kt").c_str(), ";u;q_{inv} (GeV/c);k_{T} (GeV/c)", kTHnSparseF, {{100, 0.f, 10.f}, {50, 0.f, 0.5f}, axisKt}, true); - fRegistryCF.add((sm + "hU_Qinv_dE").c_str(), ";u;q_{inv} (GeV/c);#DeltaE (GeV)", kTHnSparseF, {{100, 0.f, 10.f}, {50, 0.f, 0.5f}, {40, 0.f, 2.f}}, true); + + auto hs = fRegistryCF.add("PairSep/hLegPropStatus", "leg propagation;;legs", kTH1D, {{4, -0.5f, 3.5f}}, true); + hs->GetXaxis()->SetBinLabel(1, "propagated"); + hs->GetXaxis()->SetBinLabel(2, "below R_{conv}"); + hs->GetXaxis()->SetBinLabel(3, "out of reach"); + hs->GetXaxis()->SetBinLabel(4, "bad input"); + // low-pT legs curl up early, so N_valid differs between pairs + fRegistryCF.add("PairSep/hPropStatus_vs_LegPt", "propagation vs leg p_{T};status;p_{T}^{leg} (GeV/c)", + kTH2F, {{4, -0.5f, 3.5f}, {40, 0.f, 2.f}}, true); + fRegistryCF.add("PairSep/hPropStatus_vs_Rconv", "propagation vs conversion radius;status;R_{conv} (cm)", + kTH2F, {{4, -0.5f, 3.5f}, {50, 0.f, 100.f}}, true); + + const AxisSpec axisQcal4{{0.00, 0.01, 0.02, 0.04, 0.06, 0.10, 0.15, 0.20, 0.30, 0.50}}; + + // variable width: fine below 10 cm, coarse above + std::vector sepEdges; + for (int i = 0; i <= 20; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(0.25 * i); // 0 .. 5 cm in 0.25 cm + } + for (int i = 1; i <= 10; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(5.0 + 0.5 * i); // 5 .. 10 cm in 0.5 cm + } + for (int i = 1; i <= 10; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(10.0 + 1.0 * i); // 10 .. 20 cm in 1 cm + } + for (int i = 1; i <= 6; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(20.0 + 5.0 * i); // 20 .. 50 cm in 5 cm + } + const AxisSpec axisSep{sepEdges}; + + std::vector dirs = {"PairSep/same/", "PairSep/mix/"}; + if (mQa.pairSepAfterCut) { + dirs.push_back("PairSep/sameAfterCut/"); + dirs.push_back("PairSep/mixAfterCut/"); + } + + for (const auto& sm : dirs) { + fRegistryCF.add((sm + "hSparse_dRPhiAtMin3D_dZAtMin3D_Qinv").c_str(), "components at the closest 3D approach;d_{r#varphi} @ d^{min}_{3D} (cm);d_{z} @ d^{min}_{3D} (cm);q_{inv} (GeV/c)", + kTHnSparseF, {axisSep, axisSep, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_dMin3D_fClose_Qinv").c_str(), "closest approach vs how long they stay close;d^{min}_{3D} (cm);f_{close}^{r#varphi}(2 cm);q_{inv} (GeV/c)", + kTHnSparseF, {axisSep, {18, -0.028f, 1.028f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_dRPhiMin_fClose_Thr_Qinv").c_str(), "pure r#varphi;d_{r#varphi}^{min} (cm);f_{close}^{r#varphi};threshold index;q_{inv} (GeV/c)", + kTHnSparseF, {{40, 0.f, 10.f}, {18, -0.028f, 1.028f}, {4, -0.5f, 3.5f}, axisQcal4}, true); + fRegistryCF.add((sm + "hSparse_DPair_NClose_Qinv").c_str(), "scaled pair distance;D_{pair}^{min};N_{close};q_{inv} (GeV/c)", + kTHnSparseF, {{40, 0.f, 10.f}, {18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_dRPhi_dZ_Cond").c_str(), "control window;d_{r#varphi} @ D^{min}_{pair} (cm);d_{z} @ D^{min}_{pair} (cm);3#upoint region + drift bin", + kTHnSparseF, {axisSep, axisSep, {12, -0.5f, 11.5f}}, true); + fRegistryCF.add((sm + "hDzLocal_vs_dVtxZ").c_str(), "vertex-local;#Deltaz_{vtx} (cm);d_{z} @ D^{min}_{pair} (cm)", kTH2F, + {{80, -4.f, 4.f}, {100, 0.f, 20.f}}, true); + fRegistryCF.add((sm + "hDzGlobal_vs_dVtxZ").c_str(), "global z;#Deltaz_{vtx} (cm);|z_{1}-z_{2}| @ D^{min}_{pair} (cm)", kTH2F, + {{80, -4.f, 4.f}, {100, 0.f, 20.f}}, true); + fRegistryCF.add((sm + "hDzLocalSigned_vs_dVtxZ").c_str(), "vertex-local, signed;#Deltaz_{vtx} (cm);d_{z}^{signed} (cm)", kTH2F, + {{80, -4.f, 4.f}, {200, -20.f, 20.f}}, true); + fRegistryCF.add((sm + "hDzGlobalSigned_vs_dVtxZ").c_str(), "global z, signed;#Deltaz_{vtx} (cm);z_{1}-z_{2} (cm)", kTH2F, + {{80, -4.f, 4.f}, {200, -20.f, 20.f}}, true); + fRegistryCF.add((sm + "hDriftOld_vs_DriftNew").c_str(), "drift length, same side;L from mean z (cm);L from the two legs (cm)", kTH2F, + {{50, 0.f, 250.f}, {50, 0.f, 250.f}}, true); + fRegistryCF.add((sm + "hDriftOld_vs_DriftNew_opp").c_str(), "drift length, opposite side;L from mean z (cm);L from the two legs (cm)", kTH2F, + {{50, 0.f, 250.f}, {50, 0.f, 250.f}}, true); + fRegistryCF.add((sm + "hZ1_vs_Z2").c_str(), "leg z at D^{min}_{pair};z_{1} (cm);z_{2} (cm)", kTH2F, + {{100, -250.f, 250.f}, {100, -250.f, 250.f}}, true); + auto hss = fRegistryCF.add((sm + "hSameSide_vs_Qinv").c_str(), "TPC side;;q_{inv} (GeV/c)", kTH2F, {{2, -0.5f, 1.5f}, {50, 0.f, 0.5f}}, true); + hss->GetXaxis()->SetBinLabel(1, "opposite side"); + hss->GetXaxis()->SetBinLabel(2, "same side"); + fRegistryCF.add((sm + "hNCommon_vs_Qinv").c_str(), "usable radii;N_{valid};q_{inv} (GeV/c)", kTH2F, {{18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hNSameSide_vs_Qinv").c_str(), "usable radii on the same TPC side;N_{same side};q_{inv} (GeV/c)", kTH2F, {{18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_FClose_NClose_Qinv").c_str(), "scaled closeness;f_{close}^{D};N_{close}^{D};q_{inv} (GeV/c)", kTHnSparseF, {{18, -0.028f, 1.028f}, {18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + if (pairsep.cfgFillCalibSparse.value) { + const AxisSpec axisQcal{{0.00, 0.01, 0.02, 0.04, 0.06, 0.10, 0.15, 0.20, 0.30, 0.50}}; + fRegistryCF.add((sm + "hSparse_Calib_dRPhi_dZ_R_L_C_Q").c_str(), "per-radius calibration;d_{r#varphi} (cm);d_{z} (cm);TPC region;drift bin;charge (0 = e^{+}e^{+});q_{inv} (GeV/c)", + kTHnSparseF, {{32, 0.f, 8.f}, {32, 0.f, 8.f}, {4, -0.5f, 3.5f}, {3, -0.5f, 2.5f}, {2, -0.5f, 1.5f}, axisQcal}, true); + fRegistryCF.add((sm + "hSparse_dRPhi_dZ_LegClass_L_Q").c_str(), "by leg type;d_{r#varphi} (cm);d_{z} (cm);leg class (0: <2, 1: #geq2 ITS-TPC legs);drift bin;q_{inv} (GeV/c)", + kTHnSparseF, {{32, 0.f, 8.f}, {32, 0.f, 8.f}, {2, -0.5f, 1.5f}, {3, -0.5f, 2.5f}, axisQcal}, true); + + fRegistryCF.add((sm + "hSparse_DzSignedLocal_dVtxZ_R").c_str(), "vertex QA, all radii;d_{z}^{signed,local} (cm);#Deltaz_{vtx} (cm);r (cm)", + kTHnSparseF, {{80, -20.f, 20.f}, {20, -4.f, 4.f}, {17, 82.5f, 252.5f}}, true); + fRegistryCF.add((sm + "hSparse_Calib_OppositeSide").c_str(), "opposite-side points;d_{r#varphi} (cm);d_{z} (cm)", kTH2F, + {{32, 0.f, 8.f}, {32, 0.f, 8.f}}, true); + } + fRegistryCF.add((sm + "hSparse_fCloseRPhi_dR_Qinv").c_str(), "fraction of TPC radii with transverse leg distance < 2 cm;f_{close}^{r#varphi}(2 cm);|R_{1}-R_{2}| (cm);q_{inv} (GeV/c)", + kTHnSparseF, {{18, -0.028f, 1.028f}, {90, 0.f, 180.f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hDRPhiMin_All_vs_SameSide").c_str(), "r#varphi minimum;d_{r#varphi}^{min}, all radii (cm);d_{r#varphi}^{min}, same side (cm)", + kTH2F, {{40, 0.f, 10.f}, {40, 0.f, 10.f}}, true); + fRegistryCF.add((sm + "hDMin3D_PP_vs_NN").c_str(), "d^{min}_{3D};e^{+}e^{+} (cm);e^{-}e^{-} (cm)", kTH2F, + {axisSep, axisSep}, true); + fRegistryCF.add((sm + "hFClose_PP_vs_NN").c_str(), "f_{close}^{r#varphi}(2 cm);e^{+}e^{+};e^{-}e^{-}", kTH2F, + {{18, -0.028f, 1.028f}, {18, -0.028f, 1.028f}}, true); + } + } + + void addCrossPairHistograms() + { + if (!(crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value)) { + return; + } + for (const auto& sm : {std::string("Pair/same/CrossPair/"), std::string("Pair/mix/CrossPair/")}) { + fRegistryCF.add((sm + "hSparse_MeeRatio_dR_Qinv").c_str(), + "crossed-hypothesis QA;min(m_{ee}^{cross})/q_{inv};|R_{1}-R_{2}| (cm);q_{inv} (GeV/c)", + kTHnSparseF, {{100, 0.f, 2.f}, {80, 0.f, 80.f}, {60, 0.f, 0.3f}}, true); + auto h = fRegistryCF.add((sm + "hVetoCounter").c_str(), "crossed-pair veto;;pairs", kTH1D, {{2, -0.5f, 1.5f}}, true); + h->GetXaxis()->SetBinLabel(1, "evaluated"); + h->GetXaxis()->SetBinLabel(2, "vetoed"); } } @@ -735,8 +1062,10 @@ struct Photonhbt { } fRegistryPairQA.addClone("Pair/same/QA/", "Pair/mix/QA/"); - addLegPairQAForStep("Pair/same/QA/Before/"); - addLegPairQAForStep("Pair/same/QA/AfterPairCuts/"); + if (mQa.legPairQa) { + addLegPairQAForStep("Pair/same/QA/Before/"); + addLegPairQAForStep("Pair/same/QA/AfterPairCuts/"); + } } void addPairMCHistograms() @@ -901,9 +1230,6 @@ struct Photonhbt { axisDeltaEta, axisDeltaPhi, axisKt); addStageHistos2D("hQinvVsKt", "q_{inv}^{true} vs k_{T};k_{T} (GeV/c);q_{inv}^{true} (GeV/c)", axisKt, axQinvMC); addStageHistos2D("hDEtaDPhi", "#Delta#eta vs #Delta#phi;#Delta#eta_{#gamma#gamma};#Delta#phi_{#gamma#gamma} (rad)", axisDeltaEta, axisDeltaPhi); - const AxisSpec axisUtrue{100, 0.f, 10.f, "u^{true}"}; - addStageHistos2D("hUtrueVsKt", "u^{true} vs k_{T};k_{T} (GeV/c);u^{true}", axisKt, axisUtrue); - addStageHistos2D("hUtrueVsQinv", "u^{true} vs q_{inv}^{true};q_{inv}^{true} (GeV/c);u^{true}", axQinvMC, axisUtrue); // ─── Rconv waterfall fRegistryTruthMC.add("MC/TruthAO2D/hRconv1_vs_Rconv2_truthConverted", "denominator: R_{conv,1} vs R_{conv,2};R_{conv,1}^{true} (cm);R_{conv,2}^{true} (cm)", kTH2D, {axRconv, axRconv}, true); @@ -912,12 +1238,8 @@ struct Photonhbt { fRegistryTruthMC.add("MC/TruthAO2D/hMinRconv_vs_kT_bothPhotonsSelected", "numerator: min(R_{conv}) vs k_{T};k_{T} (GeV/c);min(R_{conv}^{true}) (cm)", kTH2D, {axisKt, axRconv}, true); // ─── Stage summary - fRegistryTruthMC.add("MC/TruthAO2D/hStage_vs_kT", - "efficiency waterfall;k_{T} (GeV/c);stage (0=converted,1=all4legs,2=bothBuilt,3=bothSel)", - kTH2D, {axisKt, AxisSpec{4, -0.5f, 3.5f, "stage"}}, true); - fRegistryTruthMC.add("MC/TruthAO2D/hStageConsistency", - "stage consistency (expect all at 0);N(V0 built but legs not found);counts", - kTH1D, {AxisSpec{20, -0.5f, 19.5f, "N_{bad}"}}, true); + fRegistryTruthMC.add("MC/TruthAO2D/hStage_vs_kT", "efficiency waterfall;k_{T} (GeV/c);stage (0=converted,1=all4legs,2=bothBuilt,3=bothSel)", kTH2D, {axisKt, AxisSpec{4, -0.5f, 3.5f, "stage"}}, true); + fRegistryTruthMC.add("MC/TruthAO2D/hStageConsistency", "stage consistency (expect all at 0);N(V0 built but legs not found);counts", kTH1D, {AxisSpec{20, -0.5f, 19.5f, "N_{bad}"}}, true); // ─── Single-leg diagnostics ────────────────────────────────────────── fRegistryTruthMC.add("MC/LegDiag/hLegDRtrue_vs_pt_legFound", "leg found: #Delta R^{true} vs p_{T};p_{T,#gamma}^{true} (GeV/c);#Delta R_{e^{+}e^{-}}^{true}", kTH2D, {axisPt, axLegDR}, true); @@ -956,8 +1278,11 @@ struct Photonhbt { const std::string base = std::string("Pair/same/MC/") + std::string(label) + "LegLS/"; fRegistryPairMC.add((base + "hSparse_DR_kT_minLegPt_PP").c_str(), "e^{+}e^{+} #DeltaR,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDR, axisKt, axisLegPt}, false); fRegistryPairMC.add((base + "hSparse_DR_kT_minLegPt_NN").c_str(), "e^{-}e^{-} #DeltaR,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDR, axisKt, axisLegPt}, false); - fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, false); - fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, false); + if (qaflags.cfgFillLegPairSparses.value) { + const AxisSpec axDE{80, -0.8f, 0.8f, "#Delta#eta"}, axDP{80, -0.8f, 0.8f, "#Delta#phi (rad)"}, axP{20, 0.f, 2.f, "p_{T} (GeV/c)"}; + fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axDE, axDP, axP, axP}, false); + fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axDE, axDP, axP, axP}, false); + } } const AxisSpec axisTruthType{{0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5}, "truth type"}; @@ -977,7 +1302,13 @@ struct Photonhbt { fRegistryCF.add((path + "hDeltaR3DVsQinv").c_str(), "#Delta r_{3D} vs q_{inv};q_{inv} (GeV/c);#Delta r_{3D} (cm)", kTH2D, {axisQinv, axisDeltaR3D}, true); fRegistryCF.add((path + "hQinvVsCent").c_str(), "q_{inv} vs centrality;centrality (%);q_{inv} (GeV/c)", kTH2D, {axisCentQA, axisQinv}, true); fRegistryCF.add((path + "hQinvVsOccupancy").c_str(), "q_{inv} vs occupancy;occupancy;q_{inv} (GeV/c)", kTH2D, {axisOccupancy, axisQinv}, true); - fRegistryCF.add((path + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv}", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); + if (mQa.fillDRDZSparse) { + fRegistryCF.add((path + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv}", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); + } + // partner radius at fixed R1, differentially in q_inv + if (mQa.fillR1R2Sparse) { + fRegistryCF.add((path + "hSparseR1R2Qinv").c_str(), "R_{1},R_{2},q_{inv};R_{1} (cm);R_{2} (cm);q_{inv} (GeV/c)", kTHnSparseD, {axisR, axisR, axisQinv}, true); + } fRegistryCF.add((path + "hDeltaRCosOAVsQinv").c_str(), "#Delta r/cos(#theta_{op}/2) vs q_{inv};q_{inv} (GeV/c);#Delta r/cos(#theta_{op}/2) (cm)", kTH2D, {axisQinv, {100, 0, 100}}, true); } @@ -1011,16 +1342,25 @@ struct Photonhbt { void addLegPairQAForStep(const std::string& path) { + // local, not members: each member costs one of the 99 decomposable slots + const AxisSpec axisLegDEtaCoarse{80, -0.8f, 0.8f, "#Delta#eta"}; + const AxisSpec axisLegDPhiCoarse{80, -0.8f, 0.8f, "#Delta#phi (rad)"}; + const AxisSpec axisLegPtCoarse{20, 0.f, 2.f, "p_{T}^{leg} (GeV/c)"}; + const AxisSpec axisPtCoarse{20, 0.f, 2.f, "p_{T} (GeV/c)"}; // LS positive fRegistryPairQA.add((path + "LegLS/hDEtaDPhi_PP").c_str(), "e^{+}e^{+} #Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisKt, axisLegPt}, true); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisKt, axisLegPtCoarse}, true); + } fRegistryPairQA.add((path + "LegLS/hDR_PP").c_str(), "e^{+}e^{+} #DeltaR;#DeltaR;counts", kTH1D, {axisLegDR}, true); fRegistryPairQA.add((path + "LegLS/hLegPtLow_vs_LegPtHigh_PP").c_str(), "e^{+}e^{+} p_{T,low} vs p_{T,high};p_{T,low}^{leg};p_{T,high}^{leg}", kTH2D, {axisLegPt, axisLegPt}, true); fRegistryPairQA.add((path + "LegLS/hDR_PP_vs_minLegPt").c_str(), "e^{+}e^{+} #DeltaR vs min(p_{T,leg});#DeltaR;min(p_{T,leg}) (GeV/c)", kTH2D, {axisLegDR, axisLegPt}, true); // LS negative fRegistryPairQA.add((path + "LegLS/hDEtaDPhi_NN").c_str(), "e^{-}e^{-} #Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisKt, axisLegPt}, true); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisKt, axisLegPtCoarse}, true); + } fRegistryPairQA.add((path + "LegLS/hDR_NN").c_str(), "e^{-}e^{-} #DeltaR;#DeltaR;counts", kTH1D, {axisLegDR}, true); fRegistryPairQA.add((path + "LegLS/hLegPtLow_vs_LegPtHigh_NN").c_str(), "e^{-}e^{-} p_{T,low} vs p_{T,high};p_{T,low}^{leg};p_{T,high}^{leg}", kTH2D, {axisLegPt, axisLegPt}, true); fRegistryPairQA.add((path + "LegLS/hDR_NN_vs_minLegPt").c_str(), "e^{-}e^{-} #DeltaR vs min(p_{T,leg});#DeltaR;min(p_{T,leg}) (GeV/c)", kTH2D, {axisLegDR, axisLegPt}, true); @@ -1032,14 +1372,16 @@ struct Photonhbt { fRegistryPairQA.add((path + "LegUScross/hDEtaDPhi_NP12").c_str(), "ele1-pos2 #Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); // 4D Photon-pT diagnostics - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), - "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" - "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", - kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, true); - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), - "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" - "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", - kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, true); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), + "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" + "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", + kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisPtCoarse, axisPtCoarse}, true); + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), + "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" + "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", + kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisPtCoarse, axisPtCoarse}, true); + } // Photon-pT Scatter fRegistryPairQA.add((path + "LegLS/hPtG1_vs_PtG2").c_str(), "p_{T,#gamma 1} vs p_{T,#gamma 2};p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", kTH2D, {axisPt, axisPt}, true); @@ -1080,10 +1422,8 @@ struct Photonhbt { static int binOf(const std::vector& edges, float val) { - const int b = static_cast( - std::lower_bound(edges.begin(), edges.end(), val) - edges.begin()) - - 1; - return clampBin(b, static_cast(edges.size()) - 2); // + const auto pos = static_cast(std::lower_bound(edges.begin(), edges.end(), val) - edges.begin()); + return clampBin(pos - 1, static_cast(edges.size()) - 2); } template @@ -1178,10 +1518,12 @@ struct Photonhbt { return o; } + // not const: fills the propagation-status histogram template - [[nodiscard]] PhotonWithLegs makePhotonWithLegs(TGamma const& g, TLeg const& pos, TLeg const& ele) const + [[nodiscard]] PhotonWithLegs makePhotonWithLegs(TGamma const& g, TLeg const& pos, TLeg const& ele, float vtxZ) { PhotonWithLegs p; + p.fVtxZ = vtxZ; p.fPt = g.pt(); p.fEta = g.eta(); p.fPhi = g.phi(); @@ -1192,15 +1534,18 @@ struct Photonhbt { p.fLegEta = {static_cast(pos.eta()), static_cast(ele.eta())}; p.fLegPhi = {static_cast(pos.phi()), static_cast(ele.phi())}; p.fLegCounts = pairutil::getV0PhotonLegCounts(pos, ele); - const float rConvCm = std::hypot(p.fVx, p.fVy); + p.fNITSTPC = p.fLegCounts.nITSTPC; + // legHelixAt itself rejects radii below the conversion point for (size_t ir = 0; ir < kPhiStarRadiiM.size(); ++ir) { - if (kPhiStarRadiiM[ir] * kCmPerM < rConvCm) { // leg does not exist below R_conv - p.fLegPhiStar[0][ir] = kPhiStarInvalid; - p.fLegPhiStar[1][ir] = kPhiStarInvalid; - continue; + for (int il = 0; il < 2; ++il) { // o2-linter: disable=magic-number (two legs) + const auto h = legHelixAt(p.fVx / kCmPerM, p.fVy / kCmPerM, p.fLegPhi[il], p.fLegPt[il], + (il == 0) ? +1 : -1, mBzT, kPhiStarRadiiM[ir]); + p.fLegPhiStar[il][ir] = h.phiStar; + p.fLegSxy[il][ir] = h.sxy; + fRegistryCF.fill(HIST("PairSep/hLegPropStatus"), static_cast(h.status)); + fRegistryCF.fill(HIST("PairSep/hPropStatus_vs_LegPt"), static_cast(h.status), p.fLegPt[il]); + fRegistryCF.fill(HIST("PairSep/hPropStatus_vs_Rconv"), static_cast(h.status), std::hypot(p.fVx, p.fVy)); } - p.fLegPhiStar[0][ir] = legPhiStar(p.fLegPhi[0], p.fLegPt[0], +1, mBzT, kPhiStarRadiiM[ir]); - p.fLegPhiStar[1][ir] = legPhiStar(p.fLegPhi[1], p.fLegPt[1], -1, mBzT, kPhiStarRadiiM[ir]); } return p; } @@ -1208,75 +1553,232 @@ struct Photonhbt { [[nodiscard]] PairSep computePairSep(PhotonWithLegs const& a, PhotonWithLegs const& b) const { PairSep s; - const float sE = pairsep.cfgUSigEta.value, sP = pairsep.cfgUSigPhi.value; - auto uSameSign = [&](int i, float& dEtaOut, float& dPhiOut) -> float { - dEtaOut = a.fLegEta[i] - b.fLegEta[i]; - if (!pairsep.cfgUsePhiStar.value) { - dPhiOut = RecoDecay::constrainAngle(a.fLegPhi[i] - b.fLegPhi[i], -o2::constants::math::PI); - return std::hypot(dEtaOut / sE, dPhiOut / sP); - } - float sumDp = 0.f; - int n = 0; + s.dVtxZ = a.fVtxZ - b.fVtxZ; + s.nLegsITSTPC = a.fNITSTPC + b.fNITSTPC; + + const float sigR = std::max(pairsep.cfgSigRPhi.value, kMinSigma); + const float sigZcm = (pairsep.cfgSigZNs.value > 0.f && mVDriftCmPerNs > 0.f) + ? pairsep.cfgSigZNs.value * mVDriftCmPerNs + : pairsep.cfgSigZ.value; + const float sigZ = std::max(sigZcm, kMinSigma); + const float dClose = pairsep.cfgDPairClose.value; + for (int i = 0; i < 2; ++i) { // o2-linter: disable=magic-number (PP and NN) + int nHere = 0, nSame = 0, nCloseD = 0; + std::array nCloseThr{}; + float best3 = 999.f, bestR = 999.f, bestD = 999.f; + float bestRAll = 999.f, bestDAll = 999.f; + float rphiAt3 = 999.f, zAt3 = 999.f, zAtR = 999.f; + float rphiAtD = 999.f, zAtD = 999.f, rAtD = -1.f, absZAtD = -1.f; + float zGlobAtD = 999.f, zSgnLocAtD = 999.f, zSgnGlobAtD = 999.f; + float driftAtD = -1.f, driftOldAtD = -1.f; for (size_t ir = 0; ir < kPhiStarRadiiM.size(); ++ir) { const float p1 = a.fLegPhiStar[i][ir], p2 = b.fLegPhiStar[i][ir]; - if (p1 < -100.f || p2 < -100.f) { // o2-linter: disable=magic-number (skip if non-sensical value is chosen) + if (p1 < -100.f || p2 < -100.f) { // o2-linter: disable=magic-number (invalid phi*) + continue; + } + const float rCm = kPhiStarRadiiM[ir] * kCmPerM; + const float dphi = RecoDecay::constrainAngle(p1 - p2, -o2::constants::math::PI); + const float dRPhi = 2.f * rCm * std::fabs(std::sin(0.5f * dphi)); + const float z1 = a.fVz + a.fLegSxy[i][ir] * kCmPerM * std::sinh(a.fLegEta[i]); + const float z2 = b.fVz + b.fLegSxy[i][ir] * kCmPerM * std::sinh(b.fLegEta[i]); + const float dZSignedLocal = (z1 - a.fVtxZ) - (z2 - b.fVtxZ); + const float dZSignedGlobal = z1 - z2; + const float dZ = std::fabs(dZSignedLocal); + const float dZGlobal = std::fabs(dZSignedGlobal); + const float d3 = std::hypot(dRPhi, dZ); + const float zMax = pairsep.cfgTpcHalfLengthCm.value; + const float l1 = std::max(0.f, zMax - std::fabs(z1)); + const float l2 = std::max(0.f, zMax - std::fabs(z2)); + const float driftHere = 0.5f * (l1 + l2); + const float driftOldHere = std::max(0.f, zMax - 0.5f * std::fabs(z1 + z2)); + const bool sameSide = (z1 * z2 >= 0.f); + const float dPair = std::hypot(dRPhi / sigR, dZ / sigZ); + ++nHere; + s.ptR[i][nHere - 1] = rCm; + s.ptDRPhi[i][nHere - 1] = dRPhi; + s.ptDZ[i][nHere - 1] = dZ; + s.ptDZSgnLocal[i][nHere - 1] = dZSignedLocal; + s.ptDrift[i][nHere - 1] = driftHere; + s.ptSameSide[i][nHere - 1] = sameSide ? 1.f : 0.f; + bestRAll = std::min(bestRAll, dRPhi); + bestDAll = std::min(bestDAll, dPair); + if (d3 < best3) { + best3 = d3; + rphiAt3 = dRPhi; + zAt3 = dZ; + } + if (!sameSide) { continue; } - sumDp += RecoDecay::constrainAngle(p1 - p2, -o2::constants::math::PI); - ++n; + ++nSame; + for (std::size_t t = 0; t < s.nCloseRPhiThr.size(); ++t) { + if (dRPhi < pairsep.cfgCloseThrCm.value[t]) { + ++nCloseThr[t]; + } + } + if (dPair < dClose) { + ++nCloseD; + } + if (dPair < bestD) { + bestD = dPair; + rphiAtD = dRPhi; + zAtD = dZ; + zGlobAtD = dZGlobal; + zSgnLocAtD = dZSignedLocal; + zSgnGlobAtD = dZSignedGlobal; + rAtD = rCm; + absZAtD = 0.5f * std::fabs(z1 + z2); + driftAtD = driftHere; + driftOldAtD = driftOldHere; + } + if (dRPhi < bestR) { + bestR = dRPhi; + zAtR = dZ; + } } - if (n == 0) { - dPhiOut = 999.f; - return 999.f; + if (nHere == 0) { + continue; } - dPhiOut = sumDp / static_cast(n); - return std::hypot(dEtaOut / sE, dPhiOut / sP); - }; - const float uPP = uSameSign(0, s.dEtaPP, s.dPhiPP); - const float uNN = uSameSign(1, s.dEtaNN, s.dPhiNN); - s.u = std::min(uPP, uNN); + s.nPoints[i] = nHere; + s.nSameSidePerCharge[i] = nSame; + s.dMin3DPerCharge[i] = best3; + s.dPairMinPerCharge[i] = bestD; + s.dMinRPhiPerCharge[i] = bestR; + s.dMinRPhiAll = std::min(s.dMinRPhiAll, bestRAll); + s.dPairMinAll = std::min(s.dPairMinAll, bestDAll); + const float invS = (nSame > 0) ? 1.f / static_cast(nSame) : 0.f; + for (std::size_t t = 0; t < nCloseThr.size(); ++t) { + s.nCloseRPhiThrPerCharge[i][t] = nCloseThr[t]; + s.fCloseRPhiThrPerCharge[i][t] = static_cast(nCloseThr[t]) * invS; + } + s.fCloseRPhiPerCharge[i] = s.fCloseRPhiThrPerCharge[i][3]; // o2-linter: disable=magic-number (last threshold) + if (bestD < s.dPairMin) { + s.dPairMin = bestD; + s.dRPhiAtDPairMin = rphiAtD; + s.dZAtDPairMin = zAtD; + s.dZGlobalAtDPairMin = zGlobAtD; + s.dZSignedLocalAtDPairMin = zSgnLocAtD; + s.dZSignedGlobalAtDPairMin = zSgnGlobAtD; + s.rAtDPairMin = rAtD; + s.absZAtDPairMin = absZAtD; + s.driftLen = driftAtD; + s.driftOldAtDPairMin = driftOldAtD; + s.nCloseScaled = nCloseD; + s.fCloseScaled = static_cast(nCloseD) * invS; + } + if (best3 < s.dMin3D) { + s.dMin3D = best3; + s.dRPhiAtMin3D = rphiAt3; + s.dZAtMin3D = zAt3; + s.criticalCharge = i; + } + if (bestR < s.dMinRPhi) { + s.dMinRPhi = bestR; + s.dZAtMinRPhi = zAtR; + s.nCloseRPhiThr = s.nCloseRPhiThrPerCharge[i]; + s.fCloseRPhiThr = s.fCloseRPhiThrPerCharge[i]; + s.fCloseRPhi = s.fCloseRPhiThr[3]; // o2-linter: disable=magic-number (last threshold) + s.nSameSide = nSame; + s.rphiCharge = i; + } + } + s.sameSideAtDPairMin = (s.nSameSidePerCharge[0] + s.nSameSidePerCharge[1]) > 0; + s.nCommon = (s.rphiCharge >= 0) ? s.nPoints[s.rphiCharge] + : std::max(s.nPoints[0], s.nPoints[1]); return s; } - [[nodiscard]] inline bool passLegSepCut(PairSep const& s) const + template + [[nodiscard]] inline bool passFastQinvGate(TG1 const& g1, TG2 const& g2) const { - if (!pairsep.cfgDoLegSepCut.value) { + const float qMax = qaflags.cfgMaxQinvForProcessing.value; + if (qMax > 1e9f) { // o2-linter: disable=magic-number (skip if non-sensical value is chosen) return true; } - return s.u > pairsep.cfgUCut.value; + const float dEta = g1.eta() - g2.eta(); + const float dPhi = RecoDecay::constrainAngle(g1.phi() - g2.phi(), -o2::constants::math::PI); + const float q2 = 2.f * g1.pt() * g2.pt() * (std::cosh(dEta) - std::cos(dPhi)); + return q2 <= qMax * qMax; } - [[nodiscard]] float uTrue(TruthGamma const& g1, TruthGamma const& g2) const + [[nodiscard]] inline bool passPairMergeCut(PairSep const& s) const { - const float sE = pairsep.cfgUSigEta.value, sP = pairsep.cfgUSigPhi.value; - auto uSameSign = [&](int i) -> float { - const float dEta = g1.legEtaTrue[i] - g2.legEtaTrue[i]; - if (!pairsep.cfgUsePhiStar.value) { - const float dp = RecoDecay::constrainAngle(g1.legPhiTrue[i] - g2.legPhiTrue[i], -o2::constants::math::PI); - return std::hypot(dEta / sE, dp / sP); - } - const int q = (i == 0) ? +1 : -1; - float sumDp = 0.f; - int n = 0; - for (const float& r : kPhiStarRadiiM) { - if ((g1.rTrue >= 0.f && r * kCmPerM < g1.rTrue) || - (g2.rTrue >= 0.f && r * kCmPerM < g2.rTrue)) { - continue; - } - const float p1 = legPhiStar(g1.legPhiTrue[i], g1.legPtTrue[i], q, mBzT, r); - const float p2 = legPhiStar(g2.legPhiTrue[i], g2.legPtTrue[i], q, mBzT, r); - if (p1 < -100.f || p2 < -100.f) { // o2-linter: disable=magic-number (skip if non-sensical value is chosen) - continue; - } - sumDp += RecoDecay::constrainAngle(p1 - p2, -o2::constants::math::PI); - ++n; - } - if (n == 0) { - return 999.f; - } - return std::hypot(dEta / sE, (sumDp / static_cast(n)) / sP); + if (!pairsep.cfgDoPairMergeCut.value) { + return true; + } + if (s.nCommon <= 0) { // nothing was propagated: no statement possible + return true; + } + if (s.dPairMin < pairsep.cfgDPairCut.value) { + return false; + } + const int nCut = pairsep.cfgNCloseCut.value; + // dipping close once is survivable, running alongside is not + return nCut <= 0 || s.nCloseScaled < nCut; + } + + [[nodiscard]] inline int tpcRegion(float rCm) const + { + if (rCm < pairsep.cfgRegionEdge1.value) { + return 0; + } + if (rCm < pairsep.cfgRegionEdge2.value) { + return 1; + } + if (rCm < pairsep.cfgRegionEdge3.value) { + return 2; // o2-linter: disable=magic-number (region index) + } + return 3; // o2-linter: disable=magic-number (region index) + } + + [[nodiscard]] inline int driftBin(float driftLen) const + { + const float third = pairsep.cfgTpcHalfLengthCm.value / 3.f; // o2-linter: disable=magic-number (three drift slices) + if (driftLen < third) { + return 0; + } + if (driftLen < 2.f * third) { // o2-linter: disable=magic-number (three drift slices) + return 1; + } + return 2; // o2-linter: disable=magic-number (three drift slices) + } + + [[nodiscard]] CrossObs computeCrossObs(PhotonWithLegs const& a, PhotonWithLegs const& b, float qinv) const + { + constexpr float kMe = 0.000510999f; // electron mass, GeV/c^2 + CrossObs c; + auto legVec = [](PhotonWithLegs const& p, int i) { + return ROOT::Math::PtEtaPhiMVector(p.fLegPt[i], p.fLegEta[i], p.fLegPhi[i], kMe); }; - return std::min(uSameSign(0), uSameSign(1)); + // Combo 0: a's e+ with b's e-. Combo 1: b's e+ with a's e-. + for (int combo = 0; combo < 2; ++combo) { // o2-linter: disable=magic-number (the two leg-swap combinations) + PhotonWithLegs const& pPos = (combo == 0) ? a : b; + PhotonWithLegs const& pEle = (combo == 0) ? b : a; + c.mee[combo] = static_cast((legVec(pPos, 0) + legVec(pEle, 1)).M()); + } + if (qinv > 0.f) { + c.meeOverQ = std::min(c.mee[0], c.mee[1]) / qinv; + } + return c; + } + + [[nodiscard]] inline bool passCrossPairVeto(CrossObs const& c) const + { + if (!crosspair.cfgDoCrossPairCut.value) { + return true; + } + return c.meeOverQ > crosspair.cfgCrossMaxMeeRatio.value; + } + + template + inline void fillCrossPair(CrossObs const& c, float qinv, float deltaR, bool vetoed) + { + constexpr auto dir = (ev_id == 0) ? "Pair/same/CrossPair/" : "Pair/mix/CrossPair/"; + fRegistryCF.fill(HIST(dir) + HIST("hVetoCounter"), vetoed ? 1.0 : 0.0); + if (qinv > crosspair.cfgCrossMaxQinvQA.value) { + return; + } + fRegistryCF.fill(HIST(dir) + HIST("hSparse_MeeRatio_dR_Qinv"), c.meeOverQ, deltaR, qinv); } /*************************************************/ @@ -1292,24 +1794,82 @@ struct Photonhbt { fRegistryCF.fill(HIST(base) + HIST("hDeltaR3DVsQinv"), obs.qinv, obs.deltaR3D); fRegistryCF.fill(HIST(base) + HIST("hQinvVsCent"), cent, obs.qinv); fRegistryCF.fill(HIST(base) + HIST("hQinvVsOccupancy"), occupancy, obs.qinv); - fRegistryCF.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), obs.deltaR, obs.deltaZ, obs.qinv); + if (mQa.fillDRDZSparse) { + fRegistryCF.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), obs.deltaR, obs.deltaZ, obs.qinv); + } + if (mQa.fillR1R2Sparse) { + // both orderings: the pair is unordered + fRegistryCF.fill(HIST(base) + HIST("hSparseR1R2Qinv"), obs.r1, obs.r2, obs.qinv); + fRegistryCF.fill(HIST(base) + HIST("hSparseR1R2Qinv"), obs.r2, obs.r1, obs.qinv); + } } template inline void fillPairSep(PairSep const& s, PairQAObservables const& obs) { - if (!pairsep.cfgDoPairSepQA.value) { + if (!mQa.pairSepQa) { return; } + // the AfterCut directories only exist when a pair cut is active + if constexpr (after_cut) { + if (!mQa.pairSepAfterCut) { + return; + } + } const float limit = pairsep.cfgPairSepMaxQinv.value; if (limit > 0.f && obs.qinv >= limit) { return; } constexpr auto dir = pairSepPrefix(); - fRegistryCF.fill(HIST(dir) + HIST("hDEtaDPhiKt_PP"), s.dEtaPP, s.dPhiPP, obs.kt); - fRegistryCF.fill(HIST(dir) + HIST("hDEtaDPhiKt_NN"), s.dEtaNN, s.dPhiNN, obs.kt); - fRegistryCF.fill(HIST(dir) + HIST("hU_Qinv_Kt"), s.u, obs.qinv, obs.kt); - fRegistryCF.fill(HIST(dir) + HIST("hU_Qinv_dE"), s.u, obs.qinv, std::fabs(obs.v1.E() - obs.v2.E())); + if (s.nCommon > 0) { + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhiAtMin3D_dZAtMin3D_Qinv"), s.dRPhiAtMin3D, s.dZAtMin3D, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dMin3D_fClose_Qinv"), s.dMin3D, s.fCloseRPhi, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_fCloseRPhi_dR_Qinv"), s.fCloseRPhi, obs.deltaR, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hDRPhiMin_All_vs_SameSide"), s.dMinRPhiAll, s.dMinRPhi); + fRegistryCF.fill(HIST(dir) + HIST("hDMin3D_PP_vs_NN"), s.dMin3DPerCharge[0], s.dMin3DPerCharge[1]); + fRegistryCF.fill(HIST(dir) + HIST("hFClose_PP_vs_NN"), s.fCloseRPhiPerCharge[0], s.fCloseRPhiPerCharge[1]); + for (std::size_t t = 0; t < s.fCloseRPhiThr.size(); ++t) { + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhiMin_fClose_Thr_Qinv"), s.dMinRPhi, + s.fCloseRPhiThr[t], static_cast(t), obs.qinv); + } + fRegistryCF.fill(HIST(dir) + HIST("hSparse_DPair_NClose_Qinv"), s.dPairMin, static_cast(s.nCloseScaled), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hDzLocal_vs_dVtxZ"), s.dVtxZ, s.dZAtDPairMin); + fRegistryCF.fill(HIST(dir) + HIST("hDzGlobal_vs_dVtxZ"), s.dVtxZ, s.dZGlobalAtDPairMin); + fRegistryCF.fill(HIST(dir) + HIST("hDzLocalSigned_vs_dVtxZ"), s.dVtxZ, s.dZSignedLocalAtDPairMin); + fRegistryCF.fill(HIST(dir) + HIST("hDzGlobalSigned_vs_dVtxZ"), s.dVtxZ, s.dZSignedGlobalAtDPairMin); + if (s.sameSideAtDPairMin) { + fRegistryCF.fill(HIST(dir) + HIST("hDriftOld_vs_DriftNew"), s.driftOldAtDPairMin, s.driftLen); + } else { + fRegistryCF.fill(HIST(dir) + HIST("hDriftOld_vs_DriftNew_opp"), s.driftOldAtDPairMin, s.driftLen); + } + fRegistryCF.fill(HIST(dir) + HIST("hSameSide_vs_Qinv"), s.sameSideAtDPairMin ? 1.f : 0.f, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hNCommon_vs_Qinv"), static_cast(s.nCommon), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hNSameSide_vs_Qinv"), static_cast(s.nSameSide), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_FClose_NClose_Qinv"), s.fCloseScaled, static_cast(s.nCloseScaled), obs.qinv); + if (pairsep.cfgFillCalibSparse.value) { + for (int ic = 0; ic < 2; ++ic) { // o2-linter: disable=magic-number (PP and NN) + for (int k = 0; k < s.nPoints[ic]; ++k) { + fRegistryCF.fill(HIST(dir) + HIST("hSparse_DzSignedLocal_dVtxZ_R"), + s.ptDZSgnLocal[ic][k], s.dVtxZ, s.ptR[ic][k]); + if (s.ptSameSide[ic][k] < 0.5f) { // o2-linter: disable=magic-number (indication of side) + fRegistryCF.fill(HIST(dir) + HIST("hSparse_Calib_OppositeSide"), s.ptDRPhi[ic][k], s.ptDZ[ic][k]); + continue; // cannot merge: different endcap + } + fRegistryCF.fill(HIST(dir) + HIST("hSparse_Calib_dRPhi_dZ_R_L_C_Q"), s.ptDRPhi[ic][k], s.ptDZ[ic][k], + static_cast(tpcRegion(s.ptR[ic][k])), static_cast(driftBin(s.ptDrift[ic][k])), + static_cast(ic), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhi_dZ_LegClass_L_Q"), s.ptDRPhi[ic][k], s.ptDZ[ic][k], + (s.nLegsITSTPC >= 2) ? 1.f : 0.f, // o2-linter: disable=magic-number (two leg classes) + static_cast(driftBin(s.ptDrift[ic][k])), obs.qinv); + } + } + } + if (obs.qinv >= pairsep.cfgCondQinvMin.value && obs.qinv < pairsep.cfgCondQinvMax.value && + s.rAtDPairMin > 0.f) { + const auto cond = static_cast(3 * tpcRegion(s.rAtDPairMin) + driftBin(s.driftLen)); // o2-linter: disable=magic-number (three drift bins per region) + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhi_dZ_Cond"), s.dRPhiAtDPairMin, s.dZAtDPairMin, cond); + } + } } template @@ -1328,7 +1888,7 @@ struct Photonhbt { template inline void fillSinglePhotonQAStep(TPhoton const& g) { - if (!qaflags.doSinglePhotonQa) { + if (!mQa.singlePhotonQa) { return; } constexpr auto base = singlePhotonQAPrefix(); @@ -1425,7 +1985,7 @@ struct Photonhbt { template inline void fillPairQAStep(PairQAObservables const& o, float /*cent*/, float /*occupancy*/) { - if (!qaflags.doPairQa) { + if (!mQa.pairQa) { return; } constexpr auto base = qaPrefix(); @@ -1465,19 +2025,23 @@ struct Photonhbt { template inline void fillLegPairQAStep(LegPairObservables const& lo, float kt) { - if (!qaflags.doPairQa) { + if (!mQa.legPairQa) { return; } constexpr auto base = qaPrefix<0, step_id>(); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDEtaDPhi_PP"), lo.dEtaPP, lo.dPhiPP); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP"), lo.dEtaPP, lo.dPhiPP, kt, lo.minLegPt_PP); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP"), lo.dEtaPP, lo.dPhiPP, kt, lo.minLegPt_PP); + } fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_PP"), lo.dRPP); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hLegPtLow_vs_LegPtHigh_PP"), lo.minLegPt_PP, lo.maxLegPt_PP); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_PP_vs_minLegPt"), lo.dRPP, lo.minLegPt_PP); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDEtaDPhi_NN"), lo.dEtaNN, lo.dPhiNN); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN"), lo.dEtaNN, lo.dPhiNN, kt, lo.minLegPt_NN); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN"), lo.dEtaNN, lo.dPhiNN, kt, lo.minLegPt_NN); + } fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_NN"), lo.dRNN); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hLegPtLow_vs_LegPtHigh_NN"), lo.minLegPt_NN, lo.maxLegPt_NN); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_NN_vs_minLegPt"), lo.dRNN, lo.minLegPt_NN); @@ -1487,8 +2051,10 @@ struct Photonhbt { fRegistryPairQA.fill(HIST(base) + HIST("LegUScross/hDEtaDPhi_PN12"), lo.dEtaPN12, lo.dPhiPN12); fRegistryPairQA.fill(HIST(base) + HIST("LegUScross/hDEtaDPhi_NP12"), lo.dEtaNP12, lo.dPhiNP12); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + } fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hPtG1_vs_PtG2"), lo.ptG1, lo.ptG2); } @@ -1498,8 +2064,10 @@ struct Photonhbt { constexpr auto base = mcDirPrefix(); fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DR_kT_minLegPt_PP"), lo.dRPP, kt, lo.minLegPt_PP); fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DR_kT_minLegPt_NN"), lo.dRNN, kt, lo.minLegPt_NN); - fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); - fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); + fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + } } inline void fillLegPairMC(PairTruthType t, LegPairObservables const& lo, float kt) @@ -1854,7 +2422,7 @@ struct Photonhbt { auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); auto photons1Coll = photons1.sliceBy(perCollision1, collision.globalIndex()); auto photons2Coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - if (qaflags.doSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photons1Coll) { if (cut1.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); @@ -1882,8 +2450,8 @@ struct Photonhbt { } const bool doQA = passQinvQAGate(obs.qinv), doFR = passQinvFullRangeGate(obs.qinv); const auto legObs = buildLegPairObservables(g1, g2, pos1, ele1, pos2, ele2); - const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1); - const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2); + const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1, collision.posZ()); + const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2, collision.posZ()); const auto sep = computePairSep(pwl1, pwl2); // ───before pair cuts ───────────────────────────────────── @@ -1903,7 +2471,7 @@ struct Photonhbt { if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } if (!passRZCut(obs.deltaR, obs.deltaZ)) { @@ -1913,6 +2481,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(pwl1, pwl2, obs.qinv); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<0>(cross, obs.qinv, obs.deltaR, vetoed); + if (vetoed) { + continue; + } + } // ───after pair cuts ────────────────────────────────────── fillPairSep<0, true>(sep, obs); @@ -1937,7 +2513,7 @@ struct Photonhbt { addToPool(g1, pwl1); addToPool(g2, pwl2); } - if (qaflags.doSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photons1Coll) { if (cut1.template IsSelected(g)) { if (idsAfterPairCuts.contains(g.globalIndex())) { @@ -1968,6 +2544,9 @@ struct Photonhbt { if (!passAsymmetryCut(g1.pt(), g2.pt())) { continue; } + if (!passFastQinvGate(g1, g2)) { + continue; + } auto obs = buildPairQAObservables(g1, g2); if (!obs.valid) { continue; @@ -1991,7 +2570,7 @@ struct Photonhbt { if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } if (!passRZCut(obs.deltaR, obs.deltaZ)) { @@ -2000,6 +2579,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(g1, g2, obs.qinv); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<1>(cross, obs.qinv, obs.deltaR, vetoed); + if (vetoed) { + continue; + } + } fillPairSep<1, true>(sep, obs); if (doQA) { @@ -2060,7 +2647,7 @@ struct Photonhbt { auto keyBin = std::make_tuple(zbin, centbin, epbin, occbin); auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); auto photonsColl = photons.sliceBy(perCollision, collision.globalIndex()); - if (qaflags.doSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); @@ -2093,8 +2680,8 @@ struct Photonhbt { } const bool doQA = passQinvQAGate(obs.qinv), doFR = passQinvFullRangeGate(obs.qinv); const auto legObs = buildLegPairObservables(g1, g2, pos1, ele1, pos2, ele2); - const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1); - const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2); + const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1, collision.posZ()); + const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2, collision.posZ()); const auto sep = computePairSep(pwl1, pwl2); // ──before pair cuts ───────────────────────────────────── @@ -2112,7 +2699,7 @@ struct Photonhbt { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } @@ -2122,6 +2709,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(pwl1, pwl2, obs.qinv); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<0>(cross, obs.qinv, obs.deltaR, vetoed); + if (vetoed) { + continue; + } + } // ─── after pair cuts ────────────────────────────────────── fillPairSep<0, true>(sep, obs); @@ -2147,7 +2742,9 @@ struct Photonhbt { } else { const bool doMCQA = passQinvMCQAGate(obs.qinv); fillMCPairQA(truthType, obs, doQA, doMCQA); - fillLegPairMC(truthType, legObs, obs.kt); + if (mQa.legPairQa) { + fillLegPairMC(truthType, legObs, obs.kt); + } if (doFR) { fillMCPairQAFullRange(truthType, obs); } @@ -2200,7 +2797,7 @@ struct Photonhbt { addToPool(g1, pwl1); addToPool(g2, pwl2); } - if (qaflags.doSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { if (idsAfterPairCuts.contains(g.globalIndex())) { @@ -2231,6 +2828,9 @@ struct Photonhbt { if (!passAsymmetryCut(g1.pt(), g2.pt())) { continue; } + if (!passFastQinvGate(g1, g2)) { + continue; + } auto obs = buildPairQAObservables(g1, g2); if (!obs.valid) { continue; @@ -2251,7 +2851,7 @@ struct Photonhbt { if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } if (!passRZCut(obs.deltaR, obs.deltaZ)) { @@ -2260,6 +2860,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(g1, g2, obs.qinv); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<1>(cross, obs.qinv, obs.deltaR, vetoed); + if (vetoed) { + continue; + } + } // ─after pair cuts ────────────────────────────────── fillPairSep<1, true>(sep, obs); @@ -2566,7 +3174,7 @@ struct Photonhbt { fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hQinvVsKt_all4LegsThisColl"), kt, qinv_true); fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hDEtaDPhi_all4LegsThisColl"), deta, dphi); } - if (g1Sel && g2Sel) { + if (g1Built && g2Built) { fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hSparse_DEtaDPhi_qinv_bothPhotonsBuilt"), deta, dphi, qinv_true); fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hSparse_DEtaDPhi_kT_bothPhotonsBuilt"), deta, dphi, kt); fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hQinvVsKt_bothPhotonsBuilt"), kt, qinv_true); @@ -2585,21 +3193,6 @@ struct Photonhbt { fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hRconv1_vs_Rconv2_bothPhotonsSelected"), g1.rTrue, g2.rTrue); } } - const float ut = uTrue(g1, g2); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_truthConverted"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_truthConverted"), qinv_true, ut); - if (pairAll4LegsThisColl) { - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_all4LegsThisColl"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_all4LegsThisColl"), qinv_true, ut); - } - if (g1Built && g2Built) { - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_bothPhotonsBuilt"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_bothPhotonsBuilt"), qinv_true, ut); - } - if (g1Sel && g2Sel && pairClassSel) { - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_bothPhotonsSelected"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_bothPhotonsSelected"), qinv_true, ut); - } const float minRconv = (g1.rTrue >= 0.f && g2.rTrue >= 0.f) ? std::min(g1.rTrue, g2.rTrue) : (g1.rTrue >= 0.f ? g1.rTrue : g2.rTrue); diff --git a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx index c14add8b083..65b3ab804df 100644 --- a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ using namespace o2::aod::pwgem::photon; enum QvecEstimator { FT0M = 0, - FT0A = 1, + FT0A, FT0C, TPCPos, TPCNeg, @@ -60,7 +61,7 @@ enum QvecEstimator { enum CentralityEstimator { None = 0, - CFT0A = 1, + CFT0A, CFT0C, CFT0M, NCentralityEstimators @@ -382,7 +383,7 @@ struct TaskFlowReso { // no selection on the centrality is applied on purpose to allow for the resolution study in post-processing return; } - if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange()) || !(collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { return; } float cent = getCentrality(collision); @@ -530,7 +531,7 @@ struct TaskFlowReso { }; // End struct TaskFlowReso -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index aa3745d9503..f882510c241 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -172,6 +173,7 @@ struct TaskPi0FlowEMC { Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + Configurable separateEMCalDCal{"separateEMCalDCal", false, "flag to only pair EMCal with EMCal and DCal with DCal clusters"}; } emccuts; V0PhotonCut fV0PhotonCut; @@ -251,6 +253,8 @@ struct TaskPi0FlowEMC { int runNow = 0; int runBefore = -1; + static constexpr float MaxPhiEMCal = 3.5f; + // Filter clusterFilter = aod::skimmedcluster::time >= emccuts.cfgEMCminTime && aod::skimmedcluster::time <= emccuts.cfgEMCmaxTime && aod::skimmedcluster::m02 >= emccuts.cfgEMCminM02 && aod::skimmedcluster::m02 <= emccuts.cfgEMCmaxM02 && aod::skimmedcluster::e >= emccuts.cfgEMCminE; Filter collisionFilter = (nabs(aod::collision::posZ) <= eventcuts.cfgZvtxMax) && (aod::evsel::ft0cOccupancyInTimeRange <= eventcuts.cfgFT0COccupancyMax) && (aod::evsel::ft0cOccupancyInTimeRange >= eventcuts.cfgFT0COccupancyMin); // using FilteredEMCalPhotons = soa::Filtered>; @@ -260,10 +264,13 @@ struct TaskPi0FlowEMC { using CollsWithQvecs = soa::Join; using Colls = soa::Join; + Partition emcalPhotons = aod::mincluster::storedPhi < static_cast(std::lround(MaxPhiEMCal * emcdownscaling::downscalingFactors[emcdownscaling::kPhi])); + Partition dcalPhotons = aod::mincluster::storedPhi >= static_cast(std::lround(MaxPhiEMCal * emcdownscaling::downscalingFactors[emcdownscaling::kPhi])); + static constexpr std::size_t NQVecEntries = 6; - PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; - PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -481,6 +488,13 @@ struct TaskPi0FlowEMC { }; // end init + /// \brief Check whether a photon (by its phi) falls in the EMCal or DCal acceptance + /// \param phi azimuthal angle of the photon + static bool isEMCalRegion(float phi) + { + return phi < MaxPhiEMCal; + } + /// Change radians to degree /// \param angle in radians /// \return angle in degree @@ -1047,7 +1061,7 @@ struct TaskPi0FlowEMC { continue; } if (rotationConfig.cfgDoRotation.value && nColl % rotationConfig.cfgDownsampling == 0) { - rotationBackground(vMeson, v1, v2, photons1, g1.globalIndex(), g2.globalIndex(), collision); + rotationBackground(vMeson, v1, v2, photons1, g1.globalIndex(), g2.globalIndex(), collision); } if (thnConfigAxisInvMass.value[1] > vMeson.M() || thnConfigAxisInvMass.value.back() < vMeson.M()) { registry.fill(HIST("hMesonCuts"), 3); @@ -1093,6 +1107,8 @@ struct TaskPi0FlowEMC { } auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + auto emcalPhotonsPerCollision = emcalPhotons.sliceBy(perCollisionEMC, collision.globalIndex()); + auto dcalPhotonsPerCollision = dcalPhotons.sliceBy(perCollisionEMC, collision.globalIndex()); if (emccuts.cfgEnableQA.value) { for (const auto& photon : photonsPerCollision) { @@ -1108,7 +1124,12 @@ struct TaskPi0FlowEMC { registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // after cuts } } - runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); + if (emccuts.separateEMCalDCal.value) { + runPairingLoop(collision, emcalPhotonsPerCollision, emcalPhotonsPerCollision, flags, flags); + runPairingLoop(collision, dcalPhotonsPerCollision, dcalPhotonsPerCollision, flags, flags); + } else { + runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); + } if (rotationConfig.cfgDoRotation.value) { if (nColl % rotationConfig.cfgDownsampling == 0) { nColl = 1; // reset counter @@ -1163,6 +1184,10 @@ struct TaskPi0FlowEMC { if (!(flags.test(g1.globalIndex())) || !(flags.test(g2.globalIndex()))) { continue; } + if (emccuts.separateEMCalDCal.value && isEMCalRegion(g1.phi()) != isEMCalRegion(g2.phi())) { + continue; // only pair EMCal-EMCal or DCal-DCal + } + // Cut edge clusters away, similar to rotation method to ensure same acceptance is used if (cfgDistanceToEdge.value > 0) { if (checkEtaPhi1D(g1.eta(), RecoDecay::constrainAngle(g1.phi())) >= cfgEMCalMapLevelBackground.value) { diff --git a/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx index c10b30fc3a6..ad2b5594c15 100644 --- a/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx +++ b/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx @@ -172,7 +172,7 @@ struct TestTaskEmc { PROCESS_SWITCH(TestTaskEmc, processEMCalCalib, "Process EMCal calibration same event", true); }; // End struct TestTaskEmc -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Utils/ClusterHistograms.h b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h index 6e51d09ab40..4d770d120e3 100644 --- a/PWGEM/PhotonMeson/Utils/ClusterHistograms.h +++ b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h @@ -20,11 +20,13 @@ #include #include +#include #include #include #include +#include #include #include @@ -112,7 +114,7 @@ inline void fillClusterHistograms(o2::framework::HistogramRegistry* fRegistry, T const auto eta = cluster.eta(); const auto phi = cluster.phi(); - static constexpr std::string_view ClusterTypes[2] = {"Cluster/before/", "Cluster/after/"}; + static constexpr std::array ClusterTypes = {"Cluster/before/", "Cluster/after/"}; if constexpr (HasTrackMatching) { for (size_t iTrack = 0; iTrack < cluster.deltaEta().size(); ++iTrack) { diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h index 6991e399625..78d09e75533 100644 --- a/PWGEM/PhotonMeson/Utils/EventHistograms.h +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -20,6 +20,7 @@ #include "Common/CCDB/TriggerAliases.h" #include +#include #include #include @@ -84,7 +85,7 @@ template void fillEventInfo(o2::framework::HistogramRegistry* fRegistry, TCollision const& collision, float weight = 1.) { const float maxZ = 10.f; - static constexpr std::string_view EventTypes[2] = {"before/", "after/"}; + static constexpr std::array EventTypes = {"before/", "after/"}; fRegistry->fill(HIST("Event/") + HIST(EventTypes[ev_id]) + HIST("hCollisionCounter"), 1.0, weight); if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { fRegistry->fill(HIST("Event/") + HIST(EventTypes[ev_id]) + HIST("hCollisionCounter"), 2.0, weight); diff --git a/PWGEM/PhotonMeson/Utils/HNMUtilities.h b/PWGEM/PhotonMeson/Utils/HNMUtilities.h index 956529610a0..9b25201ba54 100644 --- a/PWGEM/PhotonMeson/Utils/HNMUtilities.h +++ b/PWGEM/PhotonMeson/Utils/HNMUtilities.h @@ -10,9 +10,7 @@ // or submit itself to any jurisdiction. /// /// \file HNMUtilities.h -/// /// \brief This code provides helper functions for the reconstruction of heavy neutral mesons (omega and eta meson) via their three pion decay -/// /// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt /// @@ -24,6 +22,7 @@ #include #include +#include #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) @@ -68,9 +67,8 @@ struct Photon { // -------> Struct to store gamma gamma pairs (pi0 or eta meson candidates) struct GammaGammaPair { - GammaGammaPair(Photon p1, Photon p2) : p1(p1), p2(p2) + GammaGammaPair(Photon const& p1, Photon const& p2) : p1(p1), p2(p2), vGG(p1.photon + p2.photon) { - vGG = p1.photon + p2.photon; } Photon p1, p2; ROOT::Math::PxPyPzEVector vGG; @@ -80,8 +78,8 @@ struct GammaGammaPair { ushort reconstructionType = photonpair::kNpair; void setReconstructionType(ushort type) { reconstructionType = type; } - float m() const { return vGG.M(); } - float pT() const { return vGG.Pt(); } + [[nodiscard]] float m() const { return vGG.M(); } + [[nodiscard]] float pT() const { return vGG.Pt(); } }; // -------> Enum to specify how the heavy neutral meson mass should be corrected based on the PDG mass of its light neutral meson decay daughter @@ -100,7 +98,7 @@ struct HeavyNeutralMeson { GammaGammaPair* gg = nullptr; ROOT::Math::PxPyPzEVector vHeavyNeutralMeson; - float m(int massCorrectionType) const + [[nodiscard]] float m(int massCorrectionType) const { float massHNM = vHeavyNeutralMeson.M(); switch (massCorrectionType) { @@ -118,30 +116,32 @@ struct HeavyNeutralMeson { } return massHNM; } - float pT() const { return vHeavyNeutralMeson.Pt(); } - float eta() const { return vHeavyNeutralMeson.Eta(); } - float phi() const { return vHeavyNeutralMeson.Phi(); } + [[nodiscard]] float pT() const { return vHeavyNeutralMeson.Pt(); } + [[nodiscard]] float eta() const { return vHeavyNeutralMeson.Eta(); } + [[nodiscard]] float phi() const { return vHeavyNeutralMeson.Phi(); } }; const int nSMEdges = 9; -inline float smPhiEdges[nSMEdges] = {1.75, 2.1, 2.45, 2.8, 3.14, 4., 4.89, 5.24, 5.58}; +inline const std::array smPhiEdges = {1.75, 2.1, 2.45, 2.8, 3.14, 4., 4.89, 5.24, 5.58}; inline int getSMNumber(float eta, float phi) { int smNumber = 0; for (int iPhiInterval = 0; iPhiInterval < nSMEdges; iPhiInterval++) { - if (phi > smPhiEdges[iPhiInterval]) + if (phi > smPhiEdges[iPhiInterval]) { smNumber = 2 * (iPhiInterval + 1); + } } - if (eta < 0) + if (eta < 0) { smNumber += 1; + } return smNumber; } /// \brief Store photons from EMC clusters and V0s in a vector and possibly add a eta and phi offset for alignment of EMCal clusters template -void storeGammasInVector(C clusters, V v0s, std::vector& vPhotons, std::array EMCEtaShift, std::array EMCPhiShift) +void storeGammasInVector(C clusters, V v0s, std::vector& vPhotons, std::array const& EMCEtaShift, std::array const& EMCPhiShift) { vPhotons.clear(); for (const auto& cluster : clusters) { @@ -154,13 +154,14 @@ void storeGammasInVector(C clusters, V v0s, std::vector& vPhotons, std:: vPhotons.push_back(Photon::fromEtaPhiEnergy(eta, phi, cluster.e())); } - for (const auto& v0 : v0s) + for (const auto& v0 : v0s) { vPhotons.push_back(Photon::fromPxPyPz(v0.px(), v0.py(), v0.pz())); + } } /// \brief Store photons from EMC clusters in a vector and possibly add a eta and phi offset for alignment of EMCal clusters -template -void storeGammasInVector(C clusters, std::vector& vPhotons, std::array EMCEtaShift, std::array EMCPhiShift) +template +void storeGammasInVector(Clusters clusters, std::vector& vPhotons, std::array const& EMCEtaShift, std::array const& EMCPhiShift) { vPhotons.clear(); for (const auto& cluster : clusters) { @@ -175,20 +176,20 @@ void storeGammasInVector(C clusters, std::vector& vPhotons, std::array vPhotons, std::vector& vGGs) +inline void reconstructGGs(std::vector const& vPhotons, std::vector& vGGs) { vGGs.clear(); // loop over all photon combinations and build meson candidates for (unsigned int ig1 = 0; ig1 < vPhotons.size(); ++ig1) { for (unsigned int ig2 = ig1 + 1; ig2 < vPhotons.size(); ++ig2) { GammaGammaPair lightMeson(vPhotons[ig1], vPhotons[ig2]); // build lightMeson from photons - if (vPhotons[ig1].isFromConversion && vPhotons[ig2].isFromConversion) + if (vPhotons[ig1].isFromConversion && vPhotons[ig2].isFromConversion) { lightMeson.setReconstructionType(photonpair::kPCMPCM); - else if (!vPhotons[ig1].isFromConversion && !vPhotons[ig2].isFromConversion) + } else if (!vPhotons[ig1].isFromConversion && !vPhotons[ig2].isFromConversion) { lightMeson.setReconstructionType(photonpair::kEMCEMC); - else + } else { lightMeson.setReconstructionType(photonpair::kPCMEMC); - + } vGGs.push_back(lightMeson); } } diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index ff0b7307727..5dd76b4ec8b 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ #include +#include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include //_______________________________________________________________________ @@ -33,11 +35,7 @@ template bool IsPhysicalPrimary(TTrack const& mctrack) { // This is to check mctrack is ALICE physical primary. - if (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()) { - return true; - } else { - return false; - } + return (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()); } //_______________________________________________________________________ template @@ -94,7 +92,7 @@ int IsXFromY(T const& mctrack, TMCs const& mcTracks, const int pdgX, const int p //_______________________________________________________________________ // Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return this mothers daughter // E.g. Find the gamma that was created in a pi0 or eta decay -template +template int FindMotherInChain(T const& mcparticle, TMCs const& mcparticles, TTargetPDGs const& motherpdgs, const int Depth = 50) // o2-linter: disable=pdg/explicit-code (false positive) { if (!mcparticle.has_mothers() || Depth < 1) { @@ -105,9 +103,8 @@ int FindMotherInChain(T const& mcparticle, TMCs const& mcparticles, TTargetPDGs auto mother = mcparticles.iteratorAt(motherid); if (std::find(motherpdgs.begin(), motherpdgs.end(), mother.pdgCode()) != motherpdgs.end()) { return mcparticle.globalIndex(); // The mother has the required pdg code, so return its daughters global mc particle code. - } else { - return FindMotherInChain(mother, mcparticles, motherpdgs, Depth - 1); } + return FindMotherInChain(mother, mcparticles, motherpdgs, Depth - 1); } //_______________________________________________________________________ template @@ -133,7 +130,7 @@ int IsEleFromPC(T const& mctrack, TMCs const& mcTracks) return -1; } //_______________________________________________________________________ -template +template bool IsInAcceptanceNonDerived(TMCParticle const& mcparticle, TMCParticles const& mcparticles, TTargetPDGs target_pdgs, const float ymin, const float ymax, const float phimin, const float phimax) { // contents in vector of daughter ID is different. @@ -178,13 +175,10 @@ bool IsInAcceptanceNonDerived(TMCParticle const& mcparticle, TMCParticles const& bool is_equal = std::equal(pdgs.cbegin(), pdgs.cend(), target_pdgs.cbegin()); pdgs.clear(); pdgs.shrink_to_fit(); - if (!is_equal) { - return false; // garantee daughter is in acceptance. - } - return true; + return is_equal; } //_______________________________________________________________________ -template +template bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticles, TTargetPDGs target_pdgs, const float ymin, const float ymax, const float phimin, const float phimax) { if (mcparticle.y() < ymin || ymax < mcparticle.y()) { @@ -226,10 +220,7 @@ bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticl bool is_equal = std::equal(pdgs.cbegin(), pdgs.cend(), target_pdgs.cbegin()); pdgs.clear(); pdgs.shrink_to_fit(); - if (!is_equal) { - return false; // garantee daughter is in acceptance. - } - return true; + return is_equal; } //_______________________________________________________________________ template @@ -299,9 +290,48 @@ bool isMotherPDG(T& mcparticle, const int motherPDG, const int depth = 10) // o2 mcparticle.setCursor(motherid); if (mcparticle.pdgCode() == motherPDG) { return true; // The mother has the required pdg code, so return its daughters global mc particle code. - } else { - return isMotherPDG(mcparticle, motherPDG, depth - 1); } + return isMotherPDG(mcparticle, motherPDG, depth - 1); +} + +//_______________________________________________________________________ +/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return true else false +/// E.g. if electron cluster is coming from a photon return true, if primary electron return false +/// \param mcparticle iterator of mcparticle, NOT modified by this function +/// \param mcparticleWorking a second iterator of the SAME table, used as scratch space to walk up the chain -- caller must supply this so the function doesn't construct its own +/// \param motherPDG target mother PDG value +/// \param depth how many steps in the chain this check should go maximum before failing +template +bool isMotherPDG(const T& mcparticle, T& mcparticleWorking, const int motherPDG, const int depth = 10) // o2-linter: disable=pdg/explicit-code (false positive) +{ + if (!mcparticle.has_mothers() || depth < 1) { + return false; + } + + int motherid = mcparticle.mothersIds()[0]; + mcparticleWorking.setCursor(motherid); + if (mcparticleWorking.pdgCode() == motherPDG) { + return true; // The mother has the required pdg code. + } + return isMotherPDG(mcparticleWorking, mcparticleWorking, motherPDG, depth - 1); +} + +//_______________________________________________________________________ +/// \brief Check if given particle is from Bremsstrahlung +/// \param mcCursor iterator of mcparticle +/// \param iter shared iterator used to walk to the mother +template +bool isFromBremsstrahlung(TIter const& mcCursor, TIter& iter) +{ + if (!mcCursor.has_mothers()) { + return false; + } + if (mcCursor.pdgCode() != PDG_t::kGamma) { + return false; // only a photon can itself be a bremsstrahlung emission + } + const int motherId = mcCursor.mothersIds()[0]; + iter.setCursor(motherId); + return std::abs(iter.pdgCode()) == PDG_t::kElectron; } //_______________________________________________________________________ @@ -321,9 +351,30 @@ int32_t getMotherIndexFromChain(T& mcparticle, const int motherPDG, const int de mcparticle.setCursor(motherid); if (mcparticle.pdgCode() == motherPDG) { return motherid; // The mother has the required pdg code, so return its daughters global mc particle code. - } else { - return getMotherIndexFromChain(mcparticle, motherPDG, depth - 1); } + return getMotherIndexFromChain(mcparticle, motherPDG, depth - 1); +} + +//_______________________________________________________________________ +/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return id else -1 +/// E.g. if electron cluster is coming from a photon return the photon's id, if primary electron return -1 +/// \param mcparticle iterator of mcparticle, NOT modified by this function +/// \param mcparticleWorking a second iterator of the SAME table, used as scratch space to walk up the chain -- caller must supply this so the function doesn't construct its own +/// \param motherPDG target mother PDG value +/// \param depth how many steps in the chain this check should go maximum before failing +template +int32_t getMotherIndexFromChain(const T& mcparticle, T& mcparticleWorking, const int motherPDG, const int depth = 10) // o2-linter: disable=pdg/explicit-code (false positive) +{ + if (!mcparticle.has_mothers() || depth < 1) { + return -1; + } + + int32_t motherid = mcparticle.mothersIds()[0]; + mcparticleWorking.setCursor(motherid); + if (mcparticleWorking.pdgCode() == motherPDG) { + return motherid; + } + return getMotherIndexFromChain(mcparticleWorking, mcparticleWorking, motherPDG, depth - 1); } //_______________________________________________________________________ diff --git a/PWGEM/PhotonMeson/Utils/NMHistograms.h b/PWGEM/PhotonMeson/Utils/NMHistograms.h index edca1f8c3ed..0f9ce03767a 100644 --- a/PWGEM/PhotonMeson/Utils/NMHistograms.h +++ b/PWGEM/PhotonMeson/Utils/NMHistograms.h @@ -18,7 +18,9 @@ #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include #include +#include #include #include @@ -35,6 +37,7 @@ inline void addNMHistograms(o2::framework::HistogramRegistry* fRegistry, bool is { // !!Don't change pt,eta,y binning. These binnings have to be consistent with binned data at skimming.!! std::vector ptbins; + ptbins.reserve(72); for (int i = 0; i < 2; i++) { // o2-linter: disable=magic-number (just numbers for binning) ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c } @@ -84,12 +87,12 @@ void fillTruePairInfo(o2::framework::HistogramRegistry* fRegistry, TDiphoton con float weight = eventWeight; int motherid_strhad = o2::aod::pwgem::photonmeson::utils::mcutil::IsFromWD(mcparticle.template emmcevent_as(), mcparticle, mcparticles); switch (pdg) { - case kPi0: { + case PDG_t::kPi0: { if (mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator()) { fRegistry->fill(HIST("Pair/Pi0/hs_Primary"), v12.M(), v12.Pt(), weight); } else if (motherid_strhad > 0) { auto str_had = mcparticles.iteratorAt(motherid_strhad); - if (std::abs(str_had.pdgCode()) == kK0Short && f1fd_k0s_to_pi0 != nullptr) { + if (std::abs(str_had.pdgCode()) == PDG_t::kK0Short && f1fd_k0s_to_pi0 != nullptr) { weight *= f1fd_k0s_to_pi0->Eval(str_had.pt()); } fRegistry->fill(HIST("Pair/Pi0/hs_FromWD"), v12.M(), v12.Pt(), weight); @@ -98,7 +101,7 @@ void fillTruePairInfo(o2::framework::HistogramRegistry* fRegistry, TDiphoton con } break; } - case 221: { + case constants::physics::kEta: { if (mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator()) { fRegistry->fill(HIST("Pair/Eta/hs_Primary"), v12.M(), v12.Pt(), weight); } else if (motherid_strhad > 0) { diff --git a/PWGEM/PhotonMeson/Utils/PCMUtilities.h b/PWGEM/PhotonMeson/Utils/PCMUtilities.h index 269db4f46fb..7005cbcb66a 100644 --- a/PWGEM/PhotonMeson/Utils/PCMUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PCMUtilities.h @@ -21,25 +21,25 @@ #include #include +#include +#include #include #include -#include +#include // IWYU pragma: keep (for rotate) +#include // IWYU pragma: keep (do not replace with Math/Vector2Dfwd.h) +#include + +#include #include #include -#include - //_______________________________________________________________________ inline bool checkAP(const float alpha, const float qt, const float alpha_max = 0.95, const float qt_max = 0.05) { float ellipse = std::pow(alpha / alpha_max, 2) + std::pow(qt / qt_max, 2); - if (ellipse < 1.0) { - return true; - } else { - return false; - } + return (ellipse < 1.0); } //_______________________________________________________________________ inline float v0_alpha(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) @@ -58,7 +58,7 @@ inline float v0_qt(float pxpos, float pypos, float pzpos, float pxneg, float pyn } //_______________________________________________________________________ template -inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track::TrackParametrizationWithError& trackPosInformation, const o2::track::TrackParametrizationWithError& trackNegInformation, float xyz[3], o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) +inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track::TrackParametrizationWithError& trackPosInformation, const o2::track::TrackParametrizationWithError& trackNegInformation, std::array& xyz, o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) { float bz = prop->getNominalBz(); @@ -82,21 +82,21 @@ inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track: float vertexXNeg = helixNeg.xC + helixNeg.rC * std::cos(alphaNeg); float vertexYNeg = helixNeg.yC + helixNeg.rC * std::sin(alphaNeg); - TVector2 vertexPos(vertexXPos, vertexYPos); - TVector2 vertexNeg(vertexXNeg, vertexYNeg); + ROOT::Math::XYVector vertexPos(vertexXPos, vertexYPos); + ROOT::Math::XYVector vertexNeg(vertexXNeg, vertexYNeg); // Convert to local coordinate system - TVector2 vertexPosRot = vertexPos.Rotate(-trackPosInformationCopy.getAlpha()); - TVector2 vertexNegRot = vertexNeg.Rotate(-trackNegInformationCopy.getAlpha()); + vertexPos.Rotate(-trackPosInformationCopy.getAlpha()); + vertexNeg.Rotate(-trackNegInformationCopy.getAlpha()); prop->propagateToX(trackPosInformationCopy, - vertexPosRot.X(), + vertexPos.X(), bz, o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, matCorr); prop->propagateToX(trackNegInformationCopy, - vertexNegRot.X(), + vertexNeg.X(), bz, o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, @@ -104,90 +104,113 @@ inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track: xyz[2] = (trackPosInformationCopy.getZ() * helixNeg.rC + trackNegInformationCopy.getZ() * helixPos.rC) / (helixPos.rC + helixNeg.rC); } + //_______________________________________________________________________ -template -inline void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, float xyz[3], o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) +/// \brief Calculate DCA for tracks using the track helix and the inclination angl tan(lambda) +/// \param trk track parameterization to obtain helix parameters +/// \param vtx primary vertex position +/// \param magField magnetic field strenght of L3 +/// \return DCAxy, DCAz +template +std::array CalculateDCAFast(const o2::track::TrackParametrizationWithError& trk, const o2::math_utils::Point3D& vtx, const float magField) { + + std::array dca{}; + + // obtain circle from track in x-y plane + const o2::track::TrackAuxPar helixPos(trk, magField); + + // obtain position in global coordinates and tan(lambda) + const auto posTrack = trk.getXYZGlo(); + const float trX = posTrack.X(); + const float trY = posTrack.Y(); + const float trZ = posTrack.Z(); + const float tangentLambda = trk.getTgl(); + + // Calculate DCAxy + // Use distance in x and y between circle center and vtx, afterwards subtract radius of circle + const float distX = helixPos.xC - vtx.X(); + const float distY = helixPos.yC - vtx.Y(); + const float trackCircCenter = std::sqrt(distX * distX + distY * distY); + dca[0] = helixPos.rC - trackCircCenter; + + // Calculate DCAz + // First step: Calculate arc lenght of circle between current position and primary vertex in x-y + const float theta0 = std::atan2(trY - helixPos.yC, trX - helixPos.xC); + const float thetav = std::atan2(vtx.Y() - helixPos.yC, vtx.X() - helixPos.xC); + + // Make sure angle is between -pi and pi + const auto dtheta = RecoDecay::constrainAngle(thetav - theta0, -o2::constants::math::PI); + + // arc-lenght along helix + const float arcLenght = std::fabs(helixPos.rC * dtheta); + + // get global z-position at DCA + const float ZPosGlo = trZ - arcLenght * tangentLambda; + + // DCA calculated from + dca[1] = ZPosGlo - vtx.Z(); + + return dca; +} + +//_______________________________________________________________________ +/// \brief Calculate the track momentum at a different place of the track Helix. +/// \param s arc-lenght where track should be propagated to +/// \param track particle track +/// \param trHelix track helix param. for circle approximation +/// \param bz magnetic field strenght of L3 +/// \param addPhi optional additional rotation of the track in phi-direction +/// \return track momentum vector at new position +template +inline std::array getPropMomentumFromTrackHelix(const float s, const TTrack& track, const o2::track::TrackAuxPar& trHelix, const float bz, float addPhi = 0.f) +{ + + // Calculate the change in phi considering the track radius and the track arc lenght s + const float dphi = -track.sign() * 0.3f * bz * s / 100. / track.pt(); // s in cm + const float dotProd = std::cos(track.phi() + addPhi) * track.pt() * trHelix.xC + std::sin(track.phi() + addPhi) * track.pt() * trHelix.yC; + if (dotProd < 0) { + addPhi -= o2::constants::math::PI; + } + + // Calculate the phi at the secondary vertex + const auto phi = RecoDecay::constrainAngle(track.phi() + dphi + addPhi); + + // Calculate px,y,z at the new propagated vertex + std::array trackP{}; + trackP[0] = std::cos(phi) * track.pt(); + trackP[1] = std::sin(phi) * track.pt(); + trackP[2] = track.tgl() * track.pt(); + + return trackP; +} + +//_______________________________________________________________________ +template +inline void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, std::array& xyz, o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE) +{ + // o2::track::TrackParametrizationWithError = TrackParCov, I use the full version to have control over the data type o2::track::TrackParametrizationWithError trackPosInformation = getTrackParCov(lTrackPos); // first get an object that stores Track information (positive) o2::track::TrackParametrizationWithError trackNegInformation = getTrackParCov(lTrackNeg); // first get an object that stores Track information (negative) Vtx_recalculationParCov(prop, trackPosInformation, trackNegInformation, xyz, matCorr); } + //_______________________________________________________________________ -// template -// float getPtResolution(TV0 const& v0) -// { -// float px = v0.px(); -// float py = v0.py(); -// float pt = v0.pt(); -// float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); -// float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); -// float pxy_err = v0.sigmaPxPy(); -// return std::sqrt(std::pow(px / pt * px_err, 2) + std::pow(py / pt * py_err, 2) + 2.f * px / pt * py / pt * pxy_err); -// } -// //_______________________________________________________________________ -// template -// float getPhiResolution(TV0 const& v0) -// { -// float px = v0.px(); -// float py = v0.py(); -// float pt = v0.pt(); -// float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); -// float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); -// float pxy_err = v0.sigmaPxPy(); -// return std::sqrt(std::pow(px / pt / pt * py_err, 2) + std::pow(py / pt / pt * px_err, 2) - 2.f * px / pt / pt * py / pt / pt * pxy_err); -// } -// //_______________________________________________________________________ -// template -// float getThetaResolution(TV0 const& v0) -// { -// float px = v0.px(); -// float py = v0.py(); -// float pz = v0.pz(); -// float pt = v0.pt(); -// float p = v0.p(); -// float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); -// float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); -// float pz_err = std::sqrt(std::fabs(v0.sigmaPz2())); -// float pxy_err = v0.sigmaPxPy(); -// float pyz_err = v0.sigmaPyPz(); -// float pzx_err = v0.sigmaPzPx(); -// return std::sqrt(std::pow(pz * pz / p / p, 2) * (std::pow(px / pz / pt * px_err, 2) + std::pow(py / pz / pt * py_err, 2) + std::pow(pt / pz / pz * pz_err, 2) + 2.f * (px * py / pz / pz / pt / pt * pxy_err - py / pz / pz / pz * pyz_err - px / pz / pz / pz * pzx_err))); -// } -// //_______________________________________________________________________ -// template -// float getEtaResolution(TV0 const& v0) -// { -// float px = v0.px(); -// float py = v0.py(); -// float pz = v0.pz(); -// float pt = v0.pt(); -// float p = v0.p(); -// float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); -// float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); -// float pz_err = std::sqrt(std::fabs(v0.sigmaPz2())); -// float pxy_err = v0.sigmaPxPy(); -// float pyz_err = v0.sigmaPyPz(); -// float pzx_err = v0.sigmaPzPx(); -// return std::sqrt(std::pow(1.f / p / pt / pt, 2) * (std::pow(pz * px * px_err, 2) + std::pow(pz * py * py_err, 2) + std::pow(pt * pt * pz_err, 2) + 2.f * (pz * pz * px * py * pxy_err - pt * pt * py * pz * pyz_err - pt * pt * pz * px * pzx_err))); -// } -// //_______________________________________________________________________ -// template -// float getPResolution(TV0 const& v0) -// { -// float px = v0.px(); -// float py = v0.py(); -// float pz = v0.pz(); -// float p = v0.p(); -// float px_err = std::sqrt(std::fabs(v0.sigmaPx2())); -// float py_err = std::sqrt(std::fabs(v0.sigmaPy2())); -// float pz_err = std::sqrt(std::fabs(v0.sigmaPz2())); -// float pxy_err = v0.sigmaPxPy(); -// float pyz_err = v0.sigmaPyPz(); -// float pzx_err = v0.sigmaPzPx(); -// return std::sqrt(std::pow(1.f / p, 2) * (std::pow(px * px_err, 2) + std::pow(py * py_err, 2) + std::pow(pz * pz_err, 2) + 2.f * (px * py * pxy_err + py * pz * pyz_err + pz * px * pzx_err))); -// } -//_______________________________________________________________________ -//_______________________________________________________________________ +/// \brief Function to calculate a score based on cosPA and PCA. The smaller the score the better the V0 Candidate +/// \param cosPA cosine of pointing angle +/// \param pca point of closest approach in cm +/// \param weight how much is cosPA weighted (for pca its 1-weight). Weight has to be between 0 and 1 +/// \return final score +inline float getScoreV0(float cosPA, float pca, float weight) +{ + float cosScore = 60 * std::acos(cosPA); // pointing angle in degrees, the smaller the better + float pcaScore = pca / 3.f; // assume pca is between 0 and 3 + float wCos = weight; + float wPca = 1.f - wCos; // random values for now + float score = wCos * cosScore + wPca * pcaScore; + return score; +} + #endif // PWGEM_PHOTONMESON_UTILS_PCMUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/PairUtilities.h b/PWGEM/PhotonMeson/Utils/PairUtilities.h index e19b8db1458..0ae25250e0f 100644 --- a/PWGEM/PhotonMeson/Utils/PairUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PairUtilities.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include diff --git a/PWGEM/PhotonMeson/Utils/TrackSelection.h b/PWGEM/PhotonMeson/Utils/TrackSelection.h index 941a7ea2bc0..c511a00a0b0 100644 --- a/PWGEM/PhotonMeson/Utils/TrackSelection.h +++ b/PWGEM/PhotonMeson/Utils/TrackSelection.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_UTILS_TRACKSELECTION_H_ #include +#include #include diff --git a/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h b/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h index 0ef33364c80..b5a7be0d04a 100644 --- a/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h +++ b/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h @@ -35,7 +35,7 @@ o2::framework::AxisSpec const gAxis_TPCdEdxSig{401, -10.025f, 10.025f}; o2::framework::AxisSpec const gAxis_radRes{800, -o2::constants::math::PI, o2::constants::math::PI}; o2::framework::AxisSpec const gAxis_xyz{2400, -300.f, 300.f}; o2::framework::AxisSpec const gAxis_chi2{501, -1.f, 500.f}; -o2::framework::AxisSpec gAxis_pT_log{800, 0.01f, 25.f}; +o2::framework::AxisSpec const gAxis_pT_log{800, 0.01f, 25.f}; o2::framework::HistogramSpec const gHistoSpec_hCollisionZ_all_MCTrue{"hCollisionZ_all_MCTrue", "hCollisionZ_all_MCTrue;z (cm);counts", {o2::framework::HistType::kTH1F, {gAxis_zColl}}}; o2::framework::HistogramSpec const gHistoSpec_hCollisionZ_MCTrue{"hCollisionZ_MCTrue", "hCollisionZ_MCTrue;z (cm);counts", {o2::framework::HistType::kTH1F, {gAxis_zColl}}}; diff --git a/PWGHF/Core/HfMlResponseD0ToKPi.h b/PWGHF/Core/HfMlResponseD0ToKPi.h index b0c6eaccdd3..bebc1f20247 100644 --- a/PWGHF/Core/HfMlResponseD0ToKPi.h +++ b/PWGHF/Core/HfMlResponseD0ToKPi.h @@ -225,8 +225,8 @@ class HfMlResponseD0ToKPi : public HfMlResponse CHECK_AND_FILL_VEC_D0_SIGNED(candidate, nSigTpcTofKaExpKa, tpcTofNSigmaKa1, tpcTofNSigmaKa0); CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputBkg, mlProbD0, mlProbD0bar, 0); - CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputNonPrompt, mlProbD0, mlProbD0bar, 1); - CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputPrompt, mlProbD0, mlProbD0bar, 2); + CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputPrompt, mlProbD0, mlProbD0bar, 1); + CHECK_AND_FILL_VEC_D0_ML(candidate, bdtOutputNonPrompt, mlProbD0, mlProbD0bar, 2); CHECK_AND_FILL_VEC_D0(maxNormalisedDeltaIP); CHECK_AND_FILL_VEC_D0_FULL(candidate, impactParameterProduct, impactParameterProduct); diff --git a/PWGHF/D2H/Core/DataCreationCharmReso.h b/PWGHF/D2H/Core/DataCreationCharmReso.h index 87621940c91..09904380a89 100644 --- a/PWGHF/D2H/Core/DataCreationCharmReso.h +++ b/PWGHF/D2H/Core/DataCreationCharmReso.h @@ -65,9 +65,7 @@ #include #include -namespace o2::analysis -{ -namespace hf_charm_reso +namespace o2::analysis::hf_charm_reso { // event types @@ -226,7 +224,7 @@ template void addHistograms(o2::framework::HistogramRegistry& registry) { constexpr uint8_t NumBinsEvents = EventType::NEventType; - std::string labels[NumBinsEvents]; + std::array labels; labels[EventType::Processed] = "processed"; labels[EventType::NoDV0Selected] = "without DV0 pairs"; labels[EventType::DV0Selected] = "with DV0 pairs"; @@ -542,7 +540,7 @@ bool buildAndSelectGamma(const Coll& collision, const std::array& dDaugh return false; } - std::array dcaInfo; + std::array dcaInfo{}; auto trackParPos = getTrackParCov(trackPos); if (o2::pwgem::photonmeson::isTPConlyTrack(trackPos) && !vDriftMgr->moveTPCTrack(collision, trackPos, trackParPos)) { LOGP(error, "failed correction for positive tpc track"); @@ -568,7 +566,7 @@ bool buildAndSelectGamma(const Coll& collision, const std::array& dDaugh return false; } - float gammaVtx[3] = {0.f, 0.f, 0.f}; + std::array gammaVtx = {0.f, 0.f, 0.f}; Vtx_recalculationParCov(o2::base::Propagator::Instance(), trackParPropPos, trackParPropNeg, gammaVtx, matCorr); float radiusXy = std::hypot(gammaVtx[0], gammaVtx[1]); const float maxX{83.1f}; // max X for track IU @@ -585,17 +583,17 @@ bool buildAndSelectGamma(const Coll& collision, const std::array& dDaugh KFPTrack kfpTrackNeg = createKFPTrackFromTrackParCov(trackParPropNeg, trackNeg.sign(), trackNeg.tpcNClsFound(), trackNeg.tpcChi2NCl()); KFParticle kfPartPos(kfpTrackPos, kPositron); KFParticle kfPartNeg(kfpTrackNeg, kElectron); - const KFParticle* gammaDaughters[2] = {&kfPartPos, &kfPartNeg}; + std::array gammaDaughters = {&kfPartPos, &kfPartNeg}; KFParticle gamma; gamma.SetConstructMethod(2); - gamma.Construct(gammaDaughters, 2); + gamma.Construct(gammaDaughters.data(), 2); KFPVertex kfpVertex = createKFPVertexFromCollision(collision); KFParticle KFPV(kfpVertex); // Transport the gamma to the recalculated decay vertex KFParticle gammaDecayVtx = gamma; // with respect to (0,0,0) - gammaDecayVtx.TransportToPoint(gammaVtx); + gammaDecayVtx.TransportToPoint(gammaVtx.data()); v0.cosPA = cpaFromKF(gammaDecayVtx, KFPV); if (v0.cosPA < cfgGammaCuts.cosPa.value) { return false; @@ -634,10 +632,10 @@ bool buildAndSelectGamma(const Coll& collision, const std::array& dDaugh return false; } - KFParticle kfPartDecayVtxPos = kfPartPos; // Don't set Primary Vertex - KFParticle kfPartDecayVtxNeg = kfPartNeg; // Don't set Primary Vertex - kfPartDecayVtxPos.TransportToPoint(gammaVtx); // Don't set Primary Vertex - kfPartDecayVtxNeg.TransportToPoint(gammaVtx); // Don't set Primary Vertex + KFParticle kfPartDecayVtxPos = kfPartPos; // Don't set Primary Vertex + KFParticle kfPartDecayVtxNeg = kfPartNeg; // Don't set Primary Vertex + kfPartDecayVtxPos.TransportToPoint(gammaVtx.data()); // Don't set Primary Vertex + kfPartDecayVtxNeg.TransportToPoint(gammaVtx.data()); // Don't set Primary Vertex v0.dcaDau = kfPartDecayVtxPos.GetDistanceFromParticle(kfPartDecayVtxNeg); v0.momPos = RecoDecay::pVec(std::array{kfPartDecayVtxPos.GetPx(), kfPartDecayVtxPos.GetPy(), kfPartDecayVtxPos.GetPz()}); v0.momNeg = RecoDecay::pVec(std::array{kfPartDecayVtxNeg.GetPx(), kfPartDecayVtxNeg.GetPy(), kfPartDecayVtxNeg.GetPz()}); @@ -2013,7 +2011,6 @@ void runMcGen(McParticles const& mcParticles, } } } -} // namespace hf_charm_reso -} // namespace o2::analysis +} // namespace o2::analysis::hf_charm_reso #endif // PWGHF_D2H_CORE_DATACREATIONCHARMRESO_H_ diff --git a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx index 53a7c7beb24..ca043a2adb6 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx @@ -65,6 +65,7 @@ #include #include +#include #include #include #include diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index df1630a1cb7..e40d15a7c57 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -345,7 +345,6 @@ struct HfTaskD0 { if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { axes.push_back(thnAxisPtB); axes.push_back(thnAxisOrigin); - axes.push_back(thnAxisNumPvContr); } if (storeCentrality) { axes.push_back(thnAxisCent); @@ -366,8 +365,8 @@ struct HfTaskD0 { // Insert ML scores after pt (position 2) to match taskDplus structure: [mass, pt, mlScores, ...] if (doprocessDataWithDCAFitterNMlWithUpc) { - axes.insert(axes.begin() + 2, thnAxisPromptScore); axes.insert(axes.begin() + 2, thnAxisNonPromptScore); + axes.insert(axes.begin() + 2, thnAxisPromptScore); axes.insert(axes.begin() + 2, thnAxisBkgScore); } else { axes.insert(axes.begin(), thnAxisPromptScore); @@ -1125,27 +1124,27 @@ struct HfTaskD0 { registry.fill(HIST("hMassSigD0"), massD0, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } else { @@ -1167,27 +1166,27 @@ struct HfTaskD0 { registry.fill(HIST("hMassReflBkgD0"), massD0, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } @@ -1199,27 +1198,27 @@ struct HfTaskD0 { registry.fill(HIST("hMassSigD0bar"), massD0bar, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } else { @@ -1228,9 +1227,9 @@ struct HfTaskD0 { registry.fill(HIST("hMassReflBkgD0bar"), massD0bar, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); } else if (storeTrackQuality) { @@ -1240,15 +1239,15 @@ struct HfTaskD0 { } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } diff --git a/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx b/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx index 09ddb9cba1f..3910c3447ef 100644 --- a/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx +++ b/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx @@ -68,7 +68,6 @@ struct HfTaskDeuteronFromLb { Configurable cfgMinPt{"cfgMinPt", 0.5f, "Minimum pT cut"}; Configurable cfgTPCNsigma{"cfgTPCNsigma", 3.0f, "TPC n sigma for deuteron PID"}; Configurable cfgTofNsigma{"cfgTofNsigma", 3.0f, "TOF n sigma for deuteron PID"}; - Configurable ptThresholdPid{"ptThresholdPid", 0.5f, "pT threshold to switch between TPC and TPC+TOF PID"}; Configurable cfgDCAmin{"cfgDCAmin", 0.05f, "Minimum DCA for deuteron PID"}; Configurable cfgDCAmax{"cfgDCAmax", 1000.0f, "Maximum DCA for deuteron PID"}; Configurable rapidityCut{"rapidityCut", 0.5f, "Rapidity cut"}; @@ -84,7 +83,7 @@ struct HfTaskDeuteronFromLb { framework::Service ccdb{}; using CollisionCandidates = o2::soa::Join; - using MCTrackCandidates = o2::soa::Join; + using MCTrackCandidates = o2::soa::Join; using MCCollisionCandidates = o2::soa::Join; using TrackCandidates = o2::soa::Join; @@ -154,6 +153,11 @@ struct HfTaskDeuteronFromLb { qaHistos.add("MCReco/ptAntiDeuteronFromAntiLambdaB", "p_{T} #bar{d} from #bar{#Lambda}_{b} reco/MC anchored;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add( + "MCReco/ptAntiDeuteronPrimary", + "p_{T} #bar{d} primary reco/MC anchored;p_{T} (GeV/c);Counts", + HistType::kTH1F, + {ptAxis}); qaHistos.add("MCGen/ptAntiDeuteronFromBminus", "p_{T} #bar{d} from B^{-} gen;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCGen/ptAntiDeuteronFromAntiLambdaB", "p_{T} #bar{d} from #bar{#Lambda}_{b} gen;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCReco/hDCAxy-Primary", "DCAxy primary reco/MC anchored;DCA xy (cm);Counts", {HistType::kTH1D, {{400, -0.2f, 0.2f, "DCA xy (cm)"}}}); @@ -161,6 +165,16 @@ struct HfTaskDeuteronFromLb { qaHistos.add("MCReco/hMotherPdgCode", "PDG code of mother, reco/MC anchored;PDG code;Counts", HistType::kTH1I, {{12000, -6000, 6000}}); qaHistos.add("MCReco/ctauBminus", "ctau of B^{-}, reco/MC anchored;ctau (#mu m);Counts", HistType::kTH1F, {{25, 0., 2000.f}}); qaHistos.add("MCReco/ctauAntiLambdaB", "ctau of #bar{#Lambda}_{b}, reco/MC anchored;ctau (#mu m);Counts", HistType::kTH1F, {{25, 0., 2000.f}}); + qaHistos.add("MCReco/ptAntiDeuteronPIDSelected", "p_{T} #bar{d} reco/MC anchored PID selection;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add("MCReco/ptAntiDeuteronPIDSelectedTrue", "p_{T} #bar{d} reco/MC anchored PID and PDG;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add("MCReco/hnSigmaTPCVsPt", "n#sigma TPC vs p_{T} for #bar{d} hypothesis for MC; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); + qaHistos.add("MCReco/hnSigmaTOFVsPt", "n#sigma TOF vs p_{T} for #bar{d} hypothesis for MC; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); + qaHistos.add("Data/hnSigmaTOFVsPtPurity", "n#sigma TOF vs p_{T} for #bar{d} hypothesis for Data-driven purity check; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); + qaHistos.add("Data/hnSigmaTPCVsPtPurity", "n#sigma TPC vs p_{T} for #bar{d} hypothesis for Data-driven purity check; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); + qaHistos.add("MCReco/ptAntiDeuteronTPCOnlyPIDSelected", "p_{T} #bar{d} reco/MC anchored TPC only PID selection;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add("MCReco/ptAntiDeuteronTPCOnlyPIDSelectedTrue", "p_{T} #bar{d} reco/MC anchored TPC only PID and PDG;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add("MCReco/ptAntiDeuteronTPCorTPCTOFPIDSelected", "p_{T} #bar{d} reco/MC anchored TPC or TPC+TOF PID selection;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add("MCReco/ptAntiDeuteronTPCorTPCTOFPIDSelectedTrue", "p_{T} #bar{d} reco/MC anchored TPC or TPC+TOF PID and PDG;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); hProcessedEvents->GetXaxis()->SetBinLabel(1, "Events processed"); hProcessedEvents->GetXaxis()->SetBinLabel(2, "ZORRO"); @@ -193,9 +207,6 @@ struct HfTaskDeuteronFromLb { if (!track.hasTPC()) { return false; } - if (!track.hasTOF()) { - return false; - } if (track.tpcNClsFound() < cfgTPCNclsFound) { return false; } @@ -274,24 +285,20 @@ struct HfTaskDeuteronFromLb { const bool isTPCDe = std::abs(track.tpcNSigmaDe()) < cfgTPCNsigma; const bool isTOFDe = std::abs(track.tofNSigmaDe()) < cfgTofNsigma; - if (track.pt() < ptThresholdPid) { - if (isTPCDe) { - qaHistos.fill(HIST("Data/ptAntiDeuteron"), track.pt()); - qaHistos.fill(HIST("Data/etaAntideuteron"), track.eta()); - qaHistos.fill(HIST("Data/hDCAxyVsPt"), track.pt(), dca[0]); - qaHistos.fill(HIST("Data/hDCAzVsPt"), track.pt(), dca[1]); - qaHistos.fill(HIST("Data/hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe()); - qaHistos.fill(HIST("Data/hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe()); - } - } else { - if (isTPCDe && isTOFDe) { - qaHistos.fill(HIST("Data/ptAntiDeuteron"), track.pt()); - qaHistos.fill(HIST("Data/etaAntideuteron"), track.eta()); - qaHistos.fill(HIST("Data/hDCAxyVsPt"), track.pt(), dca[0]); - qaHistos.fill(HIST("Data/hDCAzVsPt"), track.pt(), dca[1]); - qaHistos.fill(HIST("Data/hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe()); - qaHistos.fill(HIST("Data/hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe()); - } + if (isTPCDe && track.hasTOF()) { + qaHistos.fill(HIST("Data/hnSigmaTOFVsPtPurity"), track.pt(), track.tofNSigmaDe()); + } + if (isTOFDe && track.hasTOF()) { + qaHistos.fill(HIST("Data/hnSigmaTPCVsPtPurity"), track.pt(), track.tpcNSigmaDe()); + } + + if (isTPCDe && isTOFDe && track.hasTOF()) { + qaHistos.fill(HIST("Data/ptAntiDeuteron"), track.pt()); + qaHistos.fill(HIST("Data/etaAntideuteron"), track.eta()); + qaHistos.fill(HIST("Data/hDCAxyVsPt"), track.pt(), dca[0]); + qaHistos.fill(HIST("Data/hDCAzVsPt"), track.pt(), dca[1]); + qaHistos.fill(HIST("Data/hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe()); + qaHistos.fill(HIST("Data/hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe()); } } } @@ -313,7 +320,40 @@ struct HfTaskDeuteronFromLb { } auto mcParticle = track.mcParticle(); - if (mcParticle.pdgCode() == pdgCodeDaughter) { + const bool isTrueDeuteron = (mcParticle.pdgCode() == pdgCodeDaughter); + const bool isTPCDe = std::abs(track.tpcNSigmaDe()) < cfgTPCNsigma; + const bool isTOFDe = std::abs(track.tofNSigmaDe()) < cfgTofNsigma; + const bool selTpcOrTpcTof = isTPCDe && (!track.hasTOF() || isTOFDe); + + if (isTPCDe) { + qaHistos.fill(HIST("MCReco/ptAntiDeuteronTPCOnlyPIDSelected"), track.pt()); + if (isTrueDeuteron) { + qaHistos.fill(HIST("MCReco/ptAntiDeuteronTPCOnlyPIDSelectedTrue"), track.pt()); + } + } + + if (track.hasTOF()) { + qaHistos.fill(HIST("MCReco/hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe()); + qaHistos.fill(HIST("MCReco/hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe()); + } + + if (selTpcOrTpcTof) { + qaHistos.fill(HIST("MCReco/ptAntiDeuteronTPCorTPCTOFPIDSelected"), track.pt()); + if (isTrueDeuteron) { + qaHistos.fill(HIST("MCReco/ptAntiDeuteronTPCorTPCTOFPIDSelectedTrue"), track.pt()); + } + } + + if (isTPCDe && isTOFDe && track.hasTOF()) { + qaHistos.fill(HIST("MCReco/ptAntiDeuteronPIDSelected"), track.pt()); + if (isTrueDeuteron) { + qaHistos.fill(HIST("MCReco/ptAntiDeuteronPIDSelectedTrue"), track.pt()); + } + } else { + continue; + } + + if (isTrueDeuteron) { if (std::abs(mcParticle.y()) > rapidityCut) { continue; } diff --git a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx index 38443379315..e6b87bd46f9 100644 --- a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx @@ -608,8 +608,8 @@ struct HfTaskFlowCharmHadrons { if constexpr (StoreInfo == RunMode::kEsE || StoreInfo == RunMode::kSPEsE) { qVecRedComps = getEseQvec(collision, qVecRedDetector.value); } - float xRedQVec = qVecRedComps[0]; - float yRedQVec = qVecRedComps[1]; + float const xRedQVec = qVecRedComps[0]; + float const yRedQVec = qVecRedComps[1]; float const amplRedQVec = qVecRedComps[2]; for (const auto& candidate : candidates) { @@ -811,12 +811,10 @@ struct HfTaskFlowCharmHadrons { // subtract daughters' contribution from the (normalized) Q-vector const float redQVecXDaugSubtr = xRedQVec - std::accumulate(tracksRedQx.begin(), tracksRedQx.end(), 0.0); const float redQVecYDaugSubtr = yRedQVec - std::accumulate(tracksRedQy.begin(), tracksRedQy.end(), 0.0); - if (qVecRedDetector.value == QvecEstimator::TPCTot || qVecRedDetector.value == QvecEstimator::TPCPos || qVecRedDetector.value == QvecEstimator::TPCNeg) { - // Correct for track multiplicity - redQVec = std::hypot(redQVecXDaugSubtr, redQVecYDaugSubtr) * std::sqrt(amplRedQVec) / std::sqrt(amplRedQVec - tracksRedQx.size()); - } else { - redQVec = std::hypot(xRedQVec, yRedQVec); - } + // Correct for track multiplicity + redQVec = std::hypot(redQVecXDaugSubtr, redQVecYDaugSubtr) * std::sqrt(amplRedQVec) / std::sqrt(amplRedQVec - tracksRedQx.size()); + } else { + redQVec = std::hypot(xRedQVec, yRedQVec); } if (storeRedQVec) { rowCandFlowEsE(massCand, ptCand, outputMl[0], outputMl[1], scalprodCand, cent, redQVec); diff --git a/PWGHF/HFC/DataModel/DMesonPairsTables.h b/PWGHF/HFC/DataModel/DMesonPairsTables.h index 35e12760919..67a352a46ae 100644 --- a/PWGHF/HFC/DataModel/DMesonPairsTables.h +++ b/PWGHF/HFC/DataModel/DMesonPairsTables.h @@ -32,6 +32,8 @@ DECLARE_SOA_COLUMN(PtCand1, ptCand1, float); //! Transverse momentum of first DECLARE_SOA_COLUMN(PtCand2, ptCand2, float); //! Transverse momentum of second candidate DECLARE_SOA_COLUMN(YCand1, yCand1, float); //! Rapidity of first candidate DECLARE_SOA_COLUMN(YCand2, yCand2, float); //! Rapidity of second candidate +DECLARE_SOA_COLUMN(EtaCand1, etaCand1, float); //! Azimuthal angle of first candidate +DECLARE_SOA_COLUMN(EtaCand2, etaCand2, float); //! Azimuthal angle of second candidate DECLARE_SOA_COLUMN(PhiCand1, phiCand1, float); //! Azimuthal angle of first candidate DECLARE_SOA_COLUMN(PhiCand2, phiCand2, float); //! Azimuthal angle of second candidate // Invariant mass @@ -55,12 +57,15 @@ DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! } // namespace hf_correlation_d_meson_pair // Definition of the D meson pair table. Contains the info needed at Data level. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_DMESON_PAIR_TABLE(_pair_type_, _marker_value_, _description_) \ DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_, o2::soa::Marker<_marker_value_>, \ hf_correlation_d_meson_pair::PtCand1, \ hf_correlation_d_meson_pair::PtCand2, \ hf_correlation_d_meson_pair::YCand1, \ hf_correlation_d_meson_pair::YCand2, \ + hf_correlation_d_meson_pair::EtaCand1, \ + hf_correlation_d_meson_pair::EtaCand2, \ hf_correlation_d_meson_pair::PhiCand1, \ hf_correlation_d_meson_pair::PhiCand2, \ hf_correlation_d_meson_pair::MDCand1, \ @@ -71,6 +76,7 @@ DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! hf_correlation_d_meson_pair::CandidateType1, \ hf_correlation_d_meson_pair::CandidateType2); // Definition of the D meson pair table with info at MC level. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_DMESON_PAIR_MCINFO_TABLE(_pair_type_, _marker_value_, _description_) \ DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_ "MCINFO", o2::soa::Marker<_marker_value_>, \ hf_correlation_d_meson_pair::Origin1, \ @@ -78,6 +84,7 @@ DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! hf_correlation_d_meson_pair::MatchedMc1, \ hf_correlation_d_meson_pair::MatchedMc2); // Definition of the table with the ML info of the D meson pair. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_DMESON_PAIR_MLINFO_TABLE(_pair_type_, _marker_value_, _description_) \ DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_ "ML", o2::soa::Marker<_marker_value_>, \ hf_correlation_d_meson_pair::MlProbD0Cand1, \ @@ -93,6 +100,47 @@ DECLARE_DMESON_PAIR_MLINFO_TABLE(D0PairMl, 1, "D0PAIR"); //! D0 pairs ML Inf DECLARE_DMESON_PAIR_TABLE(D0PairMcGen, 2, "D0PAIRGEN"); //! D0 pairs MC Gen Kinematic Info DECLARE_DMESON_PAIR_MCINFO_TABLE(D0PairMcGenInfo, 2, "D0PAIRGEN"); //! D0 pairs MC Gen Info +namespace hf_correlation_d_meson_had +{ +// D candidate +DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of the D meson +DECLARE_SOA_COLUMN(YD, yD, float); //! Rapidity of the D meson +DECLARE_SOA_COLUMN(EtaD, etaD, float); //! Pseudorapidity of the D meson +DECLARE_SOA_COLUMN(PhiD, phiD, float); //! Azimuthal angle of the D meson +DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of the D meson +DECLARE_SOA_COLUMN(PoolBinD, poolBinD, int); //! Pool bin of the D meson +DECLARE_SOA_COLUMN(GIndexColD, gIndexColD, int); //! G-index column of the D meson +DECLARE_SOA_COLUMN(TimestampD, timestampD, int64_t); //! Timestamp of the D meson + +// Associated hadron +DECLARE_SOA_COLUMN(PtHad, ptHad, float); //! Transverse momentum of the associated hadron +DECLARE_SOA_COLUMN(YHad, yHad, float); //! Rapidity of the associated hadron +DECLARE_SOA_COLUMN(EtaHad, etaHad, float); //! Pseudorapidity of the associated hadron +DECLARE_SOA_COLUMN(PhiHad, phiHad, float); //! Azimuthal angle of the associated hadron +DECLARE_SOA_COLUMN(PoolBinHad, poolBinHad, int); //! Pool bin of the associated hadron +DECLARE_SOA_COLUMN(GIndexColHad, gIndexColHad, int); //! G-index column of the associated hadron +DECLARE_SOA_COLUMN(TimestampHad, timestampHad, int64_t); //! Timestamp of the associated hadron + +} // namespace hf_correlation_d_meson_had + +// Definition of the D meson table for D-had correlations. Contains the info needed at Data level. +DECLARE_SOA_TABLE(DMesonCandInfo, "AOD", "DMESONCANDINFO", + hf_correlation_d_meson_had::PtD, + hf_correlation_d_meson_had::EtaD, + hf_correlation_d_meson_had::PhiD, + hf_correlation_d_meson_had::MD, + hf_correlation_d_meson_had::PoolBinD, + hf_correlation_d_meson_had::GIndexColD, + hf_correlation_d_meson_had::TimestampD); + +DECLARE_SOA_TABLE(AssocHadInfo, "AOD", "ASSOCHADINFO", + hf_correlation_d_meson_had::PtHad, + hf_correlation_d_meson_had::EtaHad, + hf_correlation_d_meson_had::PhiHad, + hf_correlation_d_meson_had::PoolBinHad, + hf_correlation_d_meson_had::GIndexColHad, + hf_correlation_d_meson_had::TimestampHad); + } // namespace o2::aod #endif // PWGHF_HFC_DATAMODEL_DMESONPAIRSTABLES_H_ diff --git a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx index 77e43224d52..cb91b184e64 100644 --- a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx @@ -18,11 +18,18 @@ #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponseD0ToKPi.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/HFC/DataModel/DMesonPairsTables.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" #include #include @@ -32,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +51,8 @@ #include +#include +#include #include #include #include @@ -71,6 +81,57 @@ enum PairTypeOfSelMassSel { } // namespace using McParticlesPlus2Prong = soa::Join; +// definition of ME variables +using BinningType = ColumnBinningPolicy>; + +struct HfCorrelatorD0HadronsSelection { + Produces d0Sel; + + Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable doSelD0Collision{"doSelD0Collision", true, "Select collisions with at least one D0"}; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; + Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + + SliceCache cache; + + using SelCollisions = soa::Join; + using CandidatesD0Data = soa::Join; + + Partition selectedD0Candidates = + aod::hf_sel_candidate_d0::isSelD0 >= 1 || + aod::hf_sel_candidate_d0::isSelD0bar >= 1; + + // Process function to select collisions with at least one D0 candidate passing the selection criteria + void processD0SelectionData(SelCollisions::iterator const& collision, + CandidatesD0Data const&) + { + bool isSel8 = !useSel8 || collision.sel8(); + bool isNoSameBunchPileUp = !selNoSameBunchPileUpColl || + collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + bool isD0Found = !doSelD0Collision; + + if (doSelD0Collision) { + auto grouped = selectedD0Candidates.sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + for (const auto& candidate : grouped) { + + if (candidate.isSelD0() < selectionFlagD0 && candidate.isSelD0bar() < selectionFlagD0bar) { + continue; + } + if (std::abs(HfHelper::yD0(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + continue; + } + isD0Found = true; + break; + } + } + + d0Sel(isD0Found && isSel8 && isNoSameBunchPileUp); + } + PROCESS_SWITCH(HfCorrelatorD0HadronsSelection, processD0SelectionData, "Process D0 Selection Data", true); +}; struct HfCorrelatorDMesonPairs { @@ -80,23 +141,38 @@ struct HfCorrelatorDMesonPairs { Produces entryD0PairMcGen; Produces entryD0PairMcGenInfo; + // Tables for event mixing + Produces entryDMesonCand; + Produces entryAssocHad; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; Configurable selectionFlagHf{"selectionFlagHf", 1, "Selection Flag for HF flagged candidates"}; - Configurable yCandMax{"yCandMax", 0.8, "maxmum |y| of D0 candidates"}; + Configurable yCandMax{"yCandMax", 0.8, "maximum |y| of D0 candidates"}; Configurable ptCandMin{"ptCandMin", -1., "minimum pT of D0 candidates"}; Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots"}; Configurable selectSignalRegionOnly{"selectSignalRegionOnly", false, "only use events close to PDG peak"}; Configurable massCut{"massCut", 0.05, "Maximum deviation from PDG peak allowed for signal region"}; - Configurable daughterTracksCutFlag{"daughterTracksCutFlag", false, "Flag to add cut on daughter tracks"}; Configurable removeAmbiguous{"removeAmbiguous", false, "Flag to remove ambiguous candidates"}; Configurable ptMaxRemoveAmbiguous{"ptMaxRemoveAmbiguous", 5.0, "Max. pT to remove the ambiguous candidates"}; + // Event mixing configurables + Configurable applyMixedEvent{"applyMixedEvent", false, "Flag to make the event mixing"}; + Configurable daughterTracksCutFlag{"daughterTracksCutFlag", false, "Flag to add cut on daughter tracks"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; + Configurable ptTrackMax{"ptTrackMax", 100., "max. track pT"}; + Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; + Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; + // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable> cutsMl{"cutsMl", {static_cast(hf_cuts_ml::Cuts[0]), hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; @@ -108,7 +184,20 @@ struct HfCorrelatorDMesonPairs { Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; SliceCache cache; + + using SelCollisionsWithD0 = soa::Filtered>; + using CandidatesD0Data = soa::Join; + + using FilteredD0Candidates = soa::Filtered; + using TracksData = soa::Filtered>; // trackFilter applied + + Filter collisionFilter = aod::hf_selection_dmeson_collision::dmesonSel == true; + Filter d0Filter = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK))) != static_cast(0); + Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (nabs(aod::track::pt) > ptTrackMin) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + Preslice perCol2Prong = aod::hf_cand::collisionId; + Preslice candsD0PerCollision = aod::hf_cand::collisionId; + Preslice trackIndicesPerCollision = aod::track::collisionId; o2::analysis::HfMlResponseD0ToKPi hfMlResponse; o2::ccdb::CcdbApi ccdbApi; @@ -141,6 +230,13 @@ struct HfCorrelatorDMesonPairs { HistogramConfigSpec hTH2Pid{HistType::kTH2F, {{500, 0., 10.}, {400, -20., 20.}}}; HistogramConfigSpec hTH3PtVsYVsNContrib{HistType::kTH3F, {{360, 0., 36.}, {20, -1., 1.}, {120, -0.5, 119.5}}}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; + ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 6000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsDcaXY{"binsDcaXY", {128, -0.2, 0.2}, "DCA xy"}; + BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; + HistogramRegistry registry{ "registry", {{"hPtCand", "D meson candidates;candidate #it{p}_{T} (GeV/#it{c});entries", hTH1Pt}, @@ -188,9 +284,9 @@ struct HfCorrelatorDMesonPairs { hfMlResponse.init(); } - auto vbins = (std::vector)binsPt; - constexpr int kNBinsSelStatus = 25; - std::string labels[kNBinsSelStatus]; + auto vbins = static_cast>(binsPt); + constexpr int NBinsSelStatus = 25; + std::array labels; labels[0] = "total # of Selected pairs"; // Cand1 analysis @@ -222,17 +318,17 @@ struct HfCorrelatorDMesonPairs { labels[23] = "# of True D+Dbar Pairs"; labels[24] = "# of True Dbar+D Pairs"; - AxisSpec const axisSelStatus = {kNBinsSelStatus, 0.5, kNBinsSelStatus + 0.5, ""}; + AxisSpec const axisSelStatus = {NBinsSelStatus, 0.5, NBinsSelStatus + 0.5, ""}; registry.add("hSelectionStatus", "D Meson candidates;selection status;entries", HistType::kTH1F, {axisSelStatus}); registry.add("hSelectionStatusMcGen", "D Meson candidates MC Gen;selection status;entries", HistType::kTH1F, {axisSelStatus}); - for (int iBin = 0; iBin < kNBinsSelStatus; iBin++) { + for (int iBin = 0; iBin < NBinsSelStatus; iBin++) { registry.get(HIST("hSelectionStatus"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); registry.get(HIST("hSelectionStatusMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - constexpr int kNBinsMatching = 8; - std::string labelsMatching[kNBinsMatching]; + constexpr int NBinsMatching = 8; + std::array labelsMatching; // Cand1 analysis labelsMatching[0] = "total # of Cand 1"; labelsMatching[1] = "# of matched D Cand 1"; @@ -244,17 +340,17 @@ struct HfCorrelatorDMesonPairs { labelsMatching[6] = "# of matched Dbar Cand 2"; labelsMatching[7] = "# of unmatched Cand 2"; - AxisSpec const axisMatching = {kNBinsMatching, 0.5, kNBinsMatching + 0.5, ""}; + AxisSpec const axisMatching = {NBinsMatching, 0.5, NBinsMatching + 0.5, ""}; registry.add("hMatchingMcRec", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisMatching}); registry.add("hMatchingMcGen", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisMatching}); - for (int iBin = 0; iBin < kNBinsMatching; iBin++) { + for (int iBin = 0; iBin < NBinsMatching; iBin++) { registry.get(HIST("hMatchingMcRec"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMatching[iBin].data()); registry.get(HIST("hMatchingMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMatching[iBin].data()); } - constexpr int kNBinsSinglePart = 6; - std::string labelsSinglePart[kNBinsSinglePart]; + constexpr int NBinsSinglePart = 6; + std::array labelsSinglePart; // Candidate analysis labelsSinglePart[0] = "total # of Candidates"; labelsSinglePart[1] = "# of selected D"; @@ -263,11 +359,11 @@ struct HfCorrelatorDMesonPairs { labelsSinglePart[4] = "# of true D"; labelsSinglePart[5] = "# of true Dbar"; - AxisSpec const axisSinglePart = {kNBinsSinglePart, 0.5, kNBinsSinglePart + 0.5, ""}; + AxisSpec const axisSinglePart = {NBinsSinglePart, 0.5, NBinsSinglePart + 0.5, ""}; registry.add("hStatusSinglePart", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisSinglePart}); registry.add("hStatusSinglePartMcGen", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisSinglePart}); - for (int iBin = 0; iBin < kNBinsSinglePart; iBin++) { + for (int iBin = 0; iBin < NBinsSinglePart; iBin++) { registry.get(HIST("hStatusSinglePart"))->GetXaxis()->SetBinLabel(iBin + 1, labelsSinglePart[iBin].data()); registry.get(HIST("hStatusSinglePartMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labelsSinglePart[iBin].data()); } @@ -309,6 +405,24 @@ struct HfCorrelatorDMesonPairs { registry.add("hnDMeson", "Thn for D0 candidates", HistType::kTHnSparseD, axes); registry.get(HIST("hnDMeson"))->Sumw2(); } + + // Event mixing + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec const axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisDcaXY = {binsDcaXY, "DCA xy"}; + + if (applyMixedEvent) { + registry.add("hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hD0Bin", "D0 selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hDcaXYVsPt", "DCA xy vs pt", {HistType::kTH2F, {{axisDcaXY}, {axisPtHadron}}}); + } } /// Sets bits to select candidate type for D0 @@ -408,12 +522,12 @@ struct HfCorrelatorDMesonPairs { } /// Fill counters for D0 and D0bar - /// \param selectedD0Candidates contains all D0 candidates + /// \param d0Candidates contains all D0 candidates template - void getCountersPerEvent(const T& selectedD0Candidates) + void getCountersPerEvent(const T& d0Candidates) { int nDevent = 0, nDbarevent = 0, nDDbarevent = 0, nDorDbarevent = 0; - for (const auto& candidate : selectedD0Candidates) { + for (const auto& candidate : d0Candidates) { // Get counters per event bool const isSignalD0 = std::abs(HfHelper::invMassD0ToPiK(candidate) - MassD0) < massCut; bool const isSignalD0bar = std::abs(HfHelper::invMassD0barToKPi(candidate) - MassD0Bar) < massCut; @@ -470,7 +584,7 @@ struct HfCorrelatorDMesonPairs { /// Fill selection status histogram void fillEntry(const bool& isDCand1, const bool& isDbarCand1, const bool& isDCand2, const bool& isDbarCand2, - const uint8_t& candidateType1, const uint8_t& candidateType2, float yCand1, float yCand2, float phiCand1, float phiCand2, + const uint8_t candidateType1, const uint8_t candidateType2, float yCand1, float yCand2, float etaCand1, float etaCand2, float phiCand1, float phiCand2, double ptCand1, double ptCand2, float massDCand1, float massDbarCand1, float massDCand2, float massDbarCand2) { @@ -525,7 +639,7 @@ struct HfCorrelatorDMesonPairs { } } - entryD0Pair(ptCand1, ptCand2, yCand1, yCand2, phiCand1, phiCand2, massDCand1, massDbarCand1, massDCand2, massDbarCand2, pairType, candidateType1, candidateType2); + entryD0Pair(ptCand1, ptCand2, yCand1, yCand2, etaCand1, etaCand2, phiCand1, phiCand2, massDCand1, massDbarCand1, massDCand2, massDbarCand2, pairType, candidateType1, candidateType2); } void fillMcHistos(int8_t matchedRec1, int8_t matchedRec2, int8_t isTrueDCand1, int8_t isTrueDbarCand1, int8_t isTrueDCand2, int8_t isTrueDbarCand2) @@ -571,13 +685,41 @@ struct HfCorrelatorDMesonPairs { } /// D0(bar)-D0(bar) correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) - void processData(aod::Collision const& collision, - soa::Join const& candidates, aod::Tracks const&) + void processData(SelCollisionsWithD0::iterator const& collision, + CandidatesD0Data const& candidates, TracksData const& tracks, aod::BCsWithTimestamps const&) { + + auto bc = collision.bc_as(); + int gCollisionId = collision.globalIndex(); + int64_t timeStamp = bc.timestamp(); + + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + + int nTracks = 0; + if (collision.numContrib() > 1) { + for (const auto& track : tracks) { + if (std::abs(track.eta()) >= etaTrackMax || std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { + continue; + } + nTracks++; + } + } + if (applyMixedEvent) { + registry.fill(HIST("hMultiplicityPreSelection"), nTracks); + } + if (nTracks < multMin || nTracks > multMax) { + return; + } + if (applyMixedEvent) { + registry.fill(HIST("hMultiplicity"), nTracks); + } + + int cntD0 = 0; + for (const auto& candidate : candidates) { analysePid(candidate); } - auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, gCollisionId, cache); getCountersPerEvent(selectedD0CandidatesGrouped); // protection against empty tables to be sliced if (selectedD0Candidates.size() <= 1) { @@ -594,8 +736,8 @@ struct HfCorrelatorDMesonPairs { if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); bool const isSignalD0Cand1 = std::abs(HfHelper::invMassD0ToPiK(candidate1) - MassD0) < massCut; bool const isSignalD0barCand1 = std::abs(HfHelper::invMassD0barToKPi(candidate1) - MassD0Bar) < massCut; @@ -638,6 +780,9 @@ struct HfCorrelatorDMesonPairs { registry.fill(HIST("hY"), candidate1.y(MassD0)); registry.fill(HIST("hPtCandAfterCut"), candidate1.pt()); registry.fill(HIST("hPVContrib"), collision.numContrib()); + if (applyMixedEvent) { + registry.fill(HIST("hD0Bin"), poolBin); + } if (isDCand1) { registry.fill(HIST("hMass"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt()); @@ -646,6 +791,10 @@ struct HfCorrelatorDMesonPairs { } else { registry.fill(HIST("hnDMeson"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); } + // Fill D0 table for offline event mixing + if (applyMixedEvent) { + entryDMesonCand(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0ToPiK(candidate1), poolBin, gCollisionId, timeStamp); + } } if (isDbarCand1) { registry.fill(HIST("hMass"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt()); @@ -654,8 +803,49 @@ struct HfCorrelatorDMesonPairs { } else { registry.fill(HIST("hnDMeson"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); } + // Fill D0 table for offline event mixing + if (applyMixedEvent) { + entryDMesonCand(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0barToKPi(candidate1), poolBin, gCollisionId, timeStamp); + } + } + + if (applyMixedEvent) { + // Loop on the associated tracks for offline event mixing + for (const auto& track : tracks) { + // apply track selection + if (track.collisionId() != gCollisionId) { + continue; + } + + // Manual trackFilter check + if (std::abs(track.eta()) >= etaTrackMax) { + continue; + } + if (track.pt() <= ptTrackMin) { + continue; + } + if (std::abs(track.dcaXY()) >= dcaXYTrackMax) { + continue; + } + if (std::abs(track.dcaZ()) >= dcaZTrackMax) { + continue; + } + // Removing D0 daughters by checking track indices + if (daughterTracksCutFlag) { + if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex())) { + continue; + } + } + if (cntD0 == 0) { + entryAssocHad(track.pt(), track.eta(), track.phi(), poolBin, gCollisionId, timeStamp); + registry.fill(HIST("hTracksBin"), poolBin); + registry.fill(HIST("hDcaXYVsPt"), track.dcaXY(), track.pt()); + } + } // Hadron Tracks loop + cntD0++; } + // Loop on the second D0 candidate for (auto candidate2 = candidate1 + 1; candidate2 != selectedD0CandidatesGrouped.end(); ++candidate2) { outputMlD0Cand2.clear(); @@ -667,9 +857,9 @@ struct HfCorrelatorDMesonPairs { if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { continue; } - auto prong0Cand2 = candidate2.template prong0_as(); - auto prong1Cand2 = candidate2.template prong1_as(); - if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { + auto prong0Cand2 = candidate2.template prong0_as(); + auto prong1Cand2 = candidate2.template prong1_as(); + if ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2)) { continue; } @@ -707,18 +897,25 @@ struct HfCorrelatorDMesonPairs { } fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), - candidate1.phi(), candidate2.phi(), candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), + candidate1.eta(), candidate2.eta(), candidate1.phi(), candidate2.phi(), + candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), HfHelper::invMassD0ToPiK(candidate2), HfHelper::invMassD0barToKPi(candidate2)); entryD0PairMl(outputMlD0Cand1, outputMlD0barCand1, outputMlD0Cand2, outputMlD0barCand2); } else { // Fill entries - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), candidate1.phi(), candidate2.phi(), + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), + candidate1.eta(), candidate2.eta(), candidate1.phi(), candidate2.phi(), candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), HfHelper::invMassD0ToPiK(candidate2), HfHelper::invMassD0barToKPi(candidate2)); } } // end inner loop (Cand2) } // end outer loop (Cand1) + + if (applyMixedEvent) { + registry.fill(HIST("hZvtx"), collision.posZ()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + } } PROCESS_SWITCH(HfCorrelatorDMesonPairs, processData, "Process data mode", true); @@ -730,10 +927,6 @@ struct HfCorrelatorDMesonPairs { } auto selectedD0CandidatesGroupedMc = selectedD0CandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); getCountersPerEvent(selectedD0CandidatesGroupedMc); - // protection against empty tables to be sliced - if (selectedD0CandidatesMc.size() <= 1) { - return; - } for (const auto& candidate1 : selectedD0CandidatesGroupedMc) { outputMlD0Cand1.clear(); @@ -742,10 +935,11 @@ struct HfCorrelatorDMesonPairs { auto ptCandidate1 = candidate1.pt(); auto yCandidate1 = HfHelper::yD0(candidate1); auto phiCandidate1 = candidate1.phi(); + auto etaCandidate1 = candidate1.eta(); float const massD0Cand1 = HfHelper::invMassD0ToPiK(candidate1); float const massD0barCand1 = HfHelper::invMassD0barToKPi(candidate1); - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); if (std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; @@ -857,6 +1051,7 @@ struct HfCorrelatorDMesonPairs { auto ptCandidate2 = candidate2.pt(); auto yCandidate2 = HfHelper::yD0(candidate2); auto phiCandidate2 = candidate2.phi(); + auto etaCandidate2 = candidate2.eta(); float const massD0Cand2 = HfHelper::invMassD0ToPiK(candidate2); float const massD0barCand2 = HfHelper::invMassD0barToKPi(candidate2); auto prong0Cand2 = candidate2.template prong0_as(); @@ -876,7 +1071,7 @@ struct HfCorrelatorDMesonPairs { if (candidate2.isSelD0() < selectionFlagD0 && candidate2.isSelD0bar() < selectionFlagD0bar) { continue; } - if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { + if ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2)) { continue; } auto candidateType2 = assignCandidateTypeD0(candidate2); // Candidate type attribution @@ -913,7 +1108,7 @@ struct HfCorrelatorDMesonPairs { } // Fill tables - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, etaCandidate1, etaCandidate2, phiCandidate1, phiCandidate2, ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); fillMcHistos(matchedRec1, matchedRec2, static_cast(isTrueDCand1), static_cast(isTrueDbarCand1), static_cast(isTrueDCand2), static_cast(isTrueDbarCand2)); entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); @@ -921,7 +1116,7 @@ struct HfCorrelatorDMesonPairs { } else { // Fill tables - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, etaCandidate1, etaCandidate2, phiCandidate1, phiCandidate2, ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); fillMcHistos(matchedRec1, matchedRec2, static_cast(isTrueDCand1), static_cast(isTrueDbarCand1), static_cast(isTrueDCand2), static_cast(isTrueDbarCand2)); entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); @@ -1109,7 +1304,7 @@ struct HfCorrelatorDMesonPairs { } // Fill pair Selection Status - entryD0PairMcGen(particle1.pt(), particle2.pt(), particle1.y(), particle2.y(), particle1.phi(), particle2.phi(), MassD0, MassD0Bar, MassD0, MassD0Bar, pairType, particleType1, particleType2); + entryD0PairMcGen(particle1.pt(), particle2.pt(), particle1.y(), particle2.y(), particle1.eta(), particle2.eta(), particle1.phi(), particle2.phi(), MassD0, MassD0Bar, MassD0, MassD0Bar, pairType, particleType1, particleType2); entryD0PairMcGenInfo(originGen1, originGen2, matchedGen1, matchedGen2); } // end inner loop @@ -1121,5 +1316,8 @@ struct HfCorrelatorDMesonPairs { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; } diff --git a/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx index 9ae005e732d..da60d9982c2 100644 --- a/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx @@ -353,7 +353,7 @@ struct HfCorrelatorLcScHadrons { Configurable cfgV0DaughPIDCutsTPCPr{"cfgV0DaughPIDCutsTPCPr", 2.5, "max. TPCnSigma Proton"}; Configurable cfgV0DaughPIDCutsTPCPi{"cfgV0DaughPIDCutsTPCPi", 2.5, "max. TPCnSigma Pion"}; Configurable cfgV0DaughPIDCutsTOFPi{"cfgV0DaughPIDCutsTOFPi", 2.5, "max. TOFnSigma Pion"}; - Configurable cfgV0DaughPIDCutsTOFPr{"cfgV0DaughPIDCutsTOFPr", 2.5, "max. TOFnSigma Pion"}; + Configurable cfgV0DaughPIDCutsTOFPr{"cfgV0DaughPIDCutsTOFPr", -2.5, "min. TOFnSigma Proton (put only negative value)"}; Configurable cfgHypMassWindow{"cfgHypMassWindow", 0.1, "single lambda mass selection"}; Configurable cfgIsCorrCollMatchV0{"cfgIsCorrCollMatchV0", true, "check if daughter and mother collision are same"}; Configurable cfgCalDataDrivenEffPr{"cfgCalDataDrivenEffPr", false, "calculate data driven efficiency of proton using Lambda"}; @@ -368,6 +368,7 @@ struct HfCorrelatorLcScHadrons { Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; Configurable cfgPV{"cfgPV", 10., "maximum z-vertex"}; Configurable calEffV0{"calEffV0", false, "calculate lambda0 efficiency"}; + Configurable checkTOFForPion{"checkTOFForPion", false, "if True, TOF selection on pion V0 wil only be applied if TOF present"}; } cfgV0; // Event Mixing for the Data Mode @@ -602,28 +603,32 @@ struct HfCorrelatorLcScHadrons { if (std::abs(track.eta()) > cfgCharmCand.etaTrackMax) { return false; } + // --------------------------------------------------------- // 1. Proton PID Selection // --------------------------------------------------------- if (std::abs(pid) == kProton) { + bool hasTOFProton = (pid > 0) ? v0.positiveHasTOF() : v0.negativeHasTOF(); bool passTOF = false; if (track.pt() > cfgV0.cfgV0DaughPrPtMax || track.pt() < cfgV0.cfgV0DaughPrPtMin) { return false; } - if (track.hasTOF()) { + + if (hasTOFProton && (track.pt() > cfgCharmCand.tofPIDThreshold)) { if constexpr (std::experimental::is_detected::value) { // pid > 0: Proton from Lambda (LaPr) // pid < 0: Antiproton from Anti-Lambda (ALaPr) double strangeTOF = (pid > 0) ? v0.tofNSigmaLaPr() : v0.tofNSigmaALaPr(); - passTOF = std::abs(strangeTOF) > cfgV0.cfgV0DaughPIDCutsTOFPr; + passTOF = strangeTOF > cfgV0.cfgV0DaughPIDCutsTOFPr; + } else { // if strange TOF is unavailable - passTOF = std::abs(track.tofNSigmaPr()) > cfgV0.cfgV0DaughPIDCutsTOFPr; + passTOF = track.tofNSigmaPr() > cfgV0.cfgV0DaughPIDCutsTOFPr; } } - if ((std::abs(track.tpcNSigmaPr()) > cfgV0.cfgV0DaughPIDCutsTPCPr) || passTOF) { + if ((std::abs(track.tpcNSigmaPr()) > cfgV0.cfgV0DaughPIDCutsTPCPr) && !passTOF) { return false; } } @@ -631,31 +636,31 @@ struct HfCorrelatorLcScHadrons { // --------------------------------------------------------- // 2. Pion PID Selection // --------------------------------------------------------- - if (std::abs(pid) == kPiPlus) { + if (std::abs(pid) == kPiPlus && cfgV0.checkTOFForPion) { + bool hasTOFPion = (pid < 0) ? v0.negativeHasTOF() : v0.positiveHasTOF(); bool passTOF = false; if (track.pt() > cfgV0.cfgV0DaughPiPtMax || track.pt() < cfgV0.cfgV0DaughPiPtMin) { return false; } - if (track.hasTOF()) { + if (hasTOFPion && (track.pt() > cfgCharmCand.tofPIDThreshold)) { if constexpr (std::experimental::is_detected::value) { // A pion can belong to either a Lambda/Anti-Lambda decay or a K0s decay. // We evaluate both applicable hypotheses based on charge sign and pick the best match. double tofLa = (pid > 0) ? v0.tofNSigmaALaPi() : v0.tofNSigmaLaPi(); - passTOF = tofLa > cfgV0.cfgV0DaughPIDCutsTOFPi; + passTOF = std::abs(tofLa) > cfgV0.cfgV0DaughPIDCutsTOFPi; } else { // Fallback to standard track TOF passTOF = std::abs(track.tofNSigmaPi()) > cfgV0.cfgV0DaughPIDCutsTOFPi; } } - if ((std::abs(track.tpcNSigmaPi()) > cfgV0.cfgV0DaughPIDCutsTPCPi) || passTOF) { + if ((std::abs(track.tpcNSigmaPi()) > cfgV0.cfgV0DaughPIDCutsTPCPi) && !passTOF) { return false; } } - return true; } @@ -836,7 +841,7 @@ struct HfCorrelatorLcScHadrons { auto posTrackV0 = v0.template posTrack_as(); auto negTrackV0 = v0.template negTrack_as(); - if ((candidate.prong0Id() == posTrackV0.globalIndex()) || (candidate.prong1Id() == posTrackV0.globalIndex()) || (candidate.prong2Id() == posTrackV0.globalIndex() || (candidate.prong0Id() == negTrackV0.globalIndex()) || (candidate.prong1Id() == negTrackV0.globalIndex()) || (candidate.prong2Id() == negTrackV0.globalIndex()))) { + if ((candidate.prong0Id() == posTrackV0.globalIndex()) || (candidate.prong1Id() == posTrackV0.globalIndex()) || (candidate.prong2Id() == posTrackV0.globalIndex()) || (candidate.prong0Id() == negTrackV0.globalIndex()) || (candidate.prong1Id() == negTrackV0.globalIndex()) || (candidate.prong2Id() == negTrackV0.globalIndex())) { if (!cfgCharmCand.storeAutoCorrelationFlag) { continue; } @@ -848,7 +853,7 @@ struct HfCorrelatorLcScHadrons { } // Process Lambda (proton-pion) - if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + if ((std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) && v0.alpha() > 0) { if (isSelectedV0Daughter(posTrackV0, v0, kProton) && isSelectedV0Daughter(negTrackV0, v0, kPiMinus)) { if (selLcPKPi) { @@ -869,7 +874,7 @@ struct HfCorrelatorLcScHadrons { } // Process anti-Lambda (anti-proton-pion) - if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + if ((std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) && v0.alpha() < 0) { if (isSelectedV0Daughter(negTrackV0, v0, kProtonBar) && isSelectedV0Daughter(posTrackV0, v0, kPiPlus)) { if (selLcPKPi) { @@ -956,7 +961,7 @@ struct HfCorrelatorLcScHadrons { } // Process Lambda (proton + pion) - if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow && v0.alpha() > 0) { entryHadron(v0.mLambda(), trackV0Pos.eta(), trackV0Pos.pt() * trackV0Pos.sign(), 0, 0, v0.pt()); entryTrkPID(trackV0Pos.tpcNSigmaPr(), trackV0Pos.tpcNSigmaKa(), trackV0Pos.tpcNSigmaPi(), trackV0Pos.tofNSigmaPr(), trackV0Pos.tofNSigmaKa(), trackV0Pos.tofNSigmaPi()); @@ -980,7 +985,7 @@ struct HfCorrelatorLcScHadrons { } } - if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow && v0.alpha() < 0) { entryHadron(v0.mAntiLambda(), trackV0Neg.eta(), trackV0Neg.pt() * trackV0Neg.sign(), 0, 0, v0.pt()); entryTrkPID(trackV0Neg.tpcNSigmaPr(), trackV0Neg.tpcNSigmaKa(), trackV0Neg.tpcNSigmaPi(), trackV0Neg.tofNSigmaPr(), trackV0Neg.tofNSigmaKa(), trackV0Neg.tofNSigmaPi()); @@ -1013,7 +1018,7 @@ struct HfCorrelatorLcScHadrons { auto const& partV0Pos = trackV0Pos.mcParticle(); auto const& partV0Neg = trackV0Neg.mcParticle(); - if (passV0Sel && v0Mc.pdgCode() == kLambda0) { + if (passV0Sel && v0Mc.pdgCode() == kLambda0 && v0.alpha() > 0) { if (isSelectedV0Daughter(trackV0Pos, v0, kProton) && isSelectedV0Daughter(trackV0Neg, v0, kPiMinus)) { registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); @@ -1028,7 +1033,7 @@ struct HfCorrelatorLcScHadrons { } } } - if (passV0Sel && v0Mc.pdgCode() == kLambda0Bar) { + if (passV0Sel && v0Mc.pdgCode() == kLambda0Bar && v0.alpha() < 0) { if (isSelectedV0Daughter(trackV0Neg, v0, kProtonBar) && isSelectedV0Daughter(trackV0Pos, v0, kPiPlus)) { registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); @@ -1625,7 +1630,7 @@ struct HfCorrelatorLcScHadrons { registry.fill(HIST("hPhiMcGen"), RecoDecay::constrainAngle(particle.phi(), -PIHalf)); registry.fill(HIST("hYMcGen"), yCand); - int8_t chargeCand = pdg->GetParticle(particle.pdgCode())->Charge() / PDGChargeScale; // Retrieve charge + auto chargeCand = pdg->GetParticle(particle.pdgCode())->Charge() / PDGChargeScale; // Retrieve charge if (chargeCand == ChargeZero) { chargeCand = (particle.pdgCode() > ChargeZero) ? AssignedChargeSc0 : -AssignedChargeSc0; // to distingush sc0 from anti-sc0, charge set to +1 and -1 } @@ -1854,8 +1859,8 @@ struct HfCorrelatorLcScHadrons { if (cfgCharmCand.pidTrkApplied && (std::abs(particleAssoc.pdgCode()) != kProton)) { continue; // proton PID } - int8_t const chargeLc = static_cast(pdg->GetParticle(candidate.pdgCode())->Charge()); // Retrieve charge - int8_t const chargeAssoc = static_cast(pdg->GetParticle(particleAssoc.pdgCode())->Charge()); // Retrieve charge + auto const chargeLc = pdg->GetParticle(candidate.pdgCode())->Charge(); // Retrieve charge + auto const chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); // Retrieve charge float cent = 100.0; // will be updated later int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); @@ -1906,8 +1911,8 @@ struct HfCorrelatorLcScHadrons { PROCESS_SWITCH(HfCorrelatorLcScHadrons, processLambda0EffCal, "Mc process for lambda0", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context), + adaptAnalysisTask(context)}; } diff --git a/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx index 4cb726052ea..249b4eea990 100644 --- a/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx @@ -20,6 +20,7 @@ #include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/HFC/Utils/utilsCorrelations.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/CCDB/EventSelectionParams.h" @@ -377,14 +378,14 @@ struct HfCorrelatorXicHadrons { } cfgXicCand; struct : ConfigurableGroup { - Configurable cfgDaughPrPtMax{"cfgDaughPrPtMax", 5., "max. pT Daughter Proton"}; - Configurable cfgDaughPrPtMin{"cfgDaughPrPtMin", 0.3, "min. pT Daughter Proton"}; - Configurable cfgDaughPiPtMax{"cfgDaughPiPtMax", 10., "max. pT Daughter Pion"}; - Configurable cfgDaughPiPtMin{"cfgDaughPiPtMin", 0.3, "min. pT Daughter Pion"}; - Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 2.5, "max. TPCnSigma Proton"}; - Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 2.5, "max. TPCnSigma Pion"}; - Configurable cfgDaughPIDCutsTOFPi{"cfgDaughPIDCutsTOFPi", 2.5, "max. TOFnSigma Pion"}; - Configurable cfgDaughPIDCutsTOFPr{"cfgDaughPIDCutsTOFPr", 2.5, "max. TOFnSigma Pion"}; + Configurable cfgV0DaughPrPtMax{"cfgV0DaughPrPtMax", 5., "max. pT Daughter Proton"}; + Configurable cfgV0DaughPrPtMin{"cfgV0DaughPrPtMin", 0.3, "min. pT Daughter Proton"}; + Configurable cfgV0DaughPiPtMax{"cfgV0DaughPiPtMax", 10., "max. pT Daughter Pion"}; + Configurable cfgV0DaughPiPtMin{"cfgV0DaughPiPtMin", 0.3, "min. pT Daughter Pion"}; + Configurable cfgV0DaughPIDCutsTPCPr{"cfgV0DaughPIDCutsTPCPr", 2.5, "max. TPCnSigma Proton"}; + Configurable cfgV0DaughPIDCutsTPCPi{"cfgV0DaughPIDCutsTPCPi", 2.5, "max. TPCnSigma Pion"}; + Configurable cfgV0DaughPIDCutsTOFPi{"cfgV0DaughPIDCutsTOFPi", 2.5, "max. TOFnSigma Pion"}; + Configurable cfgV0DaughPIDCutsTOFPr{"cfgV0DaughPIDCutsTOFPr", -2.5, "min. TOFnSigma Proton (put only negative value)"}; Configurable cfgHypMassWindow{"cfgHypMassWindow", 0.1, "single lambda mass selection"}; Configurable cfgIsCorrCollMatchV0{"cfgIsCorrCollMatchV0", true, "check if daughter and mother collision are same"}; Configurable cfgCalDataDrivenEffPr{"cfgCalDataDrivenEffPr", false, "calculate data driven efficiency of proton using Lambda"}; @@ -399,6 +400,7 @@ struct HfCorrelatorXicHadrons { Configurable cfgMinOccupancy{"cfgMinOccupancy", 0, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; Configurable cfgPV{"cfgPV", 10., "maximum z-vertex"}; Configurable calEffV0{"calEffV0", false, "calculate lambda0 efficiency"}; + Configurable checkTOFForPion{"checkTOFForPion", false, "if True, TOF selection on pion V0 wil only be applied if TOF present"}; } cfgV0; SliceCache cache; @@ -647,33 +649,37 @@ struct HfCorrelatorXicHadrons { } template - bool isSelectedV0Daughter(Tracktype const& track, V0Type v0, int pid) + bool isSelectedV0Daughter(Tracktype const& track, V0Type const& v0, int pid) { if (std::abs(track.eta()) > cfgXicCand.etaTrackMax) { return false; } + // --------------------------------------------------------- // 1. Proton PID Selection // --------------------------------------------------------- if (std::abs(pid) == kProton) { + bool hasTOFProton = (pid > 0) ? v0.positiveHasTOF() : v0.negativeHasTOF(); bool passTOF = false; - if (track.pt() > cfgV0.cfgDaughPrPtMax || track.pt() < cfgV0.cfgDaughPrPtMin) { + if (track.pt() > cfgV0.cfgV0DaughPrPtMax || track.pt() < cfgV0.cfgV0DaughPrPtMin) { return false; } - if (track.hasTOF()) { + + if (hasTOFProton && (track.pt() > cfgXicCand.tofPIDThreshold)) { if constexpr (std::experimental::is_detected::value) { // pid > 0: Proton from Lambda (LaPr) // pid < 0: Antiproton from Anti-Lambda (ALaPr) double strangeTOF = (pid > 0) ? v0.tofNSigmaLaPr() : v0.tofNSigmaALaPr(); - passTOF = std::abs(strangeTOF) > cfgV0.cfgDaughPIDCutsTOFPr; + passTOF = strangeTOF > cfgV0.cfgV0DaughPIDCutsTOFPr; + } else { // if strange TOF is unavailable - passTOF = std::abs(track.tofNSigmaPr()) > cfgV0.cfgDaughPIDCutsTOFPr; + passTOF = track.tofNSigmaPr() > cfgV0.cfgV0DaughPIDCutsTOFPr; } } - if ((std::abs(track.tpcNSigmaPr()) > cfgV0.cfgDaughPIDCutsTPCPr) || passTOF) { + if ((std::abs(track.tpcNSigmaPr()) > cfgV0.cfgV0DaughPIDCutsTPCPr) && !passTOF) { return false; } } @@ -681,31 +687,31 @@ struct HfCorrelatorXicHadrons { // --------------------------------------------------------- // 2. Pion PID Selection // --------------------------------------------------------- - if (std::abs(pid) == kPiPlus) { + if (std::abs(pid) == kPiPlus && cfgV0.checkTOFForPion) { + bool hasTOFPion = (pid < 0) ? v0.negativeHasTOF() : v0.positiveHasTOF(); bool passTOF = false; - if (track.pt() > cfgV0.cfgDaughPiPtMax || track.pt() < cfgV0.cfgDaughPiPtMin) { + if (track.pt() > cfgV0.cfgV0DaughPiPtMax || track.pt() < cfgV0.cfgV0DaughPiPtMin) { return false; } - if (track.hasTOF()) { + if (hasTOFPion && (track.pt() > cfgXicCand.tofPIDThreshold)) { if constexpr (std::experimental::is_detected::value) { // A pion can belong to either a Lambda/Anti-Lambda decay or a K0s decay. // We evaluate both applicable hypotheses based on charge sign and pick the best match. double tofLa = (pid > 0) ? v0.tofNSigmaALaPi() : v0.tofNSigmaLaPi(); - passTOF = tofLa > cfgV0.cfgDaughPIDCutsTOFPi; + passTOF = std::abs(tofLa) > cfgV0.cfgV0DaughPIDCutsTOFPi; } else { // Fallback to standard track TOF - passTOF = std::abs(track.tofNSigmaPi()) > cfgV0.cfgDaughPIDCutsTOFPi; + passTOF = std::abs(track.tofNSigmaPi()) > cfgV0.cfgV0DaughPIDCutsTOFPi; } } - if ((std::abs(track.tpcNSigmaPi()) > cfgV0.cfgDaughPIDCutsTPCPi) || passTOF) { + if ((std::abs(track.tpcNSigmaPi()) > cfgV0.cfgV0DaughPIDCutsTPCPi) && !passTOF) { return false; } } - return true; } @@ -730,7 +736,7 @@ struct HfCorrelatorXicHadrons { } // Process Lambda (proton + pion) - if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow && v0.alpha() > 0) { entryHadron(v0.mLambda(), trackV0Pos.eta(), trackV0Pos.pt() * trackV0Pos.sign(), 0, 0, v0.pt()); entryTrkPID(trackV0Pos.tpcNSigmaPr(), trackV0Pos.tpcNSigmaKa(), trackV0Pos.tpcNSigmaPi(), trackV0Pos.tofNSigmaPr(), trackV0Pos.tofNSigmaKa(), trackV0Pos.tofNSigmaPi()); @@ -754,7 +760,7 @@ struct HfCorrelatorXicHadrons { } } - if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + if (passV0Sel && std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow && v0.alpha() < 0) { entryHadron(v0.mAntiLambda(), trackV0Neg.eta(), trackV0Neg.pt() * trackV0Neg.sign(), 0, 0, v0.pt()); entryTrkPID(trackV0Neg.tpcNSigmaPr(), trackV0Neg.tpcNSigmaKa(), trackV0Neg.tpcNSigmaPi(), trackV0Neg.tofNSigmaPr(), trackV0Neg.tofNSigmaKa(), trackV0Neg.tofNSigmaPi()); @@ -787,7 +793,7 @@ struct HfCorrelatorXicHadrons { auto const& partV0Pos = trackV0Pos.mcParticle(); auto const& partV0Neg = trackV0Neg.mcParticle(); - if (passV0Sel && v0Mc.pdgCode() == kLambda0) { + if (passV0Sel && v0Mc.pdgCode() == kLambda0 && v0.alpha() > 0) { if (isSelectedV0Daughter(trackV0Pos, v0, kProton) && isSelectedV0Daughter(trackV0Neg, v0, kPiMinus)) { registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); @@ -802,7 +808,7 @@ struct HfCorrelatorXicHadrons { } } } - if (passV0Sel && v0Mc.pdgCode() == kLambda0Bar) { + if (passV0Sel && v0Mc.pdgCode() == kLambda0Bar && v0.alpha() < 0) { if (isSelectedV0Daughter(trackV0Neg, v0, kProtonBar) && isSelectedV0Daughter(trackV0Pos, v0, kPiPlus)) { registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); @@ -849,12 +855,12 @@ struct HfCorrelatorXicHadrons { if (std::abs(currentDaughter.pdgCode()) == kProton) { - if (currentDaughter.pt() > cfgV0.cfgDaughPrPtMax || currentDaughter.pt() < cfgV0.cfgDaughPrPtMin) { + if (currentDaughter.pt() > cfgV0.cfgV0DaughPrPtMax || currentDaughter.pt() < cfgV0.cfgV0DaughPrPtMin) { continue; } } else if (std::abs(currentDaughter.pdgCode()) == kPiPlus) { - if (currentDaughter.pt() > cfgV0.cfgDaughPiPtMax || currentDaughter.pt() < cfgV0.cfgDaughPiPtMin) { + if (currentDaughter.pt() > cfgV0.cfgV0DaughPiPtMax || currentDaughter.pt() < cfgV0.cfgV0DaughPiPtMin) { continue; } @@ -1032,7 +1038,7 @@ struct HfCorrelatorXicHadrons { } // Process Lambda (proton-pion) - if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow && v0.alpha() > 0) { if (isSelectedV0Daughter(trackV0Pos, v0, kProton) && isSelectedV0Daughter(trackV0Neg, v0, kPiMinus)) { if (selXicCand) { @@ -1050,7 +1056,7 @@ struct HfCorrelatorXicHadrons { } // Process anti-Lambda (anti-proton-pion) - if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow && v0.alpha() < 0) { if (isSelectedV0Daughter(trackV0Neg, v0, kProtonBar) && isSelectedV0Daughter(trackV0Pos, v0, kPiPlus)) { if (selXicCand) { @@ -1484,14 +1490,14 @@ struct HfCorrelatorXicHadrons { auto const& trackV0Pos = assocParticle.template posTrack_as(); auto const& trackV0Neg = assocParticle.template negTrack_as(); - if (std::abs(o2::constants::physics::MassLambda - assocParticle.mLambda()) < cfgV0.cfgHypMassWindow) { + if (std::abs(o2::constants::physics::MassLambda - assocParticle.mLambda()) < cfgV0.cfgHypMassWindow && assocParticle.alpha() > 0) { if (isSelectedV0Daughter(trackV0Pos, assocParticle, kProton) && isSelectedV0Daughter(trackV0Neg, assocParticle, kPiPlus)) { fillCorrelationTable(cfgXicCand.fillTrkPID, assocParticle, ptCand, etaCand, phiCand, outputMlXic, poolBin, correlationStatus, yCand, massCand, *mcParticles); } } - if (std::abs(o2::constants::physics::MassLambda - assocParticle.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + if (std::abs(o2::constants::physics::MassLambda - assocParticle.mAntiLambda()) < cfgV0.cfgHypMassWindow && assocParticle.alpha() < 0) { if (isSelectedV0Daughter(trackV0Neg, assocParticle, -kProton) && isSelectedV0Daughter(trackV0Pos, assocParticle, -kPiPlus)) { fillCorrelationTable(cfgXicCand.fillTrkPID, assocParticle, ptCand, etaCand, phiCand, outputMlXic, poolBin, correlationStatus, yCand, massCand, *mcParticles); } @@ -1571,6 +1577,20 @@ struct HfCorrelatorXicHadrons { listDaughters.clear(); const std::size_t nDaughtersExpected = IsXicPlus ? XicDecayDaughtersCount::XicPlusDaughtersCount : XicDecayDaughtersCount::Xic0DaughtersCount; + if (IsXicPlus) { + // Final state: p, pi-, pi-, pi+, pi+ + std::array const arrDaughXicPlusPDG = {kProton, kPiMinus, kPiMinus, kPiPlus, kPiPlus}; + + // Pass -1 to automatically traverse the entire cascade down to the final state + RecoDecay::getDaughters(particle, &listDaughters, arrDaughXicPlusPDG); + } else { + // Final state: p, pi-, pi-, pi+ + std::array const arrDaughXic0PDG = {kProton, kPiMinus, kPiMinus, kPiPlus}; + + // Pass -1 to automatically traverse the entire cascade down to the final state + RecoDecay::getDaughters(particle, &listDaughters, arrDaughXic0PDG); + } + int counterDaughters = 0; std::vector prongsId(nDaughtersExpected); if (listDaughters.size() == nDaughtersExpected) { @@ -1682,7 +1702,7 @@ struct HfCorrelatorXicHadrons { /// Data processing: XicPlus with V0 Lambda void processDataXicPlusV0(SelCollisions::iterator const& collision, TracksData const& tracks, - aod::V0Datas const& v0s, + soa::Join const& v0s, CandsXicPlusDataFiltered const& candidates, aod::BCsWithTimestamps const&) { @@ -1693,7 +1713,7 @@ struct HfCorrelatorXicHadrons { /// MC Reco processing: XicPlus with V0 Lambda void processMcRecXicPlusV0(SelCollisions::iterator const& collision, TracksWithMc const& tracks, - soa::Join const& v0s, + soa::Join const& v0s, CandsXicPlusMcRecFiltered const& candidates, aod::McParticles const& mcParticles) { @@ -1704,7 +1724,7 @@ struct HfCorrelatorXicHadrons { /// Data processing: Xic0 with V0 Lambda void processDataXic0V0(SelCollisions::iterator const& collision, TracksData const& tracks, - aod::V0Datas const& v0s, + soa::Join const& v0s, CandsXic0DataFiltered const& candidates, aod::BCsWithTimestamps const&) { @@ -1715,7 +1735,7 @@ struct HfCorrelatorXicHadrons { /// MC Reco processing: Xic0 with V0 Lambda void processMcRecXic0V0(SelCollisions::iterator const& collision, TracksWithMc const& tracks, - soa::Join const& v0s, + soa::Join const& v0s, CandsXic0McRecFiltered const& candidates, aod::McParticles const& mcParticles) { @@ -1726,7 +1746,7 @@ struct HfCorrelatorXicHadrons { /// MC Reco processing: Xic0 with V0 Lambda void processV0McRec(SelCollisions::iterator const& collision, TracksWithMc const& tracks, - soa::Join const& v0s, + soa::Join const& v0s, aod::McParticles const& mcParticles) { fillEffV0(collision, v0s, tracks, mcParticles); @@ -1783,7 +1803,7 @@ struct HfCorrelatorXicHadrons { /// NOTE: V0 mixed events are more complex - need proper binning and collision matching void processDataMixedEventXicPlusV0(SelCollisions const& collisions, CandsXicPlusDataFiltered const& candidates, - aod::V0Datas const& v0s, + soa::Join const& v0s, TracksData const& tracks) { doMixEvent(collisions, v0s, candidates, tracks); @@ -1793,7 +1813,7 @@ struct HfCorrelatorXicHadrons { /// MC Reco Mixed Event: XicPlus with V0 Lambda void processMcRecMixedEventXicPlusV0(SelCollisions const& collisions, CandsXicPlusMcRecFiltered const& candidates, - soa::Join const& v0s, + soa::Join const& v0s, TracksWithMc const& tracks, aod::McParticles const& mcParticles) { @@ -1804,7 +1824,7 @@ struct HfCorrelatorXicHadrons { /// Data Mixed Event: Xic0 with V0 Lambda void processDataMixedEventXic0V0(SelCollisions const& collisions, CandsXic0DataFiltered const& candidates, - aod::V0Datas const& v0s, + soa::Join const& v0s, TracksData const& tracks) { doMixEvent(collisions, v0s, candidates, tracks); @@ -1814,7 +1834,7 @@ struct HfCorrelatorXicHadrons { /// MC Reco Mixed Event: Xic0 with V0 Lambda void processMcRecMixedEventXic0V0(SelCollisions const& collisions, CandsXic0McRecFiltered const& candidates, - soa::Join const& v0s, + soa::Join const& v0s, TracksWithMc const& tracks, aod::McParticles const& mcParticles) { @@ -1888,7 +1908,7 @@ struct HfCorrelatorXicHadrons { candSign = ParticleType::AntiParticle; } - int8_t const chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); + auto const chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); float cent = 100.0; int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); @@ -1910,8 +1930,8 @@ struct HfCorrelatorXicHadrons { PROCESS_SWITCH(HfCorrelatorXicHadrons, processMcGenMixedEvent, "Process Mixed Event McGen", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context), + adaptAnalysisTask(context)}; } diff --git a/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx b/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx index e7f10007cfa..f02386d5894 100644 --- a/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx +++ b/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx @@ -382,10 +382,9 @@ struct HfTaskCharmHadronsTrackFemtoDream { if (cand.candidateSelFlag() == 1) { invMass = cand.m(std::array{MassPiPlus, MassKPlus}); return invMass; - } else { - invMass = cand.m(std::array{MassKPlus, MassPiPlus}); - return invMass; } + invMass = cand.m(std::array{MassKPlus, MassPiPlus}); + return invMass; } else if constexpr (Channel == DecayChannel::DstarToD0Pi) { // D* → D0Ï€ (PDG: 413) float mDstar = 0.f; float mD0 = 0.f; @@ -398,9 +397,8 @@ struct HfTaskCharmHadronsTrackFemtoDream { } if (ReturnDaughMass) { return mD0; - } else { - return mDstar - mD0; } + return mDstar - mD0; } else if constexpr (Channel == DecayChannel::XicToXiPiPi) { invMass = cand.m(std::array{MassXiMinus, MassPiPlus, MassPiPlus}); return invMass; @@ -621,7 +619,7 @@ struct HfTaskCharmHadronsTrackFemtoDream { } template - void doMixedEvent(CollisionType const& cols, PartitionType1& charms, PartitionType2& trks, TableTracks const& parts, BinningType policy) + void doMixedEvent(CollisionType const& cols, PartitionType1& charms, PartitionType2& trks, TableTracks const& parts, BinningType const& policy) { processType = 2; // for mixed event // Mixed events that contain the pair of interest @@ -912,23 +910,26 @@ struct HfTaskCharmHadronsTrackFemtoDream { auto sliceCharmHad = partitionCharmHadron3Prong->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); if (fillTableWithCharm.value && sliceCharmHad.size() == 0) { continue; - } else { - fillTables(col, sliceTrk1, sliceCharmHad); } + fillTables(col, sliceTrk1, sliceCharmHad); if (sliceCharmHad.size() > 0 && sliceTrk1.size() > 0) { doSameEvent(sliceCharmHad, sliceTrk1, parts, col); } } if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionTrk1Ka; + } switch (mixSetting.mixingBinPolicy) { case femtodreamcollision::kMult: - doMixedEvent(cols, partitionCharmHadron3Prong, partitionTrk1, parts, colBinningMult); + doMixedEvent(cols, partitionCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMult); break; case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionCharmHadron3Prong, partitionTrk1, parts, colBinningMultPercentile); + doMixedEvent(cols, partitionCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultPercentile); break; case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionCharmHadron3Prong, partitionTrk1, parts, colBinningMultMultPercentile); + doMixedEvent(cols, partitionCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultMultPercentile); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -954,23 +955,26 @@ struct HfTaskCharmHadronsTrackFemtoDream { if (fillTableWithCharm.value && sliceCharmHad.size() == 0) { continue; - } else { - fillTables(col, sliceTrk1, sliceCharmHad); } + fillTables(col, sliceTrk1, sliceCharmHad); if (sliceCharmHad.size() > 0 && sliceTrk1.size() > 0) { doSameEvent(sliceCharmHad, sliceTrk1, parts, col); } } if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionTrk1Ka; + } switch (mixSetting.mixingBinPolicy) { case femtodreamcollision::kMult: - doMixedEvent(cols, partitionCharmHadron3Prong, partitionTrk1, parts, colBinningMult); + doMixedEvent(cols, partitionCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMult); break; case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionCharmHadron3Prong, partitionTrk1, parts, colBinningMultPercentile); + doMixedEvent(cols, partitionCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultPercentile); break; case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionCharmHadron3Prong, partitionTrk1, parts, colBinningMultMultPercentile); + doMixedEvent(cols, partitionCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultMultPercentile); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -995,23 +999,26 @@ struct HfTaskCharmHadronsTrackFemtoDream { auto sliceCharmHad = partitionCharmHadron2Prong->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); if (fillTableWithCharm.value && sliceCharmHad.size() == 0) { continue; - } else { - fillTables(col, sliceTrk1, sliceCharmHad); } + fillTables(col, sliceTrk1, sliceCharmHad); if (sliceCharmHad.size() > 0 && sliceTrk1.size() > 0) { doSameEvent(sliceCharmHad, sliceTrk1, parts, col); } } if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionTrk1Ka; + } switch (mixSetting.mixingBinPolicy) { case femtodreamcollision::kMult: - doMixedEvent(cols, partitionCharmHadron2Prong, partitionTrk1, parts, colBinningMult); + doMixedEvent(cols, partitionCharmHadron2Prong, *partitionTrk1Selected, parts, colBinningMult); break; case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionCharmHadron2Prong, partitionTrk1, parts, colBinningMultPercentile); + doMixedEvent(cols, partitionCharmHadron2Prong, *partitionTrk1Selected, parts, colBinningMultPercentile); break; case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionCharmHadron2Prong, partitionTrk1, parts, colBinningMultMultPercentile); + doMixedEvent(cols, partitionCharmHadron2Prong, *partitionTrk1Selected, parts, colBinningMultMultPercentile); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1036,23 +1043,26 @@ struct HfTaskCharmHadronsTrackFemtoDream { auto sliceCharmHad = partitionCharmHadronDstar->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); if (fillTableWithCharm.value && sliceCharmHad.size() == 0) { continue; - } else { - fillTables(col, sliceTrk1, sliceCharmHad); } + fillTables(col, sliceTrk1, sliceCharmHad); if (sliceCharmHad.size() > 0 && sliceTrk1.size() > 0) { doSameEvent(sliceCharmHad, sliceTrk1, parts, col); } } if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionTrk1Ka; + } switch (mixSetting.mixingBinPolicy) { case femtodreamcollision::kMult: - doMixedEvent(cols, partitionCharmHadronDstar, partitionTrk1, parts, colBinningMult); + doMixedEvent(cols, partitionCharmHadronDstar, *partitionTrk1Selected, parts, colBinningMult); break; case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionCharmHadronDstar, partitionTrk1, parts, colBinningMultPercentile); + doMixedEvent(cols, partitionCharmHadronDstar, *partitionTrk1Selected, parts, colBinningMultPercentile); break; case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionCharmHadronDstar, partitionTrk1, parts, colBinningMultMultPercentile); + doMixedEvent(cols, partitionCharmHadronDstar, *partitionTrk1Selected, parts, colBinningMultMultPercentile); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1075,9 +1085,8 @@ struct HfTaskCharmHadronsTrackFemtoDream { auto sliceCharmHad = partitionCharmHadron3ProngXic->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); if (fillTableWithCharm.value && sliceCharmHad.size() == 0) { continue; - } else { - fillTables(col, sliceTrk1, sliceCharmHad); } + fillTables(col, sliceTrk1, sliceCharmHad); if (sliceCharmHad.size() > 0 && sliceTrk1.size() > 0) { doSameEvent(sliceCharmHad, sliceTrk1, parts, col); } @@ -1123,18 +1132,24 @@ struct HfTaskCharmHadronsTrackFemtoDream { } doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } - switch (mixSetting.mixingBinPolicy) { - case femtodreamcollision::kMult: - doMixedEvent(cols, partitionMcCharmHadron3Prong, partitionMcTrk1, parts, colBinningMult); - break; - case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionMcCharmHadron3Prong, partitionMcTrk1, parts, colBinningMultPercentile); - break; - case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionMcCharmHadron3Prong, partitionMcTrk1, parts, colBinningMultMultPercentile); - break; - default: - LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionMcTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionMcTrk1Ka; + } + switch (mixSetting.mixingBinPolicy) { + case femtodreamcollision::kMult: + doMixedEvent(cols, partitionMcCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, partitionMcCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, partitionMcCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } } } PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcLcTrk, "Enable processing LcToPKPi and Tracks correlation for Monte Carlo", false); @@ -1158,18 +1173,24 @@ struct HfTaskCharmHadronsTrackFemtoDream { } doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } - switch (mixSetting.mixingBinPolicy) { - case femtodreamcollision::kMult: - doMixedEvent(cols, partitionMcCharmHadron3Prong, partitionMcTrk1, parts, colBinningMult); - break; - case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionMcCharmHadron3Prong, partitionMcTrk1, parts, colBinningMultPercentile); - break; - case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionMcCharmHadron3Prong, partitionMcTrk1, parts, colBinningMultMultPercentile); - break; - default: - LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionMcTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionMcTrk1Ka; + } + switch (mixSetting.mixingBinPolicy) { + case femtodreamcollision::kMult: + doMixedEvent(cols, partitionMcCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, partitionMcCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, partitionMcCharmHadron3Prong, *partitionTrk1Selected, parts, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } } } PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcDplusTrk, "Enable processing DplusToPiKPi and Tracks correlation for Monte Carlo", false); @@ -1193,18 +1214,24 @@ struct HfTaskCharmHadronsTrackFemtoDream { } doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } - switch (mixSetting.mixingBinPolicy) { - case femtodreamcollision::kMult: - doMixedEvent(cols, partitionMcCharmHadron2Prong, partitionMcTrk1, parts, colBinningMult); - break; - case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionMcCharmHadron2Prong, partitionMcTrk1, parts, colBinningMultPercentile); - break; - case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionMcCharmHadron2Prong, partitionMcTrk1, parts, colBinningMultMultPercentile); - break; - default: - LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionMcTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionMcTrk1Ka; + } + switch (mixSetting.mixingBinPolicy) { + case femtodreamcollision::kMult: + doMixedEvent(cols, partitionMcCharmHadron2Prong, *partitionTrk1Selected, parts, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, partitionMcCharmHadron2Prong, *partitionTrk1Selected, parts, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, partitionMcCharmHadron2Prong, *partitionTrk1Selected, parts, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } } } PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcD0Trk, "Enable processing D0ToPiK and Tracks correlation for Monte Carlo", false); @@ -1228,18 +1255,24 @@ struct HfTaskCharmHadronsTrackFemtoDream { } doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } - switch (mixSetting.mixingBinPolicy) { - case femtodreamcollision::kMult: - doMixedEvent(cols, partitionMcCharmHadronDstar, partitionMcTrk1, parts, colBinningMult); - break; - case femtodreamcollision::kMultPercentile: - doMixedEvent(cols, partitionMcCharmHadronDstar, partitionMcTrk1, parts, colBinningMultPercentile); - break; - case femtodreamcollision::kMultMultPercentile: - doMixedEvent(cols, partitionMcCharmHadronDstar, partitionMcTrk1, parts, colBinningMultMultPercentile); - break; - default: - LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + if (mixSetting.doMixEvent) { + auto* partitionTrk1Selected = &partitionMcTrk1; + if (trackSel.pdgCodeTrack1.value == kKPlus) { + partitionTrk1Selected = &partitionMcTrk1Ka; + } + switch (mixSetting.mixingBinPolicy) { + case femtodreamcollision::kMult: + doMixedEvent(cols, partitionMcCharmHadronDstar, *partitionTrk1Selected, parts, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, partitionMcCharmHadronDstar, *partitionTrk1Selected, parts, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, partitionMcCharmHadronDstar, *partitionTrk1Selected, parts, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } } } PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcDstarTrk, "Enable processing DstarToD0Pi and Tracks correlation for Monte Carlo", false); diff --git a/PWGHF/HFC/Tasks/taskFlow.cxx b/PWGHF/HFC/Tasks/taskFlow.cxx index 6756a4e2334..b68e6a79f18 100644 --- a/PWGHF/HFC/Tasks/taskFlow.cxx +++ b/PWGHF/HFC/Tasks/taskFlow.cxx @@ -29,6 +29,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -61,6 +62,7 @@ #include +#include #include #include #include @@ -134,11 +136,19 @@ enum MftTrackSelectionStep { Pt, DCAxy, DCAz, + Chi2OverNdf, + Phi, IsLTF, IsCA, NMftTrackSelectionSteps }; +enum CentralityEstimators { + CentFT0C = 0, + CentFT0CVariant1, + CentFT0M +}; + enum MultiplicityEstimators { MultNTracksPV = 0, MultNumContrib, @@ -170,6 +180,7 @@ enum TrackSelection { static constexpr std::string_view WhatDataType[] = {"Data/", "MC/"}; static constexpr std::string_view WhatCorrelationCase[] = {"TpcTpc/", "TpcMft/", "TpcFv0a/", "MftFv0a/", "TpcFt0a/", "MftFt0a/", "TpcFt0c/", "Ft0aFt0c/"}; static constexpr std::string_view WhatParticles[] = {"ChPartChPart/", "D0ChPart/", "LcChPart/"}; +static constexpr std::string_view WhatCentralityEstimator[] = {"centFT0C", "CentFT0CVariant1", "centFT0M"}; static constexpr std::string_view WhatMultiplicityEstimator[] = {"multNTracksPV", "multNumContrib", "multFT0C", "multFT0M"}; auto static constexpr MinFt0cCell = 96; @@ -211,6 +222,7 @@ struct HfTaskFlow { Configurable etaMcParticlesAssocMax{"etaMcParticlesAssocMax", -2.4f, "Maximum value for the eta of MC particles when used in cut function"}; Configurable etaMcParticlesAssocMin{"etaMcParticlesAssocMin", -3.6f, "Minimum value for the eta of MC particles when used in cut function"}; Configurable fillOnlyStepAll{"fillOnlyStepAll", true, "Fill Mc Gen QA plots only for StepAll, or only for Primaries"}; + Configurable loadCentralityWeight{"loadCentralityWeight", "", "Ccdb path to centrality weight correction"}; Configurable loadEfficienciesForTpc{"loadEfficienciesForTpc", "", "Ccdb path to Tpc tracks efficiency correction"}; Configurable loadEfficienciesForMft{"loadEfficienciesForMft", "", "Ccdb path to Mft tracks efficiency correction"}; Configurable loadEfficienciesForNch{"loadEfficienciesForNch", "", "Ccdb path to Nch estimation efficiency correction"}; @@ -229,6 +241,7 @@ struct HfTaskFlow { // configurables for collisions struct : ConfigurableGroup { std::string prefix = "ConfigCollision_group"; + Configurable centralityEstimator{"centralityEstimator", 0, "0: centFT0C, 1: CentFT0CVariant1, 2: centFT0M"}; Configurable isApplyGoodItsLayersAll{"isApplyGoodItsLayersAll", false, "Enable GoodITSLayersAll"}; Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", false, "Enable GoodZvtxFT0vsPV cut"}; Configurable isApplyNoCollInRofStandard{"isApplyNoCollInRofStandard", false, ""}; @@ -237,9 +250,12 @@ struct HfTaskFlow { Configurable isApplyNoCollInTimeRangeStrict{"isApplyNoCollInTimeRangeStrict", false, ""}; Configurable isApplyNoHighMultCollInPrevRof{"isApplyNoHighMultCollInPrevRof", false, ""}; Configurable isApplySameBunchPileup{"isApplySameBunchPileup", false, "Enable SameBunchPileup cut"}; + Configurable maxCentrality{"maxCentrality", 20, "maximum centrality"}; + Configurable minCentrality{"minCentrality", 0, "minimum centrality"}; Configurable maxMultiplicity{"maxMultiplicity", 300, "maximum multiplicity selection for collision"}; Configurable minMultiplicity{"minMultiplicity", 0, "minimum multiplicity selection for collision"}; - Configurable multiplicityEstimator{"multiplicityEstimator", 0, "0: multNTracksPV, 1: numContrib, 2: multFT0C, 3: multFT0M, 4: centFT0C, 5: centFT0CVariants1s, 6: centFT0M, 7: centFV0A, 8: centNTracksPV, 9: centNGlobal, 10: centMFT"}; + Configurable multiplicityEstimator{"multiplicityEstimator", 0, "0: multNTracksPV, 1: numContrib, 2: multFT0C, 3: multFT0M"}; + Configurable useCentrality{"useCentrality", false, "use centrality instead of multiplicity"}; Configurable useMultiplicityFromTracks{"useMultiplicityFromTracks", false, "Use multiplicity from counting tracks"}; Configurable useMultiplicityFromTracksCorrected{"useMultiplicityFromTracksCorrected", false, "Use multiplicity from counting tracks, corrected but takes a lot of computation time"}; Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; @@ -296,11 +312,18 @@ struct HfTaskFlow { Configurable etaMftTrackMin{"etaMftTrackMin", -3.36f, "Minimum value for the eta of MFT tracks when used in cut function"}; Configurable etaMftTrackMaxFilter{"etaMftTrackMaxFilter", -2.0f, "Maximum value for the eta of MFT tracks when used in filter"}; Configurable etaMftTrackMinFilter{"etaMftTrackMinFilter", -3.9f, "Minimum value for the eta of MFT tracks when used in filter"}; + Configurable maxChi2OverNdf{"maxChi2OverNdf", 1000.f, "maximum chi2/ndf for MFT tracks"}; Configurable mftMaxDCAxy{"mftMaxDCAxy", 2.0f, "Cut on dcaXY for MFT tracks"}; Configurable mftMaxDCAz{"mftMaxDCAz", 2.0f, "Cut on dcaZ for MFT tracks"}; Configurable nClustersMftTrack{"nClustersMftTrack", 5, "Minimum number of clusters for the reconstruction of MFT tracks"}; + Configurable phiMftTrackMin{"phiMftTrackMin", 0.1, "Minimum value for the phi of MFT tracks when used in cut function"}; + Configurable phiMftTrackMiddleMin{"phiMftTrackMiddleMin", PI - 0.1, "cut to remove before phi = pi for MFT tracks when used in cut function"}; + Configurable phiMftTrackMiddleMax{"phiMftTrackMiddleMax", PI + 0.1, "cut to remove after phi = pi for MFT tracks when used in cut function"}; + Configurable phiMftTrackMax{"phiMftTrackMax", TwoPI - 0.1, "Maximum value for the phi of MFT tracks when used in cut function"}; Configurable ptMftTrackMax{"ptMftTrackMax", 10.0f, "max value of MFT tracks pT when used in cut function"}; Configurable ptMftTrackMin{"ptMftTrackMin", 0.f, "min value of MFT tracks pT when used in cut function"}; + Configurable useMftChi2OverNdfCut{"useMftChi2OverNdfCut", false, "use mft track chi2/ndf cut"}; + Configurable useMftPhiCut{"useMftPhiCut", false, "if true, use the Mft phi function cut"}; Configurable useMftPtCut{"useMftPtCut", false, "if true, use the Mft pt function cut"}; Configurable useOnlyCATracks{"useOnlyCATracks", false, "if true, use strictly MFT tracks reconstructed with CA algo."}; Configurable useOnlyLTFTracks{"useOnlyLTFTracks", false, "if true, use strictly MFT tracks reconstructed with LTF algo."}; @@ -328,6 +351,7 @@ struct HfTaskFlow { TH3D* mEfficiencyTpc = nullptr; TH3D* mEfficiencyMft = nullptr; TH1D* mEfficiencyNch = nullptr; + TH1D* mCentralityWeight = nullptr; bool areCorrectionsLoaded = false; // o2::aod::rctsel::RCTFlagsChecker rctChecker{"CBT_muon_glo", false, false, true}; @@ -336,12 +360,14 @@ struct HfTaskFlow { // using declarations : DATA // ========================= - using FilteredCollisionsWSelMult = soa::Filtered>; + using FilteredCollisionsWSelMult = soa::Filtered>; using HfCandidatesSelD0 = soa::Filtered>; using HfCandidatesSelLc = soa::Filtered>; using FilteredTracksWDcaSel = soa::Filtered>; + using FilteredTracksWDcaSelWLabels = soa::Filtered>; using FilteredMftTracks = soa::Filtered; + using FilteredMftTracksWCollsMcLabels = soa::Filtered>; // ========================= // using declarations : MC @@ -349,6 +375,7 @@ struct HfTaskFlow { using SmallGroupMcCollisions = soa::SmallGroups>; using FilteredMcCollisionsWMult = soa::Filtered>; + using FilteredMcCollisionsWMultWCollsExtra = soa::Filtered>; using FilteredMcParticles = soa::Filtered; // ========================= @@ -426,10 +453,13 @@ struct HfTaskFlow { ConfigurableAxis axisMass{"axisMass", {1, 1.5848, 2.1848}, "axis of invariant mass of candidates"}; ConfigurableAxis binsMixingMultiplicity{"binsMixingMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity bins for event mixing"}; ConfigurableAxis binsMixingVertex{"binsMixingVertex", {20, -10, 10}, "vertex bins for event mixing"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, "centrality axis for histograms"}; ConfigurableAxis axisNClusters{"axisNClusters", {9, 1, 10}, "axis for number of clusters of MFT tracks"}; ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {1, -1.0, 1.0}, "eta axis for efficiency histograms"}; ConfigurableAxis axisEtaAssociated{"axisEtaAssociated", {48, -4, -2}, "eta axis for MFT histograms"}; ConfigurableAxis axisEtaTrigger{"axisEtaTrigger", {48, -1, 1}, "eta axis for TPC histograms"}; + ConfigurableAxis axisDcaXY{"axisDcaXY", {100, 0, 2}, "dcaXY axis for MFT histograms"}; + ConfigurableAxis axisDcaZ{"axisDcaZ", {100, -2, 2}, "dcaZ axis for MFT histograms"}; ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; ConfigurableAxis axisDeltaEta{"axisDeltaEta", {48, -2.4, 2.4}, "delta eta axis for histograms"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity axis for histograms"}; @@ -496,6 +526,8 @@ struct HfTaskFlow { labelsMftTracksSelection[MftTrackSelectionStep::Pt] = "MFT tracks after pT selection"; labelsMftTracksSelection[MftTrackSelectionStep::DCAxy] = "MFT tracks after DCAxy selection"; labelsMftTracksSelection[MftTrackSelectionStep::DCAz] = "MFT tracks after DCAz selection"; + labelsMftTracksSelection[MftTrackSelectionStep::Chi2OverNdf] = "MFT tracks after Chi2OverNdf selection"; + labelsMftTracksSelection[MftTrackSelectionStep::Phi] = "MFT tracks after phi selection"; labelsMftTracksSelection[MftTrackSelectionStep::IsLTF] = "Linear Track Finder MFT tracks"; labelsMftTracksSelection[MftTrackSelectionStep::IsCA] = "Cellular Automaton MFT tracks"; registry.get(HIST("Data/Mft/hMftTracksSelection"))->SetMinimum(0); @@ -517,6 +549,8 @@ struct HfTaskFlow { registry.add("Data/Mft/hPtMft", "", {HistType::kTH1D, {configAxis.axisPt}}); registry.add("Data/Mft/hPtVsClustersLTF", "", {HistType::kTH2D, {configAxis.axisPt, configAxis.axisNClusters}}); registry.add("Data/Mft/hPtVsClustersCA", "", {HistType::kTH2D, {configAxis.axisPt, configAxis.axisNClusters}}); + registry.add("Data/Mft/hDcaXYMft", "", {HistType::kTH1D, {configAxis.axisDcaXY}}); + registry.add("Data/Mft/hDcaZMft", "", {HistType::kTH1D, {configAxis.axisDcaZ}}); registry.add("Data/Mft/hNMftTracks", "", {HistType::kTH1F, {configAxis.axisMultiplicity}}); registry.add("Data/Mft/hNBestCollisionFwd", "", {HistType::kTH1F, {configAxis.axisMultiplicity}}); } @@ -550,6 +584,7 @@ struct HfTaskFlow { registry.add("Data/hVtxZ", "v_{z} (cm)", {HistType::kTH1D, {configAxis.axisVertex}}); registry.add("Data/hNTracks", "", {HistType::kTH1F, {configAxis.axisMultiplicity}}); registry.add(Form("Data/hMultiplicity_%s", WhatMultiplicityEstimator[configCollision.multiplicityEstimator].data()), "", {HistType::kTH1D, {configAxis.axisMultiplicity}}); + registry.add(Form("Data/hCentrality_%s", WhatCentralityEstimator[configCollision.centralityEstimator].data()), "", {HistType::kTH1D, {configAxis.axisCentrality}}); registry.add("Data/hEventCounter", "hEventCounter", {HistType::kTH1D, {{EventSelectionStep::NEventSelectionSteps, -0.5, +EventSelectionStep::NEventSelectionSteps - 0.5}}}); std::string labels[EventSelectionStep::NEventSelectionSteps]; @@ -659,8 +694,7 @@ struct HfTaskFlow { registry.add("Data/hEfficiencyTrigger", "", {HistType::kTH3D, {{configAxis.axisPtTrigger}, {configAxis.axisEtaTrigger}, {configAxis.axisVertex}}}); registry.add("Data/hEfficiencyAssociated", "", {HistType::kTH3D, {{configAxis.axisPtAssoc}, {configAxis.axisEtaAssociated}, {configAxis.axisVertex}}}); - registry.add("Data/hMultiplicity_uncorrected", "", {HistType::kTH1D, {configAxis.axisMultiplicity}}); - registry.add("Data/hMultiplicity_corrected", "", {HistType::kTH1D, {configAxis.axisMultiplicity}}); + registry.add("Data/hMultiplicity_uncorrected_vs_corrected", "", {HistType::kTH2D, {{configAxis.axisMultiplicity}, {configAxis.axisMultiplicity}}}); if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { registry.add("Trig_hist_TPC_MFT", "", {HistType::kTHnSparseF, {{configAxis.axisSamples, configAxis.axisVertex, configAxis.axisPtTrigger}}}); @@ -881,7 +915,7 @@ struct HfTaskFlow { if (doprocessSameMcGen) { registry.add("MC/hEfficiencyTrigger", "", {HistType::kTH3D, {{configAxis.axisPtTrigger}, {configAxis.axisEtaTrigger}, {configAxis.axisVertex}}}); - registry.add("MC/hEfficiencyAssociated", "", {HistType::kTH3D, {{configAxis.axisPtTrigger}, {configAxis.axisEtaAssociated}, {configAxis.axisVertex}}}); + registry.add("MC/hEfficiencyAssociated", "", {HistType::kTH3D, {{configAxis.axisPtAssoc}, {configAxis.axisEtaAssociated}, {configAxis.axisVertex}}}); if (configTask.chooseCorrelationCase.value == static_cast(CorrelationCase::TpcTpc)) { addHistograms(); @@ -916,6 +950,13 @@ struct HfTaskFlow { } } + if (doprocessTrackEfficiencies) { + registry.add("MC/hEfficiencyTrigger", "", {HistType::kTH3D, {{configAxis.axisPtTrigger}, {configAxis.axisEtaTrigger}, {configAxis.axisVertex}}}); + registry.add("MC/hEfficiencyAssociated", "", {HistType::kTH3D, {{configAxis.axisPtTrigger}, {configAxis.axisEtaAssociated}, {configAxis.axisVertex}}}); + registry.add("Data/hEfficiencyTrigger", "", {HistType::kTH3D, {{configAxis.axisPtTrigger}, {configAxis.axisEtaTrigger}, {configAxis.axisVertex}}}); + registry.add("Data/hEfficiencyAssociated", "", {HistType::kTH3D, {{configAxis.axisPtAssoc}, {configAxis.axisEtaAssociated}, {configAxis.axisVertex}}}); + } + } // End of init() function // ========================= @@ -987,6 +1028,30 @@ struct HfTaskFlow { } } + template + float getCentralityEstimator(TCollision const& collision, bool isSameEvent) + { + switch (configCollision.centralityEstimator) { + case CentralityEstimators::CentFT0C: + if (isSameEvent) { + registry.fill(HIST("Data/hCentrality_centFT0C"), collision.centFT0C()); + } + return collision.centFT0C(); + case CentralityEstimators::CentFT0CVariant1: + if (isSameEvent) { + registry.fill(HIST("Data/hCentrality_centFT0CVariant1"), collision.centFT0CVariant1()); + } + return collision.centFT0CVariant1(); + case CentralityEstimators::CentFT0M: + if (isSameEvent) { + registry.fill(HIST("Data/hCentrality_centFT0M"), collision.centFT0M()); + } + return collision.centFT0M(); + default: + return collision.centFT0C(); + } + } + template float getDPhiStar(TTrack const& track1, TTrackAssoc const& track2, float radius, int magField) { @@ -1160,21 +1225,28 @@ struct HfTaskFlow { if (mEfficiencyTpc == nullptr) { LOGF(fatal, "Could not load efficiency histogram for TPC tracks from %s", configTask.loadEfficienciesForTpc.value.c_str()); } - LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForTpc.value.c_str(), (void*)mEfficiencyTpc); + LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForTpc.value.c_str(), static_cast(mEfficiencyTpc)); } if (configTask.loadEfficienciesForMft.value.empty() == false) { mEfficiencyMft = ccdb->getForTimeStamp(configTask.loadEfficienciesForTpc, timestamp); if (mEfficiencyMft == nullptr) { LOGF(fatal, "Could not load efficiency histogram for MFT tracks from %s", configTask.loadEfficienciesForMft.value.c_str()); } - LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForMft.value.c_str(), (void*)mEfficiencyMft); + LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForMft.value.c_str(), static_cast(mEfficiencyMft)); } if (configTask.loadEfficienciesForNch.value.empty() == false) { mEfficiencyNch = ccdb->getForTimeStamp(configTask.loadEfficienciesForNch, timestamp); if (!mEfficiencyNch) { LOGF(fatal, "Could not load efficiency histogram for Nch estimator from %s", configTask.loadEfficienciesForNch.value.c_str()); } - LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForNch.value.c_str(), (void*)mEfficiencyNch); + LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForNch.value.c_str(), static_cast(mEfficiencyNch)); + } + if (configTask.loadCentralityWeight.value.empty() == false) { + mCentralityWeight = ccdb->getForTimeStamp(configTask.loadCentralityWeight, timestamp); + if (mCentralityWeight == nullptr) { + LOGF(fatal, "Could not load centrality weight correction from %s", configTask.loadCentralityWeight.value.c_str()); + } + LOGF(info, "Loaded centrality weight from %s (%p)", configTask.loadCentralityWeight.value.c_str(), static_cast(mCentralityWeight)); } areCorrectionsLoaded = true; } @@ -1252,6 +1324,21 @@ struct HfTaskFlow { return trackCounter; } + bool getCentralityWeight(float& weightCent, const float centrality) + { + float weight = 1.; + if (mCentralityWeight) { + weight = mCentralityWeight->GetBinContent(mCentralityWeight->FindBin(centrality)); + } else { + weight = 1.0; + } + if (weight == 0) { + return false; + } + weightCent = weight; + return true; + } + // ========================= // Cuts with functions // ========================= @@ -1327,9 +1414,6 @@ struct HfTaskFlow { } if (fillHistograms) { registry.fill(HIST("Data/hPreciseEventCounter"), SpecificEventSelectionStep::IsRctFlagChecked); - } - - if (fillHistograms) { registry.fill(HIST("Data/hEventCounter"), EventSelectionStep::AfterEventSelection); } @@ -1429,9 +1513,34 @@ struct HfTaskFlow { } if (fillHistograms) { + registry.fill(HIST("Data/Mft/hDcaXYMft"), dcaXY); + registry.fill(HIST("Data/Mft/hDcaZMft"), dcaZ); registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::DCAz); } + if (configMft.useMftChi2OverNdfCut) { + float ndfMftTrack = std::max(2.0f * mftTrack.nClusters() - 5.0f, 1.0f); + float mftChi2OverNdf = mftTrack.chi2() / ndfMftTrack; + if (mftChi2OverNdf > configMft.maxChi2OverNdf) { + return false; + } + } + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::Chi2OverNdf); + } + + if (configMft.useMftPhiCut) { + auto phiMftTrack = mftTrack.phi(); + o2::math_utils::bringTo02Pi(phiMftTrack); + if (phiMftTrack > configMft.phiMftTrackMax || phiMftTrack < configMft.phiMftTrackMin || + (phiMftTrack > configMft.phiMftTrackMiddleMin && phiMftTrack < configMft.phiMftTrackMiddleMax)) { + return false; + } + } + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::Phi); + } + // cut on the track algorithm of MFT tracks if (mftTrack.isCA()) { if (fillHistograms) { @@ -1486,8 +1595,8 @@ struct HfTaskFlow { template void fillCorrelations(TTarget target, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, - float multiplicity, float posZ, bool sameEvent, int magneticField) + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, + float multiplicity, float posZ, bool isSameEvent, int magneticField, float centralityWeight) { auto triggerWeight = 1.0f; auto associatedWeight = 1.0f; @@ -1495,7 +1604,7 @@ struct HfTaskFlow { int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE - for (const auto& track1 : tracks1) { + for (const auto& track1 : tracksTrigger) { loopCounter++; if constexpr (std::is_same_v) { @@ -1532,21 +1641,21 @@ struct HfTaskFlow { // fill single-track distributions if (!fillingHFcontainer) { // if not HF-h case - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, centralityWeight * triggerWeight); if (configTask.doEtaDependentFlow) { - registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.eta(), triggerWeight); // think about event weight in near future + registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.eta(), centralityWeight * triggerWeight); } if (configTask.doVariationContainers) { - registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.pt(), triggerWeight); + registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.pt(), centralityWeight * triggerWeight); } } else { - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, centralityWeight * triggerWeight); } // FILL QA PLOTS for trigger particle - if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { if constexpr (!std::is_same_v) { // IF TPC-TPC case if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-TPC D0-h fillTriggerQa(multiplicity, eta1, phi1, pt1); @@ -1567,7 +1676,7 @@ struct HfTaskFlow { } // ASSOCIATED PARTICLE - for (const auto& track2 : tracks2) { + for (const auto& track2 : tracksAssoc) { if constexpr (std::is_same_v) { if (!isAcceptedCentralTrack(track2)) { @@ -1578,7 +1687,7 @@ struct HfTaskFlow { // apply cuts for MFT tracks if constexpr (std::is_same_v) { - if (sameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time + if (isSameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::NoSelection); if (!isAcceptedMftTrack(track2, 0.f, 0.f, true)) { @@ -1595,10 +1704,10 @@ struct HfTaskFlow { continue; } - if (configCentral.isApplyPtOrderingSameEvent && sameEvent && (track1.pt() <= track2.pt())) { + if (configCentral.isApplyPtOrderingSameEvent && isSameEvent && (track1.pt() <= track2.pt())) { continue; } - if (configCentral.isApplyPtOrderingMixedEvent && !sameEvent && (track1.pt() <= track2.pt())) { + if (configCentral.isApplyPtOrderingMixedEvent && !isSameEvent && (track1.pt() <= track2.pt())) { continue; } @@ -1680,21 +1789,21 @@ struct HfTaskFlow { // fill pair correlations if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } else if (configTask.doEtaDependentFlow) { target->getPairHist()->Fill(step, sampleIndex, posZ, eta2, eta1, deltaPhi, eta1 - eta2, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } else { target->getPairHist()->Fill(step, sampleIndex, posZ, pt1, multiplicity, deltaPhi, eta1 - eta2, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } } else { target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } // FILL QA PLOTS for associated particle - if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { if constexpr (!std::is_same_v) { // IF TPC-TPC case if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-TPC D0-h fillAssociatedQa(multiplicity, eta2, phi2); @@ -1723,8 +1832,8 @@ struct HfTaskFlow { template void fillCorrelationsReassociatedMftTracks(TTarget target, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, - float multiplicity, float posZ, bool sameEvent, bool cutAmbiguousTracks) + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, + float multiplicity, float posZ, bool isSameEvent, bool cutAmbiguousTracks, float centralityWeight) { auto triggerWeight = 1.0f; auto associatedWeight = 1.0f; @@ -1732,7 +1841,7 @@ struct HfTaskFlow { int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE - for (const auto& track1 : tracks1) { + for (const auto& track1 : tracksTrigger) { loopCounter++; if constexpr (std::is_same_v) { @@ -1765,21 +1874,21 @@ struct HfTaskFlow { // fill single-track distributions if (!fillingHFcontainer) { // if not HF-h case - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, centralityWeight * triggerWeight); if (configTask.doEtaDependentFlow) { - registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.eta(), triggerWeight); // think about event weight in near future + registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.eta(), centralityWeight * triggerWeight); } if (configTask.doVariationContainers) { - registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.pt(), triggerWeight); + registry.fill(HIST("Trig_hist_TPC_MFT"), sampleIndex, posZ, track1.pt(), centralityWeight * triggerWeight); } } else { - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, centralityWeight * triggerWeight); } // FILL QA PLOTS for trigger particle - if (sameEvent) { + if (isSameEvent) { if constexpr (std::is_same_v) { fillTriggerQa(multiplicity, eta1, phi1, pt1); } else if constexpr (std::is_same_v) { @@ -1791,10 +1900,10 @@ struct HfTaskFlow { } // ASSOCIATED PARTICLE - for (const auto& track2 : tracks2) { + for (const auto& track2 : tracksAssoc) { // Fill QA plot for all MFT tracks () (only if cutAmbiguousTracks is false to avoid double counting) - if (!cutAmbiguousTracks && sameEvent && (loopCounter == 1)) { + if (!cutAmbiguousTracks && isSameEvent && (loopCounter == 1)) { registry.fill(HIST("Data/Mft/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::AllMftTracks); } @@ -1810,7 +1919,7 @@ struct HfTaskFlow { reassociatedMftTrackDcaZ = track2.bestDCAZ(); } - if (sameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time + if (isSameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::NoSelection); if (!isAcceptedMftTrack(reassociatedMftTrack, reassociatedMftTrackDcaXY, reassociatedMftTrackDcaZ, true)) { @@ -1823,15 +1932,15 @@ struct HfTaskFlow { } // Fill QA plot for MFT tracks after physical selection (eta + clusters) - if (!cutAmbiguousTracks && sameEvent && (loopCounter == 1)) { + if (!cutAmbiguousTracks && isSameEvent && (loopCounter == 1)) { registry.fill(HIST("Data/Mft/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::AfterTrackSelection); } // We check if the track is ambiguous or non-ambiguous (QA plots are filled in isAmbiguousMftTrack) // Fill plots only if cutAmbiguousTracks is false (to avoid double counting) - if (isAmbiguousMftTrack(track2, (!cutAmbiguousTracks && sameEvent && (loopCounter == 1)))) { + if (isAmbiguousMftTrack(track2, (!cutAmbiguousTracks && isSameEvent && (loopCounter == 1)))) { // If the MFT track is ambiguous we may cut or not on the ambiguous track - if (sameEvent && (loopCounter == 1)) { + if (isSameEvent && (loopCounter == 1)) { registry.fill(HIST("Data/Mft/hReassociationMftTracks"), ReassociationMftTracks::NotReassociatedMftTracks); } if (cutAmbiguousTracks) { @@ -1840,7 +1949,7 @@ struct HfTaskFlow { } if (reassociatedMftTrack.collisionId() != track2.bestCollisionId()) { - if (sameEvent && (loopCounter == 1)) { + if (isSameEvent && (loopCounter == 1)) { registry.fill(HIST("Data/Mft/hReassociationMftTracks"), ReassociationMftTracks::ReassociatedMftTracks); } } @@ -1862,10 +1971,10 @@ struct HfTaskFlow { continue; } - if (configCentral.isApplyPtOrderingSameEvent && sameEvent && (track1.pt() <= reassociatedMftTrack.pt())) { + if (configCentral.isApplyPtOrderingSameEvent && isSameEvent && (track1.pt() <= reassociatedMftTrack.pt())) { continue; } - if (configCentral.isApplyPtOrderingMixedEvent && !sameEvent && (track1.pt() <= reassociatedMftTrack.pt())) { + if (configCentral.isApplyPtOrderingMixedEvent && !isSameEvent && (track1.pt() <= reassociatedMftTrack.pt())) { continue; } @@ -1889,21 +1998,21 @@ struct HfTaskFlow { if (!fillingHFcontainer) { if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } else if (configTask.doEtaDependentFlow) { target->getPairHist()->Fill(step, sampleIndex, posZ, eta2, eta1, deltaPhi, eta1 - eta2, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } else { target->getPairHist()->Fill(step, sampleIndex, posZ, pt1, multiplicity, deltaPhi, eta1 - eta2, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } } else { target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, - triggerWeight * associatedWeight); + centralityWeight * triggerWeight * associatedWeight); } // FILL QA PLOTS for associated particle - if (sameEvent && (loopCounter == 1)) { + if (isSameEvent && (loopCounter == 1)) { if constexpr (std::is_same_v) { fillAssociatedQa(multiplicity, eta2, phi2); registry.fill(HIST("Data/Mft/hPtMft"), pt2); @@ -1922,8 +2031,8 @@ struct HfTaskFlow { template void fillCorrelationsFIT(TTarget target, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TFits const&, - float multiplicity, float posZ, bool sameEvent, int fitType) + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, TFits const&, + float multiplicity, float posZ, bool isSameEvent, int fitType, float centralityWeight) { auto triggerWeight = 1.0f; auto associatedWeight = 1.0f; @@ -1931,7 +2040,7 @@ struct HfTaskFlow { int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE - for (auto const& track1 : tracks1) { + for (auto const& track1 : tracksTrigger) { loopCounter++; if constexpr (std::is_same_v) { @@ -1939,7 +2048,7 @@ struct HfTaskFlow { continue; } } else if constexpr (std::is_same_v) { - if (sameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time + if (isSameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::NoSelection); if (!isAcceptedMftTrack(track1, 0.f, 0.f, true)) { @@ -1982,29 +2091,46 @@ struct HfTaskFlow { // fill single-track distributions if (!fillingHFcontainer) { // if not HF-h case - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, centralityWeight * triggerWeight); if (configTask.doEtaDependentFlow) { if (fitType == isFT0A) { - registry.fill(HIST("Trig_hist_TPC_FT0A"), sampleIndex, posZ, track1.eta(), triggerWeight); // think about event weight in near future + if constexpr (std::is_same_v) { + registry.fill(HIST("Trig_hist_MFT_FT0A"), sampleIndex, posZ, track1.eta(), centralityWeight * triggerWeight); + } else { + registry.fill(HIST("Trig_hist_TPC_FT0A"), sampleIndex, posZ, track1.eta(), centralityWeight * triggerWeight); + } } else { - registry.fill(HIST("Trig_hist_TPC_FT0C"), sampleIndex, posZ, track1.eta(), triggerWeight); // think about event weight in near future + if constexpr (std::is_same_v) { + registry.fill(HIST("Trig_hist_MFT_FT0C"), sampleIndex, posZ, track1.eta(), centralityWeight * triggerWeight); + } else { + registry.fill(HIST("Trig_hist_TPC_FT0C"), sampleIndex, posZ, track1.eta(), centralityWeight * triggerWeight); + } } } if (configTask.doVariationContainers) { if (fitType == isFT0A) { - registry.fill(HIST("Trig_hist_TPC_FT0A"), sampleIndex, posZ, track1.pt(), triggerWeight); // think about event weight in near future + + if constexpr (std::is_same_v) { + registry.fill(HIST("Trig_hist_MFT_FT0A"), sampleIndex, posZ, track1.pt(), centralityWeight * triggerWeight); + } else { + registry.fill(HIST("Trig_hist_TPC_FT0A"), sampleIndex, posZ, track1.pt(), centralityWeight * triggerWeight); + } } else { - registry.fill(HIST("Trig_hist_TPC_FT0C"), sampleIndex, posZ, track1.pt(), triggerWeight); // think about event weight in near future + if constexpr (std::is_same_v) { + registry.fill(HIST("Trig_hist_MFT_FT0C"), sampleIndex, posZ, track1.pt(), centralityWeight * triggerWeight); + } else { + registry.fill(HIST("Trig_hist_TPC_FT0C"), sampleIndex, posZ, track1.pt(), centralityWeight * triggerWeight); + } } } } else { - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, centralityWeight * triggerWeight); } // FILL QA PLOTS for trigger particle - if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { if constexpr (!std::is_same_v) { // If not FilteredMftTracks as trigger -> TPC-FV0a correlations if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-FV0a D0-h if constexpr (std::is_same_v) { // IF NEITHER D0 NOR LC -> @@ -2062,18 +2188,18 @@ struct HfTaskFlow { // if (!fillingHFcontainer) { // if (!configTask.doEtaDependentFlow) { // target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, - // triggerWeight * associatedWeight); + // centralityWeight * triggerWeight * associatedWeight); // } else { // target->getPairHist()->Fill(step, eta1 - eta2, eta2, eta1, multiplicity, deltaPhi, posZ, - // triggerWeight * associatedWeight); + // centralityWeight * triggerWeight * associatedWeight); // } // } else { // target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, - // triggerWeight * associatedWeight); + // centralityWeight * triggerWeight * associatedWeight); // } // // FILL QA PLOTS for associated particle - // if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + // if (isSameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { // if constexpr (!std::is_same_v) { // If not FilteredMftTracks as trigger -> TPC-FV0a correlations // if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-FV0a D0-h // fillAssociatedQa(multiplicity, eta2, phi2); @@ -2095,9 +2221,9 @@ struct HfTaskFlow { // select the right channel size if it is FT0a or FT0c std::size_t channelSize = 0; if (fitType == isFT0C) { - channelSize = tracks2.channelC().size(); + channelSize = tracksAssoc.channelC().size(); } else if (fitType == isFT0A) { - channelSize = tracks2.channelA().size(); + channelSize = tracksAssoc.channelA().size(); } else { LOGF(fatal, "Cor Index %d out of range", fitType); } @@ -2106,7 +2232,7 @@ struct HfTaskFlow { int channelId = 0; float amplitude = 0.; - getChannel(tracks2, indexChannel, channelId, fitType, amplitude); + getChannel(tracksAssoc, indexChannel, channelId, fitType, amplitude); auto phi2 = getPhiFT0(channelId, fitType); auto eta2 = getEtaFT0(channelId, fitType); float deltaPhi = phi1 - phi2; @@ -2115,21 +2241,21 @@ struct HfTaskFlow { if (!fillingHFcontainer) { if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { target->getPairHist()->Fill(step, eta1 - eta2, 0.5, pt1, multiplicity, deltaPhi, posZ, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } else if (configTask.doEtaDependentFlow) { target->getPairHist()->Fill(step, sampleIndex, posZ, eta2, eta1, deltaPhi, eta1 - eta2, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } else { target->getPairHist()->Fill(step, sampleIndex, posZ, pt1, multiplicity, deltaPhi, eta1 - eta2, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } } else { target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } // FILL QA PLOTS for associated particle - if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { if constexpr (!std::is_same_v) { // If not FilteredMftTracks as trigger -> TPC-Ft0a correlations if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-FV0a D0-h if (fitType == isFT0A) { @@ -2166,8 +2292,8 @@ struct HfTaskFlow { template void fillCorrelationsFITReassociatedMftTracks(TTarget target, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TFits const&, - float multiplicity, float posZ, bool sameEvent, bool cutAmbiguousTracks, int fitType) + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, TFits const&, + float multiplicity, float posZ, bool isSameEvent, bool cutAmbiguousTracks, int fitType, float centralityWeight) { auto triggerWeight = 1.0f; auto associatedWeight = 1.0f; @@ -2175,7 +2301,7 @@ struct HfTaskFlow { int sampleIndex = gRandom->Uniform(0, configTask.nSamples); // TRIGGER PARTICLE - for (auto const& track1 : tracks1) { + for (auto const& track1 : tracksTrigger) { loopCounter++; auto reassociatedMftTrack = track1.template mfttrack_as(); @@ -2190,7 +2316,7 @@ struct HfTaskFlow { reassociatedMftTrackDcaZ = track1.bestDCAZ(); } - if (sameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time + if (isSameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::NoSelection); if (!isAcceptedMftTrack(reassociatedMftTrack, reassociatedMftTrackDcaXY, reassociatedMftTrackDcaZ, true)) { @@ -2217,17 +2343,17 @@ struct HfTaskFlow { continue; } - target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, centralityWeight * triggerWeight); if (configTask.doEtaDependentFlow) { - registry.fill(HIST("Trig_hist_MFT_FT0A"), sampleIndex, posZ, eta1, triggerWeight); // think about event weight in near future + registry.fill(HIST("Trig_hist_MFT_FT0A"), sampleIndex, posZ, eta1, centralityWeight * triggerWeight); } if (configTask.doVariationContainers) { - registry.fill(HIST("Trig_hist_MFT_FT0A"), sampleIndex, posZ, pt1, triggerWeight); + registry.fill(HIST("Trig_hist_MFT_FT0A"), sampleIndex, posZ, pt1, centralityWeight * triggerWeight); } // FILL QA PLOTS for trigger particle - if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { if constexpr (std::is_same_v) { fillTriggerQa(multiplicity, eta1, phi1, pt1); } else if constexpr (std::is_same_v) { @@ -2250,14 +2376,14 @@ struct HfTaskFlow { // if (!configTask.doEtaDependentFlow) { // target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, - // triggerWeight * associatedWeight); + // centralityWeight * triggerWeight * associatedWeight); // } else { // target->getPairHist()->Fill(step, eta1 - eta2, eta2, eta1, multiplicity, deltaPhi, posZ, - // triggerWeight * associatedWeight); + // centralityWeight * triggerWeight * associatedWeight); // } // // FILL QA PLOTS for associated particle - // if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + // if (isSameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { // fillAssociatedQa(multiplicity, eta2, phi2); // } // end of if condition to fill QA plots for associated particle // } // end of loop over FV0 channel indices @@ -2269,9 +2395,9 @@ struct HfTaskFlow { // select the right channel size if it is FT0a or FT0c std::size_t channelSize = 0; if (fitType == isFT0C) { - channelSize = tracks2.channelC().size(); + channelSize = tracksAssoc.channelC().size(); } else if (fitType == isFT0A) { - channelSize = tracks2.channelA().size(); + channelSize = tracksAssoc.channelA().size(); } else { LOGF(fatal, "Cor Index %d out of range", fitType); } @@ -2280,7 +2406,7 @@ struct HfTaskFlow { int channelId = 0; float amplitude = 0.; - getChannel(tracks2, indexChannel, channelId, fitType, amplitude); + getChannel(tracksAssoc, indexChannel, channelId, fitType, amplitude); auto phi2 = getPhiFT0(channelId, fitType); auto eta2 = getEtaFT0(channelId, fitType); float deltaPhi = phi1 - phi2; @@ -2288,17 +2414,17 @@ struct HfTaskFlow { if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { target->getPairHist()->Fill(step, eta1 - eta2, 0.5, pt1, multiplicity, deltaPhi, posZ, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } else if (configTask.doEtaDependentFlow) { target->getPairHist()->Fill(step, sampleIndex, posZ, eta2, eta1, deltaPhi, eta1 - eta2, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } else { target->getPairHist()->Fill(step, sampleIndex, posZ, pt1, multiplicity, deltaPhi, eta1 - eta2, - amplitude * triggerWeight * associatedWeight); + amplitude * centralityWeight * triggerWeight * associatedWeight); } // FILL QA PLOTS for associated particle - if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { if (fitType == isFT0A) { fillAssociatedQa(multiplicity, eta2, phi2); } @@ -2311,7 +2437,7 @@ struct HfTaskFlow { template void fillCorrelationsFt0aFt0c(TTarget target, CorrelationContainer::CFStep step, TFT0As const& ft0as, TFT0Cs const& ft0cs, - float multiplicity, float posZ, bool sameEvent) + float multiplicity, float posZ, bool isSameEvent, float centralityWeight) { auto triggerWeight = 1.0f; auto associatedWeight = 1.0f; @@ -2322,21 +2448,21 @@ struct HfTaskFlow { for (std::size_t indexChannelA = 0; indexChannelA < ft0as.channelA().size(); indexChannelA++) { loopCounter++; int channelIdA = 0; - float amplitude = 0.; - getChannel(ft0as, indexChannelA, channelIdA, isFT0A, amplitude); + float amplitudeA = 0.; + getChannel(ft0as, indexChannelA, channelIdA, isFT0A, amplitudeA); auto phiA = getPhiFT0(channelIdA, isFT0A); auto etaA = getEtaFT0(channelIdA, isFT0A); - target->getTriggerHist()->Fill(step, 0.5, multiplicity, posZ, amplitude * triggerWeight); + target->getTriggerHist()->Fill(step, 0.5, multiplicity, posZ, amplitudeA * centralityWeight * triggerWeight); if (configTask.doEtaDependentFlow) { - registry.fill(HIST("Trig_hist_FT0A_FT0C"), sampleIndex, posZ, etaA, triggerWeight); // think about event weight in near future + registry.fill(HIST("Trig_hist_FT0A_FT0C"), sampleIndex, posZ, etaA, amplitudeA * centralityWeight * triggerWeight); } if (configTask.doVariationContainers) { - registry.fill(HIST("Trig_hist_FT0A_FT0C"), sampleIndex, posZ, 0.5, triggerWeight); + registry.fill(HIST("Trig_hist_FT0A_FT0C"), sampleIndex, posZ, 0.5, amplitudeA * centralityWeight * triggerWeight); } - if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { fillTriggerQa(multiplicity, etaA, phiA, 0.5); } // end of fill trigger QA @@ -2344,24 +2470,24 @@ struct HfTaskFlow { for (std::size_t indexChannelC = 0; indexChannelC < ft0cs.channelC().size(); indexChannelC++) { int channelIdC = 0; - float amplitude = 0.; - getChannel(ft0cs, indexChannelC, channelIdC, isFT0C, amplitude); + float amplitudeC = 0.; + getChannel(ft0cs, indexChannelC, channelIdC, isFT0C, amplitudeC); auto phiC = getPhiFT0(channelIdC, isFT0C); auto etaC = getEtaFT0(channelIdC, isFT0C); float deltaPhi = RecoDecay::constrainAngle(phiA - phiC, -PIHalf); if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { target->getPairHist()->Fill(step, etaA - etaC, 0.5, 0.5, multiplicity, deltaPhi, posZ, - amplitude * triggerWeight * associatedWeight); + amplitudeA * amplitudeC * centralityWeight * triggerWeight * associatedWeight); } else if (configTask.doEtaDependentFlow) { target->getPairHist()->Fill(step, sampleIndex, posZ, etaC, etaA, deltaPhi, etaA - etaC, - amplitude * triggerWeight * associatedWeight); + amplitudeA * amplitudeC * centralityWeight * triggerWeight * associatedWeight); } else { target->getPairHist()->Fill(step, sampleIndex, posZ, 0.5, multiplicity, deltaPhi, etaA - etaC, - amplitude * triggerWeight * associatedWeight); + amplitudeA * amplitudeC * centralityWeight * triggerWeight * associatedWeight); } - if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if (isSameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { fillAssociatedQa(multiplicity, etaC, phiC); } // end of fill associated QA } // end of associated loop @@ -2370,8 +2496,8 @@ struct HfTaskFlow { template void fillCorrelationsMonteCarlo(TTarget target, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, - float multiplicity, float posZ, bool sameEvent) + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, + float multiplicity, float posZ, bool isSameEvent) { auto triggerWeight = 1.0f; auto associatedWeight = 1.0f; @@ -2389,7 +2515,7 @@ struct HfTaskFlow { } } - for (auto const& track1 : tracks1) { + for (auto const& track1 : tracksTrigger) { loopCounter++; if (track1.eta() < configTask.etaMcParticlesTriggerMin || track1.eta() > configTask.etaMcParticlesTriggerMax) { @@ -2405,14 +2531,14 @@ struct HfTaskFlow { target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, triggerWeight); if (configTask.doEtaDependentFlow) { - registry.fill(HIST("Trig_hist"), sampleIndex, posZ, track1.eta(), triggerWeight); // think about event weight in near future + registry.fill(HIST("Trig_hist"), sampleIndex, posZ, track1.eta(), triggerWeight); } if (configTask.doVariationContainers) { registry.fill(HIST("Trig_hist"), sampleIndex, posZ, track1.pt(), triggerWeight); } // FILL QA FOR TRIGGER PARTICLE - if (sameEvent && fillQaPlots) { + if (isSameEvent && fillQaPlots) { registry.fill(HIST("MC/hEfficiencyTrigger"), track1.pt(), track1.eta(), posZ); if (configTask.chooseCorrelationCase.value == static_cast(CorrelationCase::TpcTpc)) { fillTriggerQa(multiplicity, track1.eta(), track1.phi(), track1.pt()); @@ -2433,7 +2559,7 @@ struct HfTaskFlow { } } - for (auto const& track2 : tracks2) { + for (auto const& track2 : tracksAssoc) { if (track1.globalIndex() == track2.globalIndex()) { continue; @@ -2463,7 +2589,7 @@ struct HfTaskFlow { } // FILL QA PLOTS for associated particle - if (sameEvent && fillQaPlots && (loopCounter == 1)) { + if (isSameEvent && fillQaPlots && (loopCounter == 1)) { registry.fill(HIST("MC/hEfficiencyAssociated"), track2.pt(), track2.eta(), posZ); if (configTask.chooseCorrelationCase.value == static_cast(CorrelationCase::TpcTpc)) { fillAssociatedQa(multiplicity, track2.eta(), track2.phi()); @@ -2493,7 +2619,7 @@ struct HfTaskFlow { template void mixCollisions(TCollisions const& collisions, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, OutputObj& corrContainer, aod::BCsWithTimestamps const&) { // auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { @@ -2501,8 +2627,8 @@ struct HfTaskFlow { // return multiplicity; // }; - auto getMultiplicity = [&tracks1, this](FilteredCollisionsWSelMult::iterator const& collision) { - auto associatedTracks = tracks1.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto getMultiplicity = [&tracksTrigger, this](FilteredCollisionsWSelMult::iterator const& collision) { + auto associatedTracks = tracksTrigger.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); // auto mult = 0.f; if (configCollision.useMultiplicityFromTracks) { return associatedTracks.size(); @@ -2515,7 +2641,7 @@ struct HfTaskFlow { using BinningTypeData = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; BinningTypeData binningWithTracksSize{{getMultiplicity}, {configAxis.binsMixingVertex, configAxis.binsMixingMultiplicity}, true}; - auto tracksTuple = std::make_tuple(tracks1, tracks2); + auto tracksTuple = std::make_tuple(tracksTrigger, tracksAssoc); Pair pair{binningWithTracksSize, configTask.nMixedEvents, -1, collisions, tracksTuple, &cache}; for (const auto& [collision1, tracks1, collision2, tracks2] : pair) { @@ -2536,18 +2662,26 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision1, false); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision1, true)); + if (getCentralityEstimator(collision1, false) < configCollision.minCentrality || getCentralityEstimator(collision1, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } corrContainer->fillEvent(multiplicity, step); - fillCorrelations(corrContainer, step, tracks1, tracks2, multiplicity, collision1.posZ(), false, getMagneticField(bc.timestamp())); + fillCorrelations(corrContainer, step, tracks1, tracks2, multiplicity, collision1.posZ(), false, getMagneticField(bc.timestamp()), centralityWeight); } } template void mixCollisionsBis(TCollisions const& collisions, CorrelationContainer::CFStep step, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TPresliceTrigger const& presliceTrigger, TPresliceAssociated const& presliceAssociated, + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, TPresliceTrigger const& presliceTrigger, TPresliceAssociated const& presliceAssociated, OutputObj& corrContainer, aod::BCsWithTimestamps const&) { // auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { @@ -2555,8 +2689,8 @@ struct HfTaskFlow { // return multiplicity; // }; - auto getMultiplicity = [&tracks1, this](FilteredCollisionsWSelMult::iterator const& collision) { - auto associatedTracks = tracks1.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto getMultiplicity = [&tracksTrigger, this](FilteredCollisionsWSelMult::iterator const& collision) { + auto associatedTracks = tracksTrigger.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); auto mult = associatedTracks.size(); if (configCollision.useMultiplicityFromTracks) { return mult; @@ -2584,25 +2718,34 @@ struct HfTaskFlow { loadEfficiencyCorrection(bc.timestamp()); auto multiplicity = 0; if (configCollision.useMultiplicityFromTracks) { - multiplicity = tracks1.size(); + multiplicity = tracksTrigger.size(); } else { multiplicity = getMultiplicityEstimator(collision1, false); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision1, true)); + if (getCentralityEstimator(collision1, false) < configCollision.minCentrality || getCentralityEstimator(collision1, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } - auto slicedTriggerTracks = tracks1.sliceBy(presliceTrigger, collision1.globalIndex()); - auto slicedAssociatedTracks = tracks2.sliceBy(presliceAssociated, collision2.globalIndex()); + auto slicedTriggerTracks = tracksTrigger.sliceBy(presliceTrigger, collision1.globalIndex()); + auto slicedAssociatedTracks = tracksAssoc.sliceBy(presliceAssociated, collision2.globalIndex()); corrContainer->fillEvent(multiplicity, step); - fillCorrelations(corrContainer, step, slicedTriggerTracks, slicedAssociatedTracks, multiplicity, collision1.posZ(), false, getMagneticField(bc.timestamp())); + fillCorrelations(corrContainer, step, slicedTriggerTracks, slicedAssociatedTracks, multiplicity, collision1.posZ(), false, getMagneticField(bc.timestamp()), centralityWeight); } } template void mixCollisionsReassociatedMftTracks(TCollisions const& collisions, CorrelationContainer::CFStep step, TTracksTpc const& tracksTpc, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TPresliceTrigger const& presliceTrigger, TPresliceAssociated const& presliceAssociated, + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, TPresliceTrigger const& presliceTrigger, TPresliceAssociated const& presliceAssociated, OutputObj& corrContainer, bool cutAmbiguousTracks, aod::BCsWithTimestamps const&) { // auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { @@ -2641,30 +2784,39 @@ struct HfTaskFlow { } else { multiplicity = getMultiplicityEstimator(collision1, false); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision1, true)); + if (getCentralityEstimator(collision1, false) < configCollision.minCentrality || getCentralityEstimator(collision1, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } // if TPC-MFT cases if constexpr (std::is_same_v) { - auto slicedTriggerTracks = tracks1.sliceBy(presliceTrigger, collision1.globalIndex()); - auto slicedAssociatedTracks = tracks2.sliceBy(presliceAssociated, collision2.globalIndex()); + auto slicedTriggerTracks = tracksTrigger.sliceBy(presliceTrigger, collision1.globalIndex()); + auto slicedAssociatedTracks = tracksAssoc.sliceBy(presliceAssociated, collision2.globalIndex()); corrContainer->fillEvent(multiplicity, step); - fillCorrelationsReassociatedMftTracks(corrContainer, step, slicedTriggerTracks, slicedAssociatedTracks, multiplicity, collision1.posZ(), false, cutAmbiguousTracks); + fillCorrelationsReassociatedMftTracks(corrContainer, step, slicedTriggerTracks, slicedAssociatedTracks, multiplicity, collision1.posZ(), false, cutAmbiguousTracks, centralityWeight); } else if ((collision1.has_foundFT0() && collision2.has_foundFT0())) { // if MFT-FT0A cases - auto slicedTriggerTracks = tracks1.sliceBy(presliceTrigger, collision1.globalIndex()); + auto slicedTriggerTracks = tracksTrigger.sliceBy(presliceTrigger, collision1.globalIndex()); const auto& ft0 = collision2.foundFT0(); corrContainer->fillEvent(multiplicity, step); - fillCorrelationsFITReassociatedMftTracks(corrContainer, step, slicedTriggerTracks, ft0, tracks2, multiplicity, collision1.posZ(), false, cutAmbiguousTracks, isFT0A); + fillCorrelationsFITReassociatedMftTracks(corrContainer, step, slicedTriggerTracks, ft0, tracksAssoc, multiplicity, collision1.posZ(), false, cutAmbiguousTracks, isFT0A, centralityWeight); } } // end of for loop } template void mixCollisionsFIT(TCollisions const& collisions, CorrelationContainer::CFStep step, TTracksTpc const& tracksTpc, - TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TPreslice const& preslice, + TTracksTrig const& tracksTrigger, TTracksAssoc const& tracksAssoc, TPreslice const& preslice, OutputObj& corrContainer, int fitType, aod::BCsWithTimestamps const&) { // auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { @@ -2672,8 +2824,8 @@ struct HfTaskFlow { // return multiplicity; // }; - auto getMultiplicity = [&tracks1, this](FilteredCollisionsWSelMult::iterator const& collision) { - auto associatedTracks = tracks1.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto getMultiplicity = [&tracksTrigger, this](FilteredCollisionsWSelMult::iterator const& collision) { + auto associatedTracks = tracksTrigger.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); auto mult = associatedTracks.size(); if (configCollision.useMultiplicityFromTracks) { return mult; @@ -2701,7 +2853,7 @@ struct HfTaskFlow { // if constexpr (std::is_same_v) { // IF ASSOCIATED PARTICLE FROM FV0A // if (collision1.has_foundFV0() && collision2.has_foundFV0()) { - // auto slicedTriggerTracks = tracks1.sliceBy(preslice, collision1.globalIndex()); + // auto slicedTriggerTracks = tracksTrigger.sliceBy(preslice, collision1.globalIndex()); // auto tracksForMultiplicity = tracksTpc.sliceByCached(o2::aod::track::collisionId, collision1.globalIndex(), cache); // const auto& fv0 = collision2.foundFV0(); @@ -2724,7 +2876,7 @@ struct HfTaskFlow { if constexpr (std::is_same_v) { if (collision1.has_foundFT0() && collision2.has_foundFT0()) { - auto slicedTriggerTracks = tracks1.sliceBy(preslice, collision1.globalIndex()); + auto slicedTriggerTracks = tracksTrigger.sliceBy(preslice, collision1.globalIndex()); auto tracksForMultiplicity = tracksTpc.sliceByCached(o2::aod::track::collisionId, collision1.globalIndex(), cache); const auto& ft0 = collision2.foundFT0(); @@ -2735,12 +2887,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision1, false); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision1, true)); + if (getCentralityEstimator(collision1, false) < configCollision.minCentrality || getCentralityEstimator(collision1, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } corrContainer->fillEvent(multiplicity, step); - fillCorrelationsFIT(corrContainer, step, slicedTriggerTracks, ft0, tracks2, multiplicity, collision1.posZ(), false, fitType); + fillCorrelationsFIT(corrContainer, step, slicedTriggerTracks, ft0, tracksAssoc, multiplicity, collision1.posZ(), false, fitType, centralityWeight); } } // end of if condition for TPC-FT0 or MFT-FT0s } // end of for loop @@ -2793,12 +2953,21 @@ struct HfTaskFlow { } else { multiplicity = getMultiplicityEstimator(collision1, false); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision1, true)); + if (getCentralityEstimator(collision1, false) < configCollision.minCentrality || getCentralityEstimator(collision1, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } corrContainer->fillEvent(multiplicity, step); - fillCorrelationsFt0aFt0c(corrContainer, step, ft0as, ft0cs, multiplicity, collision1.posZ(), true); + fillCorrelationsFt0aFt0c(corrContainer, step, ft0as, ft0cs, multiplicity, collision1.posZ(), true, centralityWeight); } } // end of for loop } @@ -2835,12 +3004,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcChCh, "DATA : Process same-event correlations for TPC-TPC h-h case", false); @@ -2874,12 +3051,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcD0Ch, "DATA : Process same-event correlations for TPC-TPC D0-h case", false); @@ -2913,12 +3098,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcLcCh, "DATA : Process same-event correlations for TPC-TPC Lc-h case", false); @@ -2945,16 +3138,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } else { sameEventTpcMft->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChCh, "DATA : Process same-event correlations for TPC-MFT h-h case", false); @@ -2981,16 +3182,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false, centralityWeight); } else { sameEventTpcMft->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + fillCorrelationsReassociatedMftTracks(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChChReassociated, "DATA : Process same-event correlations for TPC-MFT h-h case reassociated", false); @@ -3017,22 +3226,30 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - registry.fill(HIST("Data/hMultiplicity_uncorrected"), multiplicity); + auto uncorrectedMultiplicity = multiplicity; + registry.fill(HIST("Data/hMultiplicity_uncorrected_vs_corrected"), uncorrectedMultiplicity, multiplicity); if (configCollision.useMultiplicityFromTracksCorrected) { multiplicity = getCorrectedMultiplicity(tracks); - registry.fill(HIST("Data/hMultiplicity_corrected"), multiplicity); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false, centralityWeight); } else { sameEventTpcMft->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + fillCorrelationsReassociatedMftTracks(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChChReassociated3d, "DATA : Process same-event correlations for TPC-MFT h-h case 3d reassociated", false); @@ -3059,16 +3276,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, true); + fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, true, centralityWeight); } else { sameEventTpcMft->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, true); + fillCorrelationsReassociatedMftTracks(sameEventTpcMft, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, true, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChChNonAmbiguous, "DATA : Process same-event correlations for TPC-MFT h-h case with non-ambiguous tracks", false); @@ -3103,12 +3328,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftD0Ch, "DATA : Process same-event correlations for TPC-MFT D0-h case", false); @@ -3132,12 +3365,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + fillCorrelationsReassociatedMftTracks(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, reassociatedMftTracks, multiplicity, collision.posZ(), true, false, centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftD0ChReassociated, "DATA : Process same-event correlations for TPC-MFT D0-h case reassociated", false); @@ -3171,12 +3412,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp()), centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftLcCh, "DATA : Process same-event correlations for TPC-MFT Lc-h case", false); @@ -3200,12 +3449,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsReassociatedMftTracks(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + fillCorrelationsReassociatedMftTracks(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, reassociatedMftTracks, multiplicity, collision.posZ(), true, false, centralityWeight); } PROCESS_SWITCH(HfTaskFlow, processSameTpcMftLcChReassociated, "DATA : Process same-event correlations for TPC-MFT Lc-h case reassociated", false); @@ -3413,16 +3670,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A, centralityWeight); } else { sameEventTpcFt0a->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEventTpcFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + fillCorrelationsFIT(sameEventTpcFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A, centralityWeight); } } } @@ -3455,12 +3720,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0aD0Ch, "DATA : Process same-event correlations for TPC-FT0-A D0-h case", false); @@ -3492,12 +3765,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0aLcCh, "DATA : Process same-event correlations for TPC-FT0-A Lc-h case", false); @@ -3529,16 +3810,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, mftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, mftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A, centralityWeight); } else { sameEventMftFt0a->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, mftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + fillCorrelationsFIT(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, mftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A, centralityWeight); } } } @@ -3568,16 +3857,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A, centralityWeight); } else { sameEventMftFt0a->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFITReassociatedMftTracks(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A); + fillCorrelationsFITReassociatedMftTracks(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A, centralityWeight); } } } @@ -3607,16 +3904,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A, centralityWeight); } else { sameEventMftFt0a->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFITReassociatedMftTracks(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A); + fillCorrelationsFITReassociatedMftTracks(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A, centralityWeight); } } } @@ -3646,16 +3951,24 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } if (!configTask.doEtaDependentFlow && !configTask.doVariationContainers) { sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, true, isFT0A); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, true, isFT0A, centralityWeight); } else { sameEventMftFt0a->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFITReassociatedMftTracks(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, true, isFT0A); + fillCorrelationsFITReassociatedMftTracks(sameEventMftFt0a, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, true, isFT0A, centralityWeight); } } } @@ -3688,12 +4001,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0cChCh, "DATA : Process same-event correlations for TPC-FT0C h-h case", false); @@ -3725,12 +4046,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0cD0Ch, "DATA : Process same-event correlations for TPC-FT0C D0-h case", false); @@ -3762,12 +4091,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0cLcCh, "DATA : Process same-event correlations for TPC-FT0C Lc-h case", false); @@ -3798,12 +4135,20 @@ struct HfTaskFlow { multiplicity = getMultiplicityEstimator(collision, true); } - if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { - return; + float centralityWeight = 1.0f; + if (configCollision.useCentrality) { + getCentralityWeight(centralityWeight, getCentralityEstimator(collision, true)); + if (getCentralityEstimator(collision, false) < configCollision.minCentrality || getCentralityEstimator(collision, false) >= configCollision.maxCentrality) { + return; + } + } else { + if (multiplicity < configCollision.minMultiplicity || multiplicity >= configCollision.maxMultiplicity) { + return; + } } sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelationsFt0aFt0c(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, ft0, ft0, multiplicity, collision.posZ(), true); + fillCorrelationsFt0aFt0c(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, ft0, ft0, multiplicity, collision.posZ(), true, centralityWeight); } } PROCESS_SWITCH(HfTaskFlow, processSameFt0aFt0cChCh, "DATA : Process same-event correlations for FT0A-FT0C h-h case", false); @@ -4272,6 +4617,115 @@ struct HfTaskFlow { } PROCESS_SWITCH(HfTaskFlow, processMixedMcGen, "MC Gen : Process mixed-event correlations", false); + void processTrackEfficiencies(FilteredMcCollisionsWMultWCollsExtra::iterator const& mcCollision, + SmallGroupMcCollisions const& reconstructedCollisions, + FilteredTracksWDcaSelWLabels const& tpcTracks, FilteredMftTracksWCollsMcLabels const& /*mftTracks*/, + soa::Filtered> const& reassociated3dMftTracks, + FilteredMcParticles const& mcParticles) + { + if (std::abs(mcCollision.posZ()) >= configCollision.zVertexMax) { + return; + } + + // check whether we have a selected reconstructed collision corresponding to the MC collision + bool hasReconstructedCollision = false; + for (const auto& reconstructedCollision : reconstructedCollisions) { + if (!isAcceptedCollision(reconstructedCollision)) { + continue; + } + if (reconstructedCollision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + hasReconstructedCollision = true; + } + + // fill histogram for MC Gen TPC particles + for (const auto& particle : mcParticles) { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + // check MC related properties of the particle + if (!particle.isPhysicalPrimary() || !particle.producedByGenerator()) { + continue; + } + // check charge of the particle + if (pdgParticle == nullptr || std::abs(pdgParticle->Charge()) == 0) { + continue; + } + // check kinematics of the particle for TPC + if (std::abs(particle.eta()) <= configTask.etaMcParticlesTriggerMax && + particle.pt() >= configTask.ptMcParticlesTriggerMin && + particle.pt() <= configTask.ptMcParticlesTriggerMax) { + if (hasReconstructedCollision) { + registry.fill(HIST("MC/hEfficiencyTrigger"), particle.pt(), particle.eta(), mcCollision.posZ()); + } + } + // check kinematics of the particle for MFT + if (particle.eta() <= configTask.etaMcParticlesAssocMax && + particle.eta() >= configTask.etaMcParticlesAssocMin && + particle.pt() >= configTask.ptMcParticlesAssocMin && + particle.pt() <= configTask.ptMcParticlesAssocMax) { + + if (configMft.useMftPhiCut) { + if (particle.phi() < configMft.phiMftTrackMax && particle.phi() > configMft.phiMftTrackMin && + !(particle.phi() > configMft.phiMftTrackMiddleMin && particle.phi() < configMft.phiMftTrackMiddleMax)) { + if (hasReconstructedCollision) { + registry.fill(HIST("MC/hEfficiencyAssociated"), particle.pt(), particle.eta(), mcCollision.posZ()); + } + } + } else { + if (hasReconstructedCollision) { + registry.fill(HIST("MC/hEfficiencyAssociated"), particle.pt(), particle.eta(), mcCollision.posZ()); + } + } + } + } + + // fill histogram for reconstructed TPC tracks + for (const auto& reconstructedCollision : reconstructedCollisions) { + if (!isAcceptedCollision(reconstructedCollision)) { + continue; + } + if (reconstructedCollision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + + auto groupedTpcTracks = tpcTracks.sliceBy(perColTracks, reconstructedCollision.globalIndex()); + for (const auto& tpcTrack : groupedTpcTracks) { + if (!isAcceptedCentralTrack(tpcTrack)) { + continue; + } + if (!tpcTrack.has_mcParticle()) { + continue; + } + auto tpcParticle = tpcTrack.template mcParticle_as(); + if (reconstructedCollision.mcCollisionId() != tpcParticle.mcCollisionId()) { + continue; + } + if (tpcParticle.isPhysicalPrimary()) { + registry.fill(HIST("Data/hEfficiencyTrigger"), tpcParticle.pt(), tpcParticle.eta(), mcCollision.posZ()); + } + } + + auto groupedreassociated3dMftTracks = reassociated3dMftTracks.sliceBy(perColReassociated3dTracks, reconstructedCollision.globalIndex()); + for (const auto& reassociated3dMftTrack : reassociated3dMftTracks) { + if (!reassociated3dMftTrack.has_mcParticle()) { + continue; + } + auto templatedMftTrack = reassociated3dMftTrack.template mfttrack_as(); + if (!isAcceptedMftTrack(templatedMftTrack, reassociated3dMftTrack.bestDCAXY(), reassociated3dMftTrack.bestDCAZ(), false)) { + continue; + } + auto mftParticle = templatedMftTrack.template mcParticle_as(); + if (reconstructedCollision.mcCollisionId() != mftParticle.mcCollisionId()) { + continue; + } + if (mftParticle.isPhysicalPrimary()) { + registry.fill(HIST("Data/hEfficiencyAssociated"), mftParticle.pt(), mftParticle.eta(), mcCollision.posZ()); + } + } + } + } + PROCESS_SWITCH(HfTaskFlow, processTrackEfficiencies, "process track efficiencies for TPC and MFT", false); + }; // End of struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx index 871b6e06aa8..b9f23076f24 100644 --- a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx @@ -67,6 +67,7 @@ #include #include +#include #include #include #include diff --git a/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx b/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx index a4c8f7e16db..ea8b6fbebb0 100644 --- a/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx +++ b/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx @@ -22,6 +22,7 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGLF/DataModel/mcCentrality.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -224,7 +225,9 @@ DECLARE_SOA_COLUMN(ParticlePdg, particlePdg, int); DECLARE_SOA_COLUMN(PtGenB, ptGenB, float); DECLARE_SOA_COLUMN(NContribMax, nContribMax, int); DECLARE_SOA_COLUMN(NRecoColl, nRecoColl, int); -DECLARE_SOA_COLUMN(IsXic0WithRecoCollSel8, isXic0WithRecoCollSel8, bool); +DECLARE_SOA_COLUMN(HasRecoCollTVX, hasRecoCollTVX, bool); +DECLARE_SOA_COLUMN(HasRecoCollSel8, hasRecoCollSel8, bool); +DECLARE_SOA_COLUMN(HasRecoCollSel8Zvtx, hasRecoCollSel8Zvtx, bool); } // namespace full DECLARE_SOA_TABLE(HfToXiPiEvs, "AOD", "HFTOXIPIEV", @@ -328,7 +331,9 @@ DECLARE_SOA_TABLE(HfCandToXiPiGen, "AOD", "HFCANDTOXIPIGEN", full::PtGenB, full::NContribMax, full::NRecoColl, - full::IsXic0WithRecoCollSel8); + full::HasRecoCollTVX, + full::HasRecoCollSel8, + full::HasRecoCollSel8Zvtx); } // namespace o2::aod @@ -380,9 +385,9 @@ struct HfTreeCreatorToXiPiQa { ////////////////////////////////////////////////////// template - void fillEvent(const T& collision, float cutZPv) + void fillEvent(const T& collision) { - rowEv(collision.sel8(), std::abs(collision.posZ()) < cutZPv); + rowEv(collision.sel8(), std::abs(collision.posZ()) < zPvCut); } template @@ -660,18 +665,29 @@ struct HfTreeCreatorToXiPiQa { void fillParticle(const CandType& mcParticles, const CollType& collisions) { for (const auto& particle : mcParticles) { - // Mc.Gen + auto ptGen = particle.pt(); auto yGen = particle.rapidityCharmBaryonGen(); int nContribMax = 0; + bool recoCollPassedTvx = false; bool recoCollPassedSel8 = false; + bool recoCollPassedSel8Zvtx = false; + auto mcCollision = particle.template mcCollision_as(); const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + for (const auto& recoCol : recoCollsPerMcColl) { nContribMax = recoCol.numContrib() > nContribMax ? recoCol.numContrib() : nContribMax; - if (recoCol.sel8()) { - recoCollPassedSel8 = true; + if (recoCol.selection_bit(aod::evsel::kIsTriggerTVX)) { + recoCollPassedTvx = true; + if (recoCol.sel8()) { + recoCollPassedSel8 = true; + if (std::abs(recoCol.posZ()) < zPvCut) { + recoCollPassedSel8Zvtx = true; + break; + } + } } } @@ -688,7 +704,9 @@ struct HfTreeCreatorToXiPiQa { ptGenBhad, nContribMax, recoCollsPerMcColl.size(), - recoCollPassedSel8); + recoCollPassedTvx, + recoCollPassedSel8, + recoCollPassedSel8Zvtx); } } @@ -709,7 +727,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -726,7 +744,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -743,7 +761,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -760,7 +778,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -777,7 +795,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -803,7 +821,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -820,7 +838,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -837,7 +855,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -854,7 +872,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -882,7 +900,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -907,7 +925,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -932,7 +950,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -957,7 +975,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -982,7 +1000,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1007,7 +1025,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1032,7 +1050,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1068,7 +1086,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1093,7 +1111,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1118,7 +1136,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1143,7 +1161,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate table diff --git a/PWGHF/Tasks/taskMcValidation.cxx b/PWGHF/Tasks/taskMcValidation.cxx index 4cbb1100766..242565b20b4 100644 --- a/PWGHF/Tasks/taskMcValidation.cxx +++ b/PWGHF/Tasks/taskMcValidation.cxx @@ -114,14 +114,92 @@ constexpr std::array PDGArrayParticle = {o2::constants::physics: o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kLambdaCPlus, o2::constants::physics::Pdg::kXiCPlus, o2::constants::physics::Pdg::kXiCPlus, o2::constants::physics::Pdg::kXiC0, o2::constants::physics::Pdg::kOmegaC0, o2::constants::physics::Pdg::kOmegaC0}; -constexpr std::array NDaughters = {2, 3, 3, 3, 3, 3, 5, 5, 4, 4, 4, 3, 4, 3, 3, 3, 5, 4, 4, 4}; -constexpr std::array MaxDepthForSearch = {1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 2, 3, 2, 4, 3, 3, 3}; +constexpr std::array NDaughters = { + 2, // DzeroToKPi + 3, // DstarToDzeroPi + 3, // DplusToPiKPi + 3, // DplusToPhiPiToKKPi + 3, // DsToPhiPiToKKPi + 3, // DsToK0starKToKKPi + 5, // Ds1ToDStarK0s + 5, // Ds2StarToDPlusK0s + 4, // D10ToDStarPi + 4, // D2Star0ToDPlusPi + 4, // B0ToDminusPi + 3, // BplusToD0Pi + 4, // BsToDsPi + 3, // LcToPKPi + 3, // LcToPiK0s + 3, // XiCplusToPKPi + 5, // XiCplusToXiPiPi + 4, // XiCzeroToXiPi + 4, // OmegaCToOmegaPi + 4 // OmegaCToXiPi +}; +constexpr std::array MaxDepthForSearch = { + 1, // DzeroToKPi + 2, // DstarToDzeroPi + 2, // DplusToPiKPi + 2, // DplusToPhiPiToKKPi + 2, // DsToPhiPiToKKPi + 2, // DsToK0starKToKKPi + 3, // Ds1ToDStarK0s + 3, // Ds2StarToDPlusK0s + 3, // D10ToDStarPi + 3, // D2Star0ToDPlusPi + 3, // B0ToDminusPi + 2, // BplusToD0Pi + 3, // BsToDsPi + 2, // LcToPKPi + 3, // LcToPiK0s + 2, // XiCplusToPKPi + 4, // XiCplusToXiPiPi + 3, // XiCzeroToXiPi + 3, // OmegaCToOmegaPi + 3 // OmegaCToXiPi +}; // keep coherent indexing with PDGArrayParticle // FIXME: look for a better solution -constexpr std::array, NChannels> ArrPdgFinal2Prong = {{{+kPiPlus, -kKPlus}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}}}; -constexpr std::array, NChannels> ArrPdgFinal3Prong = {{{}, {+kPiPlus, -kKPlus, +kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {+kKPlus, -kKPlus, +kPiPlus}, {}, {}, {}, {}, {}, {-kPiPlus, +kKPlus, +kPiPlus}, {}, {+kProton, -kKPlus, +kPiPlus}, {+kProton, -kPiPlus, +kPiPlus}, {+kProton, -kKPlus, +kPiPlus}, {}, {}, {}, {}}}; -constexpr std::array, NChannels> ArrPdgFinal4Prong = {{{}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, {-kPiPlus, +kKPlus, -kPiPlus, +kPiPlus}, {}, {-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, {}, {}, {}, {}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {+kPiPlus, -kKPlus, -kPiPlus, +kProton}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}}}; -constexpr std::array, NChannels> ArrPdgFinal5Prong = {{{}, {}, {}, {}, {}, {}, {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, {}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, +kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {}, {}, {}}}; +constexpr auto ArrPdgFinal2Prong = []() { + std::array, NChannels> arr{}; + arr[DzeroToKPi] = {+kPiPlus, -kKPlus}; + return arr; +}(); + +constexpr auto ArrPdgFinal3Prong = []() { + std::array, NChannels> arr{}; + arr[DstarToDzeroPi] = {+kPiPlus, -kKPlus, +kPiPlus}; + arr[DplusToPiKPi] = {+kPiPlus, -kKPlus, +kPiPlus}; + arr[DplusToPhiPiToKKPi] = {+kKPlus, -kKPlus, +kPiPlus}; + arr[DsToPhiPiToKKPi] = {+kKPlus, -kKPlus, +kPiPlus}; + arr[DsToK0starKToKKPi] = {+kKPlus, -kKPlus, +kPiPlus}; + arr[BplusToD0Pi] = {-kPiPlus, +kKPlus, +kPiPlus}; + arr[LcToPKPi] = {+kProton, -kKPlus, +kPiPlus}; + arr[LcToPiK0s] = {+kProton, -kPiPlus, +kPiPlus}; + arr[XiCplusToPKPi] = {+kProton, -kKPlus, +kPiPlus}; + return arr; +}(); + +constexpr auto ArrPdgFinal4Prong = []() { + std::array, NChannels> arr{}; + arr[D10ToDStarPi] = {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}; + arr[D2Star0ToDPlusPi] = {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}; + arr[B0ToDminusPi] = {-kPiPlus, +kKPlus, -kPiPlus, +kPiPlus}; + arr[BsToDsPi] = {-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}; + arr[XiCzeroToXiPi] = {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}; + arr[OmegaCToOmegaPi] = {+kPiPlus, -kKPlus, -kPiPlus, +kProton}; + arr[OmegaCToXiPi] = {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}; + return arr; +}(); + +constexpr auto ArrPdgFinal5Prong = []() { + std::array, NChannels> arr{}; + arr[Ds1ToDStarK0s] = {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}; + arr[Ds2StarToDPlusK0s] = {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}; + arr[XiCplusToXiPiPi] = {+kPiPlus, +kPiPlus, -kPiPlus, -kPiPlus, +kProton}; + return arr; +}(); + constexpr std::string_view Labels[NChannels] = {"D^{0} #rightarrow K#pi", "D*^{+} #rightarrow D^{0}#pi", "D^{+} #rightarrow K#pi#pi", "D^{+} #rightarrow KK#pi", "D_{s}^{+} #rightarrow #Phi#pi #rightarrow KK#pi", "D_{s}^{+} #rightarrow #bar{K}^{*0}K #rightarrow KK#pi", "D_{s}1 #rightarrow D*^{+}K^{0}_{s}", "D_{s}2* #rightarrow D^{+}K^{0}_{s}", "D1^{0} #rightarrow D*^{+}#pi", "D2^{*} #rightarrow D^{+}#pi", @@ -279,7 +357,9 @@ struct HfTaskMcValidationGen { } template - void runCheckGenParticles(GenColl const& mcCollision, Particles const& mcParticles, RecoColls const& recoCollisions, BCsInfo const&, std::array& counterPrompt, std::array& counterNonPrompt) + void runCheckGenParticles( + GenColl const& mcCollision, Particles const& mcParticles, RecoColls const& recoCollisions, + BCsInfo const&, std::array& counterPrompt, std::array& counterNonPrompt, std::array& counterBeauty) { if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { return; @@ -478,6 +558,8 @@ struct HfTaskMcValidationGen { } else if (origin == RecoDecay::OriginType::NonPrompt) { counterNonPrompt[iD]++; } + } else { // Beauty hadrons + counterBeauty[iD]++; // Matched already, no need to check origin for beauty hadrons } auto daughter0 = particle.template daughters_as().begin(); @@ -553,8 +635,8 @@ struct HfTaskMcValidationGen { for (const auto& mcCollision : mcCollisions) { const auto recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); - std::array counterPrompt{0}, counterNonPrompt{0}; - runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); + std::array counterPrompt{0}, counterNonPrompt{0}, counterBeauty{0}; + runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt, counterBeauty); static_for<0, NCharmMesonChannels - 1>([&](auto i) { // Charm mesons constexpr int Index = i.value; registry.fill(HIST("PromptCharmMesons/hCountPrompt") + HIST(ParticleNames[Index]), counterPrompt[Index]); @@ -562,7 +644,7 @@ struct HfTaskMcValidationGen { }); static_for([&](auto i) { // Beauty hadrons constexpr int Index = i.value; - registry.fill(HIST("Beauty/hCount") + HIST(ParticleNames[Index]), counterPrompt[Index]); + registry.fill(HIST("Beauty/hCount") + HIST(ParticleNames[Index]), counterBeauty[Index]); }); static_for([&](auto i) { // Charm baryons constexpr int Index = i.value; @@ -581,8 +663,8 @@ struct HfTaskMcValidationGen { for (const auto& mcCollision : mcCollisions) { const auto recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); - std::array counterPrompt{0}, counterNonPrompt{0}; - runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); + std::array counterPrompt{0}, counterNonPrompt{0}, counterBeauty{0}; + runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt, counterBeauty); static_for<0, NCharmMesonChannels - 1>([&](auto i) { // Charm mesons constexpr int Index = i.value; registry.fill(HIST("PromptCharmMesons/hCountPrompt") + HIST(ParticleNames[Index]), counterPrompt[Index]); @@ -590,7 +672,7 @@ struct HfTaskMcValidationGen { }); static_for([&](auto i) { // Beauty constexpr int Index = i.value; - registry.fill(HIST("Beauty/hCount") + HIST(ParticleNames[Index]), counterPrompt[Index]); + registry.fill(HIST("Beauty/hCount") + HIST(ParticleNames[Index]), counterBeauty[Index]); }); static_for([&](auto i) { // Charm baryons constexpr int Index = i.value; @@ -609,8 +691,8 @@ struct HfTaskMcValidationGen { for (const auto& mcCollision : mcCollisions) { const auto recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); const auto mcParticlesPerMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); - std::array counterPrompt{0}, counterNonPrompt{0}; - runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); + std::array counterPrompt{0}, counterNonPrompt{0}, counterBeauty{0}; + runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt, counterBeauty); static_for<0, NCharmMesonChannels - 1>([&](auto i) { // Charm mesons constexpr int Index = i.value; registry.fill(HIST("PromptCharmMesons/hCountPrompt") + HIST(ParticleNames[Index]), counterPrompt[Index]); @@ -618,7 +700,7 @@ struct HfTaskMcValidationGen { }); static_for([&](auto i) { // Beauty mesons constexpr int Index = i.value; - registry.fill(HIST("Beauty/hCount") + HIST(ParticleNames[Index]), counterPrompt[Index]); + registry.fill(HIST("Beauty/hCount") + HIST(ParticleNames[Index]), counterBeauty[Index]); }); static_for([&](auto i) { // Charm baryons constexpr int Index = i.value; @@ -639,6 +721,7 @@ struct HfTaskMcValidationRec { Preslice perCol = aod::track::collisionId; Configurable eventGeneratorType{"eventGeneratorType", -1, "If positive, enable event selection using subGeneratorId information. The value indicates which events to keep (0 = MB, 4 = charm triggered, 5 = beauty triggered)"}; + Configurable searchUpToQuark{"searchUpToQuark", true, "Search up to quark level when determining the origin of a particle (prompt vs non-prompt)"}; Configurable storeOccupancy{"storeOccupancy", false, "Store collision occupancy for dedicated studies"}; std::array, NChannels> histDeltaPt, histDeltaPx, histDeltaPy, histDeltaPz, histDeltaSecondaryVertexX, histDeltaSecondaryVertexY, histDeltaSecondaryVertexZ, histDeltaDecayLength; @@ -921,7 +1004,7 @@ struct HfTaskMcValidationRec { for (const auto& trackColl1 : tracksColl1) { if (trackColl1.has_mcParticle() && trackColl1.isPVContributor()) { auto particleColl1 = trackColl1.mcParticle(); - auto origin = RecoDecay::getCharmHadronOrigin(mcParticles, particleColl1, true); + auto origin = RecoDecay::getParticleOrigin(mcParticles, particleColl1, searchUpToQuark); if (origin == RecoDecay::NonPrompt) { nFromBeautyColl1++; } @@ -931,7 +1014,7 @@ struct HfTaskMcValidationRec { for (const auto& trackColl2 : tracksColl2) { if (trackColl2.has_mcParticle() && trackColl2.isPVContributor()) { auto particleColl2 = trackColl2.mcParticle(); - auto origin = RecoDecay::getCharmHadronOrigin(mcParticles, particleColl2, true); + auto origin = RecoDecay::getParticleOrigin(mcParticles, particleColl2, searchUpToQuark); if (origin == RecoDecay::NonPrompt) { nFromBeautyColl2++; } @@ -960,7 +1043,7 @@ struct HfTaskMcValidationRec { if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { continue; } - auto origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, true); + auto origin = RecoDecay::getParticleOrigin(mcParticles, particle, searchUpToQuark); histTracks->Fill(origin, track.pt()); bool const isAmbiguous = (track.compatibleCollIds().size() != 1); if (isAmbiguous) { diff --git a/PWGJE/Core/JetHFUtilities.h b/PWGJE/Core/JetHFUtilities.h index a018c0c177b..1a52ba5019c 100644 --- a/PWGJE/Core/JetHFUtilities.h +++ b/PWGJE/Core/JetHFUtilities.h @@ -609,58 +609,33 @@ bool isHFDaughterTrack(T& track, U& candidate) * @param particles particle table */ template -auto matchedHFParticle(const T& candidate, const U& /*tracks*/, const V& /*particles*/, bool& isMatched) +auto matchedHFParticle(const T& candidate, const U& /*tracks*/, const V& /*particles*/) { typename V::iterator candidateDaughterParticle; - isMatched = false; if constexpr (isD0Candidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { - candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); } if constexpr (isDplusCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { - candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); } if constexpr (isDsCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { - candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); } if constexpr (isDstarCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { - candidateDaughterParticle = candidate.template prong2_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong2_as().template mcParticle_as(); } if constexpr (isLcCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { - candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); } if constexpr (isB0Candidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::B0ToDminusPi) { - candidateDaughterParticle = candidate.template prong3_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong3_as().template mcParticle_as(); } if constexpr (isBplusCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::BplusToD0Pi) { - candidateDaughterParticle = candidate.template prong2_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong2_as().template mcParticle_as(); } if constexpr (isXicToXiPiPiCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == o2::aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) { - candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); - isMatched = true; - } + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); } return candidateDaughterParticle.template mothers_first_as(); } @@ -675,13 +650,8 @@ auto matchedHFParticle(const T& candidate, const U& /*tracks*/, const V& /*parti template auto matchedHFParticleId(const T& candidate, const U& tracks, const V& particles) { - bool isMatched = false; - auto matchedParticle = matchedHFParticle(candidate, tracks, particles, isMatched); - if (isMatched) { - return matchedParticle.globalIndex(); - } else { - return int64_t{-1}; // does this clash with the case where a track doesnt have an associated particle? - } + auto matchedParticle = matchedHFParticle(candidate, tracks, particles); + return matchedParticle.globalIndex(); } /** diff --git a/PWGJE/DataModel/JetReducedDataDQ.h b/PWGJE/DataModel/JetReducedDataDQ.h index 6246e4c808c..2f401108a87 100644 --- a/PWGJE/DataModel/JetReducedDataDQ.h +++ b/PWGJE/DataModel/JetReducedDataDQ.h @@ -154,29 +154,29 @@ namespace jdummydq DECLARE_SOA_COLUMN(DummyDQ, dummyDQ, bool); } // namespace jdummydq -DECLARE_SOA_TABLE(JDielectron1Dummys, "AOD", "JDIEL1DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JDielectron1Dummys, "JDIEL1DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JDielectron2Dummys, "AOD", "JDIEL2DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<2>); +DECLARE_SOA_TABLE_STAGED(JDielectron2Dummys, "JDIEL2DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<2>); -DECLARE_SOA_TABLE(JDielectron3Dummys, "AOD", "JDIEL3DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<3>); +DECLARE_SOA_TABLE_STAGED(JDielectron3Dummys, "JDIEL3DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<3>); -DECLARE_SOA_TABLE(JDielectron4Dummys, "AOD", "JDIEL4DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<4>); +DECLARE_SOA_TABLE_STAGED(JDielectron4Dummys, "JDIEL4DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<4>); -DECLARE_SOA_TABLE(JDielectron5Dummys, "AOD", "JDIEL5DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<5>); +DECLARE_SOA_TABLE_STAGED(JDielectron5Dummys, "JDIEL5DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<5>); -DECLARE_SOA_TABLE(JDielectron6Dummys, "AOD", "JDIEL6DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<6>); +DECLARE_SOA_TABLE_STAGED(JDielectron6Dummys, "JDIEL6DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<6>); } // namespace o2::aod diff --git a/PWGJE/Tasks/CMakeLists.txt b/PWGJE/Tasks/CMakeLists.txt index 3fa812e1308..6a3e2c8bd9a 100644 --- a/PWGJE/Tasks/CMakeLists.txt +++ b/PWGJE/Tasks/CMakeLists.txt @@ -444,4 +444,8 @@ if(FastJet_FOUND) SOURCES jetHadronsPid.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-upc-qa + SOURCES jetUpcQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils O2Physics::SGCutParHolder + COMPONENT_NAME Analysis) endif() diff --git a/PWGJE/Tasks/jetChargedV2.cxx b/PWGJE/Tasks/jetChargedV2.cxx index b1e780571d7..05d897db26f 100644 --- a/PWGJE/Tasks/jetChargedV2.cxx +++ b/PWGJE/Tasks/jetChargedV2.cxx @@ -345,19 +345,19 @@ struct JetChargedV2 { registry.add("h2_phi_rholocal_absDelta", "#varphi vs #rho(#varphi)absDelta, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); registry.add("h2_centrality_pT", "centrality vs p_{T}; p_{T}; centrality ", {HistType::kTH2F, {{210, -10.0, 200.0}, {100, 0., 100}}}); - registry.add("h2_rholocal_cent", "#centrality vs #rho(#varphi); #centrality; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_averagerho_cent", "#centrality vs #rho; #centrality; #rho ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_rholocal_cent", "#centrality vs #rho(#varphi); #centrality; #rho(#varphi) ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_averagerho_cent", "#centrality vs #rho; #centrality; #rho ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_rholocal_pt", "#varphi vs #it{p}_{T}; #it{p}_{T}; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_rholocal_raw_pt", "#varphi vs #it{p}_{T}; #it{p}_{T} - #rhoArea; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_rholocal_pt_inplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_rholocal_pt_outplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_rholocal_pt", "#varphi vs #it{p}_{T}; #it{p}_{T}; #rho(#varphi) ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_rholocal_raw_pt", "#varphi vs #it{p}_{T}; #it{p}_{T} - #rhoArea; #rho(#varphi) ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_rholocal_pt_inplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; #rho(#varphi) ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_rholocal_pt_outplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; #rho(#varphi) ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); registry.add("h2_phi_averagerho_absDelta", "#varphi vs #rho(0)absDelta, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); - registry.add("h2_averagerho_pt", "#varphi vs #it{p}_{T}; #it{p}_{T}; <#rho> ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_averagerho_raw_pt", "#varphi vs #it{p}_{T}; #it{p}_{T} - <#rho>Area; <#rho> ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_averagerho_pt_inplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; <#rho> ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); - registry.add("h2_averagerho_pt_outplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; <#rho> ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_averagerho_pt", "#varphi vs #it{p}_{T}; #it{p}_{T}; <#rho> ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_averagerho_raw_pt", "#varphi vs #it{p}_{T}; #it{p}_{T} - <#rho>Area; <#rho> ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_averagerho_pt_inplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; <#rho> ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); + registry.add("h2_averagerho_pt_outplane", "#varphi vs #it{p}_{T}; #it{p}_{T}; <#rho> ", {HistType::kTH2F, {{110, -10., 100}, {210, -10.0, 200.0}}}); registry.add("h2_phi_rholocal_absDelta_low", "#varphi vs #rho(#varphi)absDeltaLow, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); registry.add("h2_phi_rholocal_absDelta_medium", "#varphi vs #rho(#varphi)absDeltaMediun, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); @@ -370,6 +370,14 @@ struct JetChargedV2 { registry.add("h2_phi_rholocal_absDelta_low_outplane", "#varphi vs #rho(#varphi)absDeltaLow outplane, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); registry.add("h2_phi_rholocal_absDelta_medium_outplane", "#varphi vs #rho(#varphi)absDeltaMediun outplane, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); registry.add("h2_phi_rholocal_absDelta_high_outplane", "#varphi vs #rho(#varphi)absDeltahigh outplane, absDelta; #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{40, 0., o2::constants::math::TwoPI}, {210, -10.0, 200.0}}}); + + registry.add("h_good_bad_ugly", "local rho large than 0, less than 0 and total", {HistType::kTH1F, {{5, 0.0, 5.0}}}); + registry.get(HIST("h_good_bad_ugly"))->GetXaxis()->SetBinLabel(1, "#rho_{local} > 0"); + registry.get(HIST("h_good_bad_ugly"))->GetXaxis()->SetBinLabel(2, "#rho_{local} <= 0"); + registry.get(HIST("h_good_bad_ugly"))->GetXaxis()->SetBinLabel(3, "#rho_{local} total"); + registry.add("h_jet_pt_badRhoLocal", "local rho info, Jet Pt", {HistType::kTH1F, {jetPtAxis}}); + registry.add("h_jet_phi_badRhoLocal", "local rho info, Jet #phi ", {HistType::kTH1F, {phiAxis}}); + registry.add("h_jet_eta_badRhoLocal", "local rho info, Jet #eta ", {HistType::kTH1F, {jetEtaAxis}}); //< \sigma p_T at local rho test plot | end > registry.add("h_jet_pt_inclusive_v2", "jet pT rhoareasubtracted;#it{p}_{T,jet} (GeV/#it{c}); entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); @@ -379,14 +387,22 @@ struct JetChargedV2 { registry.add("leadJetEta", "leadJet constituent #eta ", {HistType::kTH1F, {{100, -1.0, 1.0}}}); //< RC test plots >// - registry.add("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphi", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphi_abs", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphi_abs_in", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphi_abs_out", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet_abs", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet_abs", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); - registry.add("h1_distribution_RC", "RC #phi-#Psi_{2}", {HistType::kTH1F, {{72, 0.0, o2::constants::math::TwoPI}}}); - registry.add("h1_distribution_random", "RC #phi-#Psi_{2}", {HistType::kTH1F, {{72, 0.0, o2::constants::math::TwoPI}}}); - registry.add("h3_randomizedPhi_check", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet_abs_in", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet_abs_out", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}; #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet_abs_in", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + registry.add("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet_abs_out", "centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho}(#varphi); #Delta#varphi_{jet}", {HistType::kTH3F, {{100, 0.0, 100.0}, {400, -200.0, 200.0}, {100, 0., o2::constants::math::TwoPI}}}); + + // registry.add("h1_distribution_RC", "RC #phi-#Psi_{2}", {HistType::kTH1F, {{72, 0.0, o2::constants::math::TwoPI}}}); //< bkg sub plot | end >// //< median rho >// @@ -710,7 +726,6 @@ struct JetChargedV2 { occupancyIsGood = true; } - float centrality = -1.0; switch (centralityMode) { case 1: centrality = collision.centFT0M(); @@ -809,7 +824,7 @@ struct JetChargedV2 { // create h_ptsum_sumpt_fit, with number of Track template - void getNtrk(T const& tracks, U const& jets, int& nTrk, double& evtnum, double& leadingJetEta) + void getNtrk(T const& tracks, U const& jets, int& nTrk, double& evtnumNtrk, double& leadingJetEta) { if (jets.size() > 0) { for (auto const& track : tracks) { @@ -820,13 +835,13 @@ struct JetChargedV2 { nTrk += 1; } } - registry.fill(HIST("h_evtnum_NTrk"), evtnum, nTrk); + registry.fill(HIST("h_evtnum_NTrk"), evtnumNtrk, nTrk); } } // fill nTrk plot for fit rho(varphi) template - void fillNtrkCheck(U const& tracks, J const& jets, TH1F* hPtsumSumptFit, double& leadingJetEta) + void fillNtrkCheck(U const& tracks, J const& jets, TH1F* hPtsumSumptFitFill, double& leadingJetEta) { if (jets.size() > 0) { double localRhoFitPtMin = 0.2; @@ -842,7 +857,7 @@ struct JetChargedV2 { registry.fill(HIST("h_accept_Track"), 2.5); if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > selectedJetsRadius) && track.pt() >= localRhoFitPtMin && track.pt() <= localRhoFitPtMax) { registry.fill(HIST("h_accept_Track"), 3.5); - hPtsumSumptFit->Fill(track.phi(), track.pt()); + hPtsumSumptFitFill->Fill(track.phi(), track.pt()); } } } @@ -866,7 +881,7 @@ struct JetChargedV2 { // Run General_Purpose MC MCP template - void fitFncAreaSubMCP(U const& collision, J const& jets, TH1F* hPtsumSumptFitMCP, bool mcLevelIsParticleLevel, float weight = 1.0) + void fitFncAreaSubMCP(U const& collision, J const& jets, TH1F* hPtsumSumptFitMCPFill, bool mcLevelIsParticleLevel, float weight = 1.0) { float centrality = -1.0; switch (centralityMode) { @@ -909,23 +924,20 @@ struct JetChargedV2 { fFitModulationV2v3P->SetParameter(1, 0.01); fFitModulationV2v3P->SetParameter(3, 0.01); - double ep2fix = 0.; - double ep3fix = 0.; - if (ep2 < 0) { - ep2fix = RecoDecay::constrainAngle(ep2); + double ep2fix = RecoDecay::constrainAngle(ep2); fFitModulationV2v3P->FixParameter(2, ep2fix); } else { fFitModulationV2v3P->FixParameter(2, ep2); } if (ep3 < 0) { - ep3fix = RecoDecay::constrainAngle(ep3); + double ep3fix = RecoDecay::constrainAngle(ep3); fFitModulationV2v3P->FixParameter(4, ep3fix); } else { fFitModulationV2v3P->FixParameter(4, ep3); } - hPtsumSumptFitMCP->Fit(fFitModulationV2v3P, "Q", "ep", 0, o2::constants::math::TwoPI); + hPtsumSumptFitMCPFill->Fit(fFitModulationV2v3P, "Q", "ep", 0, o2::constants::math::TwoPI); // double temppara[5]; std::array temppara{}; @@ -1092,7 +1104,7 @@ struct JetChargedV2 { } template - void fillGeoMatchedCorrHistograms(TBase const& jetMCD, TF1* fFitModulationRM, float tempparaA, double ep2, float rho, bool subtractMCPBackground, float mcrho, float weight = 1.0) + void fillGeoMatchedCorrHistograms(TBase const& jetMCD, TF1* fFitModulationRMFill, float tempparaA, double ep2, float rho, bool subtractMCPBackgroundBool, float mcrho, float weight = 1.0) { float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); if (jetMCD.pt() > pTHatMaxMCD * pTHat) { @@ -1119,12 +1131,12 @@ struct JetChargedV2 { int evtPlnAngleA = 7; int evtPlnAngleB = 3; int evtPlnAngleC = 5; - double integralValue = fFitModulationRM->Integral(jetMCD.phi() - selectedJetsRadius, jetMCD.phi() + selectedJetsRadius); + double integralValue = fFitModulationRMFill->Integral(jetMCD.phi() - selectedJetsRadius, jetMCD.phi() + selectedJetsRadius); double rholocal = rho / (2 * selectedJetsRadius * tempparaA) * integralValue; double corrBasejetpt = jetMCD.pt() - (rholocal * jetMCD.area()); double corrTagjetpt = 0.0; - if (subtractMCPBackground) { - double integralValueMCP = fFitModulationRM->Integral(jetMCP.phi() - selectedJetsRadius, jetMCP.phi() + selectedJetsRadius); + if (subtractMCPBackgroundBool) { + double integralValueMCP = fFitModulationRMFill->Integral(jetMCP.phi() - selectedJetsRadius, jetMCP.phi() + selectedJetsRadius); double rholocalMCP = mcrho / (2 * selectedJetsRadius * tempparaA) * integralValueMCP; corrTagjetpt = jetMCP.pt() - (rholocalMCP * jetMCP.area()); } else { @@ -1435,9 +1447,9 @@ struct JetChargedV2 { double ep3 = 0.; int cfgNmodA = 2; int cfgNmodB = 3; - int evtPlnAngleA = 7; - int evtPlnAngleB = 3; - int evtPlnAngleC = 5; + int evtPlnAngleA = 3; + // int evtPlnAngleB = 3; + // int evtPlnAngleC = 5; for (uint i = 0; i < cfgnMods->size(); i++) { int nmode = cfgnMods->at(i); int detInd = detId * 4 + cfgnTotalSystem * 4 * (nmode - 2); @@ -1460,17 +1472,14 @@ struct JetChargedV2 { fFitModulationV2v3->SetParameter(1, 0.01); fFitModulationV2v3->SetParameter(3, 0.01); - double ep2fix = 0.; - double ep3fix = 0.; - if (ep2 < 0) { - ep2fix = RecoDecay::constrainAngle(ep2); + double ep2fix = RecoDecay::constrainAngle(ep2); fFitModulationV2v3->FixParameter(2, ep2fix); } else { fFitModulationV2v3->FixParameter(2, ep2); } if (ep3 < 0) { - ep3fix = RecoDecay::constrainAngle(ep3); + double ep3fix = RecoDecay::constrainAngle(ep3); fFitModulationV2v3->FixParameter(4, ep3fix); } else { fFitModulationV2v3->FixParameter(4, ep3); @@ -1597,10 +1606,17 @@ struct JetChargedV2 { double rholocal = 0.0; if (integralValue <= 0) { rholocal = collision.rho(); + registry.fill(HIST("h_jet_pt_badRhoLocal"), jet.pt(), 1.0); + registry.fill(HIST("h_jet_phi_badRhoLocal"), jet.phi(), 1.0); + registry.fill(HIST("h_jet_eta_badRhoLocal"), jet.eta(), 1.0); + registry.fill(HIST("h_good_bad_ugly"), 1.5); + // LOGF(info, "integral rho_local got 0, checking jet info: pT=%.1f, eta=%.1f, phi=%.1f, integralValue=%.1f", jet.pt(), jet.eta(), jet.phi(), integralValue); } else { // integralValue = fFitModulationV2v3->Integral(phi - selectedJetsRadius, phi + selectedJetsRadius); rholocal = collision.rho() / (2 * selectedJetsRadius * temppara[0]) * integralValue; + registry.fill(HIST("h_good_bad_ugly"), 0.5); } + registry.fill(HIST("h_good_bad_ugly"), 2.5); if (nmode == cfgNmodA) { double phiMinusPsi2 = 0.0; @@ -1642,7 +1658,8 @@ struct JetChargedV2 { histosQA.fill(HIST("h2_ep2_FT0C_FT0M_bumpRegion"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode), helperEP.GetEventPlane(collision.qvecRe()[detIndFT0M + 3], collision.qvecIm()[detIndFT0M + 3], nmode), collision.cent()); } - if ((absDelta < o2::constants::math::PIQuarter) || (absDelta >= evtPlnAngleA * o2::constants::math::PIQuarter) || (absDelta >= evtPlnAngleB * o2::constants::math::PIQuarter && absDelta < evtPlnAngleC * o2::constants::math::PIQuarter)) { + // if ((absDelta < o2::constants::math::PIQuarter) || (absDelta >= evtPlnAngleA * o2::constants::math::PIQuarter) || (absDelta >= evtPlnAngleB * o2::constants::math::PIQuarter && absDelta < evtPlnAngleC * o2::constants::math::PIQuarter)) { + if (absDelta < o2::constants::math::PIQuarter || absDelta >= evtPlnAngleA * o2::constants::math::PIQuarter) { registry.fill(HIST("h_jet_pt_in_plane_v2"), jet.pt() - (collision.rho() * jet.area()), 1.0); registry.fill(HIST("h2_centrality_jet_pt_in_plane_v2"), centrality, jet.pt() - (collision.rho() * jet.area()), 1.0); @@ -1679,7 +1696,8 @@ struct JetChargedV2 { phiMinusPsi3 = RecoDecay::constrainAngle(jet.phi() - ep3, -o2::constants::math::PI); float absDelta3 = std::abs(phiMinusPsi3); - if ((absDelta3 < o2::constants::math::PIQuarter) || (absDelta3 >= evtPlnAngleA * o2::constants::math::PIQuarter) || (absDelta3 >= evtPlnAngleB * o2::constants::math::PIQuarter && absDelta3 < evtPlnAngleC * o2::constants::math::PIQuarter)) { + // if ((absDelta3 < o2::constants::math::PIQuarter) || (absDelta3 >= evtPlnAngleA * o2::constants::math::PIQuarter) || (absDelta3 >= evtPlnAngleB * o2::constants::math::PIQuarter && absDelta3 < evtPlnAngleC * o2::constants::math::PIQuarter)) { + if (absDelta3 < o2::constants::math::PIQuarter || absDelta3 >= evtPlnAngleA * o2::constants::math::PIQuarter) { registry.fill(HIST("h_jet_pt_in_plane_v3"), jet.pt() - (collision.rho() * jet.area()), 1.0); registry.fill(HIST("h_jet_pt_in_plane_v3_rho"), jet.pt() - (rholocal * jet.area()), 1.0); } else { @@ -1694,67 +1712,44 @@ struct JetChargedV2 { float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); float randomConePt = 0; - double integralValueRC = fFitModulationV2v3->Integral(randomConePhi - randomConeR, randomConePhi + randomConeR); - double rholocalRC = collision.rho() / (2 * randomConeR * temppara[0]) * integralValueRC; + double integralValueRC = 0.0; + double rholocalRC = 0.0; + integralValueRC = fFitModulationV2v3->Integral(randomConePhi - randomConeR, randomConePhi + randomConeR); + rholocalRC = collision.rho() / (2 * randomConeR * temppara[0]) * integralValueRC; int nmode = cfgnMods->at(i); if (nmode == cfgNmodA) { double rcPhiPsi2 = 0.0; - double rcPhiPsi2Rand = 0.0; - - // randomized φ check test - float randomPhiTest = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); - float randomEtaTest = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); - float randomConePtTest = 0.0; - // randomized φ check test end + // double rcPhiPsi2Rand = 0.0; + float absRcPhiPsi2 = 0.0; // rcPhiPsi2 = randomConePhi - ep2; rcPhiPsi2 = RecoDecay::constrainAngle(randomConePhi - ep2, -o2::constants::math::PI); - // if (rcPhiPsi2 < 0) rcPhiPsi2 += o2::constants::math::TwoPI; - if (rcPhiPsi2 < 0) { - rcPhiPsi2 = RecoDecay::constrainAngle(rcPhiPsi2, 0.0F); - } - - rcPhiPsi2Rand = RecoDecay::constrainAngle(randomPhiTest - ep2, -o2::constants::math::PI); - // if (rcPhiPsi2Rand < 0) rcPhiPsi2Rand += o2::constants::math::TwoPI; - if (rcPhiPsi2Rand < 0) { - rcPhiPsi2Rand = RecoDecay::constrainAngle(rcPhiPsi2Rand, 0.0F); - } + absRcPhiPsi2 = std::abs(rcPhiPsi2); for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { - // float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, -o2::constants::math::PI); - // float dEta = track.eta() - randomConeEta; - // if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - // randomConePt += track.pt(); - // } float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, -o2::constants::math::PI); float dEta = track.eta() - randomConeEta; if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { randomConePt += track.pt(); } - - float dPhiTest = RecoDecay::constrainAngle(track.phi() - randomPhiTest, -o2::constants::math::PI); - float dEtaTest = track.eta() - randomEtaTest; - if (std::sqrt(dEtaTest * dEtaTest + dPhiTest * dPhiTest) < randomConeR) { - randomConePtTest += track.pt(); - } } } - registry.fill(HIST("h1_distribution_RC"), rcPhiPsi2); - registry.fill(HIST("h1_distribution_random"), rcPhiPsi2Rand); - registry.fill(HIST("h3_randomizedPhi_check"), centrality, randomConePtTest - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), rcPhiPsi2Rand, 1.0); + // registry.fill(HIST("h1_distribution_RC"), rcPhiPsi2); registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphi"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, rcPhiPsi2, 1.0); - + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphi_abs"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, absRcPhiPsi2, 1.0); + if (absRcPhiPsi2 < o2::constants::math::PIQuarter || absRcPhiPsi2 >= evtPlnAngleA * o2::constants::math::PIQuarter) { + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphi_abs_in"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, absRcPhiPsi2, 1.0); + } else { + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphi_abs_out"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, absRcPhiPsi2, 1.0); + } // removing the leading jet from the random cone if (jets.size() > 0) { // if there are no jets in the acceptance (from the jetfinder cuts) then there can be no leading jet - // float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, -o2::constants::math::PI); - // float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; float dPhiLeadingJet = RecoDecay::constrainAngle(leadingJetPhi - randomConePhi, -o2::constants::math::PI); float dEtaLeadingJet = leadingJetEta - randomConeEta; bool jetWasInCone = false; - // while ((randomConeLeadJetDeltaR <= 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { while ((randomConeLeadJetDeltaR <= 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < leadingJetR + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { jetWasInCone = true; randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); @@ -1764,13 +1759,12 @@ struct JetChargedV2 { } if (jetWasInCone) { randomConePt = 0.0; + integralValueRC = fFitModulationV2v3->Integral(randomConePhi - randomConeR, randomConePhi + randomConeR); + rholocalRC = collision.rho() / (2 * randomConeR * temppara[0]) * integralValueRC; + rcPhiPsi2 = RecoDecay::constrainAngle(randomConePhi - ep2, -o2::constants::math::PI); + absRcPhiPsi2 = std::abs(rcPhiPsi2); + for (auto const& track : tracks) { - // if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > randomConeR)) { // if track selection is uniformTrack, dcaXY and dcaZ cuts need to be added as they aren't in the selection so that they can be studied here - // float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, -o2::constants::math::PI); - // float dEta = track.eta() - randomConeEta; - // if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - // randomConePt += track.pt(); - // } if (jetderiveddatautilities::selectTrack(track, trackSelection)) { // if track selection is uniformTrack, dcaXY and dcaZ cuts need to be added as they aren't in the selection so that they can be studied here float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, -o2::constants::math::PI); float dEta = track.eta() - randomConeEta; @@ -1783,6 +1777,17 @@ struct JetChargedV2 { } registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, rcPhiPsi2, 1.0); registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), rcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet_abs"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, absRcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet_abs"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), absRcPhiPsi2, 1.0); + + if (absRcPhiPsi2 < o2::constants::math::PIQuarter || absRcPhiPsi2 >= evtPlnAngleA * o2::constants::math::PIQuarter) { + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet_abs_in"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, absRcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet_abs_in"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), absRcPhiPsi2, 1.0); + } else { + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_localrhovsphiwithoutleadingjet_abs_out"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, absRcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet_abs_out"), centrality, randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), absRcPhiPsi2, 1.0); + } + } else if (nmode == cfgNmodB) { continue; } diff --git a/PWGJE/Tasks/jetCorrelationD0.cxx b/PWGJE/Tasks/jetCorrelationD0.cxx index 1196c7b52a4..e60e16c1a7f 100644 --- a/PWGJE/Tasks/jetCorrelationD0.cxx +++ b/PWGJE/Tasks/jetCorrelationD0.cxx @@ -33,13 +33,13 @@ #include +#include #include #include #include +#include #include -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -86,8 +86,7 @@ DECLARE_SOA_COLUMN(D0MD, d0MD, float); DECLARE_SOA_COLUMN(D0PtD, d0PtD, float); DECLARE_SOA_COLUMN(D0EtaD, d0EtaD, float); DECLARE_SOA_COLUMN(D0PhiD, d0PhiD, float); -DECLARE_SOA_COLUMN(D0MatchedFrom, d0MatchedFrom, int); -DECLARE_SOA_COLUMN(D0SelectedAs, d0SelectedAs, int); +DECLARE_SOA_COLUMN(D0Category, d0Category, int); DECLARE_SOA_COLUMN(D0DecayChannel, d0DecayChannel, int8_t); } // namespace d0Info @@ -114,9 +113,7 @@ DECLARE_SOA_TABLE(D0McDTables, "AOD", "D0MCDTABLE", d0Info::D0Eta, d0Info::D0Phi, d0Info::D0Y, - d0Info::D0MatchedFrom, - d0Info::D0SelectedAs, - d0Info::D0DecayChannel); + d0Info::D0Category); DECLARE_SOA_TABLE(D0McPTables, "AOD", "D0MCPTABLE", o2::soa::Index<>, @@ -357,17 +354,36 @@ struct JetCorrelationD0 { int matchedFrom = 0; int selectedAs = 0; + int category = -1; // -1 undefined, 0 signal, 1 reflection, 2-5 correlated backgrounds + constexpr int kD0ToKPi = 1; + constexpr int kD0ToKPiPi = 2; + constexpr int kD0ToPiPi = 3; + constexpr int kD0ToPiPiPi = 4; + constexpr int kD0ToKK = 5; if (d0DecayChannel > 0) { // matched to a D0 on truth level (any channel) matchedFrom = 1; } else if (d0DecayChannel < 0) { // matched to a D0bar on truth level (any channel) matchedFrom = -1; } - if (d0Candidate.candidateSelFlag() & BIT(0)) { // CandidateSelFlag == BIT(0) -> selected as D0 + if ((d0Candidate.candidateSelFlag() & BIT(0)) != 0) { // CandidateSelFlag == BIT(0) -> selected as D0 selectedAs = 1; - } else if (d0Candidate.candidateSelFlag() & BIT(1)) { // CandidateSelFlag == BIT(1) -> selected as D0bar + } else if ((d0Candidate.candidateSelFlag() & BIT(1)) != 0) { // CandidateSelFlag == BIT(1) -> selected as D0bar selectedAs = -1; } + if ((std::abs(d0DecayChannel) == kD0ToKPi) && (matchedFrom != 0) && (selectedAs == matchedFrom)) { + category = 0; // signal -> D0 or D0bar, Ï€+ K− + } else if ((d0DecayChannel == kD0ToKPi) && (selectedAs == -1 * matchedFrom)) { + category = 1; // reflection + } else if (d0DecayChannel == kD0ToKPiPi) { + category = 2; // corr bkg: Ï€+ K− Ï€0 + } else if (d0DecayChannel == kD0ToPiPi) { + category = 3; // corr bkg: Ï€+ π− + } else if (d0DecayChannel == kD0ToPiPiPi) { + category = 4; // corr bkg: Ï€+ π− Ï€0 + } else if (d0DecayChannel == kD0ToKK) { + category = 5; // corr bkg: K+ K− + } tableD0McDetector(tableCollision.lastIndex(), // might want to add some more detector level D0 quantities like prompt or non prompt info scores[2], @@ -378,9 +394,7 @@ struct JetCorrelationD0 { d0Candidate.eta(), d0Candidate.phi(), d0Candidate.y(), - matchedFrom, - selectedAs, - d0DecayChannel); + category); for (const auto& jet : jets) { if (jet.pt() < jetPtCutMin) { continue; @@ -456,11 +470,7 @@ struct JetCorrelationD0 { if (d0Candidate.pt() < d0PtCutMin) { // once settled on a mlcut, then add the lower bound of the systematics as a cut here continue; } - bool isMatched = false; - const auto& d0Particle = jethfutilities::matchedHFParticle(d0Candidate, tracks, particles, isMatched); - if (!isMatched) { - continue; - } + const auto& d0Particle = jethfutilities::matchedHFParticle(d0Candidate, tracks, particles); for (const auto& McDJet : McDJets) { if (McDJet.pt() < jetPtCutMin) { continue; diff --git a/PWGJE/Tasks/jetDsSpecSubs.cxx b/PWGJE/Tasks/jetDsSpecSubs.cxx index 68b90850fc2..eec30bba067 100644 --- a/PWGJE/Tasks/jetDsSpecSubs.cxx +++ b/PWGJE/Tasks/jetDsSpecSubs.cxx @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -77,12 +78,26 @@ struct JetDsSpecSubs { using DsMCDJets = soa::Join; using DsMCPJets = soa::Join; + using DsMCPJetsOnTheFly = soa::Join; + + using DsDataJetsEWS = soa::Join< + aod::DsChargedEventWiseSubtractedJets, + aod::DsChargedEventWiseSubtractedJetConstituents>; + + // Inclusive charged jets + using ChargedJets = soa::Join; + using ChargedJetsEWS = soa::Join; + // Slices for access to proper HF MCD jet collision that is associated to MCCollision PresliceUnsorted collisionsPerMCCollisionPreslice = aod::jmccollisionlb::mcCollisionId; + Preslice dsMCDJetsPerEXPCollisionPreslice = aod::jet::collisionId; + // Preslice dsMCDJetsEWSPerEXPCollisionPreslice = aod::jet::collisionId; + Preslice dsMCPJetsPerMCCollisionPreslice = aod::jet::mcCollisionId; + // Preslice dsMCPJetsEWSPerMCCollisionPreslice = aod::jet::mcCollisionId; - // Configurables + // Event configurables Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; @@ -90,6 +105,10 @@ struct JetDsSpecSubs { Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + // Event-wise constituent subtraction jet tables + Configurable centralityMin{"centralityMin", -999.f, "Minimum FT0M centrality"}; + Configurable centralityMax{"centralityMax", 999.f, "Maximum FT0M centrality"}; + // internals std::vector eventSelectionBits; int trackSelection = -1; @@ -97,113 +116,207 @@ struct JetDsSpecSubs { // Filters Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); // Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter collisionFilter = + nabs(aod::jcollision::posZ) < vertexZCut && + aod::jcollision::centFT0M >= centralityMin && + aod::jcollision::centFT0M < centralityMax; // Filtered jet tables using FilteredDsDataJets = soa::Filtered; using FilteredDsMCDJets = soa::Filtered; using FilteredDsMCPJets = soa::Filtered; - //============= - // Histograms - //============= - - HistogramRegistry registry{ - "registry", - { - {"h_collisions", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}}, - {"h_event_counter_data", ";Selection step;Events", {HistType::kTH1F, {{3, 0.5, 3.5}}}}, - - {"h_track_pt", ";#it{p}_{T,track};entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_track_eta", ";#eta_{track};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"h_track_phi", ";#varphi_{track};entries", {HistType::kTH1F, {{80, -1., 7.}}}}, - - // Data histograms - {"h_jet_pt_data", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_jet_eta_data", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_jet_phi_data", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - - {"h_ds_mass_data", ";m_{D_{S}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.15}}}}, - {"h_ds_pt_data", ";#it{p}_{T,D_{S}} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}}, - {"h_ds_eta_data", ";#eta_{D_{S}};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"h_ds_phi_data", ";#phi_{D_{S}};entries", {HistType::kTH1F, {{80, -1., 7.}}}}, - - {"h_ds_jet_projection_data", ";z^{D_{S},jet}_{||};entries", {HistType::kTH1F, {{200, 0., 1.2}}}}, - {"h_ds_jet_distance_data", ";#DeltaR_{D_{S},jet};entries", {HistType::kTH1F, {{200, 0., 1.}}}}, - {"h_ds_jet_mass_data", ";m_{jet}^{ch} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 0., 25.}}}}, - {"h_ds_jet_lambda11_data", ";#lambda_{1}^{1};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"h_ds_jet_lambda12_data", ";#lambda_{2}^{1};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"hSparse_ds_data", ";m_{D_{S}};#it{p}_{T,D_{S}};#it{p}_{T,jet};z^{D_{S},jet}_{||};#DeltaR_{D_{S},jet}", {HistType::kTHnSparseF, {{60, 1.7, 2.15}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.0}}}}, - - // MC general histograms - {"McEffJet", "N_{jet};", {HistType::kTH1F, {{4, 0., 4.0}}}}, - {"McEffCol", "N_{collisions};", {HistType::kTH1F, {{4, 0., 4.0}}}}, - - // MC detector-level histograms - {"h_jet_pt_mcd", "detector-level jet pT;#it{p}_{T,jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_jet_eta_mcd", "detector-level jet #eta;#eta_{jet}^{det};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_jet_phi_mcd", "detector-level jet #phi;#phi_{jet}^{det};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - - {"h_ds_pt_mcd", ";#it{p}_{T,D_{S} jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}}, - {"h_ds_eta_mcd", ";#eta_{D_{S} jet}^{det};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"h_ds_phi_mcd", ";#phi_{D_{S} jet}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}}, - {"h_ds_mass_mcd", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.15}}}}, - - {"h_ds_jet_lambda11_mcd", ";#lambda_{1}^{1, det};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"h_ds_jet_lambda12_mcd", ";#lambda_{2}^{1, det};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - - // MCD - Sparse 1: mass, p_{T,Ds}, p_{T,jet}, z|| and prompt/non-prompt - {"hSparse_ds_mcd1", ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||, det};Origin(D_{S})", {HistType::kTHnSparseF, {{60, 1.7, 2.15}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {2, -0.5, 1.5}}}}, - // MCD - Sparse 2: p_{T,Ds}, p_{T,jet}, and DeltaR - {"hSparse_ds_mcd2", ";#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.0}}}}, - // MCD - Sparse 3: p_{T,jet}, z|| and DeltaR - {"hSparse_ds_mcd3", ";#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||, det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.0}}}}, - - // MC particle-level histograms - {"h_jet_pt_mcp", "particle-level jet pT;#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}}, - {"h_jet_eta_mcp", "particle-level jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, - {"h_jet_phi_mcp", "particle-level jet #phi;#phi_{jet}^{part};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - - {"h_ds_pt_mcp", ";#it{p}_{T,D_{S} jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}}, - {"h_ds_eta_mcp", ";#eta_{D_{S} jet}^{part};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"h_ds_phi_mcp", ";#phi_{D_{S} jet}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}}, - - {"h_ds_jet_lambda11_mcp", ";#lambda_{1}^{1, part};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"h_ds_jet_lambda12_mcp", ";#lambda_{2}^{1, part};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - - // MCP - Sparse: p_{T,Ds}, p_{T,jet}, z|| and DeltaR - {"hSparse_ds_mcp", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||, part};#DeltaR_{D_{S},jet}^{part}", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.0}}}}, - }}; + using FilteredDsDataJetsEWS = soa::Filtered; + // using FilteredDsMCDJetsEWS = soa::Filtered; + // using FilteredDsMCPJetsEWS = soa::Filtered; + + // Filtered inclusive charged jets + using FilteredChargedJets = soa::Filtered; + using FilteredChargedJetsEWS = soa::Filtered; + + using FilteredDsMCPJetsOnTheFly = soa::Filtered; + + //===================================================================================== + // Histogram definitions + //===================================================================================== + + HistogramRegistry registry; + + void addInclusiveQAHistograms() + { + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{10, 0., 10.}}}); + + // Track QA + registry.add("h_track_pt", ";#it{p}_{T,track};entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_track_eta", ";#eta_{track};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_track_phi", ";#varphi_{track};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Inclusive charged-jet QA + registry.add("h_njets_inclusive", ";Number of charged jets per event;Events", {HistType::kTH1F, {{100, 0., 100.}}}); + registry.add("h_jet_pt_inclusive", ";#it{p}_{T,jet} (GeV/#it{c});Entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta_inclusive", ";#eta_{jet};Entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_jet_phi_inclusive", ";#varphi_{jet} (rad);Entries", {HistType::kTH1F, {{80, -1., 7.}}}); + registry.add("h_jet_mass_inclusive", ";#it{m}_{jet} (GeV/#it{c}^{2});Entries", {HistType::kTH1F, {{120, 0., 60.}}}); + registry.add("h_jet_nconst_inclusive", ";Jet constituents;Entries", {HistType::kTH1F, {{100, 0., 100.}}}); + registry.add("h_lambda11_inclusive", ";#lambda_{1}^{1};Entries", {HistType::kTH1F, {{100, 0., 1.}}}); + registry.add("h_lambda21_inclusive", ";#lambda_{2}^{1};Entries", {HistType::kTH1F, {{100, 0., 1.}}}); + } + + void addDataHistograms() + { + registry.add("h_event_counter_data", ";Selection step;Events", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + + // Jet QA + registry.add("h_jet_pt_data", "jet pT;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta_data", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_jet_phi_data", "jet #phi;#varphi_{jet};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Ds QA + registry.add("h_ds_mass_data", ";m_{D_{S}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.15}}}); + registry.add("h_ds_pt_data", ";#it{p}_{T,D_{S}} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}); + registry.add("h_ds_eta_data", ";#eta_{D_{S}};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_ds_phi_data", ";#varphi_{D_{S}};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Ds-tagged jet observables + registry.add("h_ds_jet_projection_data", ";z^{D_{S},jet}_{||};entries", {HistType::kTH1F, {{200, 0., 1.2}}}); + registry.add("h_ds_jet_distance_data", ";#DeltaR_{D_{S},jet};entries", {HistType::kTH1F, {{200, 0., 1.}}}); + registry.add("h_ds_jet_mass_data", ";m_{jet}^{ch} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 0., 25.}}}); + registry.add("h_ds_jet_lambda11_data", ";#lambda_{1}^{1};entries", {HistType::kTH1F, {{100, 0., 1.}}}); + registry.add("h_ds_jet_lambda21_data", ";#lambda_{2}^{1};entries", {HistType::kTH1F, {{100, 0., 1.}}}); + + // Main data sparse + registry.add("hSparse_ds_data", ";m_{D_{S}};#it{p}_{T,D_{S}};#it{p}_{T,jet};z^{D_{S},jet}_{||};#DeltaR_{D_{S},jet}", {HistType::kTHnSparseF, {{60, 1.6, 2.3}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}}}); + + auto hEventCounter = registry.get(HIST("h_event_counter_data")); + hEventCounter->GetXaxis()->SetBinLabel(1, "Input collisions"); + hEventCounter->GetXaxis()->SetBinLabel(2, "Event selection"); + hEventCounter->GetXaxis()->SetBinLabel(3, "|z| < 10 cm"); + } + + void addMCEfficiencyHistograms() + { + // General MC counters + registry.add("McEffJet", "N_{jet};", {HistType::kTH1F, {{4, 0., 4.}}}); + registry.add("McEffCol", "N_{collisions};", {HistType::kTH1F, {{4, 0., 4.}}}); + + // Detector-level jet QA + registry.add("h_jet_pt_mcd", "detector-level jet pT;#it{p}_{T,jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta_mcd", "detector-level jet #eta;#eta_{jet}^{det};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_jet_phi_mcd", "detector-level jet #varphi;#varphi_{jet}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Detector-level Ds QA + registry.add("h_ds_pt_mcd", ";#it{p}_{T,D_{S}}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_ds_eta_mcd", ";#eta_{D_{S}}^{det};entries", {HistType::kTH1F, {{60, -1., 1.}}}); + registry.add("h_ds_phi_mcd", ";#varphi_{D_{S}}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + registry.add("h_ds_mass_mcd", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{200, 1.7, 2.15}}}); + + // Detector-level sparse histograms + registry.add("hSparse_ds_mcd1", ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};Origin(D_{S})", {HistType::kTHnSparseF, {{60, 1.6, 2.3}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {2, -0.5, 1.5}}}); + registry.add("hSparse_ds_mcd2", ";#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.}}}); + registry.add("hSparse_ds_mcd3", ";#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}}}); + + // Particle-level jet QA + registry.add("h_jet_pt_mcp", "particle-level jet pT;#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta_mcp", "particle-level jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_jet_phi_mcp", "particle-level jet #varphi;#varphi_{jet}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Particle-level Ds QA + registry.add("h_ds_pt_mcp", ";#it{p}_{T,D_{S}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_ds_eta_mcp", ";#eta_{D_{S}}^{part};entries", {HistType::kTH1F, {{60, -1., 1.}}}); + registry.add("h_ds_phi_mcp", ";#varphi_{D_{S}}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Particle-level sparse with origin and matching status + registry.add("hSparse_ds_mcp", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||,part};#DeltaR_{D_{S},jet}^{part};Origin(D_{S});Matching status", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}, {2, -0.5, 1.5}, {2, -0.5, 1.5}}}); + + auto mcCollisionCounter = registry.get(HIST("McEffCol")); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::All, "MC collisions"); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::ZCut, "MC collisions passing z cut"); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::Matched, "Matched reconstructed collisions"); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::MatchedSel8ZCut, "Matched collisions passing selections"); + + auto jetCounter = registry.get(HIST("McEffJet")); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetInMCCollision, "Detector-level jets"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetInMCCollision, "Particle-level jets"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetWithMatchedCandidate, "Detector jets matched to particle"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate, "Particle jets matched to detector"); + + auto hSparseMCD = registry.get(HIST("hSparse_ds_mcd1")); + hSparseMCD->GetAxis(4)->SetBinLabel(1, "Prompt"); + hSparseMCD->GetAxis(4)->SetBinLabel(2, "Non-prompt"); + + auto hSparseMCP = registry.get(HIST("hSparse_ds_mcp")); + hSparseMCP->GetAxis(4)->SetBinLabel(1, "Prompt"); + hSparseMCP->GetAxis(4)->SetBinLabel(2, "Non-prompt"); + hSparseMCP->GetAxis(5)->SetBinLabel(1, "Unmatched"); + hSparseMCP->GetAxis(5)->SetBinLabel(2, "Matched"); + } + + void addMCPOnTheFlyHistograms() + { + registry.add("h_event_counter_mcp_on_the_fly", ";Selection step;MC collisions", {HistType::kTH1F, {{2, 0.5, 2.5}}}); + + // Particle-level jet QA + registry.add("h_jet_pt_mcp_on_the_fly", ";#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_eta_mcp_on_the_fly", ";#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_jet_phi_mcp_on_the_fly", ";#varphi_{jet}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Particle-level Ds QA + registry.add("h_ds_pt_mcp_on_the_fly", ";#it{p}_{T,D_{S}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_ds_eta_mcp_on_the_fly", ";#eta_{D_{S}}^{part};entries", {HistType::kTH1F, {{60, -1., 1.}}}); + registry.add("h_ds_phi_mcp_on_the_fly", ";#varphi_{D_{S}}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + + // Theoretical particle-level sparse + registry.add("hSparse_ds_mcp_on_the_fly", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||,part};#DeltaR_{D_{S},jet}^{part};Origin(D_{S})", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}, {2, -0.5, 1.5}}}); + + auto hCounter = registry.get(HIST("h_event_counter_mcp_on_the_fly")); + hCounter->GetXaxis()->SetBinLabel(1, "Generated collisions"); + hCounter->GetXaxis()->SetBinLabel(2, "|z_{vtx}^{gen}| < cut"); + + auto hSparse = registry.get(HIST("hSparse_ds_mcp_on_the_fly")); + hSparse->GetAxis(4)->SetBinLabel(1, "Prompt"); + hSparse->GetAxis(4)->SetBinLabel(2, "Non-prompt"); + } + //======== // INIT //======== void init(InitContext const&) { + // Initialise event and track selection criteria eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - auto hEvt = registry.get(HIST("h_event_counter_data")); - hEvt->GetXaxis()->SetBinLabel(1, "Input collisions"); - hEvt->GetXaxis()->SetBinLabel(2, "Event selection"); - hEvt->GetXaxis()->SetBinLabel(3, "|z| < 10 cm"); + // Prevent simultaneous execution of processes using alternative jet collections + if (doprocessCollisions && doprocessCollisionsEWS) { + throw std::runtime_error("Enable either processCollisions or processCollisionsEWS, not both simultaneously"); + } - // Labels - auto mcCollisionCounter = registry.get(HIST("McEffCol")); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::All, "mccollisions"); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::ZCut, "z_cut"); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::Matched, "collisions"); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::MatchedSel8ZCut, "sel8"); + if (doprocessDataChargedSubstructure && doprocessDataChargedSubstructureEWS) { + throw std::runtime_error("Enable either processDataChargedSubstructure or processDataChargedSubstructureEWS, not both simultaneously"); + } + // Determine which histogram groups are required + const bool doInclusiveQA = doprocessCollisions || doprocessCollisionsEWS; + const bool doData = doprocessDataChargedSubstructure || doprocessDataChargedSubstructureEWS; + const bool doMCEfficiency = doprocessMonteCarloEfficiencyDs; + const bool doMCPOnTheFly = doprocessMCPOnTheFly; + + // Register histograms only if the corresponding process is enabled + if (doInclusiveQA) { + addInclusiveQAHistograms(); + } - auto jetCounter = registry.get(HIST("McEffJet")); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetInMCCollision, "particle level"); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetInMCCollision, "detector level"); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetWithMatchedCandidate, "particle matched jets"); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate, "detector matched jets"); - - auto hSparse_ds_mcd1 = registry.get(HIST("hSparse_ds_mcd1")); - auto* axisOrigin = hSparse_ds_mcd1->GetAxis(4); - axisOrigin->SetBinLabel(1, "Prompt"); - axisOrigin->SetBinLabel(2, "Non-prompt"); + if (doData) { + addDataHistograms(); + } + + if (doMCEfficiency) { + addMCEfficiencyHistograms(); + } + + if (doMCPOnTheFly) { + addMCPOnTheFlyHistograms(); + } } //=============== // Lambda compute @@ -263,35 +376,76 @@ struct JetDsSpecSubs { // Collision QA //============== - void processCollisions(aod::JetCollision const& collision, aod::JetTracks const& tracks) + // This function is shared by the pp and Pb–Pb (event-wise subtraction) + template + void fillInclusiveJetQA(aod::JetCollision const& collision, + aod::JetTracks const& tracks, + JetTable const& jets) { - registry.fill(HIST("h_collisions"), 0.5); + // Collision counter + registry.fill(HIST("h_collisions"), getValFromBin(AllCollisions)); if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } + registry.fill(HIST("h_collisions"), getValFromBin(Sel8ZCut)); - registry.fill(HIST("h_collisions"), 1.5); - + // Track QA for (auto const& track : tracks) { - if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { - return; + continue; } registry.fill(HIST("h_track_pt"), track.pt()); registry.fill(HIST("h_track_eta"), track.eta()); registry.fill(HIST("h_track_phi"), track.phi()); } + + // Inclusive charged-jet QA + registry.fill(HIST("h_njets_inclusive"), jets.size()); + + for (auto const& jet : jets) { + + registry.fill(HIST("h_jet_pt_inclusive"), jet.pt()); + registry.fill(HIST("h_jet_eta_inclusive"), jet.eta()); + registry.fill(HIST("h_jet_phi_inclusive"), jet.phi()); + + auto constituents = jet.template tracks_as(); + + registry.fill(HIST("h_jet_nconst_inclusive"), constituents.size()); + + registry.fill(HIST("h_jet_mass_inclusive"), computeJetMass(constituents)); + registry.fill(HIST("h_lambda11_inclusive"), computeLambda(jet, constituents, 1.f, 1.f)); + registry.fill(HIST("h_lambda21_inclusive"), computeLambda(jet, constituents, 2.f, 1.f)); + } + } + // Inclusive charged-jet QA for pp collisions + void processCollisions(aod::JetCollision const& collision, + aod::JetTracks const& tracks, + FilteredChargedJets const& jets) + { + fillInclusiveJetQA(collision, tracks, jets); } PROCESS_SWITCH(JetDsSpecSubs, processCollisions, "collision QA", false); + // Inclusive charged-jet QA for Pb–Pb collisions using + // event-wise constituent-subtracted jets + void processCollisionsEWS(aod::JetCollision const& collision, + aod::JetTracks const& tracks, + FilteredChargedJetsEWS const& jets) + { + fillInclusiveJetQA(collision, tracks, jets); + } + PROCESS_SWITCH(JetDsSpecSubs, processCollisionsEWS, "collision QA EWS", false); - //============== - // DATA process - //============== + //===================================================================================== + // DATA function + //===================================================================================== - void processDataChargedSubstructure(aod::JetCollision const& collision, FilteredDsDataJets const& jets, - aod::CandidatesDsData const&, aod::JetTracks const&) + // Common implementation of the Ds-in-jet analysis for data + // Shared by the pp and Pb–Pb (event-wise subtraction) workflows + template + void analyseDataDsJet(aod::JetCollision const& collision, + JetTable const& jets) { registry.fill(HIST("h_event_counter_data"), 1); @@ -311,17 +465,17 @@ struct JetDsSpecSubs { registry.fill(HIST("h_jet_eta_data"), jet.eta()); registry.fill(HIST("h_jet_phi_data"), jet.phi()); - auto jetTracks = jet.tracks_as(); + auto jetTracks = jet.template tracks_as(); const float lambda11 = computeLambda(jet, jetTracks, 1.f, 1.f); - const float lambda12 = computeLambda(jet, jetTracks, 2.f, 1.f); + const float lambda21 = computeLambda(jet, jetTracks, 2.f, 1.f); const float mjet = computeJetMass(jetTracks); TVector3 jetVector(jet.px(), jet.py(), jet.pz()); - // Loop over Ds candidates (particle level) - for (const auto& dsCandidate : jet.candidates_as()) { + // Loop over Ds candidates + for (const auto& dsCandidate : jet.template candidates_as()) { TVector3 dsVector(dsCandidate.px(), dsCandidate.py(), dsCandidate.pz()); @@ -337,7 +491,6 @@ struct JetDsSpecSubs { registry.fill(HIST("h_ds_phi_data"), dsCandidate.phi()); registry.fill(HIST("h_ds_jet_projection_data"), zParallel); - registry.fill(HIST("h_ds_jet_distance_data"), deltaR); // Main THnSparse: invariant mass, pT, z, and DeltaR @@ -349,40 +502,62 @@ struct JetDsSpecSubs { deltaR); } - if (!jet.candidates_as().empty()) { - // Jet mass + if (!jet.template candidates_as().empty()) { + // Jet Mass registry.fill(HIST("h_ds_jet_mass_data"), mjet); // Jet angularity if (lambda11 >= 0.f) { registry.fill(HIST("h_ds_jet_lambda11_data"), lambda11); } - if (lambda12 >= 0.f) { - registry.fill(HIST("h_ds_jet_lambda12_data"), lambda12); + if (lambda21 >= 0.f) { + registry.fill(HIST("h_ds_jet_lambda21_data"), lambda21); } } } } + + //===================================================================================== + // DATA process + //===================================================================================== + + // Data analysis using standard charged jets (pp) + void processDataChargedSubstructure(aod::JetCollision const& collision, + FilteredDsDataJets const& jets, + aod::CandidatesDsData const&, + aod::JetTracks const&) + { + analyseDataDsJet(collision, jets); + } PROCESS_SWITCH(JetDsSpecSubs, processDataChargedSubstructure, "Data charged jets", false); - //============== + // Data analysis using event-wise constituent-subtracted charged jets (Pb–Pb) + void processDataChargedSubstructureEWS(aod::JetCollision const& collision, + FilteredDsDataJetsEWS const& jets, + aod::CandidatesDsData const&, + aod::JetTracks const&) + { + analyseDataDsJet(collision, jets); + } + PROCESS_SWITCH(JetDsSpecSubs, processDataChargedSubstructureEWS, "Data charged jets EWS", false); + + //===================================================================================== // MC function - //============== - template - void analyseMonteCarloEfficiency(MCDJetsPerMCCollissionPreslice const& jetmcdpreslice, - MCPJetsPerMCCollissionPreslice const& jetmcppreslice, + void analyseMonteCarloEfficiency(MCDJetsPerCollisionPreslice const& jetmcdpreslice, + MCPJetsPerCollisionPreslice const& jetmcppreslice, aod::JetMcCollisions const& mccollisions, aod::JetCollisionsMCD const& collisions, - FilteredDsMCDJets const& mcdjets, - FilteredDsMCPJets const& mcpjets, - DsCandidatesMCD const& /*mcdCandidates*/, - DsCandidatesMCP const& /*mcpCandidates*/, - aod::JetTracks const& tracks) + MCDJetTable const& mcdjets, + MCPJetTable const& mcpjets, + DsCandidatesMCD const&, + DsCandidatesMCP const&) { for (const auto& mccollision : mccollisions) { // Count all generated MC collisions @@ -434,15 +609,12 @@ struct JetDsSpecSubs { float mcd_zParallel = (mcd_jetvector * mcd_candvector) / (mcd_jetvector * mcd_jetvector); // Axis distance Delta_R float mcd_deltaR = jetutilities::deltaR(mcdjet, mcdDscand); - float mcd_lambda11 = computeLambda(mcdjet, tracks, 1.f, 1.f); - float mcd_lambda12 = computeLambda(mcdjet, tracks, 2.f, 1.f); // Detector-level Jet Histograms registry.fill(HIST("h_jet_pt_mcd"), mcdjet.pt()); registry.fill(HIST("h_jet_eta_mcd"), mcdjet.eta()); registry.fill(HIST("h_jet_phi_mcd"), mcdjet.phi()); - registry.fill(HIST("h_ds_jet_lambda11_mcd"), mcd_lambda11); - registry.fill(HIST("h_ds_jet_lambda12_mcd"), mcd_lambda12); + // Detector-level Ds Histgrams registry.fill(HIST("h_ds_pt_mcd"), mcdDscand.pt()); registry.fill(HIST("h_ds_mass_mcd"), mcdDscand.m()); @@ -477,6 +649,12 @@ struct JetDsSpecSubs { // obtain leading HF particle in jet auto mcpDscand = mcpjet.template candidates_first_as(); + // Check if it's prompt 0 prompt, 1 non-prompt + int originMCP = (mcpDscand.originMcGen() != RecoDecay::OriginType::Prompt) ? 1 : 0; + + // Matching status: 1 if the particle-level jet has a detector-level partner, 0 otherwise + int isMatched = mcpjet.has_matchedJetCand() ? 1 : 0; + if (mcpjet.has_matchedJetCand()) { registry.fill(HIST("McEffJet"), getValFromBin(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate)); } @@ -487,41 +665,39 @@ struct JetDsSpecSubs { float mcp_zParallel = (mcp_jetvector * mcp_candvector) / (mcp_jetvector * mcp_jetvector); // Axis distance Delta_R float mcp_deltaR = jetutilities::deltaR(mcpjet, mcpDscand); - float mcp_lambda11 = computeLambda(mcpjet, tracks, 1.f, 1.f); - float mcp_lambda12 = computeLambda(mcpjet, tracks, 2.f, 1.f); // Particle-level Jet Histograms registry.fill(HIST("h_jet_pt_mcp"), mcpjet.pt()); registry.fill(HIST("h_jet_eta_mcp"), mcpjet.eta()); registry.fill(HIST("h_jet_phi_mcp"), mcpjet.phi()); - registry.fill(HIST("h_ds_jet_lambda11_mcp"), mcp_lambda11); - registry.fill(HIST("h_ds_jet_lambda12_mcp"), mcp_lambda12); // Particle-level Ds Histgrams registry.fill(HIST("h_ds_pt_mcp"), mcpDscand.pt()); registry.fill(HIST("h_ds_eta_mcp"), mcpDscand.eta()); registry.fill(HIST("h_ds_phi_mcp"), mcpDscand.phi()); - // Main THnSparse: invariant mass, pT, z, and DeltaR + // Main THnSparse: invariant mass, pT, z, DeltaR , and origin (prompt/non-prompt) registry.fill(HIST("hSparse_ds_mcp"), mcpDscand.pt(), mcpjet.pt(), mcp_zParallel, - mcp_deltaR); + mcp_deltaR, + originMCP, + isMatched); } } } - //============== + //===================================================================================== // MC process - //============== + //===================================================================================== + // MC efficiency analysis using standard Ds-tagged jets (pp) void processMonteCarloEfficiencyDs(aod::JetMcCollisions const& mccollisions, aod::JetCollisionsMCD const& collisions, FilteredDsMCDJets const& mcdjets, FilteredDsMCPJets const& mcpjets, DsCandidatesMCD const& mcdDscand, - DsCandidatesMCP const& mcpDscand, - aod::JetTracks const& jettracks) + DsCandidatesMCP const& mcpDscand) { analyseMonteCarloEfficiency, Preslice, @@ -535,10 +711,68 @@ struct JetDsSpecSubs { mcdjets, mcpjets, mcdDscand, - mcpDscand, - jettracks); + mcpDscand); } PROCESS_SWITCH(JetDsSpecSubs, processMonteCarloEfficiencyDs, "Non-matched and matched MC Ds and jets", false); + + //===================================================================================== + // MC particle-level process for on-the-fly simulations + //===================================================================================== + + void processMCPOnTheFly(aod::JetMcCollision const& mccollision, + FilteredDsMCPJetsOnTheFly const& mcpjets, + DsCandidatesMCP const&) + { + // Count all generated MC collisions before applying event selections + registry.fill(HIST("h_event_counter_mcp_on_the_fly"), 1); + + // Apply the generated-vertex selection + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + + // Count generated MC collisions passing the vertex selection + registry.fill(HIST("h_event_counter_mcp_on_the_fly"), 2); + + // Loop over particle-level Ds-tagged charged jets in the current MC collision + for (const auto& mcpjet : mcpjets) { + + // Retrieve the leading generated Ds candidate associated with the jet + auto mcpDscand = mcpjet.template candidates_first_as(); + + // Classify the generated Ds origin: 0 = prompt, 1 = non-prompt + const int originMCP = (mcpDscand.originMcGen() == RecoDecay::OriginType::Prompt) ? 0 : 1; + + // Build the particle-level jet and Ds momentum vectors + TVector3 jetVector(mcpjet.px(), mcpjet.py(), mcpjet.pz()); + TVector3 dsVector(mcpDscand.px(), mcpDscand.py(), mcpDscand.pz()); + + // Compute the longitudinal momentum fraction of the Ds along the jet axis + const float zParallel = (jetVector * dsVector) / (jetVector * jetVector); + + // Compute the angular distance between the Ds candidate and the jet axis + const float deltaR = jetutilities::deltaR(mcpjet, mcpDscand); + + // Fill particle-level jet QA histograms + registry.fill(HIST("h_jet_pt_mcp_on_the_fly"), mcpjet.pt()); + registry.fill(HIST("h_jet_eta_mcp_on_the_fly"), mcpjet.eta()); + registry.fill(HIST("h_jet_phi_mcp_on_the_fly"), mcpjet.phi()); + + // Fill particle-level Ds QA histograms + registry.fill(HIST("h_ds_pt_mcp_on_the_fly"), mcpDscand.pt()); + registry.fill(HIST("h_ds_eta_mcp_on_the_fly"), mcpDscand.eta()); + registry.fill(HIST("h_ds_phi_mcp_on_the_fly"), mcpDscand.phi()); + + // Store the particle-level Ds-tagged jet observables and Ds origin + registry.fill(HIST("hSparse_ds_mcp_on_the_fly"), + mcpDscand.pt(), + mcpjet.pt(), + zParallel, + deltaR, + originMCP); + } + } + PROCESS_SWITCH(JetDsSpecSubs, processMCPOnTheFly, "Process on-the-fly MC particle-level Ds-tagged jets", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/Tasks/jetHadronsPid.cxx b/PWGJE/Tasks/jetHadronsPid.cxx index 825b41c0897..74da2ac91e5 100644 --- a/PWGJE/Tasks/jetHadronsPid.cxx +++ b/PWGJE/Tasks/jetHadronsPid.cxx @@ -646,52 +646,78 @@ struct JetHadronsPid { double const buffer = 999.0; double pt = track.pt(); - double dPi = 0; - double dKa = 0; - double dPr = 0; + double distForPionsPi = 0; + double distForPionsKa = 0; + double distForPionsPr = 0; + + double distForKaonsPi = 0; + double distForKaonsKa = 0; + double distForKaonsPr = 0; + + double distForProtonsPi = 0; + double distForProtonsKa = 0; + double distForProtonsPr = 0; if (pt < cfg.ptThresholdPion) { - dPi = std::abs(track.tpcNSigmaPi()); + distForPionsPi = std::abs(track.tpcNSigmaPi()); + distForPionsKa = std::abs(track.tpcNSigmaKa()); + distForPionsPr = std::abs(track.tpcNSigmaPr()); } else { if (track.hasTOF()) { - dPi = std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()); + distForPionsPi = std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()); + distForPionsKa = std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()); + distForPionsPr = std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()); } else { - dPi = buffer; + distForPionsPi = buffer; + distForPionsKa = buffer; + distForPionsPr = buffer; } } if (pt < cfg.ptThresholdKaon) { - dKa = std::abs(track.tpcNSigmaKa()); + distForKaonsPi = std::abs(track.tpcNSigmaPi()); + distForKaonsKa = std::abs(track.tpcNSigmaKa()); + distForKaonsPr = std::abs(track.tpcNSigmaPr()); } else { if (track.hasTOF()) { - dKa = std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()); + distForKaonsPi = std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()); + distForKaonsKa = std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()); + distForKaonsPr = std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()); } else { - dKa = buffer; + distForKaonsPi = buffer; + distForKaonsKa = buffer; + distForKaonsPr = buffer; } } if (pt < cfg.ptThresholdProton) { - dPr = std::abs(track.tpcNSigmaPr()); + distForProtonsPi = std::abs(track.tpcNSigmaPi()); + distForProtonsKa = std::abs(track.tpcNSigmaKa()); + distForProtonsPr = std::abs(track.tpcNSigmaPr()); } else { if (track.hasTOF()) { - dPr = std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()); + distForProtonsPi = std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()); + distForProtonsKa = std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()); + distForProtonsPr = std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()); } else { - dPr = buffer; + distForProtonsPi = buffer; + distForProtonsKa = buffer; + distForProtonsPr = buffer; } } - bool isPiMatch = (dPi <= cfg.nSigmaCut); - bool isKaMatch = (dKa <= cfg.nSigmaCut); - bool isPrMatch = (dPr <= cfg.nSigmaCut); + bool isPiMatch = (distForPionsPi <= cfg.nSigmaCut); + bool isKaMatch = (distForKaonsKa <= cfg.nSigmaCut); + bool isPrMatch = (distForProtonsPr <= cfg.nSigmaCut); PidResult res{.isPion = false, .isKaon = false, .isProton = false}; if (cfg.pidMethod == ClosestMatch) { - if (isPiMatch && dPi < dKa && dPi < dPr) { + if (isPiMatch && distForPionsPi < distForPionsKa && distForPionsPi < distForPionsPr) { res.isPion = true; - } else if (isKaMatch && dKa < dPi && dKa < dPr) { + } else if (isKaMatch && distForKaonsKa < distForKaonsPi && distForKaonsKa < distForKaonsPr) { res.isKaon = true; - } else if (isPrMatch && dPr < dPi && dPr < dKa) { + } else if (isPrMatch && distForProtonsPr < distForProtonsPi && distForProtonsPr < distForProtonsKa) { res.isProton = true; } } else if (cfg.pidMethod == ExclusiveMatch) { @@ -703,11 +729,11 @@ struct JetHadronsPid { res.isProton = true; } } else if (cfg.pidMethod == RejectionBased) { - if (isPiMatch && dKa > cfg.rejectionSigma && dPr > cfg.rejectionSigma) { + if (isPiMatch && distForPionsKa > cfg.rejectionSigma && distForPionsPr > cfg.rejectionSigma) { res.isPion = true; - } else if (isKaMatch && dPi > cfg.rejectionSigma && dPr > cfg.rejectionSigma) { + } else if (isKaMatch && distForKaonsPi > cfg.rejectionSigma && distForKaonsPr > cfg.rejectionSigma) { res.isKaon = true; - } else if (isPrMatch && dPi > cfg.rejectionSigma && dKa > cfg.rejectionSigma) { + } else if (isPrMatch && distForProtonsPi > cfg.rejectionSigma && distForProtonsKa > cfg.rejectionSigma) { res.isProton = true; } } diff --git a/PWGJE/Tasks/jetLundPlane.cxx b/PWGJE/Tasks/jetLundPlane.cxx index ade6f2ed3b9..e956ff1e530 100644 --- a/PWGJE/Tasks/jetLundPlane.cxx +++ b/PWGJE/Tasks/jetLundPlane.cxx @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -58,11 +59,13 @@ DECLARE_SOA_COLUMN(MiniCollTag, miniCollTag, uint8_t); DECLARE_SOA_COLUMN(MiniCollMcCollisionId, miniCollMcCollisionId, int64_t); DECLARE_SOA_COLUMN(MiniCollWeight, miniCollWeight, float); DECLARE_SOA_COLUMN(MiniCollPtHard, miniCollPtHard, float); +DECLARE_SOA_COLUMN(MiniCollCentrality, miniCollCentrality, float); DECLARE_SOA_TABLE(MiniCollisions, "AOD", "MINICOLL", MiniCollTag, MiniCollMcCollisionId, MiniCollWeight, - MiniCollPtHard); + MiniCollPtHard, + MiniCollCentrality); // MiniJets -> MiniCollisions DECLARE_SOA_INDEX_COLUMN_CUSTOM(MiniCollision, miniCollision, "MINICOLLS"); @@ -220,7 +223,7 @@ std::vector buildUniqueSplittingMatches(const std::vector -std::vector buildFastJetInputs(ConstituentRangeT&& constituents, float trackPtMin) +std::vector buildFastJetInputs(ConstituentRangeT const& constituents, float trackPtMin) { std::vector fjInputs; fjInputs.reserve(64); @@ -283,6 +286,9 @@ struct JetLundPlaneUnfolding { Configurable jetEtaMax{"jetEtaMax", 0.5f, "max jet eta"}; Configurable jetR{"jetR", 0.4f, "jet radius (must match derived tables)"}; Configurable trackPtMin{"trackPtMin", 0.15f, "min constituent pT"}; + Configurable centralityMin{"centralityMin", 0.f, "minimum FT0M centrality for subtracted data"}; + Configurable centralityMax{"centralityMax", 100.f, "maximum FT0M centrality for subtracted data"}; + Configurable reclusteringAlgorithm{"reclusteringAlgorithm", 0, "reclustering algorithm: 0 = C/A, 1 = generalized-kT p=0.5 (tau)"}; Configurable nBinsJetPt{"nBinsJetPt", 200, "jet pT bins"}; Configurable jetPtMax{"jetPtMax", 200.f, "jet pT max"}; @@ -312,7 +318,7 @@ struct JetLundPlaneUnfolding { Produces outMiniSplittingsAll; Produces outMiniJetMatches; - // FastJet reclustering setup (C/A) + // FastJet reclustering setup JetFinder reclusterer; std::vector jetReclustered; @@ -403,7 +409,13 @@ struct JetLundPlaneUnfolding { // reclusterer config reclusterer.isReclustering = true; - reclusterer.algorithm = fastjet::cambridge_algorithm; + if (reclusteringAlgorithm.value == 0) { + reclusterer.algorithm = fastjet::cambridge_algorithm; + } else if (reclusteringAlgorithm.value == 1) { + reclusterer.algorithm = fastjet::genkt_algorithm; + reclusterer.fastjetExtraParam = 0.5; + } + reclusterer.jetR = 1.0; // recluster radius for declustering tree reclusterer.recombScheme = fastjet::E_scheme; reclusterer.strategy = fastjet::Best; @@ -422,6 +434,8 @@ struct JetLundPlaneUnfolding { // Type aliases using RecoJets = soa::Join; + using SubtractedRecoJets = soa::Join; using DetJetsMatched = soa::Join; @@ -537,15 +551,14 @@ struct JetLundPlaneUnfolding { } // DATA / RECO PROCESSING - void processData(soa::Filtered::iterator const&, - soa::Filtered const& jets, - aod::JetTracks const& tracks) + template + void processDataImpl(JetTableT const& jets, ConstituentTableT const& tracks, float centrality) { registry.fill(HIST("hEventCount"), 0.5); int miniCollIdx = -1; if (writeMiniAOD.value) { - outMiniCollisions(static_cast(0), int64_t{-1}, 1.f, -1.f); + outMiniCollisions(static_cast(0), int64_t{-1}, 1.f, -1.f, centrality); miniCollIdx = outMiniCollisions.lastIndex(); } for (auto const& jet : jets) { @@ -570,7 +583,27 @@ struct JetLundPlaneUnfolding { } } } - PROCESS_SWITCH(JetLundPlaneUnfolding, processData, "Reco/data Lund + jet spectra", true); + + void processData(soa::Filtered::iterator const&, + soa::Filtered const& jets, + aod::JetTracks const& tracks) + { + processDataImpl(jets, tracks, -1.f); + } + PROCESS_SWITCH(JetLundPlaneUnfolding, processData, "Unsubtracted reco/data Lund + jet spectra", true); + + void processDataEventWiseSubCentrality(soa::Filtered::iterator const& collision, + soa::Filtered const& jets, + aod::JetTracksSub const& tracks) + { + const float centrality = collision.centFT0M(); + if (centrality < centralityMin.value || centrality >= centralityMax.value) { + return; + } + processDataImpl(jets, tracks, centrality); + } + PROCESS_SWITCH(JetLundPlaneUnfolding, processDataEventWiseSubCentrality, + "Event-wise constituent-subtracted reco/data Lund with FT0M centrality", false); // MC PROCESSING (det + part + response) @@ -604,7 +637,7 @@ struct JetLundPlaneUnfolding { for (auto const& mcCollision : mcCollisions) { const int64_t mcCollisionId = mcCollision.globalIndex(); mcEventInfoById.emplace(mcCollisionId, - McEventInfo{mcCollisionId, mcCollision.weight(), mcCollision.ptHard()}); + McEventInfo{.mcCollisionId = mcCollisionId, .weight = mcCollision.weight(), .ptHard = mcCollision.ptHard()}); } std::unordered_map mcEventInfoByDetCollisionId; @@ -651,7 +684,7 @@ struct JetLundPlaneUnfolding { int partMiniCollIdx = -1; auto collIt = partMiniCollByKey.find(partCollKey); if (collIt == partMiniCollByKey.end()) { - outMiniCollisions(static_cast(0), partMcInfo.mcCollisionId, partMcInfo.weight, partMcInfo.ptHard); + outMiniCollisions(static_cast(0), partMcInfo.mcCollisionId, partMcInfo.weight, partMcInfo.ptHard, -1.f); partMiniCollIdx = outMiniCollisions.lastIndex(); partMiniCollByKey.emplace(partCollKey, partMiniCollIdx); } else { @@ -730,7 +763,7 @@ struct JetLundPlaneUnfolding { int detMiniCollIdx = -1; auto collIt = detMiniCollByKey.find(detCollKey); if (collIt == detMiniCollByKey.end()) { - outMiniCollisions(static_cast(0), detMcInfo.mcCollisionId, detMcInfo.weight, detMcInfo.ptHard); + outMiniCollisions(static_cast(0), detMcInfo.mcCollisionId, detMcInfo.weight, detMcInfo.ptHard, -1.f); detMiniCollIdx = outMiniCollisions.lastIndex(); detMiniCollByKey.emplace(detCollKey, detMiniCollIdx); } else { @@ -758,7 +791,7 @@ struct JetLundPlaneUnfolding { for (auto const& candPartJet : detJet.template matchedJetGeo_as>()) { const uint64_t candTruthKey = candPartJet.globalIndex(); - if (acceptedTruthJetKeys.find(candTruthKey) == acceptedTruthJetKeys.end()) { + if (!acceptedTruthJetKeys.contains(candTruthKey)) { continue; } @@ -853,9 +886,9 @@ struct JetLundPlaneUnfolding { for (const auto& m : splitMatches) { const auto& detS = detSpl[m.recoIdx]; const auto& partS = bestPartSpl[m.truthIdx]; - double x[6] = {detS.lnRoverDR, detS.lnkt, detJet.pt(), - partS.lnRoverDR, partS.lnkt, bestPartPt}; - h6->Fill(x); + const std::array x{detS.lnRoverDR, detS.lnkt, detJet.pt(), + partS.lnRoverDR, partS.lnkt, bestPartPt}; + h6->Fill(x.data()); registry.fill(HIST("hLnRoverDRResidual"), detS.lnRoverDR - partS.lnRoverDR); registry.fill(HIST("hLnKtResidual"), detS.lnkt - partS.lnkt); } @@ -872,7 +905,7 @@ struct JetLundPlaneUnfolding { continue; } - if (mcEventInfoById.find(partJet.mcCollisionId()) == mcEventInfoById.end()) { + if (!mcEventInfoById.contains(partJet.mcCollisionId())) { continue; } diff --git a/PWGJE/Tasks/jetSpectraEseTask.cxx b/PWGJE/Tasks/jetSpectraEseTask.cxx index 0272ebec174..d45a1af4116 100644 --- a/PWGJE/Tasks/jetSpectraEseTask.cxx +++ b/PWGJE/Tasks/jetSpectraEseTask.cxx @@ -113,6 +113,7 @@ struct JetSpectraEseTask { Configurable> cfgOccupancyPtCut{"cfgOccupancyPtCut", {0, 100}, "pT cut"}; Configurable cfgrhoPhi{"cfgrhoPhi", true, "Flag for rho(phi)"}; + Configurable cfgRhoPhiPvalCriteria{"cfgRhoPhiPvalCriteria", true, "Use instead of rho(phi) when the rho(phi) fit p-value is below 0.01"}; Configurable cfgnTotalSystem{"cfgnTotalSystem", 7, "total qvector number // look in Qvector table for this number"}; Configurable cfgnCorrLevel{"cfgnCorrLevel", 3, "QVector step: 0 = no corr, 1 = rect, 2 = twist, 3 = full"}; @@ -347,6 +348,7 @@ struct JetSpectraEseTask { registry.add("eventQA/before/hVtxZ", ";z_{vtx} (cm);entries", {HistType::kTH1F, {{vertexZAxis}}}); registry.add("eventQA/after/hVtxZ", ";z_{vtx} (cm);entries", {HistType::kTH1F, {{vertexZAxis}}}); + registry.add("eventQA/hRhoPhiCheck", "event status;event status;entries", {HistType::kTH1F, {{2, 0.0, 2.0}}}); registry.get(HIST("eventQA/hEventCounter"))->GetXaxis()->SetBinLabel(kFilteredInputEv, "Input filtered event"); registry.get(HIST("eventQA/hEventCounter"))->GetXaxis()->SetBinLabel(kEventSel, "Event selection"); @@ -607,7 +609,7 @@ struct JetSpectraEseTask { if (cfg.hEff == nullptr) { LOGF(fatal, "Could not find %s as TH1F in track efficiency list %s", efficiencyName.c_str(), cfgEfficiency.value.c_str()); } - LOGF(info, "Loaded tracking efficiency %s from %s (%p)", efficiencyName.c_str(), cfgEfficiency.value.c_str(), (void*)cfg.hEff); + LOGF(info, "Loaded tracking efficiency %s from %s", efficiencyName.c_str(), cfgEfficiency.value.c_str()); } if (!cfgEfficiency3D.value.empty()) { cfg.h3EffList = ccdb->getForTimeStamp(cfgEfficiency3D, timestamp); @@ -618,7 +620,7 @@ struct JetSpectraEseTask { if (cfg.h3Eff == nullptr) { LOGF(fatal, "Could not find %s as TH3F in 3D track efficiency list %s", efficiencyName.c_str(), cfgEfficiency3D.value.c_str()); } - LOGF(info, "Loaded 3D tracking efficiency %s from %s (%p)", efficiencyName.c_str(), cfgEfficiency3D.value.c_str(), (void*)cfg.h3Eff); + LOGF(info, "Loaded 3D tracking efficiency %s from %s", efficiencyName.c_str(), cfgEfficiency3D.value.c_str()); cfg.is3D = true; } cfg.isLoaded = true; @@ -1480,6 +1482,16 @@ struct JetSpectraEseTask { return nullptr; auto cDF = 1. - TMath::Gamma(nDF, chi2); + if constexpr (fillHist) + registry.fill(HIST("eventQA/hRhoPhiCheck"), 0.5); + const float pValue = 0.01; + if (cfgRhoPhiPvalCriteria && cDF < pValue) { + const float noFlow = 0.0f; + modulationFit->SetParameter(1, noFlow); // o2-linter: disable=magic-number (fit params) + modulationFit->SetParameter(3, noFlow); // o2-linter: disable=magic-number (fit params) + if constexpr (fillHist) + registry.fill(HIST("eventQA/hRhoPhiCheck"), 1.5); + } if constexpr (fillHist) { registry.fill(HIST("eventQA/hPValueCentCDF"), col.centFT0M(), cDF); diff --git a/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx b/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx index 4f403b404ea..9be92a9434b 100644 --- a/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx +++ b/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx @@ -32,7 +32,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using JetSubstructureOutputDielectron = JetSubstructureHFOutputTask, aod::McCollisionsDielectron, aod::CandidatesDielectronData, aod::CandidatesDielectronMCD, aod::CandidatesDielectronMCP, aod::BkgDielectronRhos, aod::BkgDielectronMcRhos, aod::JTrackDielectronSubs, soa::Join, soa::Join, aod::DielectronCJetRs, soa::Join, soa::Join, aod::DielectronCJetCOs, aod::DielectronCJetOs, aod::DielectronCJetSSOs, aod::DielectronCJetMOs, aod::DielectronCJetROs, soa::Join, aod::DielectronCMCDJetRs, soa::Join, soa::Join, aod::DielectronCMCDJetCOs, aod::DielectronCMCDJetOs, aod::DielectronCMCDJetSSOs, aod::DielectronCMCDJetMOs, aod::DielectronCMCDJetROs, aod::DielectronCMCDJetRMOs, soa::Join, soa::Join, aod::DielectronCMCPJetRs, soa::Join, soa::Join, aod::DielectronCMCPJetCOs, aod::DielectronCMCPJetMCCOs, aod::DielectronCMCPJetOs, aod::DielectronCMCPJetSSOs, aod::DielectronCMCPJetMOs, aod::DielectronCMCPJetROs, aod::DielectronCMCPJetRMOs, soa::Join, soa::Join, soa::Join, aod::DielectronCEWSJetCOs, aod::DielectronCEWSJetOs, aod::DielectronCEWSJetSSOs, aod::DielectronCEWSJetMOs, aod::StoredReducedEvents, aod::StoredDielectrons, aod::StoredDielectronsAll, aod::JDielectron1Dummys, aod::JDielectron2Dummys, aod::JDielectron3Dummys, aod::JDielectron4Dummys, aod::JDielectron5Dummys, aod::JDielectron6Dummys, aod::StoredJDielectronMcCollisions, aod::JDielectronMcRCollDummys, aod::StoredJDielectronMcs>; +using JetSubstructureOutputDielectron = JetSubstructureHFOutputTask, aod::McCollisionsDielectron, aod::CandidatesDielectronData, aod::CandidatesDielectronMCD, aod::CandidatesDielectronMCP, aod::BkgDielectronRhos, aod::BkgDielectronMcRhos, aod::JTrackDielectronSubs, soa::Join, soa::Join, aod::DielectronCJetRs, soa::Join, soa::Join, aod::DielectronCJetCOs, aod::DielectronCJetOs, aod::DielectronCJetSSOs, aod::DielectronCJetMOs, aod::DielectronCJetROs, soa::Join, aod::DielectronCMCDJetRs, soa::Join, soa::Join, aod::DielectronCMCDJetCOs, aod::DielectronCMCDJetOs, aod::DielectronCMCDJetSSOs, aod::DielectronCMCDJetMOs, aod::DielectronCMCDJetROs, aod::DielectronCMCDJetRMOs, soa::Join, soa::Join, aod::DielectronCMCPJetRs, soa::Join, soa::Join, aod::DielectronCMCPJetCOs, aod::DielectronCMCPJetMCCOs, aod::DielectronCMCPJetOs, aod::DielectronCMCPJetSSOs, aod::DielectronCMCPJetMOs, aod::DielectronCMCPJetROs, aod::DielectronCMCPJetRMOs, soa::Join, soa::Join, soa::Join, aod::DielectronCEWSJetCOs, aod::DielectronCEWSJetOs, aod::DielectronCEWSJetSSOs, aod::DielectronCEWSJetMOs, aod::StoredReducedEvents, aod::StoredDielectrons, aod::StoredDielectronsAll, aod::StoredJDielectron1Dummys, aod::StoredJDielectron2Dummys, aod::StoredJDielectron3Dummys, aod::StoredJDielectron4Dummys, aod::StoredJDielectron5Dummys, aod::StoredJDielectron6Dummys, aod::StoredJDielectronMcCollisions, aod::StoredJDielectronMcRCollDummys, aod::StoredJDielectronMcs>; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/Tasks/jetUpcQa.cxx b/PWGJE/Tasks/jetUpcQa.cxx new file mode 100644 index 00000000000..fa1da836679 --- /dev/null +++ b/PWGJE/Tasks/jetUpcQa.cxx @@ -0,0 +1,945 @@ +// 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 jetUpcQa.cxx +/// \brief Standalone QA task for UPC event tagging and charged-jet information. +/// \author Jaehyeok Ryu + +#include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ + +// ============================================================ +// DATA tables +// ============================================================ +namespace upcjetevent +{ +DECLARE_SOA_COLUMN(GapSide, gapSide, int); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(NeutronClass, neutronClass, int); +DECLARE_SOA_COLUMN(IsGapTagged, isGapTagged, bool); +DECLARE_SOA_COLUMN(IsZDCTagged, isZDCTagged, bool); +} // namespace upcjetevent + +DECLARE_SOA_TABLE(UpcJetEvents, "AOD", "UPCJETEVENT", + upcjetevent::GapSide, + upcjetevent::PosZ, + upcjetevent::CentFT0M, + upcjetevent::EnergyCommonZNA, + upcjetevent::EnergyCommonZNC, + upcjetevent::TimeZNA, + upcjetevent::TimeZNC, + upcjetevent::NeutronClass, + upcjetevent::IsGapTagged, + upcjetevent::IsZDCTagged); +using UpcJetEvent = UpcJetEvents::iterator; + +namespace upcjet +{ +DECLARE_SOA_INDEX_COLUMN(UpcJetEvent, upcJetEvent); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, int); +} // namespace upcjet + +DECLARE_SOA_TABLE(UpcJets, "AOD", "UPCJET", + upcjet::UpcJetEventId, + upcjet::Pt, + upcjet::Eta, + upcjet::Phi, + upcjet::Area, + upcjet::NConstituents); +using UpcJet = UpcJets::iterator; + +namespace upctrack +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEvent, upcJetEvent, int32_t, UpcJetEvents, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upctrack + +DECLARE_SOA_TABLE(UpcTracks, "AOD", "UPCTRACK", + upctrack::UpcJetEventId, + upctrack::Pt, + upctrack::Eta, + upctrack::Phi); +using UpcTrack = UpcTracks::iterator; + +namespace upcjettrack +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJet, upcJet, int32_t, UpcJets, ""); +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEvent, upcJetEvent, int32_t, UpcJetEvents, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upcjettrack + +DECLARE_SOA_TABLE(UpcJetTracks, "AOD", "UPCJETTRACK", + upcjettrack::UpcJetId, + upcjettrack::UpcJetEventId, + upcjettrack::Pt, + upcjettrack::Eta, + upcjettrack::Phi); +using UpcJetTrack = UpcJetTracks::iterator; + +// ============================================================ +// MCD tables +// ============================================================ +namespace upcjeteventmcd +{ +DECLARE_SOA_COLUMN(GapSide, gapSide, int); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(NeutronClass, neutronClass, int); +DECLARE_SOA_COLUMN(IsGapTagged, isGapTagged, bool); +DECLARE_SOA_COLUMN(IsZDCTagged, isZDCTagged, bool); +} // namespace upcjeteventmcd + +DECLARE_SOA_TABLE(UpcJetEventsMCD, "AOD", "UPCJETEVENTMCD", + upcjeteventmcd::GapSide, + upcjeteventmcd::PosZ, + upcjeteventmcd::CentFT0M, + upcjeteventmcd::EnergyCommonZNA, + upcjeteventmcd::EnergyCommonZNC, + upcjeteventmcd::TimeZNA, + upcjeteventmcd::TimeZNC, + upcjeteventmcd::NeutronClass, + upcjeteventmcd::IsGapTagged, + upcjeteventmcd::IsZDCTagged); +using UpcJetEventMCD = UpcJetEventsMCD::iterator; + +namespace upctrackmcd +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCD, upcJetEventMCD, int32_t, UpcJetEventsMCD, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upctrackmcd + +DECLARE_SOA_TABLE(UpcTracksMCD, "AOD", "UPCTRACKMCD", + upctrackmcd::UpcJetEventMCDId, + upctrackmcd::Pt, + upctrackmcd::Eta, + upctrackmcd::Phi); +using UpcTrackMCD = UpcTracksMCD::iterator; + +namespace upcjetmcd +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCD, upcJetEventMCD, int32_t, UpcJetEventsMCD, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, int); +} // namespace upcjetmcd + +DECLARE_SOA_TABLE(UpcJetsMCD, "AOD", "UPCJETMCD", + upcjetmcd::UpcJetEventMCDId, + upcjetmcd::Pt, + upcjetmcd::Eta, + upcjetmcd::Phi, + upcjetmcd::Area, + upcjetmcd::NConstituents); +using UpcJetMCD = UpcJetsMCD::iterator; + +namespace upcjettrackmcd +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetMCD, upcJetMCD, int32_t, UpcJetsMCD, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upcjettrackmcd + +DECLARE_SOA_TABLE(UpcJetTracksMCD, "AOD", "UPCJETTRACKMCD", + upcjettrackmcd::UpcJetMCDId, + upcjettrackmcd::Pt, + upcjettrackmcd::Eta, + upcjettrackmcd::Phi); +using UpcJetTrackMCD = UpcJetTracksMCD::iterator; + +// ============================================================ +// MCP tables +// ============================================================ +namespace upcjeteventmcp +{ +DECLARE_SOA_COLUMN(PosZ, posZ, float); +} // namespace upcjeteventmcp + +DECLARE_SOA_TABLE(UpcJetEventsMCP, "AOD", "UPCJETEVENTMCP", + upcjeteventmcp::PosZ); +using UpcJetEventMCP = UpcJetEventsMCP::iterator; + +namespace upctrackmcp +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCP, upcJetEventMCP, int32_t, UpcJetEventsMCP, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upctrackmcp + +DECLARE_SOA_TABLE(UpcTracksMCP, "AOD", "UPCTRACKMCP", + upctrackmcp::UpcJetEventMCPId, + upctrackmcp::Pt, + upctrackmcp::Eta, + upctrackmcp::Phi); +using UpcTrackMCP = UpcTracksMCP::iterator; + +namespace upcjetmcp +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCP, upcJetEventMCP, int32_t, UpcJetEventsMCP, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, int); +} // namespace upcjetmcp + +DECLARE_SOA_TABLE(UpcJetsMCP, "AOD", "UPCJETMCP", + upcjetmcp::UpcJetEventMCPId, + upcjetmcp::Pt, + upcjetmcp::Eta, + upcjetmcp::Phi, + upcjetmcp::Area, + upcjetmcp::NConstituents); +using UpcJetMCP = UpcJetsMCP::iterator; + +namespace upcjettrackmcp +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetMCP, upcJetMCP, int32_t, UpcJetsMCP, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upcjettrackmcp + +DECLARE_SOA_TABLE(UpcJetTracksMCP, "AOD", "UPCJETTRACKMCP", + upcjettrackmcp::UpcJetMCPId, + upcjettrackmcp::Pt, + upcjettrackmcp::Eta, + upcjettrackmcp::Phi); +using UpcJetTrackMCP = UpcJetTracksMCP::iterator; + +} // namespace o2::aod + +/// Stand-alone QA task for validating UPC event tagging for charged-jet studies. +/// The tagging and QA developed here are intended to guide a future integration +/// of the required UPC information into the PWGJE derived-data workflow. +struct JetUpcQa { + static constexpr int RequiredSingleGapA = 1; + static constexpr int RequiredSingleGapC = 2; + static constexpr int RequiredDoubleGap = 3; + + // Output tables + Produces upcJetEventTable; + Produces upcJetTable; + Produces upcJetTrackTable; + + Produces upcJetEventTableMCD; + Produces upcJetTableMCD; + Produces upcJetTrackTableMCD; + + Produces upcJetEventTableMCP; + Produces upcJetTableMCP; + Produces upcJetTrackTableMCP; + + Produces upcTrackTable; + Produces upcTrackTableMCD; + Produces upcTrackTableMCP; + + // Type aliases + using BCsWithSel = soa::Join; + using CollisionsData = soa::Join; + using TracksData = soa::Join; + using CollisionsMC = soa::Join; + using TracksMC = soa::Join; + + // Preslices + // Preslice tracksPerCollision = aod::track::collisionId; + // Preslice tracksPerCollisionMC = aod::track::collisionId; + + // SGSelector buffers + std::vector amplitudesFV0; + std::vector amplitudesFT0A; + std::vector amplitudesFT0C; + std::vector amplitudesFDDA; + std::vector amplitudesFDDC; + + // Configurables + Configurable cfgFT0AMax{"cfgFT0AMax", 100.f, "FT0A amplitude threshold"}; + Configurable cfgFT0CMax{"cfgFT0CMax", 50.f, "FT0C amplitude threshold"}; + Configurable cfgFV0AMax{"cfgFV0AMax", 100.f, "FV0A amplitude threshold"}; + Configurable cfgFDDAMax{"cfgFDDAMax", -1.f, "FDDA amplitude (-1 = ignore)"}; + Configurable cfgFDDCMax{"cfgFDDCMax", -1.f, "FDDC amplitude (-1 = ignore)"}; + Configurable cfgFITTime{"cfgFITTime", 4.f, "FIT time window (ns)"}; + Configurable cfgMinNBCs{"cfgMinNBCs", 7, "Minimum number of BCs"}; + Configurable cfgNDtcoll{"cfgNDtcoll", 1, "Time resolution multiplier for compatible BCs"}; + Configurable cfgMinNTracks{"cfgMinNTracks", 0, "Min tracks"}; + Configurable cfgMaxNTracks{"cfgMaxNTracks", 100, "Max tracks"}; + + Configurable cfgTrackPtMin{"cfgTrackPtMin", 0.15f, "Min track pT (GeV/c)"}; + Configurable cfgTrackEtaMax{"cfgTrackEtaMax", 0.9f, "Max track |eta|"}; + Configurable cfgTrackSelection{"cfgTrackSelection", "kinematicsOnly", "Reconstructed-track selection: kinematicsOnly, globalTracks, or udDefault"}; + Configurable cfgTrackDCAZMax{"cfgTrackDCAZMax", 2.f, "Maximum |DCAz| for udDefault track selection (cm)"}; + Configurable cfgTrackDCAXYMax{"cfgTrackDCAXYMax", 0.f, "Maximum |DCAxy| for udDefault (cm); 0 uses the pT-dependent UD cut"}; + Configurable cfgTrackTPCChi2NClMax{"cfgTrackTPCChi2NClMax", 4.f, "Maximum TPC chi2 per cluster for udDefault"}; + Configurable cfgTrackTPCNClsFindableMin{"cfgTrackTPCNClsFindableMin", 70, "Minimum findable TPC clusters for udDefault"}; + Configurable cfgTrackITSChi2NClMax{"cfgTrackITSChi2NClMax", 36.f, "Maximum ITS chi2 per cluster for udDefault"}; + Configurable cfgJetR{"cfgJetR", 0.4f, "Jet radius"}; + Configurable cfgJetPtMin{"cfgJetPtMin", 5.0f, "Min jet pT (GeV/c)"}; + Configurable cfgJetEtaMax{"cfgJetEtaMax", 0.5f, "Max jet |eta|"}; + Configurable cfgZDCEnergyCut{"cfgZDCEnergyCut", 10.f, "ZDC common energy threshold for Xn tagging"}; + Configurable cfgZDCTimeCut{"cfgZDCTimeCut", 2.f, "ZDC time window for Xn tagging (ns)"}; + Configurable cfgUseGapTagging{"cfgUseGapTagging", true, "Require SGSelector gap tag for event selection"}; + Configurable cfgUseZDCTagging{"cfgUseZDCTagging", false, "Require ZDC neutron tag for event selection"}; + Configurable cfgRequiredGapSide{"cfgRequiredGapSide", 0, "Required gap side when gap tagging is enabled (0 = any selected gap, 1 = SingleGapA, 2 = SingleGapC, 3 = DoubleGap)"}; + Configurable cfgRequiredNeutronClass{"cfgRequiredNeutronClass", 0, "Required neutron class when ZDC tagging is enabled (0 = any valid class, 1 = XnXn, 2 = Xn0n, 3 = 0nXn, 4 = 0n0n)"}; + + struct ZDCTagInfo { + float energyCommonZNA = -999.f; + float energyCommonZNC = -999.f; + float timeZNA = -999.f; + float timeZNC = -999.f; + int neutronClass = 0; + }; + + struct GapSelectionInfo { + int gapSide = o2::aod::sgselector::NoGap; + ZDCTagInfo zdc; + }; + + SGSelector sgSelector; + SGCutParHolder sgCuts; + + HistogramRegistry registry{"registry"}; + enum class TrackSelectionMode { + KinematicsOnly, + GlobalTracks, + UDDefault + }; + TrackSelectionMode trackSelectionMode = TrackSelectionMode::KinematicsOnly; + + // Init + void init(InitContext&) + { + if (cfgTrackSelection.value == "kinematicsOnly") { + trackSelectionMode = TrackSelectionMode::KinematicsOnly; + } else if (cfgTrackSelection.value == "globalTracks") { + trackSelectionMode = TrackSelectionMode::GlobalTracks; + } else if (cfgTrackSelection.value == "udDefault") { + trackSelectionMode = TrackSelectionMode::UDDefault; + } else { + LOGP(fatal, "Unknown cfgTrackSelection '{}'. Choose kinematicsOnly, globalTracks, or udDefault.", cfgTrackSelection.value); + } + + sgCuts.SetNDtcoll(cfgNDtcoll); + sgCuts.SetMinNBCs(cfgMinNBCs); + sgCuts.SetNTracks(cfgMinNTracks, cfgMaxNTracks); + sgCuts.SetMaxFITtime(cfgFITTime); + sgCuts.SetFITAmpLimits({cfgFV0AMax, cfgFT0AMax, cfgFT0CMax, cfgFDDAMax, cfgFDDCMax}); + + // Event-level QA only + registry.add("hGapSide", "Gap Side (Data);Gap Side;Counts", {HistType::kTH1F, {{6, -1.5, 4.5}}}); + registry.add("hGapSideMCD", "Gap Side (MCD);Gap Side;Counts", {HistType::kTH1F, {{6, -1.5, 4.5}}}); + + registry.add("hPosZ", "Vertex Z (Data);z (cm);Counts", {HistType::kTH1F, {{100, -15., 15.}}}); + registry.add("hPosZMCD", "Vertex Z (MCD);z (cm);Counts", {HistType::kTH1F, {{100, -15., 15.}}}); + registry.add("hPosZMCP", "Vertex Z (MCP);z (cm);Counts", {HistType::kTH1F, {{100, -15., 15.}}}); + + registry.add("hCentralityFT0M", "Centrality FT0M (Data);Cent;Counts", {HistType::kTH1F, {{100, 0., 100.}}}); + registry.add("hCentMCD", "Centrality FT0M (MCD);Cent;Counts", {HistType::kTH1F, {{100, 0., 100.}}}); + + registry.add("hMCDFoundBC", "MCD has_foundBC;0=false 1=true;Counts", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("hMCPNCharged", "MCP N charged primaries;N;Counts", {HistType::kTH1F, {{200, -0.5, 199.5}}}); + + registry.add("hZNAEnergy", "ZNA common energy (Data);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNCEnergy", "ZNC common energy (Data);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNATime", "ZNA time (Data);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hZNCTime", "ZNC time (Data);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hNeutronClass", "Neutron class (Data);class;Counts", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("hZNAEnergyMCD", "ZNA common energy (MCD);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNCEnergyMCD", "ZNC common energy (MCD);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNATimeMCD", "ZNA time (MCD);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hZNCTimeMCD", "ZNC time (MCD);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hNeutronClassMCD", "Neutron class (MCD);class;Counts", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("hSelectionBits", "Selection bits (Data);0 all 1 gap 2 zdc 3 accepted;Counts", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + registry.add("hSelectionBitsMCD", "Selection bits (MCD);0 all 1 gap 2 zdc 3 accepted;Counts", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + } + + template + bool isSelectedTrack(TTrack const& track) const + { + if (std::abs(track.eta()) > cfgTrackEtaMax.value || track.pt() < cfgTrackPtMin.value) { + return false; + } + if (trackSelectionMode == TrackSelectionMode::KinematicsOnly) { + return true; + } + if (trackSelectionMode == TrackSelectionMode::GlobalTracks) { + return track.isGlobalTrack(); + } + if (!track.isPVContributor()) { + return false; + } + if (std::abs(track.dcaZ()) > cfgTrackDCAZMax.value) { + return false; + } + float maxDCAxy = cfgTrackDCAXYMax.value; + if (maxDCAxy <= 0.f) { + maxDCAxy = 0.0105f + 0.035f / std::pow(track.pt(), 1.1f); + } + if (std::abs(track.dcaXY()) > maxDCAxy) { + return false; + } + if (track.tpcChi2NCl() > cfgTrackTPCChi2NClMax.value || track.tpcNClsFindable() < cfgTrackTPCNClsFindableMin.value) { + return false; + } + if (track.itsChi2NCl() > cfgTrackITSChi2NClMax.value) { + return false; + } + return true; + } + + // Helper: event tagging and selection + bool isSelectedGap(int gapSide) const + { + if (cfgRequiredGapSide.value == RequiredSingleGapA) { + return gapSide == o2::aod::sgselector::SingleGapA; + } + if (cfgRequiredGapSide.value == RequiredSingleGapC) { + return gapSide == o2::aod::sgselector::SingleGapC; + } + if (cfgRequiredGapSide.value == RequiredDoubleGap) { + return gapSide == o2::aod::sgselector::DoubleGap; + } + return gapSide == o2::aod::sgselector::SingleGapA || + gapSide == o2::aod::sgselector::SingleGapC || + gapSide == o2::aod::sgselector::DoubleGap; + } + + int getNeutronClass(ZDCTagInfo const& zdc) + { + if (zdc.energyCommonZNA < 0.f || zdc.energyCommonZNC < 0.f) { + return 0; + } + + bool aXn = zdc.energyCommonZNA > cfgZDCEnergyCut && std::abs(zdc.timeZNA) < cfgZDCTimeCut; + bool cXn = zdc.energyCommonZNC > cfgZDCEnergyCut && std::abs(zdc.timeZNC) < cfgZDCTimeCut; + bool a0n = zdc.energyCommonZNA <= cfgZDCEnergyCut; + bool c0n = zdc.energyCommonZNC <= cfgZDCEnergyCut; + + if (aXn && cXn) { + return 1; // XnXn + } + if (aXn && c0n) { + return 2; // Xn0n + } + if (a0n && cXn) { + return 3; // 0nXn + } + if (a0n && c0n) { + return 4; // 0n0n + } + return 0; + } + + bool isSelectedZDC(ZDCTagInfo const& zdc) const + { + if (cfgRequiredNeutronClass.value > 0) { + return zdc.neutronClass == cfgRequiredNeutronClass.value; + } + return zdc.neutronClass > 0; + } + + bool isAcceptedEvent(bool isGapTagged, bool isZDCTagged) const + { + return (!cfgUseGapTagging.value || isGapTagged) && + (!cfgUseZDCTagging.value || isZDCTagged); + } + + void fillSelectionBits(bool isMCD, bool isGapTagged, bool isZDCTagged, bool isAccepted) + { + if (isMCD) { + registry.fill(HIST("hSelectionBitsMCD"), 0); + if (isGapTagged) { + registry.fill(HIST("hSelectionBitsMCD"), 1); + } + if (isZDCTagged) { + registry.fill(HIST("hSelectionBitsMCD"), 2); + } + if (isAccepted) { + registry.fill(HIST("hSelectionBitsMCD"), 3); + } + return; + } + + registry.fill(HIST("hSelectionBits"), 0); + if (isGapTagged) { + registry.fill(HIST("hSelectionBits"), 1); + } + if (isZDCTagged) { + registry.fill(HIST("hSelectionBits"), 2); + } + if (isAccepted) { + registry.fill(HIST("hSelectionBits"), 3); + } + } + + template + ZDCTagInfo getZDCTagInfo(TBC const& bc) + { + ZDCTagInfo zdcInfo; + if (!bc.has_zdc()) { + return zdcInfo; + } + + auto const& zdc = bc.zdc(); + zdcInfo.energyCommonZNA = zdc.energyCommonZNA(); + zdcInfo.energyCommonZNC = zdc.energyCommonZNC(); + zdcInfo.timeZNA = zdc.timeZNA(); + zdcInfo.timeZNC = zdc.timeZNC(); + zdcInfo.neutronClass = getNeutronClass(zdcInfo); + return zdcInfo; + } + + template + GapSelectionInfo getGapSide(TCollision const& collision, TBCs const& bcs) + { + amplitudesFV0.clear(); + amplitudesFT0A.clear(); + amplitudesFT0C.clear(); + amplitudesFDDA.clear(); + amplitudesFDDC.clear(); + + GapSelectionInfo selection; + + if (!collision.has_foundBC()) { + return selection; + } + + auto const bc = collision.template foundBC_as(); + auto const bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + + auto const result = sgSelector.IsSelected(sgCuts, collision, bcRange, bc, + &litudesFV0, &litudesFT0A, &litudesFT0C, + &litudesFDDA, &litudesFDDC); + + selection.gapSide = result.value; + if (result.bc) { + selection.zdc = getZDCTagInfo(*result.bc); + } + + if (!isSelectedGap(selection.gapSide)) { + amplitudesFV0.clear(); + amplitudesFT0A.clear(); + amplitudesFT0C.clear(); + amplitudesFDDA.clear(); + amplitudesFDDC.clear(); + } + + return selection; + } + + // Helper: jet finding for detector-level tracks + template + void runJetFindingDet(TTracks const& tracks, + int evtIdx, + TJetTable& jetTable, + TTrkTable& trkTable) + { + std::vector fjInput; + fjInput.reserve(tracks.size()); + + for (auto const& t : tracks) { + if (!isSelectedTrack(t)) { + continue; + } + + fastjet::PseudoJet p; + p.reset_PtYPhiM(t.pt(), t.eta(), t.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(p); + } + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef(fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + jetTable(evtIdx, jet.pt(), jet.eta(), jet.phi_std(), + jet.area(), static_cast(constituents.size())); + int jetIdx = jetTable.lastIndex(); + + for (auto const& c : constituents) { + trkTable(jetIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + + // Helper: jet finding for particle-level MC + template + void runJetFindingMCP(aod::McParticles const& particles, + int evtIdx, + TJetTable& jetTable, + TTrkTable& trkTable) + { + std::vector fjInput; + int nCharged = 0; + + for (auto const& p : particles) { + if (!p.isPhysicalPrimary()) { + continue; + } + if (std::abs(p.eta()) > cfgTrackEtaMax) { + continue; + } + if (p.pt() < cfgTrackPtMin) { + continue; + } + + auto pdg = std::abs(p.pdgCode()); + bool charged = (pdg == kPiPlus || pdg == kKPlus || pdg == kProton || pdg == kElectron || pdg == kMuonMinus); + if (!charged) { + continue; + } + + fastjet::PseudoJet fpp; + fpp.reset_PtYPhiM(p.pt(), p.eta(), p.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(fpp); + ++nCharged; + } + + registry.fill(HIST("hMCPNCharged"), nCharged); + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef(fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + jetTable(evtIdx, jet.pt(), jet.eta(), jet.phi_std(), + jet.area(), static_cast(constituents.size())); + int jetIdx = jetTable.lastIndex(); + + for (auto const& c : constituents) { + trkTable(jetIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + + template + void fillEventTracksDet(TTracks const& tracks, int evtIdx, TTrackTable& trackTable) + { + int nAll = 0; + int nFilled = 0; + for (auto const& t : tracks) { + ++nAll; + if (!isSelectedTrack(t)) + continue; + trackTable(evtIdx, t.pt(), t.eta(), t.phi()); + ++nFilled; + } + LOGP(info, "fillEventTracksDet: evtIdx={} nAll={} nFilled={}", evtIdx, nAll, nFilled); + } + + template + void fillEventTracksMCP(aod::McParticles const& particles, int evtIdx, TTrackTable& trackTable) + { + for (auto const& p : particles) { + if (!p.isPhysicalPrimary()) + continue; + if (std::abs(p.eta()) > cfgTrackEtaMax) + continue; + if (p.pt() < cfgTrackPtMin) + continue; + + auto pdg = std::abs(p.pdgCode()); + bool charged = (pdg == kPiPlus || pdg == kKPlus || pdg == kProton || + pdg == kElectron || pdg == kMuonMinus); + if (!charged) + continue; + + trackTable(evtIdx, p.pt(), p.eta(), p.phi()); + } + } + + // Process: Data + void processData(CollisionsData::iterator const& collision, + BCsWithSel const& bcs, + aod::Zdcs const&, + aod::FT0s const&, aod::FV0As const&, aod::FDDs const&, + TracksData const& tracks) + { + auto gapInfo = getGapSide(collision, bcs); + int gapSide = gapInfo.gapSide; + bool isGapTagged = isSelectedGap(gapSide); + bool isZDCTagged = isSelectedZDC(gapInfo.zdc); + bool isAccepted = isAcceptedEvent(isGapTagged, isZDCTagged); + registry.fill(HIST("hGapSide"), gapSide); + registry.fill(HIST("hZNAEnergy"), gapInfo.zdc.energyCommonZNA); + registry.fill(HIST("hZNCEnergy"), gapInfo.zdc.energyCommonZNC); + registry.fill(HIST("hZNATime"), gapInfo.zdc.timeZNA); + registry.fill(HIST("hZNCTime"), gapInfo.zdc.timeZNC); + registry.fill(HIST("hNeutronClass"), gapInfo.zdc.neutronClass); + fillSelectionBits(false, isGapTagged, isZDCTagged, isAccepted); + + if (!isAccepted) { + return; + } + + registry.fill(HIST("hPosZ"), collision.posZ()); + registry.fill(HIST("hCentralityFT0M"), collision.centFT0M()); + + upcJetEventTable(gapSide, + collision.posZ(), + collision.centFT0M(), + gapInfo.zdc.energyCommonZNA, + gapInfo.zdc.energyCommonZNC, + gapInfo.zdc.timeZNA, + gapInfo.zdc.timeZNC, + gapInfo.zdc.neutronClass, + isGapTagged, + isZDCTagged); + int evtIdx = upcJetEventTable.lastIndex(); + + std::vector fjInput; + fjInput.reserve(256); + + for (auto const& t : tracks) { + if (t.collisionId() != collision.globalIndex()) { + continue; + } + if (!isSelectedTrack(t)) { + continue; + } + + // event-level track table + upcTrackTable(evtIdx, t.pt(), t.eta(), t.phi()); + + // jet finding input + fastjet::PseudoJet p; + p.reset_PtYPhiM(t.pt(), t.eta(), t.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(p); + } + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef( + fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + + upcJetTable(evtIdx, + jet.pt(), + jet.eta(), + jet.phi_std(), + jet.area(), + static_cast(constituents.size())); + + int jetIdx = upcJetTable.lastIndex(); + + for (auto const& c : constituents) { + upcJetTrackTable(jetIdx, evtIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + PROCESS_SWITCH(JetUpcQa, processData, "Process real data", false); + // Process: MCD + void processMCD(CollisionsMC::iterator const& collision, + BCsWithSel const& bcs, + aod::Zdcs const&, + aod::FT0s const&, aod::FV0As const&, aod::FDDs const&, + TracksMC const& tracks) + { + registry.fill(HIST("hMCDFoundBC"), collision.has_foundBC() ? 1 : 0); + + auto gapInfo = getGapSide(collision, bcs); + int gapSide = gapInfo.gapSide; + bool isGapTagged = isSelectedGap(gapSide); + bool isZDCTagged = isSelectedZDC(gapInfo.zdc); + bool isAccepted = isAcceptedEvent(isGapTagged, isZDCTagged); + registry.fill(HIST("hGapSideMCD"), gapSide); + registry.fill(HIST("hZNAEnergyMCD"), gapInfo.zdc.energyCommonZNA); + registry.fill(HIST("hZNCEnergyMCD"), gapInfo.zdc.energyCommonZNC); + registry.fill(HIST("hZNATimeMCD"), gapInfo.zdc.timeZNA); + registry.fill(HIST("hZNCTimeMCD"), gapInfo.zdc.timeZNC); + registry.fill(HIST("hNeutronClassMCD"), gapInfo.zdc.neutronClass); + fillSelectionBits(true, isGapTagged, isZDCTagged, isAccepted); + + if (!isAccepted) { + return; + } + + registry.fill(HIST("hPosZMCD"), collision.posZ()); + registry.fill(HIST("hCentMCD"), collision.centFT0M()); + + upcJetEventTableMCD(gapSide, + collision.posZ(), + collision.centFT0M(), + gapInfo.zdc.energyCommonZNA, + gapInfo.zdc.energyCommonZNC, + gapInfo.zdc.timeZNA, + gapInfo.zdc.timeZNC, + gapInfo.zdc.neutronClass, + isGapTagged, + isZDCTagged); + int evtIdx = upcJetEventTableMCD.lastIndex(); + + std::vector fjInput; + fjInput.reserve(256); + + for (auto const& t : tracks) { + if (t.collisionId() != collision.globalIndex()) { + continue; + } + if (!isSelectedTrack(t)) { + continue; + } + + upcTrackTableMCD(evtIdx, t.pt(), t.eta(), t.phi()); + + fastjet::PseudoJet p; + p.reset_PtYPhiM(t.pt(), t.eta(), t.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(p); + } + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef( + fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + + upcJetTableMCD(evtIdx, + jet.pt(), + jet.eta(), + jet.phi_std(), + jet.area(), + static_cast(constituents.size())); + + int jetIdx = upcJetTableMCD.lastIndex(); + + for (auto const& c : constituents) { + upcJetTrackTableMCD(jetIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + PROCESS_SWITCH(JetUpcQa, processMCD, "Process MC detector level", true); + + // Process: MCP + void processMCP(aod::McCollision const& mcCollision, + aod::McParticles const& particles) + { + registry.fill(HIST("hPosZMCP"), mcCollision.posZ()); + + upcJetEventTableMCP(mcCollision.posZ()); + int evtIdx = upcJetEventTableMCP.lastIndex(); + fillEventTracksMCP(particles, evtIdx, upcTrackTableMCP); + runJetFindingMCP(particles, evtIdx, upcJetTableMCP, upcJetTrackTableMCP); + } + PROCESS_SWITCH(JetUpcQa, processMCP, "Process MC particle level", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/trackEfficiency.cxx b/PWGJE/Tasks/trackEfficiency.cxx index 0968e2fd660..4840f3432c2 100644 --- a/PWGJE/Tasks/trackEfficiency.cxx +++ b/PWGJE/Tasks/trackEfficiency.cxx @@ -106,6 +106,7 @@ struct TrackEfficiency { std::vector eventSelectionBits; int trackSelection = -1; + float pTHatSettingSentinelValue = 999.0; enum AcceptSplitCollisionsOptions { NonSplitOnly = 0, @@ -425,12 +426,17 @@ struct TrackEfficiency { registry.add("h_track_pt_track_dcaxy_mcprimary", "#it{p}_{T, track} (GeV/#it{c}); primaries dca_{xy}", {HistType::kTH2F, {ptAxisEff, dcaxyAxis}}); registry.add("h_track_pt_track_dcaz_mcprimary", "#it{p}_{T, track} (GeV/#it{c}); primaries dca_{z}", {HistType::kTH2F, {ptAxisEff, dcazAxis}}); - registry.add("h_track_pt_track_dcaxy_mcsecondary", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{xy}", {HistType::kTH2F, {ptAxisEff, dcaxyAxis}}); - registry.add("h_track_pt_track_dcaz_mcsecondary", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{z}", {HistType::kTH2F, {ptAxisEff, dcazAxis}}); + registry.add("h_track_pt_track_dcaxy_mcsecondarydecay", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{xy}", {HistType::kTH2F, {ptAxisEff, dcaxyAxis}}); + registry.add("h_track_pt_track_dcaz_mcsecondarydecay", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{z}", {HistType::kTH2F, {ptAxisEff, dcazAxis}}); + registry.add("h_track_pt_track_dcaxy_mcsecondarymat", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{xy}", {HistType::kTH2F, {ptAxisEff, dcaxyAxis}}); + registry.add("h_track_pt_track_dcaz_mcsecondarymat", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{z}", {HistType::kTH2F, {ptAxisEff, dcazAxis}}); + registry.add("h_track_pt_high_track_dcaxy_mcprimary", "#it{p}_{T, track} (GeV/#it{c}); primaries dca_{xy}", {HistType::kTH2F, {ptAxisHighEff, dcaxyAxis}}); registry.add("h_track_pt_high_track_dcaz_mcprimary", "#it{p}_{T, track} (GeV/#it{c}); primaries dca_{z}", {HistType::kTH2F, {ptAxisHighEff, dcazAxis}}); - registry.add("h_track_pt_high_track_dcaxy_mcsecondary", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{xy}", {HistType::kTH2F, {ptAxisHighEff, dcaxyAxis}}); - registry.add("h_track_pt_high_track_dcaz_mcsecondary", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{z}", {HistType::kTH2F, {ptAxisHighEff, dcazAxis}}); + registry.add("h_track_pt_high_track_dcaxy_mcsecondarydecay", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{xy}", {HistType::kTH2F, {ptAxisHighEff, dcaxyAxis}}); + registry.add("h_track_pt_high_track_dcaz_mcsecondarydecay", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{z}", {HistType::kTH2F, {ptAxisHighEff, dcazAxis}}); + registry.add("h_track_pt_high_track_dcaxy_mcsecondarymat", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{xy}", {HistType::kTH2F, {ptAxisHighEff, dcaxyAxis}}); + registry.add("h_track_pt_high_track_dcaz_mcsecondarymat", "#it{p}_{T, track} (GeV/#it{c}); secondaries dca_{z}", {HistType::kTH2F, {ptAxisHighEff, dcazAxis}}); } } @@ -513,7 +519,7 @@ struct TrackEfficiency { } registry.fill(HIST("hMcCollCutsCounts"), 5.5); // at least one of the reconstructed collisions associated with this mcCollision is selected with regard to centrality - float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : simPtRef / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < pTHatSettingSentinelValue ? mcCollision.ptHard() : simPtRef / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -856,7 +862,7 @@ struct TrackEfficiency { return; } - float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : simPtRef / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < pTHatSettingSentinelValue ? collision.mcCollision().ptHard() : simPtRef / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -885,7 +891,7 @@ struct TrackEfficiency { return; } - float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < pTHatSettingSentinelValue ? collision.mcCollision().ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -910,7 +916,7 @@ struct TrackEfficiency { return; } - float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : simPtRef / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < pTHatSettingSentinelValue ? mcCollision.ptHard() : simPtRef / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -973,7 +979,7 @@ struct TrackEfficiency { return; } - float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < pTHatSettingSentinelValue ? mcCollision.ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -1067,7 +1073,7 @@ struct TrackEfficiency { registry.fill(HIST("h_collisions"), 3.5); registry.fill(HIST("h2_centrality_collisions"), centrality, 3.5); - float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : simPtRef / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < pTHatSettingSentinelValue ? collision.mcCollision().ptHard() : simPtRef / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -1104,7 +1110,7 @@ struct TrackEfficiency { registry.fill(HIST("h_collisions"), 3.5); registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); - float pTHat = collision.mcCollision().ptHard() < 999.0f ? collision.mcCollision().ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = collision.mcCollision().ptHard() < pTHatSettingSentinelValue ? collision.mcCollision().ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max return; } @@ -1119,7 +1125,7 @@ struct TrackEfficiency { // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is float eventWeight = mcCollision.weight(); - float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < pTHatSettingSentinelValue ? mcCollision.ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.ptHard()); float centrality = -1; @@ -1191,7 +1197,7 @@ struct TrackEfficiency { // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is float eventWeight = mcCollision.weight(); - float pTHat = mcCollision.ptHard() < 999.0f ? mcCollision.ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); + float pTHat = mcCollision.ptHard() < pTHatSettingSentinelValue ? mcCollision.ptHard() : simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)); registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.ptHard()); registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted"), simPtRef / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.ptHard(), eventWeight); @@ -1388,6 +1394,7 @@ struct TrackEfficiency { void processItsTpcMatchingMC(soa::Filtered::iterator const& collision, soa::Join const& jetTracks, soa::Join const&, aod::McParticles const&) { + // could be added in future: pions+kaons vs protons distinction; easy in MC but what is the procedure for data? if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { return; } @@ -1474,11 +1481,18 @@ struct TrackEfficiency { registry.fill(HIST("h_track_pt_high_track_dcaz_mcprimary"), aodTrack.pt(), aodTrack.dcaZ()); } - if (!aodMcParticleFromTrack.isPhysicalPrimary()) { - registry.fill(HIST("h_track_pt_track_dcaxy_mcsecondary"), aodTrack.pt(), aodTrack.dcaXY()); - registry.fill(HIST("h_track_pt_track_dcaz_mcsecondary"), aodTrack.pt(), aodTrack.dcaZ()); - registry.fill(HIST("h_track_pt_high_track_dcaxy_mcsecondary"), aodTrack.pt(), aodTrack.dcaXY()); - registry.fill(HIST("h_track_pt_high_track_dcaz_mcsecondary"), aodTrack.pt(), aodTrack.dcaZ()); + if (!aodMcParticleFromTrack.isPhysicalPrimary()) { // Secondaries (weak decays and material) + if (aodMcParticleFromTrack.getProcess() == kPDecay) { // Particles from decay + registry.fill(HIST("h_track_pt_track_dcaxy_mcsecondarydecay"), aodTrack.pt(), aodTrack.dcaXY()); + registry.fill(HIST("h_track_pt_track_dcaz_mcsecondarydecay"), aodTrack.pt(), aodTrack.dcaZ()); + registry.fill(HIST("h_track_pt_high_track_dcaxy_mcsecondarydecay"), aodTrack.pt(), aodTrack.dcaXY()); + registry.fill(HIST("h_track_pt_high_track_dcaz_mcsecondarydecay"), aodTrack.pt(), aodTrack.dcaZ()); + } else { // Particles from the material + registry.fill(HIST("h_track_pt_track_dcaxy_mcsecondarymat"), aodTrack.pt(), aodTrack.dcaXY()); + registry.fill(HIST("h_track_pt_track_dcaz_mcsecondarymat"), aodTrack.pt(), aodTrack.dcaZ()); + registry.fill(HIST("h_track_pt_high_track_dcaxy_mcsecondarymat"), aodTrack.pt(), aodTrack.dcaXY()); + registry.fill(HIST("h_track_pt_high_track_dcaz_mcsecondarymat"), aodTrack.pt(), aodTrack.dcaZ()); + } } } } diff --git a/PWGLF/DataModel/LFCKSSpinalignmentTables.h b/PWGLF/DataModel/LFCKSSpinalignmentTables.h index 7988f76da31..0571c108b4e 100644 --- a/PWGLF/DataModel/LFCKSSpinalignmentTables.h +++ b/PWGLF/DataModel/LFCKSSpinalignmentTables.h @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// \file LFCKSSpinalignmentTables.h -/// \brief DataModel for Charged KStar spin alignment +/// \brief DataModel for reduced K0s and pion tables for charged KStar analysis /// /// \author Prottay Das @@ -20,7 +20,6 @@ #include #include -#include #include namespace o2::aod @@ -29,77 +28,89 @@ namespace kshortpionevent { DECLARE_SOA_COLUMN(Cent, cent, float); DECLARE_SOA_COLUMN(Posz, posz, float); -// DECLARE_SOA_COLUMN(CollIndex, collIndex, float); DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); } // namespace kshortpionevent + DECLARE_SOA_TABLE(KShortpionEvents, "AOD", "KSHORTPIONEVENT", o2::soa::Index<>, kshortpionevent::Cent, kshortpionevent::Posz, - // kshortpionevent::CollIndex, kshortpionevent::PsiFT0C, kshortpionevent::PsiFT0A, - kshortpionevent::PsiTPC) + kshortpionevent::PsiTPC); + using KShortpionEvent = KShortpionEvents::iterator; -namespace kshortpionpair +// ------------------------------------------------------------ +// K0s candidate table +// ------------------------------------------------------------ +namespace kshorttrack { DECLARE_SOA_INDEX_COLUMN(KShortpionEvent, kshortpionevent); -DECLARE_SOA_COLUMN(V0Cospa, v0Cospa, float); //! V0 Cospa -DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); //! V0 Radius -DECLARE_SOA_COLUMN(DcaPositive, dcaPositive, float); //! DCA Positive -DECLARE_SOA_COLUMN(DcaNegative, dcaNegative, float); //! DCA Negative -DECLARE_SOA_COLUMN(DcaBetweenDaughter, dcaBetweenDaughter, float); //! DCA between daughters -DECLARE_SOA_COLUMN(V0Lifetime, v0Lifetime, float); //! KShort lifetime -DECLARE_SOA_COLUMN(KShortPx, kShortPx, float); //! KShort Px -DECLARE_SOA_COLUMN(KShortPy, kShortPy, float); //! KShort Py -DECLARE_SOA_COLUMN(KShortPz, kShortPz, float); //! KShort Pz -DECLARE_SOA_COLUMN(KShortMass, kShortMass, float); //! KShort Mass -DECLARE_SOA_COLUMN(PionBachPx, pionBachPx, float); //! Bachelor Pion Px -DECLARE_SOA_COLUMN(PionBachPy, pionBachPy, float); //! Bachelor Pion Py -DECLARE_SOA_COLUMN(PionBachPz, pionBachPz, float); //! Bachelor Pion Pz -/*DECLARE_SOA_COLUMN(PionBachTPC, pionBachTPC, float); //! Bachelor Pion nsigmatpc -DECLARE_SOA_COLUMN(PionBachTOFHit, pionBachTOFHit, int); //! Bachelor Pion tof hit availability -DECLARE_SOA_COLUMN(PionBachTOF, pionBachTOF, float); //! Bachelor Pion nsigmatof*/ -DECLARE_SOA_COLUMN(PionBachIndex, pionBachIndex, int); //! Bachelor Pion index -DECLARE_SOA_COLUMN(PionIndex1, pionIndex1, int); //! Daughter Pion index1 -DECLARE_SOA_COLUMN(PionIndex2, pionIndex2, int); //! Daughter Pion index2 -DECLARE_SOA_COLUMN(PionPidMask, pionPidMask, uint8_t); //! bitmask for PID selections -} // namespace kshortpionpair + +DECLARE_SOA_COLUMN(V0Cospa, v0Cospa, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(DcaPositive, dcaPositive, float); +DECLARE_SOA_COLUMN(DcaNegative, dcaNegative, float); +DECLARE_SOA_COLUMN(DcaBetweenDaughter, dcaBetweenDaughter, float); +// DECLARE_SOA_COLUMN(V0Lifetime, v0Lifetime, float); + +DECLARE_SOA_COLUMN(KShortPx, kShortPx, float); +DECLARE_SOA_COLUMN(KShortPy, kShortPy, float); +DECLARE_SOA_COLUMN(KShortPz, kShortPz, float); +DECLARE_SOA_COLUMN(KShortMass, kShortMass, float); + +DECLARE_SOA_COLUMN(PionIndex1, pionIndex1, int64_t); +DECLARE_SOA_COLUMN(PionIndex2, pionIndex2, int64_t); +} // namespace kshorttrack + DECLARE_SOA_TABLE(KShortTracks, "AOD", "KSHORTTRACK", o2::soa::Index<>, - kshortpionpair::KShortpionEventId, - kshortpionpair::V0Cospa, - kshortpionpair::V0Radius, - kshortpionpair::DcaPositive, - kshortpionpair::DcaNegative, - kshortpionpair::DcaBetweenDaughter, - kshortpionpair::V0Lifetime, - // kshortpionpair::Armenteros, - kshortpionpair::KShortPx, - kshortpionpair::KShortPy, - kshortpionpair::KShortPz, - kshortpionpair::KShortMass, - kshortpionpair::PionIndex1, - kshortpionpair::PionIndex2); + kshorttrack::KShortpionEventId, + kshorttrack::V0Cospa, + kshorttrack::V0Radius, + kshorttrack::DcaPositive, + kshorttrack::DcaNegative, + kshorttrack::DcaBetweenDaughter, + // kshorttrack::V0Lifetime, + kshorttrack::KShortPx, + kshorttrack::KShortPy, + kshorttrack::KShortPz, + kshorttrack::KShortMass, + kshorttrack::PionIndex1, + kshorttrack::PionIndex2); using KShortTrack = KShortTracks::iterator; +// ------------------------------------------------------------ +// Bachelor pion table +// ------------------------------------------------------------ +namespace piontrack +{ +DECLARE_SOA_INDEX_COLUMN(KShortpionEvent, kshortpionevent); + +DECLARE_SOA_COLUMN(PionBachPx, pionBachPx, float); +DECLARE_SOA_COLUMN(PionBachPy, pionBachPy, float); +DECLARE_SOA_COLUMN(PionBachPz, pionBachPz, float); +DECLARE_SOA_COLUMN(Charge, charge, int8_t); +DECLARE_SOA_COLUMN(PionBachIndex, pionBachIndex, int64_t); +DECLARE_SOA_COLUMN(PionPidMask, pionPidMask, uint8_t); +} // namespace piontrack + DECLARE_SOA_TABLE(PionTracks, "AOD", "PIONTRACK", o2::soa::Index<>, - kshortpionpair::KShortpionEventId, - kshortpionpair::PionBachPx, - kshortpionpair::PionBachPy, - kshortpionpair::PionBachPz, - // kshortpionpair::PionBachSign, - // kshortpionpair::PionBachTPC, - // kshortpionpair::PionBachTOFHit, - // kshortpionpair::PionBachTOF, - kshortpionpair::PionBachIndex, - kshortpionpair::PionPidMask); + piontrack::KShortpionEventId, + piontrack::PionBachPx, + piontrack::PionBachPy, + piontrack::PionBachPz, + piontrack::Charge, + piontrack::PionBachIndex, + piontrack::PionPidMask); using PionTrack = PionTracks::iterator; + } // namespace o2::aod + #endif // PWGLF_DATAMODEL_LFCKSSPINALIGNMENTTABLES_H_ diff --git a/PWGLF/DataModel/LFHStrangeCorrelationTables.h b/PWGLF/DataModel/LFHStrangeCorrelationTables.h index 34404079cbc..fc44ef7a56f 100644 --- a/PWGLF/DataModel/LFHStrangeCorrelationTables.h +++ b/PWGLF/DataModel/LFHStrangeCorrelationTables.h @@ -29,6 +29,8 @@ #include #include +#include + // Simple checker #define bitcheck(var, nbit) ((var) & (1 << (nbit))) @@ -43,8 +45,9 @@ DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true ph DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trigger"); //! DECLARE_SOA_COLUMN(MCOriginalPt, mcOriginalPt, float); // true generated pt DECLARE_SOA_COLUMN(IsLeading, isLeading, bool); // is leading track in the event +DECLARE_SOA_COLUMN(MCMask, mcMask, uint16_t); // MC mask of the MC particle } // namespace triggerTracks -DECLARE_SOA_TABLE(TriggerTracks, "AOD", "TRIGGERTRACKS", o2::soa::Index<>, triggerTracks::CollisionId, triggerTracks::MCPhysicalPrimary, triggerTracks::TrackId, triggerTracks::MCOriginalPt, triggerTracks::IsLeading); +DECLARE_SOA_TABLE(TriggerTracks, "AOD", "TRIGGERTRACKS", o2::soa::Index<>, triggerTracks::CollisionId, triggerTracks::MCPhysicalPrimary, triggerTracks::TrackId, triggerTracks::MCOriginalPt, triggerTracks::IsLeading, triggerTracks::MCMask); namespace triggerTrackExtras { DECLARE_SOA_COLUMN(Extra, extra, int); // true physical primary flag @@ -59,8 +62,9 @@ DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true phys DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Assoc"); //! DECLARE_SOA_COLUMN(MCOriginalPt, mcOriginalPt, float); // true generated pt DECLARE_SOA_COLUMN(PDGCode, pdgCode, float); // pdg code of the MC particle +DECLARE_SOA_COLUMN(MCMask, mcMask, uint16_t); // MC mask of the MC particle } // namespace assocHadrons -DECLARE_SOA_TABLE(AssocHadrons, "AOD", "ASSOCHADRONS", o2::soa::Index<>, assocHadrons::CollisionId, assocHadrons::MCPhysicalPrimary, assocHadrons::TrackId, assocHadrons::MCOriginalPt, assocHadrons::PDGCode); +DECLARE_SOA_TABLE(AssocHadrons, "AOD", "ASSOCHADRONS", o2::soa::Index<>, assocHadrons::CollisionId, assocHadrons::MCPhysicalPrimary, assocHadrons::TrackId, assocHadrons::MCOriginalPt, assocHadrons::PDGCode, assocHadrons::MCMask); /// _________________________________________ /// Table for storing assoc track PID namespace assocPID diff --git a/PWGLF/DataModel/LFKinkDecayTables.h b/PWGLF/DataModel/LFKinkDecayTables.h index 45afb41325d..0b9137d64b1 100644 --- a/PWGLF/DataModel/LFKinkDecayTables.h +++ b/PWGLF/DataModel/LFKinkDecayTables.h @@ -159,6 +159,141 @@ DECLARE_SOA_TABLE(SlimKinkCandsMC, "AOD", "SLIMKINKCANDSMC", kinkcand::MothPdgCode, kinkcand::DaugPdgCode, kinkcand::PtMC, kinkcand::PzMC, kinkcand::MassMC, kinkcand::DecayRadiusMC, kinkcand::CollisionIdCheck); +namespace sigmapluscand +{ + +DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); //! Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); //! Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); //! Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(Radius, radius, float); //! Decay radius of the candidate (cm) +DECLARE_SOA_COLUMN(FlightDistance, flightDistance, float); //! Flight distance of the candidate (PV to decay vertex, cm) +DECLARE_SOA_COLUMN(DcaProtonGamma, dcaProtonGamma, float); //! DCA between proton and photon at the fitted vertex (cm) +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! chi2 of the proton-photon vertex fit + +DECLARE_SOA_COLUMN(PxProton, pxProton, float); //! Px of the proton +DECLARE_SOA_COLUMN(PyProton, pyProton, float); //! Py of the proton +DECLARE_SOA_COLUMN(PzProton, pzProton, float); //! Pz of the proton +DECLARE_SOA_COLUMN(PxGamma1, pxGamma1, float); //! Px of the measured (PCM) photon +DECLARE_SOA_COLUMN(PyGamma1, pyGamma1, float); //! Py of the measured (PCM) photon +DECLARE_SOA_COLUMN(PzGamma1, pzGamma1, float); //! Pz of the measured (PCM) photon +DECLARE_SOA_COLUMN(PxGamma2, pxGamma2, float); //! Px of the reconstructed (missing) photon +DECLARE_SOA_COLUMN(PyGamma2, pyGamma2, float); //! Py of the reconstructed (missing) photon +DECLARE_SOA_COLUMN(PzGamma2, pzGamma2, float); //! Pz of the reconstructed (missing) photon + +DECLARE_SOA_COLUMN(NSigmaTPCProton, nSigmaTPCProton, float); //! TPC nSigma of the proton track +DECLARE_SOA_COLUMN(NSigmaTOFProton, nSigmaTOFProton, float); //! TOF nSigma of the proton track +DECLARE_SOA_COLUMN(NSigmaTPCElPos, nSigmaTPCElPos, float); //! TPC nSigma_el of the photon's positive daughter +DECLARE_SOA_COLUMN(NSigmaTPCElNeg, nSigmaTPCElNeg, float); //! TPC nSigma_el of the photon's negative daughter + +DECLARE_SOA_COLUMN(PhotonMass, photonMass, float); //! Invariant mass of the measured photon (V0) candidate (GeV/c^2) +DECLARE_SOA_COLUMN(PhotonAlpha, photonAlpha, float); //! Armenteros-Podolanski alpha of the measured photon +DECLARE_SOA_COLUMN(PhotonQt, photonQt, float); //! Armenteros-Podolanski qT of the measured photon (GeV/c) +DECLARE_SOA_COLUMN(PhotonConvRadius, photonConvRadius, float); //! Conversion radius of the measured photon (cm) +DECLARE_SOA_COLUMN(PhotonOpeningAngle, photonOpeningAngle, float); //! Opening angle between the photon's e+e- daughters (rad) +DECLARE_SOA_COLUMN(PhotonPointingAngle, photonPointingAngle, float); //! Angle between the photon momentum and the line from its conversion point to the candidate decay vertex (rad) +DECLARE_SOA_COLUMN(PhotonDcaToPV, photonDcaToPV, float); //! DCA of the photon's flight line to the primary vertex (cm) + +DECLARE_SOA_COLUMN(ProtonItsNCls, protonItsNCls, uint8_t); //! Number of ITS clusters of the proton track +DECLARE_SOA_COLUMN(ProtonTpcNCls, protonTpcNCls, int16_t); //! Number of found TPC clusters of the proton track +DECLARE_SOA_COLUMN(ProtonDcaXY, protonDcaXY, float); //! DCA of the proton track to the primary vertex, xy (cm) +DECLARE_SOA_COLUMN(ProtonDcaZ, protonDcaZ, float); //! DCA of the proton track to the primary vertex, z (cm) + +DECLARE_SOA_COLUMN(PhotonPosItsNCls, photonPosItsNCls, uint8_t); //! Number of ITS clusters of the photon's positive daughter +DECLARE_SOA_COLUMN(PhotonPosTpcNCls, photonPosTpcNCls, int16_t); //! Number of found TPC clusters of the photon's positive daughter +DECLARE_SOA_COLUMN(PhotonNegItsNCls, photonNegItsNCls, uint8_t); //! Number of ITS clusters of the photon's negative daughter +DECLARE_SOA_COLUMN(PhotonNegTpcNCls, photonNegTpcNCls, int16_t); //! Number of found TPC clusters of the photon's negative daughter + +// MC columns +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! True if proton and photon are MC-truth matched to the same Sigma+ + +DECLARE_SOA_COLUMN(ProtonPdgCode, protonPdgCode, int); //! PDG code of the proton's MC particle +DECLARE_SOA_COLUMN(ProtonMotherPdgCode, protonMotherPdgCode, int); //! PDG code of the proton's MC mother +DECLARE_SOA_COLUMN(GammaPdgCode, gammaPdgCode, int); //! PDG code of the measured photon's MC particle +DECLARE_SOA_COLUMN(GammaMotherPdgCode, gammaMotherPdgCode, int); //! PDG code of the photon's MC mother (expected: pi0) +DECLARE_SOA_COLUMN(GammaGMotherPdgCode, gammaGMotherPdgCode, int); //! PDG code of the photon's MC grandmother (expected: Sigma+) + +DECLARE_SOA_COLUMN(XDecVtxMC, xDecVtxMC, float); //! MC-truth Sigma+ decay vertex (x direction) +DECLARE_SOA_COLUMN(YDecVtxMC, yDecVtxMC, float); //! MC-truth Sigma+ decay vertex (y direction) +DECLARE_SOA_COLUMN(ZDecVtxMC, zDecVtxMC, float); //! MC-truth Sigma+ decay vertex (z direction) +DECLARE_SOA_COLUMN(PxProtonMC, pxProtonMC, float); //! MC-truth proton Px +DECLARE_SOA_COLUMN(PyProtonMC, pyProtonMC, float); //! MC-truth proton Py +DECLARE_SOA_COLUMN(PzProtonMC, pzProtonMC, float); //! MC-truth proton Pz +DECLARE_SOA_COLUMN(PxGammaMC, pxGammaMC, float); //! MC-truth momentum of the measured photon (Px) +DECLARE_SOA_COLUMN(PyGammaMC, pyGammaMC, float); //! MC-truth momentum of the measured photon (Py) +DECLARE_SOA_COLUMN(PzGammaMC, pzGammaMC, float); //! MC-truth momentum of the measured photon (Pz) + +// DYNAMIC COLUMNS + +DECLARE_SOA_DYNAMIC_COLUMN(PxSigmaPlus, pxSigmaPlus, //! Px of the Sigma+ candidate + [](float pxProton, float pxGamma1, float pxGamma2) -> float { return pxProton + pxGamma1 + pxGamma2; }); + +DECLARE_SOA_DYNAMIC_COLUMN(PySigmaPlus, pySigmaPlus, //! Py of the Sigma+ candidate + [](float pyProton, float pyGamma1, float pyGamma2) -> float { return pyProton + pyGamma1 + pyGamma2; }); + +DECLARE_SOA_DYNAMIC_COLUMN(PzSigmaPlus, pzSigmaPlus, //! Pz of the Sigma+ candidate + [](float pzProton, float pzGamma1, float pzGamma2) -> float { return pzProton + pzGamma1 + pzGamma2; }); + +DECLARE_SOA_DYNAMIC_COLUMN(PtSigmaPlus, ptSigmaPlus, //! pT of the Sigma+ candidate + [](float pxProton, float pxGamma1, float pxGamma2, float pyProton, float pyGamma1, float pyGamma2) -> float { return std::hypot(pxProton + pxGamma1 + pxGamma2, pyProton + pyGamma1 + pyGamma2); }); + +DECLARE_SOA_DYNAMIC_COLUMN(MassSigmaPlus, massSigmaPlus, //! Invariant mass of the Sigma+ candidate (p + gamma1 + gamma2) + [](float pxProton, float pyProton, float pzProton, + float pxGamma1, float pyGamma1, float pzGamma1, + float pxGamma2, float pyGamma2, float pzGamma2) -> float { return RecoDecay::m(std::array{std::array{pxProton, pyProton, pzProton}, + std::array{pxGamma1, pyGamma1, pzGamma1}, + std::array{pxGamma2, pyGamma2, pzGamma2}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassGamma, o2::constants::physics::MassGamma}); }); + +} // namespace sigmapluscand + +DECLARE_SOA_TABLE(SigmaPlusCands, "AOD", "SIGMAPLUSCANDS", + sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, + sigmapluscand::Radius, sigmapluscand::FlightDistance, + sigmapluscand::DcaProtonGamma, sigmapluscand::Chi2, + sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, + sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, + sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, + sigmapluscand::NSigmaTPCProton, sigmapluscand::NSigmaTOFProton, + sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, + sigmapluscand::PhotonMass, sigmapluscand::PhotonAlpha, sigmapluscand::PhotonQt, sigmapluscand::PhotonConvRadius, + sigmapluscand::PhotonOpeningAngle, sigmapluscand::PhotonPointingAngle, sigmapluscand::PhotonDcaToPV, + sigmapluscand::ProtonItsNCls, sigmapluscand::ProtonTpcNCls, sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, + sigmapluscand::PhotonPosItsNCls, sigmapluscand::PhotonPosTpcNCls, sigmapluscand::PhotonNegItsNCls, sigmapluscand::PhotonNegTpcNCls, + + // dynamic columns + sigmapluscand::PxSigmaPlus, + sigmapluscand::PySigmaPlus, + sigmapluscand::PzSigmaPlus, + sigmapluscand::PtSigmaPlus, + sigmapluscand::MassSigmaPlus); + +DECLARE_SOA_TABLE(SigmaPlusCandsMC, "AOD", "SIGMAPLUSMC", + sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, + sigmapluscand::Radius, sigmapluscand::FlightDistance, + sigmapluscand::DcaProtonGamma, sigmapluscand::Chi2, + sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, + sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, + sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, + sigmapluscand::NSigmaTPCProton, sigmapluscand::NSigmaTOFProton, + sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, + sigmapluscand::PhotonMass, sigmapluscand::PhotonAlpha, sigmapluscand::PhotonQt, sigmapluscand::PhotonConvRadius, + sigmapluscand::PhotonOpeningAngle, sigmapluscand::PhotonPointingAngle, sigmapluscand::PhotonDcaToPV, + sigmapluscand::ProtonItsNCls, sigmapluscand::ProtonTpcNCls, sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, + sigmapluscand::PhotonPosItsNCls, sigmapluscand::PhotonPosTpcNCls, sigmapluscand::PhotonNegItsNCls, sigmapluscand::PhotonNegTpcNCls, + sigmapluscand::IsSignal, + sigmapluscand::ProtonPdgCode, sigmapluscand::ProtonMotherPdgCode, + sigmapluscand::GammaPdgCode, sigmapluscand::GammaMotherPdgCode, sigmapluscand::GammaGMotherPdgCode, + sigmapluscand::XDecVtxMC, sigmapluscand::YDecVtxMC, sigmapluscand::ZDecVtxMC, + sigmapluscand::PxProtonMC, sigmapluscand::PyProtonMC, sigmapluscand::PzProtonMC, + sigmapluscand::PxGammaMC, sigmapluscand::PyGammaMC, sigmapluscand::PzGammaMC, + + // dynamic columns + sigmapluscand::PxSigmaPlus, + sigmapluscand::PySigmaPlus, + sigmapluscand::PzSigmaPlus, + sigmapluscand::PtSigmaPlus, + sigmapluscand::MassSigmaPlus); + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFKINKDECAYTABLES_H_ diff --git a/PWGLF/DataModel/LFLambda1405Table.h b/PWGLF/DataModel/LFLambda1405Table.h index 103065146c6..44339682b7c 100644 --- a/PWGLF/DataModel/LFLambda1405Table.h +++ b/PWGLF/DataModel/LFLambda1405Table.h @@ -9,11 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// /// \file LFLambda1405Tables.h /// \brief Slim tables for Lambda(1405) candidates -/// \author Francesco Mazzaschi /// +/// \author Francesco Mazzaschi #ifndef PWGLF_DATAMODEL_LFLAMBDA1405TABLE_H_ #define PWGLF_DATAMODEL_LFLAMBDA1405TABLE_H_ @@ -44,13 +43,15 @@ DECLARE_SOA_COLUMN(NSigmaTPCPiKink, nSigmaTPCPiKink, float); //! Number of sigma DECLARE_SOA_COLUMN(NSigmaTOFPiKink, nSigmaTOFPiKink, float); //! Number of sigmas for the pion candidate from Sigma kink in TOF DECLARE_SOA_COLUMN(NSigmaTPCPrKink, nSigmaTPCPrKink, float); //! Number of sigmas for the proton candidate from Sigma kink in TPC DECLARE_SOA_COLUMN(NSigmaTOFPrKink, nSigmaTOFPrKink, float); //! Number of sigmas for the proton candidate from Sigma kink in TOF -DECLARE_SOA_COLUMN(DCAKinkDauToPV, dcaKinkDauToPV, float); //! DCA of the kink daughter to the primary vertex +DECLARE_SOA_COLUMN(DcaKinkDauToPv, dcaKinkDauToPv, float); //! DCA of the kink daughter to the primary vertex +DECLARE_SOA_COLUMN(DcaSigmaToPv, dcaSigmaToPv, float); //! DCA of the sigma to the primary vertex DECLARE_SOA_COLUMN(NSigmaTPCPiDau, nSigmaTPCPiDau, float); //! Number of sigmas for the lambda1405 pion daughter in TPC DECLARE_SOA_COLUMN(NSigmaTOFPiDau, nSigmaTOFPiDau, float); //! Number of sigmas for the lambda1405 pion daughter in TOF // Event properties DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality of the candidate DECLARE_SOA_COLUMN(Occupancy, occupancy, float); //! Occupancy of the candidate +DECLARE_SOA_COLUMN(PvContrib, pvContrib, float); //! Number of primary vertex contributors // Flow columns DECLARE_SOA_COLUMN(ScalarProd, scalarProd, float); //! Scalar product of the candidate @@ -61,6 +62,44 @@ DECLARE_SOA_COLUMN(MassMC, massMC, float); //! Invariant mass of t DECLARE_SOA_COLUMN(SigmaPdgCode, sigmaPdgCode, int); //! PDG code of the Sigma daughter DECLARE_SOA_COLUMN(KinkDauPdgCode, kinkDauPdgCode, int); //! PDG code of the kink daughter +// Sigma efficiency MC columns +DECLARE_SOA_COLUMN(PxSigma, pxSigma, float); //! Px of the sigma candidate +DECLARE_SOA_COLUMN(PySigma, pySigma, float); //! Py of the sigma candidate +DECLARE_SOA_COLUMN(PzSigma, pzSigma, float); //! Pz of the sigma candidate +DECLARE_SOA_COLUMN(MassSigma, massSigma, float); //! Mass of the sigma candidate +DECLARE_SOA_COLUMN(DeltaPxSigma, deltaPxSigma, float); //! Gen-reco diff of sigma p_x +DECLARE_SOA_COLUMN(DeltaPySigma, deltaPySigma, float); //! Gen-reco diff of sigma p_y +DECLARE_SOA_COLUMN(DeltaPzSigma, deltaPzSigma, float); //! Gen-reco diff of sigma p_z +DECLARE_SOA_COLUMN(DeltaPtSigma, deltaPtSigma, float); //! Gen-reco diff of sigma p_z +DECLARE_SOA_COLUMN(DeltaRadiusSigma, deltaRadiusSigma, float); //! Gen-reco diff of sigma radius +DECLARE_SOA_COLUMN(DeltaMassSigma, deltaMassSigma, float); //! Gen-reco diff of sigma mass +DECLARE_SOA_COLUMN(GenPhiSigma, genPhiSigma, float); //! Gen-reco diff of sigma phi +DECLARE_SOA_COLUMN(GenEtaSigma, genEtaSigma, float); //! Gen-reco diff of sigma eta +DECLARE_SOA_COLUMN(DeltaPxSigmaRecalc, deltaPxSigmaRecalc, float); //! reco recalc-original diff of sigma p_x +DECLARE_SOA_COLUMN(DeltaPySigmaRecalc, deltaPySigmaRecalc, float); //! reco recalc-original diff of sigma p_y +DECLARE_SOA_COLUMN(DeltaPzSigmaRecalc, deltaPzSigmaRecalc, float); //! reco recalc-original diff of sigma p_z +DECLARE_SOA_COLUMN(AlphaAPSigmaRecalc, alphaAPSigmaRecalc, float); //! Alpha of the Sigma +DECLARE_SOA_COLUMN(QtAPSigmaRecalc, qtAPSigmaRecalc, float); //! qT of the Sigma +DECLARE_SOA_COLUMN(PxKinkDaug, pxKinkDaug, float); //! Px of the sigma candidate +DECLARE_SOA_COLUMN(PyKinkDaug, pyKinkDaug, float); //! Py of the sigma candidate +DECLARE_SOA_COLUMN(PzKinkDaug, pzKinkDaug, float); //! Pz of the sigma candidate +DECLARE_SOA_COLUMN(PtKinkDaug, ptKinkDaug, float); //! Pt of the sigma candidate +DECLARE_SOA_COLUMN(DeltaPxKinkDaug, deltaPxKinkDaug, float); //! Gen-reco diff of kink daughter p_x +DECLARE_SOA_COLUMN(DeltaPyKinkDaug, deltaPyKinkDaug, float); //! Gen-reco diff of kink daughter p_y +DECLARE_SOA_COLUMN(DeltaPzKinkDaug, deltaPzKinkDaug, float); //! Gen-reco diff of kink daughter p_z +DECLARE_SOA_COLUMN(DeltaPtKinkDaug, deltaPtKinkDaug, float); //! Gen-reco diff of kink daughter p_t +DECLARE_SOA_COLUMN(GenPhiKinkDaug, genPhiKinkDaug, float); //! Gen-reco diff of kink daughter phi +DECLARE_SOA_COLUMN(GenEtaKinkDaug, genEtaKinkDaug, float); //! Gen-reco diff of kink daughter eta +DECLARE_SOA_COLUMN(XKinkVtx, xKinkVtx, float); //! X of kink vertex +DECLARE_SOA_COLUMN(YKinkVtx, yKinkVtx, float); //! Y of kink vertex +DECLARE_SOA_COLUMN(ZKinkVtx, zKinkVtx, float); //! Z of kink vertex +DECLARE_SOA_COLUMN(DeltaXKinkVtx, deltaXKinkVtx, float); //! Gen-reco diff of X of kink vertex +DECLARE_SOA_COLUMN(DeltaYKinkVtx, deltaYKinkVtx, float); //! Gen-reco diff of Y of kink vertex +DECLARE_SOA_COLUMN(DeltaZKinkVtx, deltaZKinkVtx, float); //! Gen-reco diff of Z of kink vertex + +// Event mixing +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Signed pT of the Sigma daughter for mixed events + } // namespace lambda1405 DECLARE_SOA_TABLE(Lambda1405Cands, "AOD", "LAMBDA1405", @@ -72,21 +111,10 @@ DECLARE_SOA_TABLE(Lambda1405Cands, "AOD", "LAMBDA1405", lambda1405::PtKink, lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, - lambda1405::DCAKinkDauToPV, + lambda1405::DcaKinkDauToPv, lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, - lambda1405::Centrality, lambda1405::Occupancy); - -DECLARE_SOA_TABLE(Lambda1405Flow, "AOD", "LAMBDA1405FLOW", - o2::soa::Index<>, - lambda1405::Pt, lambda1405::Mass, - lambda1405::PtSigma, - lambda1405::SigmaMinusMass, lambda1405::SigmaPlusMass, - lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, - lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, - lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, - lambda1405::DCAKinkDauToPV, - lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, - lambda1405::ScalarProd, lambda1405::Centrality); + lambda1405::ScalarProd, + lambda1405::Centrality, lambda1405::Occupancy, lambda1405::PoolBin); DECLARE_SOA_TABLE(Lambda1405CandsMC, "AOD", "MCLAMBDA1405", o2::soa::Index<>, @@ -97,11 +125,36 @@ DECLARE_SOA_TABLE(Lambda1405CandsMC, "AOD", "MCLAMBDA1405", lambda1405::PtKink, lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, - lambda1405::DCAKinkDauToPV, + lambda1405::DcaKinkDauToPv, lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, lambda1405::PtMC, lambda1405::MassMC, lambda1405::SigmaPdgCode, lambda1405::KinkDauPdgCode, lambda1405::Centrality, lambda1405::Occupancy); +DECLARE_SOA_TABLE(Lambda1405SigmaEffMC, "AOD", "MCL1405SIGEFF", + o2::soa::Index<>, + lambda1405::PxSigma, lambda1405::DeltaPxSigma, + lambda1405::PySigma, lambda1405::DeltaPySigma, + lambda1405::PzSigma, lambda1405::DeltaPzSigma, + lambda1405::MassSigma, lambda1405::DeltaMassSigma, + lambda1405::DeltaPxSigmaRecalc, + lambda1405::DeltaPySigmaRecalc, + lambda1405::DeltaPzSigmaRecalc, + lambda1405::GenPhiSigma, + lambda1405::GenEtaSigma, + lambda1405::PxKinkDaug, lambda1405::DeltaPxKinkDaug, + lambda1405::PyKinkDaug, lambda1405::DeltaPyKinkDaug, + lambda1405::PzKinkDaug, lambda1405::DeltaPzKinkDaug, + lambda1405::GenPhiKinkDaug, + lambda1405::GenEtaKinkDaug, + lambda1405::XKinkVtx, lambda1405::DeltaXKinkVtx, + lambda1405::YKinkVtx, lambda1405::DeltaYKinkVtx, + lambda1405::ZKinkVtx, lambda1405::DeltaZKinkVtx, + lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, + lambda1405::AlphaAPSigmaRecalc, lambda1405::QtAPSigmaRecalc, + lambda1405::DcaKinkDauToPv, lambda1405::DcaSigmaToPv, + lambda1405::SigmaPdgCode, lambda1405::KinkDauPdgCode, + lambda1405::Centrality, lambda1405::Occupancy, lambda1405::PvContrib); + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFLAMBDA1405TABLE_H_ diff --git a/PWGLF/DataModel/LFNonPromptCascadeTables.h b/PWGLF/DataModel/LFNonPromptCascadeTables.h index 9b503213edf..6a69bc8016c 100644 --- a/PWGLF/DataModel/LFNonPromptCascadeTables.h +++ b/PWGLF/DataModel/LFNonPromptCascadeTables.h @@ -128,7 +128,10 @@ DECLARE_SOA_COLUMN(NoSameBunchPileup, noSameBunchPileup, bool); DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); DECLARE_SOA_COLUMN(PtGen, ptGen, float); DECLARE_SOA_COLUMN(PtRec, ptRec, float); +DECLARE_SOA_COLUMN(EtaGen, etaGen, float); +DECLARE_SOA_COLUMN(EtaRec, etaRec, float); DECLARE_SOA_COLUMN(MultGen, multGen, int); +DECLARE_SOA_COLUMN(MultGenFT0, multGenFT0, int); } // namespace NPCascadeTable DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", @@ -455,8 +458,11 @@ DECLARE_SOA_TABLE(NPCascTableGen, "AOD", "NPCASCTABLEGen", DECLARE_SOA_TABLE(NPMCChargedTable, "AOD", "NPMCChargedTABLE", NPCascadeTable::PtGen, NPCascadeTable::PtRec, + NPCascadeTable::EtaGen, + NPCascadeTable::EtaRec, NPCascadeTable::MultNTracksNP, - NPCascadeTable::MultGen); + NPCascadeTable::MultGen, + NPCascadeTable::MultGenFT0); DECLARE_SOA_TABLE(NPCollisionTable, "AOD", "NPCollisionTABLE", NPCascadeTable::RunNumber, NPCascadeTable::GlobalBC, @@ -469,7 +475,8 @@ DECLARE_SOA_TABLE(NPCollisionTable, "AOD", "NPCollisionTABLE", DECLARE_SOA_INDEX_COLUMN_FULL(NPCollision, npCollision, int32_t, NPCollisionTable, ""); DECLARE_SOA_TABLE(NPRecoChargedCand, "AOD", "NPRecoChargedCand", NPCollisionId, - NPCascadeTable::PtRec); + NPCascadeTable::PtRec, + NPCascadeTable::EtaRec); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFNONPROMPTCASCADETABLES_H_ diff --git a/PWGLF/DataModel/LFSpincorrelationTables.h b/PWGLF/DataModel/LFSpincorrelationTables.h index 571a3413549..d4fdffd2442 100644 --- a/PWGLF/DataModel/LFSpincorrelationTables.h +++ b/PWGLF/DataModel/LFSpincorrelationTables.h @@ -52,6 +52,8 @@ DECLARE_SOA_COLUMN(ProtonEta, protonEta, float); //! Proton Et DECLARE_SOA_COLUMN(ProtonPhi, protonPhi, float); //! Proton Phi DECLARE_SOA_COLUMN(ProtonIndex, protonIndex, int); //! Proton index DECLARE_SOA_COLUMN(PionIndex, pionIndex, int); //! Pion index +DECLARE_SOA_COLUMN(DcaV0ToPV, dcaV0ToPV, float); //! DCA of V0 to primary vertex + } // namespace lambdapair DECLARE_SOA_TABLE(LambdaPairs, "AOD", "LAMBDAPAIR", o2::soa::Index<>, @@ -71,7 +73,8 @@ DECLARE_SOA_TABLE(LambdaPairs, "AOD", "LAMBDAPAIR", lambdapair::ProtonEta, lambdapair::ProtonPhi, lambdapair::ProtonIndex, - lambdapair::PionIndex); + lambdapair::PionIndex, + lambdapair::DcaV0ToPV); using LambdaPair = LambdaPairs::iterator; @@ -105,6 +108,7 @@ DECLARE_SOA_COLUMN(ProtonEtamc, protonEtamc, float); //! Proto DECLARE_SOA_COLUMN(ProtonPhimc, protonPhimc, float); //! Proton Phi in montecarlo DECLARE_SOA_COLUMN(ProtonIndexmc, protonIndexmc, int); //! Proton index in montecarlo DECLARE_SOA_COLUMN(PionIndexmc, pionIndexmc, int); //! Pion index in montecarlo +DECLARE_SOA_COLUMN(DcaV0ToPVmc, dcaV0ToPVmc, float); //! DCA of V0 to primary vertex } // namespace lambdapairmc DECLARE_SOA_TABLE(LambdaPairmcs, "AOD", "LAMBDAPAIRMC", o2::soa::Index<>, @@ -124,7 +128,8 @@ DECLARE_SOA_TABLE(LambdaPairmcs, "AOD", "LAMBDAPAIRMC", lambdapairmc::ProtonEtamc, lambdapairmc::ProtonPhimc, lambdapairmc::ProtonIndexmc, - lambdapairmc::PionIndexmc); + lambdapairmc::PionIndexmc, + lambdapairmc::DcaV0ToPVmc); using LambdaPairmc = LambdaPairmcs::iterator; diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index a2c8ad8a396..e0714108b5f 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -335,6 +335,100 @@ DECLARE_SOA_TABLE(McVtx3BodyDatas, "AOD", "MC3BODYDATA", //! using Vtx3BodyDatasCovs = soa::Join; using Vtx3BodyDatasCovsIndexed = soa::Join; +namespace nuclei3body +{ +DECLARE_SOA_COLUMN(SignHe3, signHe3, int8_t); //! He3 charge sign +DECLARE_SOA_COLUMN(SignDaughter1, signDaughter1, int8_t); //! daughter 1 charge sign +DECLARE_SOA_COLUMN(SignDaughter2, signDaughter2, int8_t); //! daughter 2 charge sign +DECLARE_SOA_COLUMN(Pt, pt, float); //! candidate transverse momentum +DECLARE_SOA_COLUMN(Eta, eta, float); //! candidate pseudorapidity +DECLARE_SOA_COLUMN(Phi, phi, float); //! candidate azimuth +DECLARE_SOA_COLUMN(PHe3, pHe3, float); //! magnitude of fitted, charge-corrected He3 momentum +DECLARE_SOA_COLUMN(PDaughter1, pDaughter1, float); //! magnitude of fitted daughter 1 momentum +DECLARE_SOA_COLUMN(PDaughter2, pDaughter2, float); //! magnitude of fitted daughter 2 momentum +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! DCA-fitter chi2 at PCA +DECLARE_SOA_COLUMN(DcaDaughters, dcaDaughters, float); //! square root of DCA-fitter chi2 at PCA +DECLARE_SOA_COLUMN(CosPA, cosPA, float); //! cosine of pointing angle +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! PV-to-SV distance + +DECLARE_SOA_COLUMN(DcaXYHe3ToPv, dcaXYHe3ToPv, float); //! He3 DCAxy to PV +DECLARE_SOA_COLUMN(DcaZHe3ToPv, dcaZHe3ToPv, float); //! He3 DCAz to PV +DECLARE_SOA_COLUMN(DcaXYDaughter1ToPv, dcaXYDaughter1ToPv, float); //! daughter 1 DCAxy to PV +DECLARE_SOA_COLUMN(DcaZDaughter1ToPv, dcaZDaughter1ToPv, float); //! daughter 1 DCAz to PV +DECLARE_SOA_COLUMN(DcaXYDaughter2ToPv, dcaXYDaughter2ToPv, float); //! daughter 2 DCAxy to PV +DECLARE_SOA_COLUMN(DcaZDaughter2ToPv, dcaZDaughter2ToPv, float); //! daughter 2 DCAz to PV + +DECLARE_SOA_COLUMN(TpcNSigmaHe3, tpcNSigmaHe3, float); //! custom He3 TPC n-sigma +DECLARE_SOA_COLUMN(TofNSigmaHe3, tofNSigmaHe3, float); //! He3 TOF n-sigma; sentinel without TOF +DECLARE_SOA_COLUMN(TpcNSigmaPiDaughter1, tpcNSigmaPiDaughter1, float); +DECLARE_SOA_COLUMN(TpcNSigmaKaDaughter1, tpcNSigmaKaDaughter1, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrDaughter1, tpcNSigmaPrDaughter1, float); +DECLARE_SOA_COLUMN(TofNSigmaPiDaughter1, tofNSigmaPiDaughter1, float); +DECLARE_SOA_COLUMN(TofNSigmaKaDaughter1, tofNSigmaKaDaughter1, float); +DECLARE_SOA_COLUMN(TofNSigmaPrDaughter1, tofNSigmaPrDaughter1, float); +DECLARE_SOA_COLUMN(TpcNSigmaPiDaughter2, tpcNSigmaPiDaughter2, float); +DECLARE_SOA_COLUMN(TpcNSigmaKaDaughter2, tpcNSigmaKaDaughter2, float); +DECLARE_SOA_COLUMN(TpcNSigmaPrDaughter2, tpcNSigmaPrDaughter2, float); +DECLARE_SOA_COLUMN(TofNSigmaPiDaughter2, tofNSigmaPiDaughter2, float); +DECLARE_SOA_COLUMN(TofNSigmaKaDaughter2, tofNSigmaKaDaughter2, float); +DECLARE_SOA_COLUMN(TofNSigmaPrDaughter2, tofNSigmaPrDaughter2, float); + +DECLARE_SOA_COLUMN(TpcNClsHe3, tpcNClsHe3, uint16_t); +DECLARE_SOA_COLUMN(TpcNClsDaughter1, tpcNClsDaughter1, uint16_t); +DECLARE_SOA_COLUMN(TpcNClsDaughter2, tpcNClsDaughter2, uint16_t); +DECLARE_SOA_COLUMN(TpcCrossedRowsHe3, tpcCrossedRowsHe3, uint16_t); +DECLARE_SOA_COLUMN(TpcCrossedRowsDaughter1, tpcCrossedRowsDaughter1, uint16_t); +DECLARE_SOA_COLUMN(TpcCrossedRowsDaughter2, tpcCrossedRowsDaughter2, uint16_t); +DECLARE_SOA_COLUMN(ItsNClsHe3, itsNClsHe3, uint8_t); +DECLARE_SOA_COLUMN(ItsNClsDaughter1, itsNClsDaughter1, uint8_t); +DECLARE_SOA_COLUMN(ItsNClsDaughter2, itsNClsDaughter2, uint8_t); + +DECLARE_SOA_COLUMN(McPdgHe3, mcPdgHe3, int); +DECLARE_SOA_COLUMN(McPdgDaughter1, mcPdgDaughter1, int); +DECLARE_SOA_COLUMN(McPdgDaughter2, mcPdgDaughter2, int); +DECLARE_SOA_COLUMN(McMatchStatus, mcMatchStatus, uint8_t); //! 0 missing label, 1 no common mother, 2 common mother, 3 configured decay +DECLARE_SOA_COLUMN(McMotherPdg, mcMotherPdg, int); +DECLARE_SOA_COLUMN(GenMotherPt, genMotherPt, float); +DECLARE_SOA_COLUMN(GenMotherEta, genMotherEta, float); +DECLARE_SOA_COLUMN(GenMotherPhi, genMotherPhi, float); +DECLARE_SOA_COLUMN(GenDecayLength, genDecayLength, float); +} // namespace nuclei3body + +#define NUCLEI_THREE_BODY_RECO_COLUMNS \ + nuclei3body::SignHe3, nuclei3body::SignDaughter1, nuclei3body::SignDaughter2, \ + nuclei3body::Pt, nuclei3body::Eta, nuclei3body::Phi, \ + nuclei3body::PHe3, nuclei3body::PDaughter1, nuclei3body::PDaughter2, \ + nuclei3body::Chi2, nuclei3body::DcaDaughters, nuclei3body::CosPA, \ + nuclei3body::DecayLength, \ + nuclei3body::DcaXYHe3ToPv, nuclei3body::DcaZHe3ToPv, \ + nuclei3body::DcaXYDaughter1ToPv, nuclei3body::DcaZDaughter1ToPv, \ + nuclei3body::DcaXYDaughter2ToPv, nuclei3body::DcaZDaughter2ToPv, \ + nuclei3body::TpcNSigmaHe3, nuclei3body::TofNSigmaHe3, \ + nuclei3body::TpcNSigmaPiDaughter1, nuclei3body::TpcNSigmaKaDaughter1, \ + nuclei3body::TpcNSigmaPrDaughter1, nuclei3body::TofNSigmaPiDaughter1, \ + nuclei3body::TofNSigmaKaDaughter1, nuclei3body::TofNSigmaPrDaughter1, \ + nuclei3body::TpcNSigmaPiDaughter2, nuclei3body::TpcNSigmaKaDaughter2, \ + nuclei3body::TpcNSigmaPrDaughter2, nuclei3body::TofNSigmaPiDaughter2, \ + nuclei3body::TofNSigmaKaDaughter2, nuclei3body::TofNSigmaPrDaughter2, \ + nuclei3body::TpcNClsHe3, nuclei3body::TpcNClsDaughter1, nuclei3body::TpcNClsDaughter2, \ + nuclei3body::TpcCrossedRowsHe3, nuclei3body::TpcCrossedRowsDaughter1, \ + nuclei3body::TpcCrossedRowsDaughter2, nuclei3body::ItsNClsHe3, \ + nuclei3body::ItsNClsDaughter1, nuclei3body::ItsNClsDaughter2 + +DECLARE_SOA_TABLE(NucleiThreeBodyDatas, "AOD", "NUC3BODYDATA", + o2::soa::Index<>, + NUCLEI_THREE_BODY_RECO_COLUMNS); + +DECLARE_SOA_TABLE(McNucleiThreeBodyDatas, "AOD", "MCNUC3BODY", + o2::soa::Index<>, + NUCLEI_THREE_BODY_RECO_COLUMNS, + nuclei3body::McPdgHe3, nuclei3body::McPdgDaughter1, nuclei3body::McPdgDaughter2, + nuclei3body::McMatchStatus, nuclei3body::McMotherPdg, + nuclei3body::GenMotherPt, nuclei3body::GenMotherEta, + nuclei3body::GenMotherPhi, nuclei3body::GenDecayLength); + +#undef NUCLEI_THREE_BODY_RECO_COLUMNS + } // namespace o2::aod #endif // PWGLF_DATAMODEL_VTX3BODYTABLES_H_ diff --git a/PWGLF/TableProducer/Nuspex/CMakeLists.txt b/PWGLF/TableProducer/Nuspex/CMakeLists.txt index be0b3c3fc2e..eeadf523aac 100644 --- a/PWGLF/TableProducer/Nuspex/CMakeLists.txt +++ b/PWGLF/TableProducer/Nuspex/CMakeLists.txt @@ -29,6 +29,11 @@ o2physics_add_dpl_workflow(tracked-hypertriton-reco-task PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2::TOFBase O2::DetectorsVertexing O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(nuclei-three-body-builder + SOURCES nucleiThreeBodyBuilder.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(lnn-reco-task SOURCES lnnRecoTask.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter diff --git a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx index 729ab2a6981..0dfed02c7f6 100644 --- a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx +++ b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx @@ -111,9 +111,10 @@ enum V0Selections { enum CascSelections { kCascNoCut = 0, kCascTopology, + kNSigmaTPCV0Daughters, kRejectedXi, - kAcceptedOmega, kNSigmaTPC, + kAcceptedOmega, kCascAll }; @@ -274,12 +275,12 @@ struct LfTreeCreatorClusterStudies { {"photon_conversion_position", "Photon conversion position; #it{x} (cm); #it{y} (cm)", {HistType::kTH2F, {{250, -5.f, 5.f}, {250, -5.f, 5.f}}}}, {"photon_conversion_position_layer", "Photon conversion position (ITS layers); #it{x} (cm); #it{y} (cm)", {HistType::kTH2F, {{100, -5.f, 5.f}, {100, -5.f, 5.f}}}}, {"casc_dca_daughter_pairs", "DCA (xy) for cascade daughter pairs; DCA_{#it{xy}} (cm); counts", {HistType::kTH1F, {{100, -0.1, 0.1}}}}, - {"Xi_vs_Omega", "Mass Xi vs Omega; mass Omega (GeV/#it{c}^{2}); #it{m}_#Xi (GeV/#it{c}^{2})", {HistType::kTH2F, {{50, 1.f, 2.f}, {50, 1.f, 2.f}}}}, + {"Xi_vs_Omega", "Mass Xi vs Omega; #it{m}_{#Omega} (GeV/#it{c}^{2}); #it{m}_{#Xi} (GeV/#it{c}^{2})", {HistType::kTH2F, {{60, 1.5f, 2.1f}, {50, 1.1f, 1.6f}}}}, {"massOmega", "Mass #Omega; signed #it{p}_{T} (GeV/#it{c}); #it{m}_{#Omega} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {400, 1.62f, 1.72f}}}}, {"massOmegaMc", "Mass #Omega (MC); signed #it{p}_{T} (GeV/#it{c}); #it{m}_{#Omega} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {400, 1.62f, 1.72f}}}}, - {"massPi0", "Mass #pi^{0}; #it{m}_{#pi^{0}} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, - {"massPi0Mc", "Mass #pi^{0} (MC); #it{m}_{#pi^{0}} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, - {"massPi0WithBkg", "Mass #pi^{0} with Background; #it{m}_{#pi^{0}} (GeV/#it{c}^{2}); counts", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0", "Mass #pi^{0}; #it{m}_{ee} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0Mc", "Mass #pi^{0} (MC); #it{m}_{ee} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0WithBkg", "Mass #pi^{0} with Background; #it{m}_{ee} (GeV/#it{c}^{2}); counts", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, {"zVtx", "Binning for the vertex z in cm; #it{z}_{vertex} (cm)", {HistType::kTH1F, {{100, -20.f, 20.f}}}}, {"isPositive", "is the candidate positive?; isPositive; counts", {HistType::kTH1F, {{2, -0.5f, 1.5f}}}}, @@ -472,6 +473,23 @@ struct LfTreeCreatorClusterStudies { return true; } + template + bool selectPidV0Daughters(const Track& posTrack, const Track& negTrack, uint8_t v0Bitmask) + { + if (TESTBIT(v0Bitmask, Lambda)) { + if (std::abs(posTrack.tpcNSigmaPr()) > v0settingNsigmatpcPr || std::abs(negTrack.tpcNSigmaPi()) > v0settingNsigmatpcPi) { + return false; + } + } else if (TESTBIT(v0Bitmask, AntiLambda)) { + if (std::abs(posTrack.tpcNSigmaPi()) > v0settingNsigmatpcPi || std::abs(negTrack.tpcNSigmaPr()) > v0settingNsigmatpcPr) { + return false; + } + } else { + return false; + } + return true; + } + /** * Fill the histograms for the V0 candidate and return the mass of the V0 */ @@ -585,8 +603,9 @@ struct LfTreeCreatorClusterStudies { mHistograms.fill(HIST(cNames[partID]) + HIST("/nSigmaTPC"), track.p() * track.sign(), nsigmaTpc); mHistograms.fill(HIST(cNames[partID]) + HIST("/nSigmaITS"), track.p() * track.sign(), nsigmaIts); mHistograms.fill(HIST(cNames[partID]) + HIST("/nSigmaTOF"), track.p() * track.sign(), nsigmaTof); - if (partID == static_cast(PartID::de) || partID == static_cast(PartID::he)) + if (partID == static_cast(PartID::de) || partID == static_cast(PartID::he)) { mHistograms.fill(HIST(cNames[partID]) + HIST("/TOFmass"), track.p() * track.sign(), massTof); + } mHistograms.fill(HIST(cNames[partID]) + HIST("/pmatching"), correctedTpcInnerParam * track.sign(), (correctedTpcInnerParam - track.p()) / correctedTpcInnerParam); } @@ -740,7 +759,7 @@ struct LfTreeCreatorClusterStudies { } const auto& timestamp = bc.timestamp(); - o2::parameters::GRPMagField* grpmag = 0x0; + o2::parameters::GRPMagField* grpmag = nullptr; auto grpmagPath{"GLO/Config/GRPMagField"}; grpmag = mccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); @@ -805,24 +824,29 @@ struct LfTreeCreatorClusterStudies { LOG(info) << "resolution: " << mBBparamsDe[5]; std::vector collisionSelectionLabels = {"All", "sel8", "z_{VTX} < 10 cm"}; - for (int i = 0; i < Selections::kAll; i++) + for (int i = 0; i < Selections::kAll; i++) { mHistograms.get(HIST("collision_selections"))->GetXaxis()->SetBinLabel(i + 1, collisionSelectionLabels[i].c_str()); + } std::vector V0selectionLabels = {"All", "daughter track quality", "V0 topology", "V0 mass selection"}; - for (int i = 0; i < V0Selections::kV0All; i++) + for (int i = 0; i < V0Selections::kV0All; i++) { mHistograms.get(HIST("v0_selections"))->GetXaxis()->SetBinLabel(i + 1, V0selectionLabels[i].c_str()); + } - std::vector CascSelectionLabels = {"All", "Topology", "Veto Xi", "Accepted Omega", "n#sigma_{TPC} K"}; - for (int i = 0; i < CascSelections::kCascAll; i++) + std::vector CascSelectionLabels = {"All", "Topology", "n#sigma_{TPC} V0 daughters", "Veto Xi", "n#sigma_{TPC} K", "Accepted Omega"}; + for (int i = 0; i < CascSelections::kCascAll; i++) { mHistograms.get(HIST("casc_selections"))->GetXaxis()->SetBinLabel(i + 1, CascSelectionLabels[i].c_str()); + } std::vector ESelectionLabels = {"All", "Track quality", "Primary", "Pid", "#pi^{0}"}; - for (int i = 0; i < ESelections::kEAll; i++) + for (int i = 0; i < ESelections::kEAll; i++) { mHistograms.get(HIST("e_selections"))->GetXaxis()->SetBinLabel(i + 1, ESelectionLabels[i].c_str()); + } std::vector V0TypeLabels = {"K0s", "#Lambda", "#bar{#Lambda}", "Photon"}; - for (int i = 0; i < V0Type::V0TypeAll; i++) + for (int i = 0; i < V0Type::V0TypeAll; i++) { mHistograms.get(HIST("v0_type"))->GetXaxis()->SetBinLabel(i + 1, V0TypeLabels[i].c_str()); + } } template @@ -879,7 +903,6 @@ struct LfTreeCreatorClusterStudies { const auto& posMcParticle = posTrack.mcParticle(); const auto& negMcParticle = negTrack.mcParticle(); - candidatePos.pdgCode = posMcParticle.pdgCode(); candidateNeg.pdgCode = negMcParticle.pdgCode(); @@ -906,6 +929,15 @@ struct LfTreeCreatorClusterStudies { } mHistograms.fill(HIST("casc_selections"), CascSelections::kCascTopology); + const auto& posTrack = cascade.template posTrack_as(); + const auto& negTrack = cascade.template negTrack_as(); + uint8_t v0Bitmask = 0; + SETBIT(v0Bitmask, bachelorTrack.sign() < 0 ? V0Type::Lambda : V0Type::AntiLambda); + if (!selectPidV0Daughters(posTrack, negTrack, v0Bitmask)) { + return; + } + mHistograms.fill(HIST("casc_selections"), CascSelections::kNSigmaTPCV0Daughters); + const float& massXi = cascade.mXi(); const float& massOmega = cascade.mOmega(); mHistograms.fill(HIST("Xi_vs_Omega"), massOmega, massXi); @@ -914,6 +946,10 @@ struct LfTreeCreatorClusterStudies { return; } mHistograms.fill(HIST("casc_selections"), CascSelections::kRejectedXi); + if (std::abs(bachelorTrack.tpcNSigmaKa()) > cascsettingNsigmatpc) { + return; + } + mHistograms.fill(HIST("casc_selections"), CascSelections::kNSigmaTPC); mHistograms.fill(HIST("massOmega"), cascade.pt() * bachelorTrack.sign(), massOmega); if (std::abs(massOmega - o2::constants::physics::MassOmegaMinus) > cascsettingMassWindowOmega) { @@ -921,10 +957,6 @@ struct LfTreeCreatorClusterStudies { } mHistograms.fill(HIST("casc_selections"), CascSelections::kAcceptedOmega); - if (std::abs(bachelorTrack.tpcNSigmaKa()) > cascsettingNsigmatpc) { - return; - } - mHistograms.fill(HIST("casc_selections"), CascSelections::kNSigmaTPC); fillHistogramsParticle(bachelorTrack); mClusterStudiesTable( @@ -973,8 +1005,9 @@ struct LfTreeCreatorClusterStudies { } mHistograms.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiNoCut); - if (track.itsNCls() < desettingNclsIts) + if (track.itsNCls() < desettingNclsIts) { return; + } mHistograms.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiNClsIts); const float tpcNsigma = kPartID == static_cast(PartID::de) ? track.tpcNSigmaDe() : computeNSigmaTPCHe3(track); @@ -1415,8 +1448,9 @@ struct LfTreeCreatorClusterStudies { const auto& negTracks_thisCollision = negTracksMc.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), mcache); for (const auto& [posTrack, negTrack] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posTracks_thisCollision, negTracks_thisCollision))) { - if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) { continue; + } fillElectronTableFromPi0Dalitz(posTrack, negTrack); } diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index 31fb7c63a0f..dc6995d51f1 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx b/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx index ba8c5baee07..8525881ff0e 100644 --- a/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx +++ b/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx @@ -90,7 +90,6 @@ #include #include #include -#include #include #include diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx index d7936c25005..ec84cb4c179 100644 --- a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -146,41 +146,43 @@ enum ParticleFlags { kFromOtherDecays = BIT(4), // from other (weak) decays }; -constexpr double kItsParamsDefault[static_cast(Species::kAllSpecies)][6] = { +constexpr std::array, static_cast(Species::kAllSpecies)> kItsParamsDefault = {{ {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}, // He3 {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32} // hadron -}; -static const std::vector kItsParNames{"p0", "p1", "p2", "res0", "res1", "res2"}; +}}; +const std::vector kItsParNames{"p0", "p1", "p2", "res0", "res1", "res2"}; -constexpr double kBetheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; -static const std::vector kBetheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr std::array, 1> kBetheBlochDefault = {{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}}; +const std::vector kBetheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -constexpr double kBetheBlochCorrectionDefault[1][6]{{0.0, -1.e32, -1.e32, 0.0, -1.e32, -1.e32}}; -static const std::vector kBetheBlochCorrectionParNames{"p0", "p1", "p2", "p3", "p4", "p5"}; +constexpr std::array, 1> kBetheBlochCorrectionDefault = {{{0.0, -1.e32, -1.e32, 0.0, -1.e32, -1.e32}}}; +const std::vector kBetheBlochCorrectionParNames{"p0", "p1", "p2", "p3", "p4", "p5"}; -constexpr double kDCAxyResDefault[static_cast(Species::kAllSpecies)][4] = { +constexpr std::array, static_cast(Species::kAllSpecies)> kDCAxyResDefault = {{ {1.09e-4, 0.0011, 0.0065, 1.0399}, // He3 {8.19e-5, 0.004, 0.0026, 1.1741} // Pr -}; -constexpr double kDCAzResDefault[static_cast(Species::kAllSpecies)][4] = { +}}; +constexpr std::array, static_cast(Species::kAllSpecies)> kDCAzResDefault = {{ {9.36e-5, 0.0019, 0.0080, 1.416}, // He3 {1.18e-4, 0.0020, 0.0025, 1.3460} // Pr -}; -static const std::vector kDCAResParNames{"res0", "res1", "res2", "mean"}; +}}; +const std::vector kDCAResParNames{"res0", "res1", "res2", "mean"}; -constexpr double kHePidTrkPtParamsHeDefault[3] = {0.3101, -0.1759, 0.0262}; -constexpr double kHePidTrkPParamsHeDefault[3] = {1.1157, -0.9171, 0.1987}; +constexpr std::array kHePidTrkPtParamsHeDefault = {0.3101, -0.1759, 0.0262}; +constexpr std::array kHePidTrkPParamsHeDefault = {0., 0., 0.}; } // namespace struct He3HadCandidate { - float recoPtHe3() const { return signHe3 * std::hypot(momHe3[0], momHe3[1]); } - float recoPhiHe3() const { return std::atan2(momHe3[1], momHe3[0]); } - float recoEtaHe3() const { return std::asinh(momHe3[2] / std::abs(recoPtHe3())); } - float recoPtHad() const { return signHad * std::hypot(momHad[0], momHad[1]); } - float recoPhiHad() const { return std::atan2(momHad[1], momHad[0]); } - float recoEtaHad() const { return std::asinh(momHad[2] / std::abs(recoPtHad())); } + [[nodiscard]] float recoPtHe3() const { return signHe3 * std::hypot(momHe3[0], momHe3[1]); } + [[nodiscard]] float recoPhiHe3() const { return std::atan2(momHe3[1], momHe3[0]); } + [[nodiscard]] float recoEtaHe3() const { return std::asinh(momHe3[2] / std::abs(recoPtHe3())); } + [[nodiscard]] float recoPtHad() const { return signHad * std::hypot(momHad[0], momHad[1]); } + [[nodiscard]] float recoPhiHad() const { return std::atan2(momHad[1], momHad[0]); } + [[nodiscard]] float recoEtaHad() const { return std::asinh(momHad[2] / std::abs(recoPtHad())); } + [[nodiscard]] float recoKstar() const { return getkstar(recoPtHe3(), recoEtaHe3(), recoPhiHe3(), constants::physics::MassHelium3, 1.f, + recoPtHad(), recoEtaHad(), recoPhiHad(), constants::physics::MassProton, 1.f); } std::array momHe3 = {99.f, 99.f, 99.f}; std::array momHad = {99.f, 99.f, 99.f}; @@ -258,6 +260,7 @@ struct he3HadronFemto { Configurable settingHadPDGCode{"settingHadPDGCode", 211, "Hadron - PDG code"}; struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember std::string prefix{"cutSettings"}; Configurable settingCutVertex{"settingCutVertex", 10.0f, "Accepted z-vertex range"}; Configurable settingCutRigidityMinHe3{"settingCutRigidityMinHe3", 0.8f, "Minimum rigidity for He3"}; @@ -311,13 +314,13 @@ struct he3HadronFemto { Configurable settingGeoPath{"settingGeoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable settingPidPath{"settingPidPath", "", "Path to the PID response object"}; - Configurable> settingBetheBlochParams{"settingBetheBlochParams", {kBetheBlochDefault[0], 1, 6, {"He3"}, kBetheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; - Configurable> settingBetheBlochCorrectionParams{"settingBetheBlochCorrectionParams", {kBetheBlochCorrectionDefault[0], 1, 6, {"He3"}, kBetheBlochCorrectionParNames}, "TPC Bethe-Bloch correction parameterisation for He3"}; - Configurable> settingItsParams{"settingItsParams", {kItsParamsDefault[0], 2, 6, {"He3", "Had"}, kItsParNames}, "ITS parameterisation"}; - Configurable> settingDCAxyResParams{"settingDCAxyResParams", {kDCAxyResDefault[0], 2, 4, {"He3", "Had"}, kDCAResParNames}, "DCAxy resolution parameterisation"}; - Configurable> settingDCAzResParams{"settingDCAzResParams", {kDCAzResDefault[0], 2, 4, {"He3", "Had"}, kDCAResParNames}, "DCAz resolution parameterisation"}; - Configurable> settingHePidTrkPtParams{"settingHePidTrkPtParams", {kHePidTrkPtParamsHeDefault, 1, 3, {"He3"}, {"p0", "p1", "p2"}}, "PID in tracking pT dependence for He3"}; - Configurable> settingHePidTrkPParams{"settingHePidTrkPParams", {kHePidTrkPParamsHeDefault, 1, 3, {"He3"}, {"p0", "p1", "p2"}}, "PID in tracking p dependence for He3"}; + Configurable> settingBetheBlochParams{"settingBetheBlochParams", {kBetheBlochDefault[0].data(), 1, 6, {"He3"}, kBetheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + Configurable> settingBetheBlochCorrectionParams{"settingBetheBlochCorrectionParams", {kBetheBlochCorrectionDefault[0].data(), 1, 6, {"He3"}, kBetheBlochCorrectionParNames}, "TPC Bethe-Bloch correction parameterisation for He3"}; + Configurable> settingItsParams{"settingItsParams", {kItsParamsDefault[0].data(), 2, 6, {"He3", "Had"}, kItsParNames}, "ITS parameterisation"}; + Configurable> settingDCAxyResParams{"settingDCAxyResParams", {kDCAxyResDefault[0].data(), 2, 4, {"He3", "Had"}, kDCAResParNames}, "DCAxy resolution parameterisation"}; + Configurable> settingDCAzResParams{"settingDCAzResParams", {kDCAzResDefault[0].data(), 2, 4, {"He3", "Had"}, kDCAResParNames}, "DCAz resolution parameterisation"}; + Configurable> settingHePidTrkPtParams{"settingHePidTrkPtParams", {kHePidTrkPtParamsHeDefault.data(), 1, 3, {"He3"}, {"p0", "p1", "p2"}}, "PID in tracking pT dependence for He3"}; + Configurable> settingHePidTrkPParams{"settingHePidTrkPParams", {kHePidTrkPParamsHeDefault.data(), 1, 3, {"He3"}, {"p0", "p1", "p2"}}, "PID in tracking p dependence for He3"}; Configurable settingCompensatePIDinTracking{"settingCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; Configurable settingMaterialCorrection{"settingMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Material correction type"}; @@ -334,24 +337,23 @@ struct he3HadronFemto { SameKindPair mPair{binningPolicy, settingNoMixedEvents, -1, &cache}; struct He3HadronParams { - std::array betheBlochParams; - std::array betheBlochCorrectionParams; - std::array, static_cast(Species::kAllSpecies)> itsParams; - std::array, static_cast(Species::kAllSpecies)> dcaxyResParams; - std::array, static_cast(Species::kAllSpecies)> dcazResParams; - std::array hePidTrkPtParams; - std::array hePidTrkPParams; + std::array betheBlochParams{}; + std::array betheBlochCorrectionParams{}; + std::array, static_cast(Species::kAllSpecies)> itsParams{}; + std::array, static_cast(Species::kAllSpecies)> dcaxyResParams{}; + std::array, static_cast(Species::kAllSpecies)> dcazResParams{}; + std::array hePidTrkPtParams{}; + std::array hePidTrkPParams{}; } mHe3HadronParams; o2::aod::ITSResponse mResponseITS; - std::vector mRecoCollisionIDs; std::vector mGoodCollisions; std::vector mTrackPairs; o2::vertexing::DCAFitterN<2> mFitter; svPoolCreator mSvPoolCreator{He3PDG, ProtonPDG}; - int mRunNumber; - float mDbz; + int mRunNumber = 0; + float mDbz = 0.f; Service mCcdb; Zorro mZorro; OutputObj mZorroSummary{"zorroSummary"}; @@ -368,7 +370,8 @@ struct he3HadronFemto { {"hNcontributor", "Number of primary vertex contributor", {HistType::kTH1F, {{2000, 0.0f, 2000.0f}}}}, {"hTrackSel", "Accepted tracks", {HistType::kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}}}, {"hEmptyPool", "svPoolCreator did not find track pairs false/true", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"hhe3HadtInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, + {"hhe3HadInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, + {"hhe3HadKstar", "; #it{k}* (GeV/#it{c})", {HistType::kTH1F, {{300, 0.f, 0.8f}}}}, {"hKstarRecVsKstarGen", "; #it{k}*_{gen} (GeV/#it{c}); #it{k}*_{rec} (GeV/#it{c})", {HistType::kTH2F, {{400, 0.f, 0.8f}, {400, 0.f, 0.8f}}}}, {"He3/hDCAxyHe3", "^{3}He;DCA_{xy} (cm)", {HistType::kTH1F, {{200, -0.5f, 0.5f}}}}, @@ -377,24 +380,26 @@ struct he3HadronFemto { {"He3/hChi2NClHe3ITS", "^{3}He;Chi2_{ITS} Ncluster", {HistType::kTH1F, {{100, 0, 100.0f}}}}, {"He3/hHe3Pt", "^{3}He; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, {"He3/h2dEdxHe3candidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, - {"He3/h2NsigmaHe3ITS", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} ^{3}He", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {120, -3.0f, 3.0f}}}}, - {"He3/h2NsigmaHe3ITS_preselection", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} ^{3}He", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}}}}, - {"He3/h2NsigmaHe3TPC", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, - {"He3/h2NsigmaHe3TPC_preselection", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"He3/h2NsigmaHe3ITS", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS}(^{3}He); Centrality FT0C (%)", {HistType::kTH3F, {{100, -5.0f, 5.0f}, {120, -3.0f, 3.0f}, {100, 0.0f, 100.0f}}}}, + {"He3/h2NsigmaHe3ITS_preselection", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS}(^{3}He); Centrality FT0C (%)", {HistType::kTH3F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}, {100, 0.0f, 100.0f}}}}, + {"He3/h2NsigmaHe3TPC", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He); Centrality FT0C (%)", {HistType::kTH3F, {{100, -5.0f, 5.0f}, {200, -5.0f, 5.0f}, {100, 0.0f, 100.0f}}}}, + {"He3/h2NsigmaHe3TPC_preselection", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He); Centrality FT0C (%)", {HistType::kTH3F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/hDCAxyHad", "had;DCA_{xy} (cm)", {HistType::kTH1F, {{200, -0.5f, 0.5f}}}}, + {"Had/hDCAzHad", "had;DCA_{z} (cm)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, {"Had/hNClsHadITS", "had;N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, {"Had/hChi2NClHadITS", "had;Chi2_{ITS} Ncluster", {HistType::kTH1F, {{100, 0, 100.0f}}}}, {"Had/hHadronPt", "had; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, - {"Had/h2NsigmaHadronITS", "NsigmaHadron ITS distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{ITS}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, - {"Had/h2NsigmaHadronITS_preselection", "NsigmaHadron ITS distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, - {"Had/h2NsigmaHadronTPC", "NsigmaHadron TPC distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, - {"Had/h2NsigmaHadronTPC_preselection", "NsigmaHadron TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, - {"Had/h2NsigmaHadronTPC_mcBackground", "NsigmaHadron TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, - {"Had/h2NsigmaHadronTPC_mcSignal", "NsigmaHadron TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, - {"Had/h2NsigmaHadronTOF", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, - {"Had/h2NsigmaHadronTOF_preselection", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, - {"Had/h2NsigmaHadronTOF_mcBackground", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, - {"Had/h2NsigmaHadronTOF_mcSignal", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"Had/h2NsigmaHadronITS", "NsigmaHadron ITS distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{ITS}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronITS_preselection", "NsigmaHadron ITS distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTPC", "NsigmaHadron TPC distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTPC_preselection", "NsigmaHadron TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTPC_mcBackground", "NsigmaHadron TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTPC_mcSignal", "NsigmaHadron TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTOF", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTOF_preselection", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTOF_mcBackground", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, + {"Had/h2NsigmaHadronTOF_mcSignal", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had); Centrality FT0C (%)", {HistType::kTH3F, {{200, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {100, 0.0f, 100.0f}}}}, }, OutputObjHandlingPolicy::AnalysisObject, false, @@ -494,8 +499,8 @@ struct he3HadronFemto { mRunNumber = bc.runNumber(); const float defaultBzValue = -999.0f; auto run3GrpTimestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = mCcdb->getForTimeStamp(settingGrpPath, run3GrpTimestamp); - o2::parameters::GRPMagField* grpmag = 0x0; + auto grpo = mCcdb->getForTimeStamp(settingGrpPath, run3GrpTimestamp); + o2::parameters::GRPMagField* grpmag = nullptr; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); if (settingDbz < defaultBzValue) { @@ -554,7 +559,7 @@ struct he3HadronFemto { if (std::abs(candidate.eta()) > cutSettings.settingCutEta) { return false; } - const int minTPCNClsFound = ispecies == Species::kHe3 ? static_cast(cutSettings.settingCutNClsTPCHe3) : static_cast(cutSettings.settingCutNClsTPCHe3); + const int minTPCNClsFound = ispecies == Species::kHe3 ? static_cast(cutSettings.settingCutNClsTPCHe3) : static_cast(cutSettings.settingCutNClsTPC); const int minTPCNClsCrossedRows = 70; const float minChi2NCl = ispecies == Species::kHe3 ? static_cast(cutSettings.settingCutChi2tpcLowHe3) : static_cast(cutSettings.settingCutChi2tpcLow); const float maxChi2NCl = 4.f; @@ -572,8 +577,9 @@ struct he3HadronFemto { float correctPtHe3TrackedAsTriton(const float pt, const uint32_t pidForTracking) { - if (pt < 2.5 && pidForTracking == o2::track::PID::Triton) + if (pt < 2.5 && pidForTracking == o2::track::PID::Triton) { return pt * (1. - mHe3HadronParams.hePidTrkPtParams[0] - mHe3HadronParams.hePidTrkPtParams[1] * pt - mHe3HadronParams.hePidTrkPtParams[2] * pt * pt); + } return pt; } @@ -584,8 +590,9 @@ struct he3HadronFemto { float correctedTPCinnerParam = (heliumPID && settingCompensatePIDinTracking) ? tpcInnerParam / 2.f : tpcInnerParam; correctedTPCinnerParam *= 2.f; // rigidity to momentum - if (correctedTPCinnerParam < 2.5 && pidForTracking == o2::track::PID::Triton) + if (correctedTPCinnerParam < 2.5 && pidForTracking == o2::track::PID::Triton) { return correctedTPCinnerParam * (1. - mHe3HadronParams.hePidTrkPParams[0] - mHe3HadronParams.hePidTrkPParams[1] * correctedTPCinnerParam - mHe3HadronParams.hePidTrkPParams[2] * correctedTPCinnerParam * correctedTPCinnerParam); + } return correctedTPCinnerParam; } @@ -593,7 +600,7 @@ struct he3HadronFemto { float computeNsigmaDCA(const float pt, const float dca, const int iSpecies, const char* dcaType = "xy") { - std::array parameters; + std::array parameters{{0., 0., 0., 0.}}; if (std::strcmp(dcaType, "xy") == 0) { parameters = mHe3HadronParams.dcaxyResParams[iSpecies]; } else if (std::strcmp(dcaType, "z") == 0) { @@ -613,8 +620,9 @@ struct he3HadronFemto { const float nsigmaDcaZ = computeNsigmaDCA(pt, dcaZ, ispecies, "z"); if (std::abs(nsigmaDcaXy) > cutSettings.settingCutNsigmaDcaXy || - std::abs(nsigmaDcaZ) > cutSettings.settingCutNsigmaDcaZ) + std::abs(nsigmaDcaZ) > cutSettings.settingCutNsigmaDcaZ) { return false; + } return true; } @@ -647,26 +655,26 @@ struct he3HadronFemto { return tofNSigmaHad; } - template - bool selectionPIDHadron(const Ttrack& candidate) + template + bool selectionPIDHadron(const Ttrack& candidate, const Tcollision& collision) { auto tpcNSigmaHad = computeTPCNSigmaHadron(candidate); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), candidate.tpcInnerParam(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), candidate.tpcInnerParam(), tpcNSigmaHad, collision.centFT0C()); if (candidate.hasTOF() && candidate.pt() > cutSettings.settingCutPtMinTOFHad) { auto tofNSigmaHad = computeTOFNSigmaHadron(candidate); if (std::abs(tpcNSigmaHad) > cutSettings.settingCutNsigmaTPC) { return false; } - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), candidate.pt(), tofNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), candidate.pt(), tofNSigmaHad, collision.centFT0C()); if (std::abs(tofNSigmaHad) > cutSettings.settingCutNsigmaTOF) { return false; } - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC"), candidate.pt(), tpcNSigmaHad); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF"), candidate.pt(), tofNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC"), candidate.pt(), tpcNSigmaHad, collision.centFT0C()); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF"), candidate.pt(), tofNSigmaHad, collision.centFT0C()); return true; } else if (std::abs(tpcNSigmaHad) < cutSettings.settingCutNsigmaTPC) { - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC"), candidate.pt(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC"), candidate.pt(), tpcNSigmaHad, collision.centFT0C()); return true; } return false; @@ -696,8 +704,8 @@ struct he3HadronFemto { return static_cast((tpcSignal - expTPCSignal) / resoTPC); } - template - bool selectionPIDHe3(const Ttrack& candidate) + template + bool selectionPIDHe3(const Ttrack& candidate, const Tcollision& collision) { const float correctedTPCinnerParam = correctTpcInnerParamHe3(candidate.tpcInnerParam(), candidate.pidForTracking()); const float correctedPt = correctPtHe3TrackedAsTriton(candidate.pt(), candidate.pidForTracking()); @@ -707,20 +715,20 @@ struct he3HadronFemto { } auto nSigmaHe3 = computeNSigmaHe3(correctedTPCinnerParam, candidate.tpcSignal(), /*applyCorrection*/ true); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), candidate.sign() * correctedPt, nSigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), candidate.sign() * correctedPt, nSigmaHe3, collision.centFT0C()); if (std::abs(nSigmaHe3) > cutSettings.settingCutNsigmaTPC) { return false; } auto itsNsigmaHe3 = mResponseITS.nSigmaITS(candidate.itsClusterSizes(), 2 * candidate.p(), candidate.eta()); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS_preselection"), candidate.sign() * correctedPt, itsNsigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS_preselection"), candidate.sign() * correctedPt, itsNsigmaHe3, collision.centFT0C()); if (itsNsigmaHe3 < cutSettings.settingCutNsigmaITSHe3) { return false; } mQaRegistry.fill(HIST("He3/h2dEdxHe3candidates"), candidate.sign() * correctedTPCinnerParam, candidate.tpcSignal()); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC"), candidate.sign() * correctedPt, nSigmaHe3); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS"), candidate.sign() * correctedPt, itsNsigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC"), candidate.sign() * correctedPt, nSigmaHe3, collision.centFT0C()); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS"), candidate.sign() * correctedPt, itsNsigmaHe3, collision.centFT0C()); return true; } @@ -784,8 +792,9 @@ struct he3HadronFemto { std::array collisionVertex = getCollisionVertex(collisions, he3Hadcand.collisionID); he3Hadcand.momHe3 = std::array{trackHe3.px(), trackHe3.py(), trackHe3.pz()}; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { he3Hadcand.momHe3[i] = he3Hadcand.momHe3[i] * 2; + } he3Hadcand.momHad = std::array{trackHad.px(), trackHad.py(), trackHad.pz()}; float invMass = CommonInite; if (settingHadPDGCode == PDG_t::kPiPlus) { @@ -814,7 +823,7 @@ struct he3HadronFemto { } else { auto trackCovHe3 = getTrackParCov(trackHe3); auto trackCovHad = getTrackParCov(trackHad); - std::array dcaInfo; + std::array dcaInfo{{-999., -999.}}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collisionVertex[0], collisionVertex[1], collisionVertex[2]}, trackCovHe3, 2.f, mFitter.getMatCorrType(), &dcaInfo); he3Hadcand.dcaxyHe3 = dcaInfo[0]; he3Hadcand.dcazHe3 = dcaInfo[1]; @@ -898,8 +907,8 @@ struct he3HadronFemto { he3Hadcand.l4MassMC = std::sqrt(eLit * eLit - mctrackMother.p() * mctrackMother.p()); } - template - void pairTracksSameEvent(const Ttrack& tracks) + template + void pairTracksSameEvent(const Ttrack& tracks, const Tcollision& collision) { for (const auto& track0 : tracks) { @@ -910,7 +919,7 @@ struct he3HadronFemto { } mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); - if (!selectionPIDHe3(track0)) { + if (!selectionPIDHe3(track0, collision)) { continue; } mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); @@ -930,7 +939,7 @@ struct he3HadronFemto { } } - if (!selectTrack(track1, Species::kHad) || !selectionPIDHadron(track1)) { + if (!selectTrack(track1, Species::kHad) || !selectionPIDHadron(track1, collision)) { continue; } @@ -945,15 +954,15 @@ struct he3HadronFemto { } } - template - void pairTracksEventMixing(T& he3Cands, T& hadronCands) + template + void pairTracksEventMixing(Ttrack& he3Cands, Ttrack& hadronCands, const Tcollision& collision) { for (const auto& he3Cand : he3Cands) { - if (!selectTrack(he3Cand, Species::kHe3) || !selectionPIDHe3(he3Cand)) { + if (!selectTrack(he3Cand, Species::kHe3) || !selectionPIDHe3(he3Cand, collision)) { continue; } for (const auto& hadronCand : hadronCands) { - if (!selectTrack(hadronCand, Species::kHad) || !selectionPIDHadron(hadronCand)) { + if (!selectTrack(hadronCand, Species::kHad) || !selectionPIDHadron(hadronCand, collision)) { continue; } @@ -1005,9 +1014,12 @@ struct he3HadronFemto { { mQaRegistry.fill(HIST("He3/hHe3Pt"), he3Hadcand.recoPtHe3()); mQaRegistry.fill(HIST("Had/hHadronPt"), he3Hadcand.recoPtHad()); - mQaRegistry.fill(HIST("hhe3HadtInvMass"), he3Hadcand.invMass); + mQaRegistry.fill(HIST("hhe3HadInvMass"), he3Hadcand.invMass); + mQaRegistry.fill(HIST("hhe3HadKstar"), he3Hadcand.recoKstar()); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), he3Hadcand.dcaxyHe3); mQaRegistry.fill(HIST("He3/hDCAzHe3"), he3Hadcand.dcazHe3); + mQaRegistry.fill(HIST("Had/hDCAxyHad"), he3Hadcand.dcaxyHad); + mQaRegistry.fill(HIST("Had/hDCAzHad"), he3Hadcand.dcazHad); mQaRegistry.fill(HIST("He3/hNClsHe3ITS"), he3Hadcand.nclsITSHe3); mQaRegistry.fill(HIST("Had/hNClsHadITS"), he3Hadcand.nclsITSHad); mQaRegistry.fill(HIST("He3/hChi2NClHe3ITS"), he3Hadcand.chi2nclITSHe3); @@ -1160,9 +1172,9 @@ struct he3HadronFemto { auto trackTableThisCollision = tracks.sliceBy(mPerCol, collIdx); trackTableThisCollision.bindExternalIndices(&tracks); - pairTracksSameEvent(trackTableThisCollision); + pairTracksSameEvent(trackTableThisCollision, collision); - if (mTrackPairs.size() == 0) { + if (mTrackPairs.empty()) { continue; } @@ -1184,8 +1196,8 @@ struct he3HadronFemto { mQaRegistry.fill(HIST("hNcontributor"), c1.numContrib()); mQaRegistry.fill(HIST("hVtxZ"), c1.posZ()); - pairTracksEventMixing(tracks1, tracks2); - pairTracksEventMixing(tracks2, tracks1); + pairTracksEventMixing(tracks1, tracks2, c1); + pairTracksEventMixing(tracks2, tracks1, c2); } fillPairs(collisions, tracks, /*isMixedEvent*/ true); @@ -1212,7 +1224,7 @@ struct he3HadronFemto { auto trackTableThisCollision = tracks.sliceBy(mPerColMC, collIdx); trackTableThisCollision.bindExternalIndices(&tracks); - pairTracksSameEvent(trackTableThisCollision); + pairTracksSameEvent(trackTableThisCollision, collision); for (const auto& trackPair : mTrackPairs) { @@ -1243,14 +1255,14 @@ struct he3HadronFemto { he3Hadcand.flags |= Flags::kBothPrimaries; isMixedPair = false; - } else if ((he3Hadcand.flagsHe3 & ParticleFlags::kFromLi4) && (he3Hadcand.flagsHad & ParticleFlags::kFromLi4)) { + } else if (static_cast(he3Hadcand.flagsHe3 & ParticleFlags::kFromLi4) && static_cast(he3Hadcand.flagsHad & ParticleFlags::kFromLi4)) { searchForCommonMotherTrack(motherHe3Idxs, motherHadIdxs, mcParticles, motherParticle, he3Hadcand, isMixedPair, Li4PDG); if (!isMixedPair) { he3Hadcand.flags |= Flags::kBothFromLi4; } - } else if ((he3Hadcand.flagsHe3 & ParticleFlags::kFromHypertriton) && (he3Hadcand.flagsHad & ParticleFlags::kFromHypertriton)) { + } else if (static_cast(he3Hadcand.flagsHe3 & ParticleFlags::kFromHypertriton) && static_cast(he3Hadcand.flagsHad & ParticleFlags::kFromHypertriton)) { searchForCommonMotherTrack(motherHe3Idxs, motherHadIdxs, mcParticles, motherParticle, he3Hadcand, isMixedPair, H3LPDG); if (!isMixedPair) { @@ -1286,7 +1298,6 @@ struct he3HadronFemto { } fillHistograms(he3Hadcand, /*isMc*/ true); - auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); fillTable(he3Hadcand, collision, /*isMC*/ true); } } @@ -1302,37 +1313,41 @@ struct he3HadronFemto { for (const auto& track : tracks) { - if (!selectTrack(track, Species::kHad)) + if (!selectTrack(track, Species::kHad)) { continue; + } const float itsNSigmaHad = settingHadPDGCode == PDG_t::kProton ? mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()) : mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronITS_preselection"), track.sign() * track.pt(), itsNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronITS_preselection"), track.sign() * track.pt(), itsNSigmaHad, collision.centFT0C()); if (selectDcaNsigmaCut(track.pt(), track.dcaXY(), track.dcaZ(), Species::kHad) && (itsNSigmaHad > cutSettings.settingCutNsigmaITSHad)) { mQaRegistry.fill(HIST("Had/hHadronPt"), track.sign() * track.pt()); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronITS"), track.sign() * track.pt(), itsNSigmaHad); + mQaRegistry.fill(HIST("Had/hDCAxyHad"), track.dcaXY()); + mQaRegistry.fill(HIST("Had/hDCAzHad"), track.dcaZ()); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronITS"), track.sign() * track.pt(), itsNSigmaHad, collision.centFT0C()); const float tpcNSigmaHad = computeTPCNSigmaHadron(track); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), track.sign() * track.pt(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), track.sign() * track.pt(), tpcNSigmaHad, collision.centFT0C()); if (track.hasTOF()) { const float tofNSigmaHad = computeTOFNSigmaHadron(track); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), track.sign() * track.pt(), tofNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), track.sign() * track.pt(), tofNSigmaHad, collision.centFT0C()); } } const float ptHe3Corrected = correctPtHe3TrackedAsTriton(track.pt(), track.pidForTracking()); const float itsNSigmaHe3 = mResponseITS.nSigmaITS(track.itsClusterSizes(), 2 * track.p(), track.eta()); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS_preselection"), ptHe3Corrected, itsNSigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS_preselection"), ptHe3Corrected, itsNSigmaHe3, collision.centFT0C()); - if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3) || (itsNSigmaHe3 < cutSettings.settingCutNsigmaITSHe3)) + if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3) || (itsNSigmaHe3 < cutSettings.settingCutNsigmaITSHe3)) { continue; + } mQaRegistry.fill(HIST("He3/hHe3Pt"), track.sign() * ptHe3Corrected); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), track.dcaXY()); mQaRegistry.fill(HIST("He3/hDCAzHe3"), track.dcaZ()); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS"), track.sign() * ptHe3Corrected, itsNSigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS"), track.sign() * ptHe3Corrected, itsNSigmaHe3, collision.centFT0C()); const float correctedTPCinnerParam = correctTpcInnerParamHe3(track.tpcInnerParam(), track.pidForTracking()); if (correctedTPCinnerParam < cutSettings.settingCutRigidityMinHe3) { @@ -1340,52 +1355,56 @@ struct he3HadronFemto { } const float tpcNSigmaHe3 = computeNSigmaHe3(correctedTPCinnerParam, track.tpcSignal(), /*applyCorrection*/ true); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), track.sign() * ptHe3Corrected, tpcNSigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), track.sign() * ptHe3Corrected, tpcNSigmaHe3, collision.centFT0C()); } } PROCESS_SWITCH(he3HadronFemto, processPurity, "Process for purity studies", false); void processPurityMc(const CollisionsFullMC::iterator& collision, const TrackCandidatesMC& tracks, const aod::BCsWithTimestamps& bcs, const aod::McParticles& /*mcParticles*/, const aod::McTrackLabels& /*mcTrackLabels*/) { - if (!selectCollision(collision, bcs)) + if (!selectCollision(collision, bcs)) { return; + } for (const auto& track : tracks) { - if (!track.has_mcParticle()) + if (!track.has_mcParticle()) { continue; + } const auto& particle = track.mcParticle_as(); - if (!selectTrack(track, Species::kHad)) + if (!selectTrack(track, Species::kHad)) { continue; + } if (selectDcaNsigmaCut(track.pt(), track.dcaXY(), track.dcaZ(), Species::kHad)) { mQaRegistry.fill(HIST("Had/hHadronPt"), track.pt()); const float tpcNSigmaHad = computeTPCNSigmaHadron(track); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), track.sign() * track.pt(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), track.sign() * track.pt(), tpcNSigmaHad, collision.centFT0C()); if (std::abs(particle.pdgCode()) != settingHadPDGCode) { - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_mcBackground"), track.sign() * track.pt(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_mcBackground"), track.sign() * track.pt(), tpcNSigmaHad, collision.centFT0C()); } else { - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_mcSignal"), track.sign() * track.pt(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_mcSignal"), track.sign() * track.pt(), tpcNSigmaHad, collision.centFT0C()); } if (track.hasTOF()) { const float tofNSigmaHad = computeTOFNSigmaHadron(track); - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), track.sign() * track.pt(), tofNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), track.sign() * track.pt(), tofNSigmaHad, collision.centFT0C()); if (std::abs(particle.pdgCode()) != settingHadPDGCode) { - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_mcBackground"), track.sign() * track.pt(), tofNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_mcBackground"), track.sign() * track.pt(), tofNSigmaHad, collision.centFT0C()); } else { - mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_mcSignal"), track.sign() * track.pt(), tofNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_mcSignal"), track.sign() * track.pt(), tofNSigmaHad, collision.centFT0C()); } } } const float ptHe3Corrected = correctPtHe3TrackedAsTriton(track.pt(), track.pidForTracking()); - if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3)) + if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3)) { continue; + } mQaRegistry.fill(HIST("He3/hHe3Pt"), ptHe3Corrected); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), track.dcaXY()); @@ -1397,7 +1416,7 @@ struct he3HadronFemto { } const float nSigmaHe3 = computeNSigmaHe3(correctedTPCinnerParam, track.tpcSignal(), /*applyCorrection*/ true); - mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), track.sign() * ptHe3Corrected, nSigmaHe3); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), track.sign() * ptHe3Corrected, nSigmaHe3, collision.centFT0C()); } } PROCESS_SWITCH(he3HadronFemto, processPurityMc, "Process for purity studies mc", false); diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index 6a26cbef2b4..b5dc7ca67f2 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -964,23 +964,26 @@ struct hyperRecoTask { // now we fill only the signal candidates that were not reconstructed for (const auto& mcPart : particlesMC) { - if (std::abs(mcPart.pdgCode()) != hyperPdg) + if (std::abs(mcPart.pdgCode()) != hyperPdg) { continue; - std::array secVtx; + } + std::array secVtx{0.f, 0.f, 0.f}; + std::array lastDaugVtx{0.f, 0.f, 0.f}; std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; - std::array momHe3; + std::array momHe3{0.f, 0.f, 0.f}; bool isHeFound = false; int mcProcess = {0}; for (const auto& mcDaught : mcPart.daughters_as()) { + if (mcDaught.pdgCode() != PDG_t::kElectron) { // we do not care about delta electrons + lastDaugVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; + mcProcess = mcDaught.getProcess(); + } if (std::abs(mcDaught.pdgCode()) == heDauPdg) { - secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; + secVtx = lastDaugVtx; momHe3 = {mcDaught.px(), mcDaught.py(), mcDaught.pz()}; isHeFound = true; } - if (mcDaught.pdgCode() != PDG_t::kElectron) { // we do not care about delta electrons - mcProcess = mcDaught.getProcess(); - } } if (mcPart.pdgCode() > 0) { hIsMatterGen->Fill(0.); @@ -1005,7 +1008,7 @@ struct hyperRecoTask { hypCand.isSurvEvSelection = isSurvEvSelCollision[mcPart.mcCollisionId()]; int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); for (int i = 0; i < 3; i++) { - hypCand.gDecVtx[i] = secVtx[i] - primVtx[i]; + hypCand.gDecVtx[i] = (isHeFound ? secVtx[i] : lastDaugVtx[i]) - primVtx[i]; hypCand.gMom[i] = momMother[i]; hypCand.gMomHe3[i] = momHe3[i]; } diff --git a/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx b/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx new file mode 100644 index 00000000000..a78843606e5 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx @@ -0,0 +1,750 @@ +// Copyright 2019-2026 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 nucleiThreeBodyBuilder.cxx +/// \brief Generic He3-hadron-hadron secondary-vertex table producer +/// \author ALICE Collaboration + +#include "PWGLF/DataModel/Vtx3BodyTables.h" +#include "PWGLF/Utils/svPoolCreator.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +namespace +{ +using Collisions = soa::Join; +using CollisionsPbPb = soa::Join; +using CollisionsMC = soa::Join; +using Tracks = soa::Join; +using TracksMC = soa::Join; + +constexpr int He3Pdg = o2::constants::physics::Pdg::kHelium3; +constexpr float InvalidFloat = -999.f; +constexpr int InvalidLabel = -1; +constexpr int NProngs = 3; +constexpr float He3Charge = 2.f; +constexpr float UseCCDBBzThreshold = -990.f; +constexpr int He3PoolId = 1; +constexpr int Daughter1PoolId = 2; +constexpr int Daughter2PoolId = 3; +constexpr std::array DefaultHe3BetheBloch{-321.34, 0.6539, 1.591, 0.8225, 2.363, 0.09}; +const std::vector BetheBlochNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +const std::vector He3Name{"He3"}; + +enum MCMatchStatus : uint8_t { + MissingDaughterLabel = 0, + NoCommonImmediateMother, + CommonImmediateMother, + ConfiguredDecay +}; + +bool isSupportedHadronPdg(int pdg) +{ + const int absPdg = std::abs(pdg); + return absPdg == PDG_t::kPiPlus || + absPdg == PDG_t::kKPlus || absPdg == PDG_t::kProton; +} +} // namespace + +struct NucleiThreeBodyBuilder { + Produces outputData; + Produces outputMC; + + Service ccdb; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + struct : ConfigurableGroup { + std::string prefix{"event"}; + Configurable requireSel8{"requireSel8", true, "Require sel8 (main pp default)"}; + Configurable maxAbsZvtx{"maxAbsZvtx", 10.f, "Maximum absolute PV z; negative disables"}; + Configurable requireNoITSROFrameBorder{"requireNoITSROFrameBorder", false, "Require kNoITSROFrameBorder"}; + Configurable requireNoTimeFrameBorder{"requireNoTimeFrameBorder", false, "Require kNoTimeFrameBorder"}; + Configurable requireNoSameBunchPileup{"requireNoSameBunchPileup", false, "Require kNoSameBunchPileup"}; + Configurable requireGoodZvtxFT0vsPV{"requireGoodZvtxFT0vsPV", false, "Require kIsGoodZvtxFT0vsPV"}; + } event; + + struct : ConfigurableGroup { + std::string prefix{"pbpb"}; + Configurable minCentFT0C{"minCentFT0C", 0.f, "Minimum FT0C centrality"}; + Configurable maxCentFT0C{"maxCentFT0C", 100.f, "Maximum FT0C centrality"}; + } pbpb; + + struct : ConfigurableGroup { + std::string prefix{"he3"}; + Configurable minTPCInnerParam{"minTPCInnerParam", 0.8f, "Minimum He3 TPC rigidity"}; + Configurable maxAbsTPCNSigma{"maxAbsTPCNSigma", 5.f, "Maximum absolute custom He3 TPC n-sigma"}; + Configurable requirePIDForTracking{"requirePIDForTracking", false, "Require Helium3 or Alpha PID during tracking"}; + Configurable compensatePIDinTracking{"compensatePIDinTracking", true, "Divide TPC inner parameter by two for charge-two tracking PID"}; + Configurable> betheBlochParams{"betheBlochParams", {DefaultHe3BetheBloch.data(), 1, 6, He3Name, BetheBlochNames}, "TPC Bethe-Bloch parameters for He3"}; + } he3; + + struct : ConfigurableGroup { + std::string prefix{"track"}; + Configurable maxAbsEta{"maxAbsEta", 0.9f, "Maximum absolute eta for every daughter"}; + Configurable minTPCCrossedRows{"minTPCCrossedRows", 70, "Minimum TPC crossed rows for every daughter"}; + Configurable minAbsDCAxyToPV{"minAbsDCAxyToPV", 0.f, "Minimum absolute DCAxy to the assigned/candidate PV for every daughter; zero disables"}; + Configurable minAbsDCAzToPV{"minAbsDCAzToPV", 0.f, "Minimum absolute DCAz to the assigned/candidate PV for every daughter; zero disables"}; + } trackSelections; + + struct : ConfigurableGroup { + std::string prefix{"decay"}; + Configurable daughter1Pdg{"daughter1Pdg", PDG_t::kProton, "Signed pi/K/p PDG relative to a positive He3; used for charge pairing, optional PID selection, and MC matching"}; + Configurable daughter2Pdg{"daughter2Pdg", -PDG_t::kPiPlus, "Signed pi/K/p PDG relative to a positive He3; used for charge pairing, optional PID selection, and MC matching"}; + Configurable motherPdg{"motherPdg", 1010020040, "Mother PDG for MC matching; zero accepts either common mother"}; + } decay; + + struct : ConfigurableGroup { + std::string prefix{"vertex"}; + Configurable minCosPA{"minCosPA", 0.9f, "Minimum cosine of pointing angle; below -1 disables"}; + } vertexSelections; + + struct : ConfigurableGroup { + std::string prefix{"candidate"}; + Configurable applySelections{"applySelections", false, "Apply the additional candidate selections"}; + Configurable maxChi2{"maxChi2", 100.f, "Maximum DCA-fitter chi2"}; + Configurable maxDCADaughters{"maxDCADaughters", 1.f, "Maximum square root of fitter chi2"}; + Configurable maxAbsTPCNSigmaDaughter1{"maxAbsTPCNSigmaDaughter1", 5.f, "Maximum daughter 1 TPC n-sigma for its configured hypothesis"}; + Configurable maxAbsTOFNSigmaDaughter1{"maxAbsTOFNSigmaDaughter1", 5.f, "Maximum daughter 1 TOF n-sigma; applied only with TOF"}; + Configurable maxAbsTPCNSigmaDaughter2{"maxAbsTPCNSigmaDaughter2", 5.f, "Maximum daughter 2 TPC n-sigma for its configured hypothesis"}; + Configurable maxAbsTOFNSigmaDaughter2{"maxAbsTOFNSigmaDaughter2", 5.f, "Maximum daughter 2 TOF n-sigma; applied only with TOF"}; + Configurable minDecayLength{"minDecayLength", 0.f, "Minimum decay length"}; + Configurable maxDecayLength{"maxDecayLength", 100.f, "Maximum decay length"}; + } candidateSelections; + + struct : ConfigurableGroup { + std::string prefix{"pool"}; + Configurable timeMargin{"timeMargin", 800.f, "Track-collision compatibility margin in ns"}; + Configurable skipAmbiguousTracks{"skipAmbiguousTracks", false, "Reject unassigned ambiguous tracks"}; + } pool; + + struct : ConfigurableGroup { + std::string prefix{"zorro"}; + Configurable enabled{"enabled", false, "Enable fHe trigger selection and accounting for skimmed pp data"}; + Configurable ccdbPath{"ccdbPath", "EventFiltering/Zorro/", "Base path of Zorro CCDB objects"}; + Configurable bcTolerance{"bcTolerance", 100, "Zorro BC matching tolerance"}; + } zorroOptions; + + struct : ConfigurableGroup { + std::string prefix{"mc"}; + Configurable requireConfiguredDecayForGen{"requireConfiguredDecayForGen", true, "Fill generated quantities only for the configured daughters and optional mother PDG"}; + } mc; + + Configurable ccdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "CCDB URL"}; // o2-linter: disable=name/configurable (Established CCDB option name.) + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of magnetic-field object"}; + Configurable bzInput{"bz", -999.f, "Magnetic field in kG; below -990 uses CCDB"}; // o2-linter: disable=name/configurable (Established magnetic-field option name.) + + o2::vertexing::DCAFitterN<3> fitter; + svPoolCreator3Body tripletPool{He3PoolId, Daughter1PoolId, Daughter2PoolId}; + int runNumber = -1; + float bz = 0.f; + std::array he3BetheBloch{}; + std::vector selectedCollisions; + std::vector collisionsWithHe3; + std::vector identifiedHe3Tracks; + std::vector preselectedTracks; + + struct RecoCandidate { + std::array signs{}; + float pt = 0.f; + float eta = 0.f; + float phi = 0.f; + std::array daughterMomentum{}; + float chi2 = 0.f; + float dcaDaughters = 0.f; + float cosPA = 0.f; + float decayLength = 0.f; + std::array dcaXYToPV{}; + std::array dcaZToPV{}; + float tpcNSigmaHe3 = InvalidFloat; + float tofNSigmaHe3 = InvalidFloat; + std::array, 2> tpcNSigmaHadron{}; + std::array, 2> tofNSigmaHadron{}; + std::array tpcNCls{}; + std::array tpcCrossedRows{}; + std::array itsNCls{}; + }; + + struct MCInfo { + std::array pdgs{}; + uint8_t matchStatus = MissingDaughterLabel; + int motherPdg = 0; + float motherPt = InvalidFloat; + float motherEta = InvalidFloat; + float motherPhi = InvalidFloat; + float decayLength = InvalidFloat; + }; + + void init(InitContext const&) + { + const int enabledProcesses = static_cast(doprocessData) + static_cast(doprocessPbPb) + static_cast(doprocessMC); + if (enabledProcesses != 1) { + LOG(fatal) << "Enable exactly one of processData, processPbPb, and processMC"; + } + if (zorroOptions.enabled && !doprocessData) { + LOG(fatal) << "Zorro is supported only by the pp data process path"; + } + if (!isSupportedHadronPdg(decay.daughter1Pdg) || !isSupportedHadronPdg(decay.daughter2Pdg)) { + LOG(fatal) << "Signed daughter PDG codes must identify a pion, kaon, or proton"; + } + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + zorroSummary.setObject(zorro.getZorroSummary()); + zorro.setBaseCCDBPath(zorroOptions.ccdbPath); + zorro.setBCtolerance(zorroOptions.bcTolerance); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.f); + fitter.setMinParamChange(1.e-3f); + fitter.setMinRelChi2Change(0.9f); + fitter.setMaxDZIni(1.e9f); + fitter.setMaxChi2(1.e9f); + fitter.setUseAbsDCA(true); + + tripletPool.setTimeMargin(pool.timeMargin); + if (pool.skipAmbiguousTracks) { + tripletPool.setSkipAmbiTracks(); + } + for (size_t i = 0; i < he3BetheBloch.size(); ++i) { + he3BetheBloch[i] = he3.betheBlochParams->get("He3", BetheBlochNames[i].c_str()); + } + + registry.add("events", "Event and He3 preselection;step;events", HistType::kTH1D, {{5, -0.5, 4.5}}); + auto events = registry.get(HIST("events")); + events->GetXaxis()->SetBinLabel(1, "all"); + events->GetXaxis()->SetBinLabel(2, "Zorro fHe"); + events->GetXaxis()->SetBinLabel(3, "event selected"); + events->GetXaxis()->SetBinLabel(4, "identified He3"); + events->GetXaxis()->SetBinLabel(5, "candidate filled"); + registry.add("zorroEvents", "Zorro accounting;selection;events", HistType::kTH1D, {{2, -0.5, 1.5}}); + auto zorroEvents = registry.get(HIST("zorroEvents")); + zorroEvents->GetXaxis()->SetBinLabel(1, "fHe before event selection"); + zorroEvents->GetXaxis()->SetBinLabel(2, "fHe after event selection"); + registry.add("triplets", "Triplet building;step;count", HistType::kTH1D, {{3, -0.5, 2.5}}); + auto triplets = registry.get(HIST("triplets")); + triplets->GetXaxis()->SetBinLabel(1, "pool combinations"); + triplets->GetXaxis()->SetBinLabel(2, "fit succeeded"); + triplets->GetXaxis()->SetBinLabel(3, "stored"); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (runNumber == bc.runNumber()) { + return; + } + if (zorroOptions.enabled) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + auto* grpmag = ccdb->getForTimeStamp(grpmagPath, bc.timestamp()); + if (!grpmag) { + LOG(fatal) << "Missing magnetic-field object " << grpmagPath << " for timestamp " << bc.timestamp(); + } + o2::base::Propagator::initFieldFromGRP(grpmag); + bz = bzInput < UseCCDBBzThreshold ? o2::base::Propagator::Instance()->getNominalBz() : bzInput; + o2::base::Propagator::Instance()->setNominalBz(bz); + fitter.setBz(bz); + runNumber = bc.runNumber(); + } + + template + float correctedHe3Rigidity(TTrack const& track) + { + const bool chargeTwoPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + return chargeTwoPID && he3.compensatePIDinTracking ? track.tpcInnerParam() / He3Charge : track.tpcInnerParam(); + } + + template + float tpcNSigmaHe3(TTrack const& track) + { + const float rigidity = correctedHe3Rigidity(track); + const float expected = o2::common::BetheBlochAleph(static_cast(rigidity * He3Charge / constants::physics::MassHelium3), + he3BetheBloch[0], he3BetheBloch[1], he3BetheBloch[2], + he3BetheBloch[3], he3BetheBloch[4]); + return (track.tpcSignal() - expected) / (expected * he3BetheBloch[5]); + } + + template + bool isIdentifiedHe3(TTrack const& track) + { + if (!track.hasTPC() || correctedHe3Rigidity(track) < he3.minTPCInnerParam || + std::abs(tpcNSigmaHe3(track)) > he3.maxAbsTPCNSigma) { + return false; + } + if (he3.requirePIDForTracking && + track.pidForTracking() != o2::track::PID::Helium3 && + track.pidForTracking() != o2::track::PID::Alpha) { + return false; + } + return true; + } + + template + bool passesEventSelection(TCollision const& collision) + { + if (event.requireSel8 && !collision.sel8()) { + return false; + } + if (event.maxAbsZvtx >= 0.f && std::abs(collision.posZ()) > event.maxAbsZvtx) { + return false; + } + if (event.requireNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (event.requireNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (event.requireNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (event.requireGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + return true; + } + + template + void selectCollisions(TCollisions const& collisions, bool applyZorro) + { + selectedCollisions.assign(collisions.size(), false); + collisionsWithHe3.assign(collisions.size(), false); + for (const auto& collision : collisions) { + registry.fill(HIST("events"), 0.); + const auto bc = collision.template bc_as(); + initCCDB(bc); + + if (applyZorro) { + if (!zorro.isSelected(bc.globalBC(), zorroOptions.bcTolerance)) { + continue; + } + registry.fill(HIST("events"), 1.); + registry.fill(HIST("zorroEvents"), 0.); + } + if (!passesEventSelection(collision)) { + continue; + } + if constexpr (applyCentrality) { + if (collision.centFT0C() < pbpb.minCentFT0C || collision.centFT0C() > pbpb.maxCentFT0C) { + continue; + } + } + selectedCollisions[collision.globalIndex()] = true; + registry.fill(HIST("events"), 2.); + if (applyZorro) { + registry.fill(HIST("zorroEvents"), 1.); + } + } + } + + template + std::array dcaToPV(TCollision const& collision, TTrack const& track) + { + auto trackPar = getTrackParCov(track); + std::array dca{}; + o2::base::Propagator::Instance()->propagateToDCABxByBz( + {collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, fitter.getMatCorrType(), &dca); + return dca; + } + + template + bool passesTrackSelections(TTrack const& track, std::array const& dca) + { + return std::abs(track.eta()) <= trackSelections.maxAbsEta && + track.tpcNClsCrossedRows() >= trackSelections.minTPCCrossedRows && + std::abs(dca[0]) >= trackSelections.minAbsDCAxyToPV && + std::abs(dca[1]) >= trackSelections.minAbsDCAzToPV; + } + + template + static std::array tpcHadronNSigma(TTrack const& track) + { + return {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + } + + template + static std::array tofHadronNSigma(TTrack const& track) + { + if (!track.hasTOF()) { + return {InvalidFloat, InvalidFloat, InvalidFloat}; + } + return {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + } + + static float selectedNSigma(std::array const& values, int pdg) + { + switch (std::abs(pdg)) { + case PDG_t::kPiPlus: + return values[0]; + case PDG_t::kKPlus: + return values[1]; + case PDG_t::kProton: + return values[2]; + default: + return 0.f; + } + } + + template + bool buildCandidate(TCollision const& collision, TTrack const& he3Track, + TTrack const& daughter1Track, TTrack const& daughter2Track, + RecoCandidate& out) + { + const std::array tracks{he3Track, daughter1Track, daughter2Track}; + for (int i = 0; i < NProngs; ++i) { + const auto dca = dcaToPV(collision, tracks[i]); + if (!passesTrackSelections(tracks[i], dca)) { + return false; + } + out.dcaXYToPV[i] = dca[0]; + out.dcaZToPV[i] = dca[1]; + } + + auto he3TrackFit = getTrackParCov(he3Track); + auto daughter1TrackFit = getTrackParCov(daughter1Track); + auto daughter2TrackFit = getTrackParCov(daughter2Track); + int nCandidates = 0; + try { + nCandidates = fitter.process(he3TrackFit, daughter1TrackFit, daughter2TrackFit); + } catch (...) { + LOG(error) << "Exception while fitting a nuclei three-body candidate"; + return false; + } + if (nCandidates == 0) { + return false; + } + registry.fill(HIST("triplets"), 1.); + + out.signs = {static_cast(he3Track.sign() > 0 ? 1 : -1), + static_cast(daughter1Track.sign() > 0 ? 1 : -1), + static_cast(daughter2Track.sign() > 0 ? 1 : -1)}; + + std::array, 3> daughterMomenta{}; + std::array momentum{}; + for (int i = 0; i < NProngs; ++i) { + fitter.getTrack(i).getPxPyPzGlo(daughterMomenta[i]); + } + for (int component = 0; component < NProngs; ++component) { + daughterMomenta[0][component] *= He3Charge; + momentum[component] = daughterMomenta[0][component] + + daughterMomenta[1][component] + + daughterMomenta[2][component]; + } + for (int i = 0; i < NProngs; ++i) { + out.daughterMomentum[i] = RecoDecay::sqrtSumOfSquares( + daughterMomenta[i][0], daughterMomenta[i][1], daughterMomenta[i][2]); + } + out.pt = RecoDecay::sqrtSumOfSquares(momentum[0], momentum[1]); + out.eta = RecoDecay::eta(momentum); + out.phi = RecoDecay::phi(momentum); + const float momentumMagnitude = RecoDecay::sqrtSumOfSquares(momentum[0], momentum[1], momentum[2]); + + out.chi2 = fitter.getChi2AtPCACandidate(); + out.dcaDaughters = std::sqrt(std::max(0.f, out.chi2)); + const auto& secondaryVertex = fitter.getPCACandidate(); + const std::array flight{ + static_cast(secondaryVertex[0] - collision.posX()), + static_cast(secondaryVertex[1] - collision.posY()), + static_cast(secondaryVertex[2] - collision.posZ())}; + out.decayLength = RecoDecay::sqrtSumOfSquares(flight[0], flight[1], flight[2]); + out.cosPA = (flight[0] * momentum[0] + flight[1] * momentum[1] + flight[2] * momentum[2]) / + (out.decayLength * momentumMagnitude + 1.e-10f); + if (out.cosPA < vertexSelections.minCosPA) { + return false; + } + + out.tpcNSigmaHe3 = tpcNSigmaHe3(he3Track); + out.tofNSigmaHe3 = he3Track.hasTOF() ? he3Track.tofNSigmaHe() : InvalidFloat; + out.tpcNSigmaHadron[0] = tpcHadronNSigma(daughter1Track); + out.tpcNSigmaHadron[1] = tpcHadronNSigma(daughter2Track); + out.tofNSigmaHadron[0] = tofHadronNSigma(daughter1Track); + out.tofNSigmaHadron[1] = tofHadronNSigma(daughter2Track); + for (int i = 0; i < NProngs; ++i) { + out.tpcNCls[i] = tracks[i].tpcNClsFound(); + out.tpcCrossedRows[i] = tracks[i].tpcNClsCrossedRows(); + out.itsNCls[i] = tracks[i].itsNCls(); + } + + if (!candidateSelections.applySelections) { + return true; + } + if (out.chi2 > candidateSelections.maxChi2 || + out.dcaDaughters > candidateSelections.maxDCADaughters || + out.decayLength < candidateSelections.minDecayLength || + out.decayLength > candidateSelections.maxDecayLength || + std::abs(selectedNSigma(out.tpcNSigmaHadron[0], decay.daughter1Pdg)) > candidateSelections.maxAbsTPCNSigmaDaughter1 || + std::abs(selectedNSigma(out.tpcNSigmaHadron[1], decay.daughter2Pdg)) > candidateSelections.maxAbsTPCNSigmaDaughter2 || + (daughter1Track.hasTOF() && + std::abs(selectedNSigma(out.tofNSigmaHadron[0], decay.daughter1Pdg)) > candidateSelections.maxAbsTOFNSigmaDaughter1) || + (daughter2Track.hasTOF() && + std::abs(selectedNSigma(out.tofNSigmaHadron[1], decay.daughter2Pdg)) > candidateSelections.maxAbsTOFNSigmaDaughter2)) { + return false; + } + return true; + } + + void fillDataTable(RecoCandidate const& c) + { + outputData(c.signs[0], c.signs[1], c.signs[2], + c.pt, c.eta, c.phi, + c.daughterMomentum[0], c.daughterMomentum[1], c.daughterMomentum[2], + c.chi2, c.dcaDaughters, c.cosPA, c.decayLength, + c.dcaXYToPV[0], c.dcaZToPV[0], + c.dcaXYToPV[1], c.dcaZToPV[1], + c.dcaXYToPV[2], c.dcaZToPV[2], + c.tpcNSigmaHe3, c.tofNSigmaHe3, + c.tpcNSigmaHadron[0][0], c.tpcNSigmaHadron[0][1], c.tpcNSigmaHadron[0][2], + c.tofNSigmaHadron[0][0], c.tofNSigmaHadron[0][1], c.tofNSigmaHadron[0][2], + c.tpcNSigmaHadron[1][0], c.tpcNSigmaHadron[1][1], c.tpcNSigmaHadron[1][2], + c.tofNSigmaHadron[1][0], c.tofNSigmaHadron[1][1], c.tofNSigmaHadron[1][2], + c.tpcNCls[0], c.tpcNCls[1], c.tpcNCls[2], + c.tpcCrossedRows[0], c.tpcCrossedRows[1], c.tpcCrossedRows[2], + c.itsNCls[0], c.itsNCls[1], c.itsNCls[2]); + } + + template + MCInfo getMCInfo(TTrack const& he3Track, TTrack const& daughter1Track, + TTrack const& daughter2Track, aod::McParticles const& mcParticles) + { + MCInfo info; + if (!he3Track.has_mcParticle() || !daughter1Track.has_mcParticle() || !daughter2Track.has_mcParticle()) { + return info; + } + const auto he3Particle = he3Track.template mcParticle_as(); + const auto daughter1Particle = daughter1Track.template mcParticle_as(); + const auto daughter2Particle = daughter2Track.template mcParticle_as(); + info.pdgs = {he3Particle.pdgCode(), daughter1Particle.pdgCode(), daughter2Particle.pdgCode()}; + info.matchStatus = NoCommonImmediateMother; + + int commonMotherLabel = InvalidLabel; + for (const auto& he3Mother : he3Particle.template mothers_as()) { + for (const auto& daughter1Mother : daughter1Particle.template mothers_as()) { + if (he3Mother.globalIndex() != daughter1Mother.globalIndex()) { + continue; + } + for (const auto& daughter2Mother : daughter2Particle.template mothers_as()) { + if (he3Mother.globalIndex() == daughter2Mother.globalIndex()) { + commonMotherLabel = he3Mother.globalIndex(); + break; + } + } + } + } + if (commonMotherLabel < 0) { + return info; + } + + const auto selectedMother = mcParticles.rawIteratorAt(commonMotherLabel); + info.matchStatus = CommonImmediateMother; + info.motherPdg = selectedMother.pdgCode(); + const int he3Sign = he3Track.sign() > 0 ? 1 : -1; + const bool expectedDaughters = info.pdgs[0] == he3Sign * He3Pdg && + info.pdgs[1] == he3Sign * decay.daughter1Pdg && + info.pdgs[2] == he3Sign * decay.daughter2Pdg; + const bool motherAccepted = decay.motherPdg == 0 || + info.motherPdg == he3Sign * std::abs(decay.motherPdg.value); + const bool configuredDecay = expectedDaughters && motherAccepted; + if (configuredDecay) { + info.matchStatus = ConfiguredDecay; + } + if ((!mc.requireConfiguredDecayForGen || configuredDecay) && motherAccepted) { + const std::array motherMomentum{selectedMother.px(), selectedMother.py(), selectedMother.pz()}; + info.motherPt = RecoDecay::sqrtSumOfSquares(motherMomentum[0], motherMomentum[1]); + info.motherEta = RecoDecay::eta(motherMomentum); + info.motherPhi = RecoDecay::phi(motherMomentum); + info.decayLength = RecoDecay::sqrtSumOfSquares(he3Particle.vx() - selectedMother.vx(), + he3Particle.vy() - selectedMother.vy(), + he3Particle.vz() - selectedMother.vz()); + } + return info; + } + + void fillMCTable(RecoCandidate const& c, MCInfo const& m) + { + outputMC(c.signs[0], c.signs[1], c.signs[2], + c.pt, c.eta, c.phi, + c.daughterMomentum[0], c.daughterMomentum[1], c.daughterMomentum[2], + c.chi2, c.dcaDaughters, c.cosPA, c.decayLength, + c.dcaXYToPV[0], c.dcaZToPV[0], + c.dcaXYToPV[1], c.dcaZToPV[1], + c.dcaXYToPV[2], c.dcaZToPV[2], + c.tpcNSigmaHe3, c.tofNSigmaHe3, + c.tpcNSigmaHadron[0][0], c.tpcNSigmaHadron[0][1], c.tpcNSigmaHadron[0][2], + c.tofNSigmaHadron[0][0], c.tofNSigmaHadron[0][1], c.tofNSigmaHadron[0][2], + c.tpcNSigmaHadron[1][0], c.tpcNSigmaHadron[1][1], c.tpcNSigmaHadron[1][2], + c.tofNSigmaHadron[1][0], c.tofNSigmaHadron[1][1], c.tofNSigmaHadron[1][2], + c.tpcNCls[0], c.tpcNCls[1], c.tpcNCls[2], + c.tpcCrossedRows[0], c.tpcCrossedRows[1], c.tpcCrossedRows[2], + c.itsNCls[0], c.itsNCls[1], c.itsNCls[2], + m.pdgs[0], m.pdgs[1], m.pdgs[2], + m.matchStatus, m.motherPdg, + m.motherPt, m.motherEta, m.motherPhi, m.decayLength); + } + + template + void build(TCollisions const& collisions, TTracks const& tracks, + aod::AmbiguousTracks const& ambiguousTracks, + aod::BCsWithTimestamps const& bcs, + aod::McParticles const* mcParticles = nullptr) + { + selectCollisions(collisions, zorroOptions.enabled && !isMC); + identifiedHe3Tracks.assign(tracks.size(), false); + preselectedTracks.assign(tracks.size(), false); + + // Apply the common track preselection before identifying He3 candidates. + // Consequently, the triplet pools are never built unless a selected event + // contains at least one He3 that also passes the minimal track selections. + for (const auto& track : tracks) { + if (!track.has_collision() || track.collisionId() < 0 || + !selectedCollisions[track.collisionId()]) { + continue; + } + const auto collision = collisions.rawIteratorAt(track.collisionId()); + const auto dca = dcaToPV(collision, track); + if (!passesTrackSelections(track, dca)) { + continue; + } + preselectedTracks[track.globalIndex()] = true; + if (isIdentifiedHe3(track)) { + identifiedHe3Tracks[track.globalIndex()] = true; + collisionsWithHe3[track.collisionId()] = true; + } + } + for (size_t i = 0; i < collisionsWithHe3.size(); ++i) { + if (collisionsWithHe3[i]) { + registry.fill(HIST("events"), 3.); + } + } + + tripletPool.clearPools(); + tripletPool.fillBC2Coll(collisions, bcs); + for (const auto& track : tracks) { + if (!track.has_collision() || track.collisionId() < 0 || + !preselectedTracks[track.globalIndex()] || + !collisionsWithHe3[track.collisionId()]) { + continue; + } + if (identifiedHe3Tracks[track.globalIndex()]) { + tripletPool.appendTrackCand(track, collisions, He3PoolId, ambiguousTracks, bcs); + } else { + tripletPool.appendTrackCand(track, collisions, Daughter1PoolId, ambiguousTracks, bcs); + tripletPool.appendTrackCand(track, collisions, Daughter2PoolId, ambiguousTracks, bcs); + } + } + + const bool daughter1LikeSign = decay.daughter1Pdg > 0; + const bool daughter2LikeSign = decay.daughter2Pdg > 0; + auto& triplets = tripletPool.getSVCandPool(collisions, daughter1LikeSign, daughter2LikeSign); + for (const auto& triplet : triplets) { + registry.fill(HIST("triplets"), 0.); + const auto he3Track = tracks.rawIteratorAt(triplet.tr0Idx); + const auto daughter1Track = tracks.rawIteratorAt(triplet.tr1Idx); + const auto daughter2Track = tracks.rawIteratorAt(triplet.tr2Idx); + for (int collisionIndex = triplet.collBracket.getMin(); collisionIndex <= triplet.collBracket.getMax(); ++collisionIndex) { + if (!selectedCollisions[collisionIndex] || !collisionsWithHe3[collisionIndex]) { + continue; + } + const auto collision = collisions.rawIteratorAt(collisionIndex); + RecoCandidate reco; + if (!buildCandidate(collision, he3Track, daughter1Track, daughter2Track, reco)) { + continue; + } + if constexpr (isMC) { + fillMCTable(reco, getMCInfo(he3Track, daughter1Track, daughter2Track, *mcParticles)); + } else { + fillDataTable(reco); + } + registry.fill(HIST("events"), 4.); + registry.fill(HIST("triplets"), 2.); + } + } + } + + void processData(Collisions const& collisions, Tracks const& tracks, + aod::AmbiguousTracks const& ambiguousTracks, + aod::BCsWithTimestamps const& bcs) + { + build(collisions, tracks, ambiguousTracks, bcs); + } + PROCESS_SWITCH(NucleiThreeBodyBuilder, processData, "Process pp data", true); + + void processPbPb(CollisionsPbPb const& collisions, Tracks const& tracks, + aod::AmbiguousTracks const& ambiguousTracks, + aod::BCsWithTimestamps const& bcs) + { + build(collisions, tracks, ambiguousTracks, bcs); + } + PROCESS_SWITCH(NucleiThreeBodyBuilder, processPbPb, "Process Pb-Pb data", false); + + void processMC(CollisionsMC const& collisions, TracksMC const& tracks, + aod::AmbiguousTracks const& ambiguousTracks, + aod::BCsWithTimestamps const& bcs, + aod::McParticles const& mcParticles) + { + build(collisions, tracks, ambiguousTracks, bcs, &mcParticles); + } + PROCESS_SWITCH(NucleiThreeBodyBuilder, processMC, "Process reconstructed MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx index bb15833d0e1..4e29bd71d05 100644 --- a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx @@ -63,8 +63,8 @@ #include #include #include +#include #include -#include #include using namespace o2; diff --git a/PWGLF/TableProducer/QC/nucleiQC.cxx b/PWGLF/TableProducer/QC/nucleiQC.cxx index b92eac75b5d..c9c417b08eb 100644 --- a/PWGLF/TableProducer/QC/nucleiQC.cxx +++ b/PWGLF/TableProducer/QC/nucleiQC.cxx @@ -52,7 +52,6 @@ #include -#include #include #include #include diff --git a/PWGLF/TableProducer/Resonances/cksspinalignment.cxx b/PWGLF/TableProducer/Resonances/cksspinalignment.cxx index 014002da82b..eddf20adbd7 100644 --- a/PWGLF/TableProducer/Resonances/cksspinalignment.cxx +++ b/PWGLF/TableProducer/Resonances/cksspinalignment.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// \file cksspinalignment.cxx -/// \brief Table producer for Charged KStar spin alignment +/// \brief Reduced table producer for K0s and charged pions for later charged K* reconstruction /// /// \author prottay.das@cern.ch @@ -28,7 +28,6 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include #include #include #include @@ -44,10 +43,9 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include -#include +#include #include #include -#include #include using namespace o2; @@ -61,8 +59,6 @@ struct cksspinalignment { Produces kshortTrack; Produces pionTrack; - Service ccdb; - struct : ConfigurableGroup { Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; @@ -74,459 +70,456 @@ struct cksspinalignment { Configurable useGoodITSLayersAll{"useGoodITSLayersAll", true, "Apply kIsGoodITSLayersAll selection bit"}; Configurable cfgCutOccupancy{"cfgCutOccupancy", 2000, "Occupancy cut"}; - // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Accepted maximum Centrality"}; - Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 0.0f, "Accepted minimum Centrality"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Accepted maximum centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 0.0f, "Accepted minimum centrality"}; - // Configs for track - Configurable cfgCutPt{"cfgCutPt", 0.2, "Pt cut on daughter track"}; - Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + Configurable cfgCutPt{"cfgCutPt", 0.2f, "Prefilter minimum pT for bachelor pion"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Prefilter maximum eta for bachelor pion"}; - // Configs for pion struct : ConfigurableGroup { - Configurable itsPIDSelection{"itsPIDSelection", true, "PID ITS"}; - Configurable lowITSPIDNsigma{"lowITSPIDNsigma", -3.0, "lower cut on PID nsigma for ITS"}; - Configurable highITSPIDNsigma{"highITSPIDNsigma", 3.0, "higher cut on PID nsigma for ITS"}; - Configurable itsclusterPiMeson{"itsclusterPiMeson", 5, "Minimum number of ITS cluster for pi meson track"}; - Configurable tpcCrossedRowsPiMeson{"tpcCrossedRowsPiMeson", 80, "Minimum number of TPC Crossed Rows for pi meson track"}; - Configurable cutDCAxyPiMeson{"cutDCAxyPiMeson", 0.1, "Maximum DCAxy for pi meson track"}; - Configurable cutDCAzPiMeson{"cutDCAzPiMeson", 0.1, "Maximum DCAz for pi meson track"}; - Configurable cutEtaPiMeson{"cutEtaPiMeson", 0.8, "Maximum eta for pi meson track"}; - Configurable cutPTPiMeson{"cutPTPiMeson", 0.8, "Maximum pt for pi meson track"}; - Configurable usePID{"usePID", true, "Flag for using PID selection for pi meson track"}; - Configurable nsigmaCutTPCPiMeson{"nsigmaCutTPCPiMeson", 3.0, "Maximum nsigma cut TPC for pi meson track"}; - Configurable nsigmaCutTOFPiMeson{"nsigmaCutTOFPiMeson", 3.0, "Maximum nsigma cut TOF for pi meson track"}; - Configurable cutTOFBetaPiMeson{"cutTOFBetaPiMeson", 3.0, "Maximum beta cut for pi meson track"}; + Configurable itsPIDSelection{"itsPIDSelection", true, "Apply ITS PID for bachelor pion"}; + Configurable lowITSPIDNsigma{"lowITSPIDNsigma", -3.0f, "Lower ITS n-sigma pion cut"}; + Configurable highITSPIDNsigma{"highITSPIDNsigma", 3.0f, "Upper ITS n-sigma pion cut"}; + Configurable itsclusterPiMeson{"itsclusterPiMeson", 5, "Minimum ITS clusters for bachelor pion"}; + Configurable tpcCrossedRowsPiMeson{"tpcCrossedRowsPiMeson", 80, "Minimum TPC crossed rows for bachelor pion"}; + Configurable cutDCAxyPiMeson{"cutDCAxyPiMeson", 0.1f, "Maximum DCAxy for bachelor pion"}; + Configurable cutDCAzPiMeson{"cutDCAzPiMeson", 0.1f, "Maximum DCAz for bachelor pion"}; + Configurable cutEtaPiMeson{"cutEtaPiMeson", 0.8f, "Maximum eta for bachelor pion"}; + Configurable cutPTPiMeson{"cutPTPiMeson", 0.2f, "Minimum pT for bachelor pion"}; + Configurable usePID{"usePID", true, "Apply pion PID"}; + Configurable nsigmaCutTPCPiMeson{"nsigmaCutTPCPiMeson", 3.0f, "Maximum TPC n-sigma pion cut"}; + Configurable nsigmaCutTOFPiMeson{"nsigmaCutTOFPiMeson", 3.0f, "Maximum TOF n-sigma pion cut"}; + Configurable cutTOFBetaPiMeson{"cutTOFBetaPiMeson", 0.5f, "Minimum TOF beta for bachelor pion"}; + Configurable pSwitchPID{"pSwitchPID", 0.5f, "pT switch for pT-dependent pion PID"}; } grpPion; enum PionPidBits : uint8_t { - kPID1 = 1u << 0, // selectionPID - kPID2 = 1u << 1, // selectionPID2 - kPID3 = 1u << 2, // selectionPID3 - kPID4 = 1u << 3 // selectionPID4 + kPID1 = 1u << 0, + kPID2 = 1u << 1, }; - // Configs for V0 - Configurable confV0PtMin{"confV0PtMin", 0.f, "Minimum transverse momentum of V0"}; - Configurable confV0PtMax{"confV0PtMax", 1000.f, "Maximum transverse momentum of V0"}; - Configurable confV0Rap{"confV0Rap", 0.8f, "Rapidity range of V0"}; - Configurable confV0DCADaughMax{"confV0DCADaughMax", 1.0f, "Maximum DCA between the V0 daughters"}; - Configurable confV0CPAMin{"confV0CPAMin", 0.9998f, "Minimum CPA of V0"}; - Configurable confV0TranRadV0Min{"confV0TranRadV0Min", 1.5f, "Minimum transverse radius"}; - Configurable confV0TranRadV0Max{"confV0TranRadV0Max", 100.f, "Maximum transverse radius"}; - Configurable cMaxV0DCA{"cMaxV0DCA", 1.2, "Maximum V0 DCA to PV"}; - Configurable cMinV0DCAPi{"cMinV0DCAPi", 0.05, "Minimum V0 daughters DCA to PV for Pi"}; - Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 50, "Maximum V0 life time"}; - Configurable qtArmenterosMin{"qtArmenterosMin", 0.2, "Minimum armenteros cut for K0s"}; - // config for V0 daughters - Configurable confDaughEta{"confDaughEta", 0.8f, "V0 Daugh sel: max eta"}; - Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2, "minimum daughter pion pt"}; - Configurable confDaughTPCnclsMin{"confDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; - Configurable confDaughTPCncrwsMin{"confDaughTPCncrwsMin", 70.f, "V0 Daugh sel: Min. nCrws TPC"}; - Configurable confDaughPIDCuts{"confDaughPIDCuts", 3, "PID selections for Kshortpion daughters"}; - - // configurable for chargedkstar - Configurable cfgKstarMassMin{"cfgKstarMassMin", 0.75f, "K* mass min"}; - Configurable cfgKstarMassMax{"cfgKstarMassMax", 1.05f, "K* mass max"}; - - Configurable iMNbins{"iMNbins", 50, "Number of bins in invariant mass"}; - Configurable lbinIM{"lbinIM", 1.09, "lower bin value in IM histograms"}; - Configurable hbinIM{"hbinIM", 1.14, "higher bin value in IM histograms"}; + Configurable confV0PtMin{"confV0PtMin", 0.0f, "Minimum K0s pT"}; + Configurable confV0PtMax{"confV0PtMax", 1000.0f, "Maximum K0s pT"}; + Configurable confV0Rap{"confV0Rap", 0.8f, "Maximum K0s rapidity"}; + Configurable confV0DCADaughMax{"confV0DCADaughMax", 1.0f, "Maximum DCA between V0 daughters"}; + Configurable confV0CPAMin{"confV0CPAMin", 0.9998, "Minimum K0s CPA"}; + Configurable confV0TranRadV0Min{"confV0TranRadV0Min", 1.5f, "Minimum K0s transverse radius"}; + Configurable confV0TranRadV0Max{"confV0TranRadV0Max", 100.0f, "Maximum K0s transverse radius"}; + Configurable cMaxV0DCA{"cMaxV0DCA", 1.2, "Maximum K0s DCA to PV"}; + Configurable cMinV0DCAPi{"cMinV0DCAPi", 0.05f, "Minimum V0 daughter DCA to PV"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 50.0f, "Maximum K0s lifetime"}; + Configurable qtArmenterosMin{"qtArmenterosMin", 0.2f, "Minimum Armenteros qT/|alpha| for K0s"}; + + Configurable confDaughEta{"confDaughEta", 0.8f, "Maximum V0 daughter eta"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2f, "Minimum V0 daughter pion pT"}; + Configurable confDaughTPCnclsMin{"confDaughTPCnclsMin", 50.0f, "Minimum V0 daughter TPC clusters"}; + Configurable confDaughTPCncrwsMin{"confDaughTPCncrwsMin", 70.0f, "Minimum V0 daughter TPC crossed rows"}; + Configurable confDaughPIDCuts{"confDaughPIDCuts", 3.0f, "TPC pion PID cut for V0 daughters"}; + + Configurable cfgK0sMassMin{"cfgK0sMassMin", 0.45f, "Minimum K0s invariant mass"}; + Configurable cfgK0sMassMax{"cfgK0sMassMax", 0.55f, "Maximum K0s invariant mass"}; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; RCTFlagsChecker rctChecker; + void init(o2::framework::InitContext&) { rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); - AxisSpec thnAxisInvMass{iMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; - histos.add("hCent", "hCent", kTH1F, {{8, 0, 80.0}}); - histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{5, 0, 5.0}}); - histos.add("hTrkSelInfo", "hTrkSelInfo", kTH1F, {{5, 0, 5.0}}); - histos.add("hKShortMass", "hKShortMass", kTH1F, {thnAxisInvMass}); - histos.add("hV0Info", "hV0Info", kTH1F, {{5, 0, 5.0}}); + histos.add("hCent", "hCent", kTH1F, {{16, 0.0f, 80.0f}}); + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{6, 0.0f, 6.0f}}); + histos.add("hTrkSelInfo", "hTrkSelInfo", kTH1F, {{5, 0.0f, 5.0f}}); + histos.add("hV0Info", "hV0Info", kTH1F, {{5, 0.0f, 5.0f}}); + histos.add("hKShortMass", "hKShortMass;M_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2});Counts", kTH1F, {{200, 0.4f, 0.6f}}); + histos.add("hNStoredK0s", "hNStoredK0s;N_{K^{0}_{S}};Events", kTH1F, {{100, 0.0f, 100.0f}}); + histos.add("hNStoredPions", "hNStoredPions;N_{#pi};Events", kTH1F, {{500, 0.0f, 500.0f}}); } template bool selectionTrack(const T& candidate) { - if (candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() >= grpPion.itsclusterPiMeson && candidate.tpcNClsCrossedRows() > grpPion.tpcCrossedRowsPiMeson && std::abs(candidate.dcaXY()) <= grpPion.cutDCAxyPiMeson && std::abs(candidate.dcaZ()) <= grpPion.cutDCAzPiMeson && std::abs(candidate.eta()) <= grpPion.cutEtaPiMeson && candidate.pt() >= grpPion.cutPTPiMeson) { - return true; - } - return false; + return candidate.isGlobalTrack() && + candidate.isPVContributor() && + candidate.itsNCls() > grpPion.itsclusterPiMeson && + candidate.tpcNClsCrossedRows() > grpPion.tpcCrossedRowsPiMeson && + std::abs(candidate.dcaXY()) < grpPion.cutDCAxyPiMeson && + std::abs(candidate.dcaZ()) < grpPion.cutDCAzPiMeson && + std::abs(candidate.eta()) < grpPion.cutEtaPiMeson && + candidate.pt() > grpPion.cutPTPiMeson; } template bool selectionPID(const T& candidate) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < grpPion.nsigmaCutTPCPiMeson) { - return true; - } - if (candidate.hasTOF() && candidate.beta() > grpPion.cutTOFBetaPiMeson && std::abs(candidate.tpcNSigmaPi()) < grpPion.nsigmaCutTPCPiMeson && std::abs(candidate.tofNSigmaPi()) < grpPion.nsigmaCutTOFPiMeson) { - return true; - } - return false; - } + const float pt = candidate.pt(); + const float nTPC = candidate.tpcNSigmaPi(); - template - bool selectionPID2(const T& candidate) - { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < grpPion.nsigmaCutTPCPiMeson) { - return true; + if (pt < grpPion.pSwitchPID) { + return std::abs(nTPC) < grpPion.nsigmaCutTPCPiMeson; } - if (candidate.hasTOF() && candidate.beta() > grpPion.cutTOFBetaPiMeson && std::sqrt(candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) < grpPion.nsigmaCutTOFPiMeson) { - return true; + + if (!candidate.hasTOF()) { + return false; } - return false; - } - template - bool selectionPID3(const T& candidate) - { - auto px = candidate.px(); - auto py = candidate.py(); - // auto pz = candidate.pz(); - auto pt = std::sqrt(px * px + py * py); - float lowmom = 0.5; - if (pt < lowmom) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < grpPion.nsigmaCutTPCPiMeson) { - return true; - } else if (candidate.hasTOF() && std::sqrt(candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) < grpPion.nsigmaCutTOFPiMeson) { - return true; - } - } else if (candidate.hasTOF() && std::sqrt(candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) < grpPion.nsigmaCutTOFPiMeson) { - return true; + if (candidate.beta() <= grpPion.cutTOFBetaPiMeson) { + return false; } - return false; + + const float nTOF = candidate.tofNSigmaPi(); + const float nCombined = std::sqrt(nTPC * nTPC + nTOF * nTOF); + + return nCombined < grpPion.nsigmaCutTOFPiMeson; } template - bool selectionPID4(const T& candidate) + bool selectionPID2(const T& candidate) { - // Use total momentum p (as you said). If you really want pT, replace with sqrt(px^2+py^2). - const float px = candidate.px(); - const float py = candidate.py(); - // const float pz = candidate.pz(); - const float pt = std::sqrt(px * px + py * py); - - constexpr float pSwitch = 0.5f; // GeV/c - + const float pt = candidate.pt(); const float nTPC = candidate.tpcNSigmaPi(); - // Low momentum: TPC-only, TOF not required and not used - if (pt < pSwitch) { - return std::abs(nTPC) < grpPion.nsigmaCutTPCPiMeson; // e.g. 3 + if (pt < grpPion.pSwitchPID) { + return std::abs(nTPC) < grpPion.nsigmaCutTPCPiMeson; } - // High momentum: TOF hit mandatory + separate 3σ cuts if (!candidate.hasTOF()) { return false; } + if (candidate.beta() <= grpPion.cutTOFBetaPiMeson) { + return false; + } + const float nTOF = candidate.tofNSigmaPi(); - return (std::abs(nTPC) < grpPion.nsigmaCutTPCPiMeson) && - (std::abs(nTOF) < grpPion.nsigmaCutTOFPiMeson); + + return std::abs(nTPC) < grpPion.nsigmaCutTPCPiMeson && + std::abs(nTOF) < grpPion.nsigmaCutTOFPiMeson; } template uint8_t pionPidMask(const T& trk) { - uint8_t m = 0; - if (selectionPID(trk)) - m |= kPID1; - if (selectionPID2(trk)) - m |= kPID2; - if (selectionPID3(trk)) - m |= kPID3; - if (selectionPID4(trk)) - m |= kPID4; - return m; + uint8_t mask = 0; + + if (selectionPID(trk)) { + mask |= kPID1; + } + + if (selectionPID2(trk)) { + mask |= kPID2; + } + + return mask; } + struct StoredK0s { + float px; + float py; + float pz; + float mass; + float cospa; + float radius; + float dcaPositive; + float dcaNegative; + float dcaBetweenDaughters; + // float lifetime; + int64_t positiveIndex; + int64_t negativeIndex; + }; + + struct StoredPion { + float px; + float py; + float pz; + int8_t charge; + int64_t index; + uint8_t pidMask; + }; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (aod::cent::centFT0C < cfgCutCentralityMax && aod::cent::centFT0C >= cfgCutCentralityMin); + + using EventCandidates = soa::Filtered>; + using FullTrackCandidates = soa::Join; + using ResoV0s = aod::V0Datas; + Partition bachelorPionCandidates = nabs(aod::track::eta) < cfgCutEta && aod::track::pt > cfgCutPt; + template bool selectionV0(Collision const& collision, V0 const& candidate) { - if (std::abs(candidate.dcav0topv()) > cMaxV0DCA) { - return false; - } const float pT = candidate.pt(); const float tranRad = candidate.v0radius(); const float dcaDaughv0 = std::abs(candidate.dcaV0daughters()); const float cpav0 = candidate.v0cosPA(); - float ctauKShort = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * (o2::constants::physics::MassK0); + const float ctauKShort = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0; - if (pT < confV0PtMin) { + if (std::abs(candidate.dcav0topv()) >= cMaxV0DCA) { return false; } - if (pT > confV0PtMax) { - return false; - } - if (dcaDaughv0 > confV0DCADaughMax) { + + if (pT <= confV0PtMin || pT >= confV0PtMax) { return false; } - if (cpav0 < confV0CPAMin) { + + if (dcaDaughv0 >= confV0DCADaughMax) { return false; } - if (tranRad < confV0TranRadV0Min) { + + if (cpav0 <= confV0CPAMin) { return false; } - if (tranRad > confV0TranRadV0Max) { + + if (tranRad <= confV0TranRadV0Min || tranRad >= confV0TranRadV0Max) { return false; } - if (std::abs(ctauKShort) > cMaxV0LifeTime) { + + if (std::abs(ctauKShort) >= cMaxV0LifeTime) { return false; } - if ((candidate.qtarm() / std::abs(candidate.alpha())) < qtArmenterosMin) { + + if ((candidate.qtarm() / std::abs(candidate.alpha())) <= qtArmenterosMin) { return false; } - if (std::abs(candidate.yK0Short()) > confV0Rap) { // use full rapidity 0.8 for K0s + + if (std::abs(candidate.yK0Short()) >= confV0Rap) { return false; } + return true; } template bool isSelectedV0Daughter(V0 const& candidate) { - auto postrack = candidate.template posTrack_as(); - auto negtrack = candidate.template negTrack_as(); - - const auto ncrfc = 0.8; + auto postrack = candidate.template posTrack_as(); + auto negtrack = candidate.template negTrack_as(); if (postrack.sign() < 0 || negtrack.sign() > 0) { return false; } - if (postrack.tpcNClsCrossedRows() < confDaughTPCncrwsMin || negtrack.tpcNClsCrossedRows() < confDaughTPCncrwsMin) { + + if (postrack.tpcNClsCrossedRows() <= confDaughTPCncrwsMin || + negtrack.tpcNClsCrossedRows() <= confDaughTPCncrwsMin) { return false; } - if (postrack.tpcNClsFound() < confDaughTPCnclsMin || negtrack.tpcNClsFound() < confDaughTPCnclsMin) { + + if (postrack.tpcNClsFound() <= confDaughTPCnclsMin || + negtrack.tpcNClsFound() <= confDaughTPCnclsMin) { return false; } - if (postrack.tpcCrossedRowsOverFindableCls() < ncrfc || negtrack.tpcCrossedRowsOverFindableCls() < ncrfc) { + + if (std::abs(postrack.tpcNSigmaPi()) >= confDaughPIDCuts || + std::abs(negtrack.tpcNSigmaPi()) >= confDaughPIDCuts) { return false; } - if (std::abs(postrack.tpcNSigmaPi()) > confDaughPIDCuts || std::abs(negtrack.tpcNSigmaPi()) > confDaughPIDCuts) { + + if (candidate.positivept() <= cfgDaughPiPt || + candidate.negativept() <= cfgDaughPiPt) { return false; } - if (candidate.positivept() < cfgDaughPiPt || candidate.negativept() < cfgDaughPiPt) { + + if (std::abs(candidate.positiveeta()) >= confDaughEta || + std::abs(candidate.negativeeta()) >= confDaughEta) { return false; } - if (std::abs(candidate.positiveeta()) > confDaughEta || std::abs(candidate.negativeeta()) > confDaughEta) { + + if (std::abs(candidate.dcapostopv()) <= cMinV0DCAPi || + std::abs(candidate.dcanegtopv()) <= cMinV0DCAPi) { return false; } - if (std::abs(candidate.dcapostopv()) < cMinV0DCAPi || std::abs(candidate.dcanegtopv()) < cMinV0DCAPi) { + + return true; + } + + template + bool selectionK0s(Collision const& collision, V0 const& v0) + { + if (!isSelectedV0Daughter(v0)) { + return false; + } + + if (!selectionV0(collision, v0)) { + return false; + } + + if (v0.mK0Short() < cfgK0sMassMin || v0.mK0Short() > cfgK0sMassMax) { return false; } return true; } - std::tuple getK0sTags(const auto& v0, const auto& collision) + void processData(EventCandidates::iterator const& collision, + FullTrackCandidates const& /*tracks*/, + ResoV0s const& v0s) { - // auto postrack = v0.template posTrack_as(); - // auto negtrack = v0.template negTrack_as(); + o2::aod::ITSResponse itsResponse; - int kshortTag = 0; + const float centrality = collision.centFT0C(); + const float vz = collision.posZ(); + const int occupancy = collision.trackOccupancyInTimeRange(); - if (isSelectedV0Daughter(v0) && v0.mK0Short() > lbinIM && v0.mK0Short() < hbinIM) { - kshortTag = 1; - } + const float psiFT0C = collision.psiFT0C(); + const float psiFT0A = collision.psiFT0A(); + const float psiTPC = collision.psiTPC(); - if (!kshortTag) { - return {0, false}; // No valid tags + histos.fill(HIST("hEvtSelInfo"), 0.5); + + if ((rctCut.requireRCTFlagChecker && !rctChecker(collision)) || + !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || + !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || + !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || + !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || + (useNoCollInTimeRangeStandard && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) || + !collision.sel8() || + (useGoodITSLayersAll && + !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) || + occupancy >= cfgCutOccupancy) { + return; } - if (!selectionV0(collision, v0)) { - return {0, false}; // Fails selection + histos.fill(HIST("hEvtSelInfo"), 1.5); + + if (!collision.triggereventep()) { + return; } - return {kshortTag, true}; // Valid candidate - } + histos.fill(HIST("hEvtSelInfo"), 2.5); + histos.fill(HIST("hCent"), centrality); - ROOT::Math::PxPyPzMVector kshort, pion, pionbach, antiPion; - ROOT::Math::PxPyPzMVector kshortDummy, pionDummy; + std::vector selectedK0s; + std::vector selectedPions; - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); - Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && (aod::track::pt) > cfgCutPt); + for (const auto& track : bachelorPionCandidates) { + histos.fill(HIST("hTrkSelInfo"), 0.5); - using EventCandidates = soa::Filtered>; - using AllTrackCandidates = soa::Filtered>; - using ResoV0s = aod::V0Datas; - void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& tracks, ResoV0s const& V0s) - { - o2::aod::ITSResponse itsResponse; - std::vector kshortMother, pionBachelor; - std::vector v0Cospa = {}; - std::vector v0Radius = {}; - std::vector dcaPositive = {}; - std::vector dcaNegative = {}; - std::vector positiveIndex = {}; - std::vector negativeIndex = {}; - std::vector dcaBetweenDaughter = {}; - std::vector v0Lifetime = {}; - // std::vector armenteros = {}; - std::vector pionBachelorIndex = {}; - // std::vector pionBachelorSign = {}; - // std::vector pionBachelorTPC = {}; - // std::vector pionBachelorTOF = {}; - // std::vector pionBachelorTOFHit = {}; - std::vector pionBachelorPidMask = {}; - - int numbV0 = 0; - auto centrality = collision.centFT0C(); - auto vz = collision.posZ(); - int occupancy = collision.trackOccupancyInTimeRange(); - auto psiFT0C = collision.psiFT0C(); - auto psiFT0A = collision.psiFT0A(); - auto psiTPC = collision.psiTPC(); - // auto psiTPCR = collision.psiTPCR(); - // auto psiTPCL = collision.psiTPCL(); - histos.fill(HIST("hEvtSelInfo"), 0.5); - // if ((!rctCut.requireRCTFlagChecker || rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && collision.sel8() && collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && occupancy < cfgCutOccupancy) { - if ((!rctCut.requireRCTFlagChecker || rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && (!useNoCollInTimeRangeStandard || collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) && collision.sel8() && (!useGoodITSLayersAll || collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) && occupancy < cfgCutOccupancy) { - histos.fill(HIST("hEvtSelInfo"), 1.5); - if (collision.triggereventep()) { - histos.fill(HIST("hEvtSelInfo"), 2.5); - histos.fill(HIST("hCent"), centrality); - - for (const auto& track1 : tracks) { - histos.fill(HIST("hTrkSelInfo"), 0.5); - if (!selectionTrack(track1)) { - continue; - } - histos.fill(HIST("hTrkSelInfo"), 1.5); - - if (grpPion.itsPIDSelection && !(itsResponse.nSigmaITS(track1) > grpPion.lowITSPIDNsigma && itsResponse.nSigmaITS(track1) < grpPion.highITSPIDNsigma)) { - continue; - } - histos.fill(HIST("hTrkSelInfo"), 2.5); - /* - if (grpPion.usePID && !selectionPID2(track1)) { - continue; - }*/ - const uint8_t mask = pionPidMask(track1); - if (grpPion.usePID && mask == 0) { - continue; - } - histos.fill(HIST("hTrkSelInfo"), 3.5); - - auto track1ID = track1.globalIndex(); - auto track1sign = track1.sign(); - if (track1sign == 0) - continue; - /*auto track1nsigTPC = track1.tpcNSigmaPi(); - auto track1nsigTOF = -999.9; - auto track1TOFHit = -1; - if (track1.hasTOF()) { - track1TOFHit = 1; - track1nsigTOF = track1.tofNSigmaPi(); - histos.fill(HIST("hTrkSelInfo"), 4.5); - }*/ - pionbach = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassPionCharged); - pionBachelor.push_back(pionbach); - pionBachelorIndex.push_back(track1ID); - // pionBachelorSign.push_back(track1sign); - // pionBachelorTPC.push_back(track1nsigTPC); - // pionBachelorTOF.push_back(track1nsigTOF); - // pionBachelorTOFHit.push_back(track1TOFHit); - pionBachelorPidMask.push_back(mask); - } - for (const auto& v0 : V0s) { - histos.fill(HIST("hV0Info"), 0.5); - auto [kshortTag, isValid] = getK0sTags(v0, collision); - if (kshortTag && isValid) { - histos.fill(HIST("hV0Info"), 1.5); - auto postrack1 = v0.template posTrack_as(); - auto negtrack1 = v0.template negTrack_as(); - positiveIndex.push_back(postrack1.globalIndex()); - negativeIndex.push_back(negtrack1.globalIndex()); - v0Cospa.push_back(v0.v0cosPA()); - v0Radius.push_back(v0.v0radius()); - dcaPositive.push_back(std::abs(v0.dcapostopv())); - dcaNegative.push_back(std::abs(v0.dcanegtopv())); - dcaBetweenDaughter.push_back(std::abs(v0.dcaV0daughters())); - v0Lifetime.push_back(v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * (o2::constants::physics::MassK0)); - // armenteros.push_back((v0.qtarm() / std::abs(v0.alpha()))); - - pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassPionCharged); - antiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), o2::constants::physics::MassPionCharged); - kshort = pion + antiPion; - // chargedkstar = kshort + pionbach; - kshortMother.push_back(kshort); - // chargedkstarMother.push_back(chargedkstar); - histos.fill(HIST("hKShortMass"), kshort.M()); - } - numbV0 = numbV0 + 1; - } - if (numbV0 > 1 && v0Cospa.size() > 1 && !kshortMother.empty() && !pionBachelor.empty()) { - - std::vector useK0(kshortMother.size(), 0); - std::vector usePi(pionBachelor.size(), 0); - bool anyPair = false; - for (size_t ik0 = 0; ik0 < kshortMother.size(); ++ik0) { - const auto& k0 = kshortMother[ik0]; - const int posId = positiveIndex[ik0]; - const int negId = negativeIndex[ik0]; - - for (size_t ipi = 0; ipi < pionBachelor.size(); ++ipi) { - const int piId = pionBachelorIndex[ipi]; - - // avoid self-combination: bachelor pion can't be a V0 daughter - if (piId == posId || piId == negId) { - continue; - } - - const auto kstar = k0 + pionBachelor[ipi]; - const float m = kstar.M(); - - if (m < cfgKstarMassMin || m > cfgKstarMassMax) { - continue; - } - - useK0[ik0] = 1; - usePi[ipi] = 1; - anyPair = true; - } - } - - // only write event + tables if at least one K* candidate exists in window - if (anyPair) { - histos.fill(HIST("hEvtSelInfo"), 3.5); - // kshortpionEvent(centrality, vz, collision.index(), psiFT0C, psiFT0A, psiTPC); - kshortpionEvent(centrality, vz, psiFT0C, psiFT0A, psiTPC); - auto indexEvent = kshortpionEvent.lastIndex(); - // write only used K0s - for (size_t ik0 = 0; ik0 < kshortMother.size(); ++ik0) { - if (!useK0[ik0]) { - continue; - } - kshortDummy = kshortMother[ik0]; - kshortTrack(indexEvent, v0Cospa[ik0], v0Radius[ik0], dcaPositive[ik0], dcaNegative[ik0], dcaBetweenDaughter[ik0], v0Lifetime[ik0], kshortDummy.Px(), kshortDummy.Py(), kshortDummy.Pz(), kshortDummy.M(), positiveIndex[ik0], negativeIndex[ik0]); - } - // write only used pions - for (size_t ipi = 0; ipi < pionBachelor.size(); ++ipi) { - if (!usePi[ipi]) { - continue; - } - pionDummy = pionBachelor[ipi]; - /* - pionTrack(indexEvent, - pionDummy.Px(), pionDummy.Py(), pionDummy.Pz(), - pionBachelorTPC[ipi], - pionBachelorTOFHit[ipi], - pionBachelorTOF[ipi], - pionBachelorIndex[ipi]);*/ - pionTrack(indexEvent, pionDummy.Px(), pionDummy.Py(), pionDummy.Pz(), pionBachelorIndex[ipi], pionBachelorPidMask[ipi]); - } - } - } + if (!selectionTrack(track)) { + continue; } + + histos.fill(HIST("hTrkSelInfo"), 1.5); + + const float nSigmaITS = + itsResponse.nSigmaITS(track); + + if (grpPion.itsPIDSelection && + (nSigmaITS <= grpPion.lowITSPIDNsigma || + nSigmaITS >= grpPion.highITSPIDNsigma)) { + continue; + } + + histos.fill(HIST("hTrkSelInfo"), 2.5); + + const uint8_t mask = pionPidMask(track); + + if (grpPion.usePID && mask == 0) { + continue; + } + + const auto charge = static_cast(track.sign()); + + if (charge == 0) { + continue; + } + + histos.fill(HIST("hTrkSelInfo"), 3.5); + + selectedPions.push_back({track.px(), + track.py(), + track.pz(), + charge, + track.globalIndex(), + mask}); + } + + for (const auto& v0 : v0s) { + histos.fill(HIST("hV0Info"), 0.5); + + if (!selectionK0s(collision, v0)) { + continue; + } + + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + const auto posId = static_cast(postrack.globalIndex()); + const auto negId = static_cast(negtrack.globalIndex()); + + ROOT::Math::PxPyPzMVector pionPos(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassPionCharged); + ROOT::Math::PxPyPzMVector pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg(), o2::constants::physics::MassPionCharged); + ROOT::Math::PxPyPzMVector k0s = pionPos + pionNeg; + + // const float lifetime = + // v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * + // o2::constants::physics::MassK0; + + selectedK0s.push_back({static_cast(k0s.Px()), + static_cast(k0s.Py()), + static_cast(k0s.Pz()), + static_cast(k0s.M()), + static_cast(v0.v0cosPA()), + static_cast(v0.v0radius()), + static_cast(std::abs(v0.dcapostopv())), + static_cast(std::abs(v0.dcanegtopv())), + static_cast(std::abs(v0.dcaV0daughters())), + // lifetime, + posId, + negId}); + + histos.fill(HIST("hV0Info"), 1.5); + histos.fill(HIST("hKShortMass"), k0s.M()); + } + + histos.fill(HIST("hNStoredK0s"), selectedK0s.size()); + histos.fill(HIST("hNStoredPions"), selectedPions.size()); + + if (selectedK0s.empty() && selectedPions.empty()) { + return; } + + histos.fill(HIST("hEvtSelInfo"), 3.5); + + kshortpionEvent(centrality, + vz, + psiFT0C, + psiFT0A, + psiTPC); + + const int64_t indexEvent = kshortpionEvent.lastIndex(); + + for (const auto& k0s : selectedK0s) { + kshortTrack(indexEvent, + k0s.cospa, + k0s.radius, + k0s.dcaPositive, + k0s.dcaNegative, + k0s.dcaBetweenDaughters, + // k0s.lifetime, + k0s.px, + k0s.py, + k0s.pz, + k0s.mass, + k0s.positiveIndex, + k0s.negativeIndex); + } + + for (const auto& pion : selectedPions) { + pionTrack(indexEvent, + pion.px, + pion.py, + pion.pz, + pion.charge, + pion.index, + pion.pidMask); + } + + histos.fill(HIST("hEvtSelInfo"), 4.5); } + PROCESS_SWITCH(cksspinalignment, processData, "Process data", true); }; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; diff --git a/PWGLF/TableProducer/Resonances/doublephitable.cxx b/PWGLF/TableProducer/Resonances/doublephitable.cxx index 57744ddf693..2e04cd9be96 100644 --- a/PWGLF/TableProducer/Resonances/doublephitable.cxx +++ b/PWGLF/TableProducer/Resonances/doublephitable.cxx @@ -16,7 +16,6 @@ #include "PWGLF/DataModel/ReducedDoublePhiTables.h" -#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/Zorro.h" #include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" @@ -29,6 +28,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include +#include #include #include #include @@ -39,20 +39,21 @@ #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 #include #include #include @@ -720,6 +721,12 @@ struct doublephitable { const auto phi2Fit = k3Fit + k4Fit; const auto pairFit = phi1Fit + phi2Fit; + if (pairFit.Pt() < 6.0) { + continue; + } + if (pairFit.M() < 2.5 || pairFit.M() > 3.2) { + continue; + } // No pair-pT or pair-mass cut here. PhiPhiPairPayload pair; diff --git a/PWGLF/TableProducer/Strangeness/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/CMakeLists.txt index 1522e629b48..83b05e9a1bc 100644 --- a/PWGLF/TableProducer/Strangeness/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/CMakeLists.txt @@ -86,6 +86,11 @@ o2physics_add_dpl_workflow(sigmaminus-task PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(sigmaplusbuilder + SOURCES sigmaplusbuilder.cxx + PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(strange-tree-creator SOURCES strangeTreeCreator.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx index b94dd91714d..e8f0d23ed0d 100644 --- a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx @@ -19,9 +19,12 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include +#include #include #include +#include + using namespace o2; using namespace o2::framework; diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index ecd50c6dd54..1a4710576e1 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -50,7 +50,10 @@ #include #include +#include + #include +#include #include #include @@ -59,12 +62,9 @@ using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; -#define BIT_SET(var, nbit) ((var) |= (1 << (nbit))) -#define BIT_CHECK(var, nbit) ((var) & (1 << (nbit))) - struct HStrangeCorrelationFilter { - const float ctauxi = 4.91; // from PDG - const float ctauomega = 2.461; // from PDG + static constexpr float Xictau = 4.91; // from PDG + static constexpr float Omegactau = 2.461; // from PDG Service ccdb; @@ -249,33 +249,33 @@ struct HStrangeCorrelationFilter { TF1* fXiWidth = new TF1("fXiWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); TF1* fOmegaMean = new TF1("fomegaMean", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); TF1* fOmegaWidth = new TF1("fomegaWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); - TH1F* hK0ShortMean; - TH1F* hK0ShortWidth; - TH1F* hLambdaMean; - TH1F* hLambdaWidth; - TH1F* hXiMean; - TH1F* hXiWidth; - TH1F* hOmegaMean; - TH1F* hOmegaWidth; + TH1F* hK0ShortMean = nullptr; + TH1F* hK0ShortWidth = nullptr; + TH1F* hLambdaMean = nullptr; + TH1F* hLambdaWidth = nullptr; + TH1F* hXiMean = nullptr; + TH1F* hXiWidth = nullptr; + TH1F* hOmegaMean = nullptr; + TH1F* hOmegaWidth = nullptr; Zorro zorro; OutputObj zorroSummary{"zorroSummary"}; - int mRunNumber; + int mRunNumberZorro = -1; + int mRunNumberParameters = -1; struct TriggCandidate { - float pt; - int collisionId; - int trackId; - bool isPhysicalPrimary; - float origPt; + float pt = 0.f; + int collisionId = -1; + int trackId = -1; + bool isPhysicalPrimary = false; + float origPt = 0.f; + uint16_t mcMask = 0; }; - TriggCandidate thisTrigg; std::vector triggerCandidates; void init(InitContext const&) { zorroSummary.setObject(zorro.getZorroSummary()); - mRunNumber = -1; if (useParameterization) { fK0Mean->SetParameters(parameters.massParsK0Mean->at(0), parameters.massParsK0Mean->at(1), parameters.massParsK0Mean->at(2), parameters.massParsK0Mean->at(3)); fK0Width->SetParameters(parameters.massParsK0Width->at(0), parameters.massParsK0Width->at(1), parameters.massParsK0Width->at(2), parameters.massParsK0Width->at(3)); @@ -286,14 +286,14 @@ struct HStrangeCorrelationFilter { fOmegaMean->SetParameters(parameters.massParsOmegaMean->at(0), parameters.massParsOmegaMean->at(1), parameters.massParsOmegaMean->at(2), parameters.massParsOmegaMean->at(3)); fOmegaWidth->SetParameters(parameters.massParsOmegaWidth->at(0), parameters.massParsOmegaWidth->at(1), parameters.massParsOmegaWidth->at(2), parameters.massParsOmegaWidth->at(3)); } else { - hK0ShortMean = 0x0; - hK0ShortWidth = 0x0; - hLambdaMean = 0x0; - hLambdaWidth = 0x0; - hXiMean = 0x0; - hXiWidth = 0x0; - hOmegaMean = 0x0; - hOmegaWidth = 0x0; + hK0ShortMean = nullptr; + hK0ShortWidth = nullptr; + hLambdaMean = nullptr; + hLambdaWidth = nullptr; + hXiMean = nullptr; + hXiWidth = nullptr; + hOmegaMean = nullptr; + hOmegaWidth = nullptr; } if (doprocessV0s || doprocessV0sMC) { histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisK0ShortMass, axesConfigurations.axisMult}); @@ -310,43 +310,43 @@ struct HStrangeCorrelationFilter { void initCCDB(aod::BCsWithTimestamps::iterator const& bc) { - if (mRunNumber == bc.runNumber()) { + if (mRunNumberZorro == bc.runNumber()) { return; } zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), zorroMask.value); zorro.populateHistRegistry(histos, bc.runNumber()); - mRunNumber = bc.runNumber(); + mRunNumberZorro = bc.runNumber(); } void initParametersFromCCDB(aod::BCsWithTimestamps::iterator const& bc) { - if (mRunNumber == bc.runNumber()) { + if (mRunNumberParameters == bc.runNumber()) { return; } - mRunNumber = bc.runNumber(); - LOG(info) << "Loading mean and sigma from CCDB for run " << mRunNumber << " now..."; + mRunNumberParameters = bc.runNumber(); + LOG(info) << "Loading mean and sigma from CCDB for run " << mRunNumberParameters << " now..."; auto timeStamp = bc.timestamp(); - TList* listParameters = ccdb->getForTimeStamp(parameterCCDBPath, timeStamp); + auto listParameters = ccdb->getForTimeStamp(parameterCCDBPath, timeStamp); if (!listParameters) { LOG(fatal) << "Problem getting TList object with parameters!"; } if (doprocessV0s || doprocessV0sMC) { - hK0ShortMean = static_cast(listParameters->FindObject("hK0ShortMean")); - hK0ShortWidth = static_cast(listParameters->FindObject("hK0ShortWidth")); - hLambdaMean = static_cast(listParameters->FindObject("hLambdaMean")); - hLambdaWidth = static_cast(listParameters->FindObject("hLambdaWidth")); + hK0ShortMean = dynamic_cast(listParameters->FindObject("hK0ShortMean")); + hK0ShortWidth = dynamic_cast(listParameters->FindObject("hK0ShortWidth")); + hLambdaMean = dynamic_cast(listParameters->FindObject("hLambdaMean")); + hLambdaWidth = dynamic_cast(listParameters->FindObject("hLambdaWidth")); } if (doprocessCascades || doprocessCascadesMC) { - hXiMean = static_cast(listParameters->FindObject("hXiMean")); - hXiWidth = static_cast(listParameters->FindObject("hXiWidth")); - hOmegaMean = static_cast(listParameters->FindObject("hOmegaMean")); - hOmegaWidth = static_cast(listParameters->FindObject("hOmegaWidth")); + hXiMean = dynamic_cast(listParameters->FindObject("hXiMean")); + hXiWidth = dynamic_cast(listParameters->FindObject("hXiWidth")); + hOmegaMean = dynamic_cast(listParameters->FindObject("hOmegaMean")); + hOmegaWidth = dynamic_cast(listParameters->FindObject("hOmegaWidth")); } - LOG(info) << "parameters now loaded for " << mRunNumber; + LOG(info) << "parameters now loaded for " << mRunNumberParameters; } // this function allows for all event selections to be done in a modular way @@ -383,29 +383,36 @@ struct HStrangeCorrelationFilter { // more event selections in Pb-Pb template - bool isCollisionSelectedPbPb(TCollision collision) + bool isCollisionSelectedPbPb(TCollision const& collision) { - if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && eventSelections.requireGoodTriggerTVX) /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */ + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && eventSelections.requireGoodTriggerTVX) { /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */ return false; - if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && eventSelections.requireAllGoodITSLayers) // cut time intervals with dead ITS staves + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && eventSelections.requireAllGoodITSLayers) { // cut time intervals with dead ITS staves return false; - if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && eventSelections.requireGoodZvtxFT0vsPV) // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && eventSelections.requireGoodZvtxFT0vsPV) { // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference return false; + } auto occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) /* Below min occupancy and Above max occupancy*/ + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) { /* Below min occupancy and Above max occupancy*/ return false; - if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) // reject collisions close to Time Frame borders + } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { // reject collisions close to Time Frame borders return false; - if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) // reject events affected by the ITS ROF border + } + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { // reject events affected by the ITS ROF border return false; - if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) // rejects collisions which are associated with the same "found-by-T0" bunch crossing + } + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { // rejects collisions which are associated with the same "found-by-T0" bunch crossing return false; + } return true; } // reco-level trigger quality checks (N.B.: DCA is filtered, not selected) template - bool isValidTrigger(TTrack track) + bool isValidTrigger(TTrack const& track) { if (track.eta() > generalSelections.triggerEtaMax || track.eta() < generalSelections.triggerEtaMin) { return false; @@ -423,13 +430,13 @@ struct HStrangeCorrelationFilter { if (track.tpcNClsShared() > trackSelections.triggerMaxTPCSharedClusters) { return false; // skip, has shared clusters } - if (!(BIT_CHECK(track.itsClusterMap(), 0)) && trackSelections.triggerRequireL0) { + if (!(TESTBIT(track.itsClusterMap(), 0)) && trackSelections.triggerRequireL0) { return false; // skip, doesn't have cluster in ITS L0 } return true; } template - bool isValidAssocTrack(TTrack assoc) + bool isValidAssocTrack(TTrack const& assoc) { if (assoc.eta() > generalSelections.assocEtaMax || assoc.eta() < generalSelections.assocEtaMin) { return false; @@ -445,30 +452,38 @@ struct HStrangeCorrelationFilter { } // do this only if information is available - float nSigmaTPCTOF[8] = {-10, -10, -10, -10, -10, -10, -10, -10}; + std::array nSigmaTPCTOF = {-10, -10, -10, -10, -10, -10, -10, -10}; if constexpr (requires { assoc.tofSignal(); } && !requires { assoc.mcParticle(); }) { if (assoc.tofSignal() > 0) { - if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > trackSelections.assocPionNSigmaTPCFOF) + if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > trackSelections.assocPionNSigmaTPCFOF) { return false; - if (assoc.tofNSigmaPr() < trackSelections.rejectSigma) + } + if (assoc.tofNSigmaPr() < trackSelections.rejectSigma) { return false; - if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) { return false; - if (assoc.tofNSigmaKa() < trackSelections.rejectSigma) + } + if (assoc.tofNSigmaKa() < trackSelections.rejectSigma) { return false; - if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) { return false; + } nSigmaTPCTOF[4] = assoc.tofNSigmaPi(); nSigmaTPCTOF[5] = assoc.tofNSigmaKa(); nSigmaTPCTOF[6] = assoc.tofNSigmaPr(); nSigmaTPCTOF[7] = assoc.tofNSigmaEl(); } else { - if (assoc.tpcNSigmaPi() > trackSelections.assocPionNSigmaTPCFOF) + if (assoc.tpcNSigmaPi() > trackSelections.assocPionNSigmaTPCFOF) { return false; - if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) { return false; - if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) { return false; + } } nSigmaTPCTOF[0] = assoc.tpcNSigmaPi(); nSigmaTPCTOF[1] = assoc.tpcNSigmaKa(); @@ -479,12 +494,14 @@ struct HStrangeCorrelationFilter { bool physicalPrimary = false; float origPt = -1; float code = -9999; + uint16_t mcMask = 0; if constexpr (requires { assoc.mcParticle(); }) { if (assoc.has_mcParticle()) { auto mcParticle = assoc.mcParticle(); physicalPrimary = mcParticle.isPhysicalPrimary(); origPt = mcParticle.pt(); code = mcParticle.pdgCode(); + mcMask = assoc.mcMask(); } } @@ -493,7 +510,8 @@ struct HStrangeCorrelationFilter { physicalPrimary, assoc.globalIndex(), origPt, - code); + code, + mcMask); assocPID( nSigmaTPCTOF[0], nSigmaTPCTOF[1], @@ -508,43 +526,54 @@ struct HStrangeCorrelationFilter { // cascadeselection in PbPb template - bool cascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) + bool cascadeSelectedPbPb(TCascade const& casc, float pvx, float pvy, float pvz) { // bachBaryonCosPA - if (casc.bachBaryonCosPA() < cascSelection.bachBaryonCosPA) + if (casc.bachBaryonCosPA() < cascSelection.bachBaryonCosPA) { return false; + } // bachBaryonDCAxyToPV - if (std::abs(casc.bachBaryonDCAxyToPV()) > cascSelection.bachBaryonDCAxyToPV) + if (std::abs(casc.bachBaryonDCAxyToPV()) > cascSelection.bachBaryonDCAxyToPV) { return false; + } // casccosPA - if (casc.casccosPA(pvx, pvy, pvz) < cascSelection.cascCospa) + if (casc.casccosPA(pvx, pvy, pvz) < cascSelection.cascCospa) { return false; + } // dcacascdaughters float ptDepCut = cascSelection.dcaCacsDauPar0; - if (casc.pt() > cascSelection.lowPtForCascDaugPtDep && casc.pt() < cascSelection.highPtForCascDaugPtDep) + if (casc.pt() > cascSelection.lowPtForCascDaugPtDep && casc.pt() < cascSelection.highPtForCascDaugPtDep) { ptDepCut = cascSelection.dcaCacsDauPar1; - else if (casc.pt() > cascSelection.highPtForCascDaugPtDep) + } else if (casc.pt() > cascSelection.highPtForCascDaugPtDep) { ptDepCut = cascSelection.dcaCacsDauPar2; - if (casc.dcacascdaughters() > ptDepCut) + } + if (casc.dcacascdaughters() > ptDepCut) { return false; + } // dcaV0daughters - if (casc.dcaV0daughters() > cascSelection.cascdcaV0dau) + if (casc.dcaV0daughters() > cascSelection.cascdcaV0dau) { return false; + } // dcav0topv - if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascSelection.cascMindcav0topv) + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascSelection.cascMindcav0topv) { return false; + } // cascradius - if (casc.cascradius() < cascSelection.cascRadius) + if (casc.cascradius() < cascSelection.cascRadius) { return false; + } // v0radius - if (casc.v0radius() < cascSelection.cascv0RadiusMin) + if (casc.v0radius() < cascSelection.cascv0RadiusMin) { return false; + } // v0cosPA - if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascSelection.cascv0cospa) + if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascSelection.cascv0cospa) { return false; + } // lambdaMassWin - if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.lambdaMassWin) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.lambdaMassWin) { return false; + } return true; } @@ -561,8 +590,10 @@ struct HStrangeCorrelationFilter { double leadingPt = -1.; int leadingId = -1; for (auto const& track : tracks) { - if (!isValidTrigger(track)) + if (!isValidTrigger(track)) { continue; + } + TriggCandidate thisTrigg{}; thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); thisTrigg.collisionId = track.collisionId(); @@ -581,7 +612,8 @@ struct HStrangeCorrelationFilter { TriggCandidate.isPhysicalPrimary, TriggCandidate.trackId, TriggCandidate.origPt, - isLeading); + isLeading, + 0); triggerTrackExtra(1); } } @@ -599,8 +631,10 @@ struct HStrangeCorrelationFilter { double leadingPt = -1.; int leadingId = -1; for (auto const& track : tracks) { - if (!isValidTrigger(track)) + if (!isValidTrigger(track)) { continue; + } + TriggCandidate thisTrigg{}; thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); thisTrigg.collisionId = track.collisionId(); @@ -608,6 +642,7 @@ struct HStrangeCorrelationFilter { auto mcParticle = track.mcParticle(); thisTrigg.isPhysicalPrimary = mcParticle.isPhysicalPrimary(); thisTrigg.origPt = mcParticle.pt(); + thisTrigg.mcMask = track.mcMask(); } triggerCandidates.push_back(thisTrigg); if (track.pt() > leadingPt) { @@ -623,7 +658,8 @@ struct HStrangeCorrelationFilter { TriggCandidate.isPhysicalPrimary, TriggCandidate.trackId, TriggCandidate.origPt, - isLeading); + isLeading, + TriggCandidate.mcMask); triggerTrackExtra(1); } } @@ -651,8 +687,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } @@ -679,8 +716,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } @@ -707,8 +745,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } void processAssocHadronsMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::McParticles const&, aod::BCsWithTimestamps const&) @@ -734,8 +773,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } @@ -763,12 +803,15 @@ struct HStrangeCorrelationFilter { auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } float dcaDauCutForK0s = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; bool isGoodK0Short = (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && @@ -780,48 +823,48 @@ struct HStrangeCorrelationFilter { std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV); if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 0); + SETBIT(compatibleK0Short, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 1); + SETBIT(compatibleK0Short, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 2); + SETBIT(compatibleK0Short, 2); } } if (v0.v0cosPA() > v0Selection.lambdaCospa) { if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 0); + SETBIT(compatibleLambda, 0); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 1); + SETBIT(compatibleLambda, 1); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 2); + SETBIT(compatibleLambda, 2); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 0); + SETBIT(compatibleAntiLambda, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 1); + SETBIT(compatibleAntiLambda, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 2); + SETBIT(compatibleAntiLambda, 2); } } } @@ -846,12 +889,15 @@ struct HStrangeCorrelationFilter { massNSigmaAntiLambda = (v0.mAntiLambda() - hLambdaMean->Interpolate(v0.pt())) / (hLambdaWidth->Interpolate(v0.pt()) + 1e-6); } } - if (compatibleK0Short) + if (compatibleK0Short > 0) { histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), cent); - if (compatibleLambda) + } + if (compatibleLambda > 0) { histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), cent); - if (compatibleAntiLambda) + } + if (compatibleAntiLambda > 0) { histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -892,12 +938,15 @@ struct HStrangeCorrelationFilter { auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } float dcaDauCutForK0s = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; bool isGoodK0Short = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && @@ -909,49 +958,49 @@ struct HStrangeCorrelationFilter { std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV; if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 0); + SETBIT(compatibleK0Short, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 1); + SETBIT(compatibleK0Short, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 2); + SETBIT(compatibleK0Short, 2); } } if (v0.v0cosPA() > v0Selection.lambdaCospa) { if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 0); + SETBIT(compatibleLambda, 0); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 1); + SETBIT(compatibleLambda, 1); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 2); + SETBIT(compatibleLambda, 2); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 0); + SETBIT(compatibleAntiLambda, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 1); + SETBIT(compatibleAntiLambda, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 2); + SETBIT(compatibleAntiLambda, 2); } } } @@ -982,18 +1031,24 @@ struct HStrangeCorrelationFilter { bool trueLambda = false; bool trueAntiLambda = false; v0PhysicalPrimary = v0.isPhysicalPrimary(); - if (v0.pdgCode() == PDG_t::kK0Short) + if (v0.pdgCode() == PDG_t::kK0Short) { trueK0Short = true; - if (v0.pdgCode() == PDG_t::kLambda0) + } + if (v0.pdgCode() == PDG_t::kLambda0) { trueLambda = true; - if (v0.pdgCode() == PDG_t::kLambda0Bar) + } + if (v0.pdgCode() == PDG_t::kLambda0Bar) { trueAntiLambda = true; - if (compatibleK0Short && (!doTrueSelectionInMass || (trueK0Short && v0PhysicalPrimary))) + } + if (compatibleK0Short > 0 && (!doTrueSelectionInMass || (trueK0Short && v0PhysicalPrimary))) { histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), cent); - if (compatibleLambda && (!doTrueSelectionInMass || (trueLambda && v0PhysicalPrimary))) + } + if (compatibleLambda > 0 && (!doTrueSelectionInMass || (trueLambda && v0PhysicalPrimary))) { histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), cent); - if (compatibleAntiLambda && (!doTrueSelectionInMass || (trueAntiLambda && v0PhysicalPrimary))) + } + if (compatibleAntiLambda > 0 && (!doTrueSelectionInMass || (trueAntiLambda && v0PhysicalPrimary))) { histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -1029,23 +1084,29 @@ struct HStrangeCorrelationFilter { casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascCospa || casc.cascradius() < cascSelection.cascRadius || std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascSelection.cascMindcav0topv || - std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) { continue; + } auto bachTrackCast = casc.bachelor_as(); auto posTrackCast = casc.posTrack_as(); auto negTrackCast = casc.negTrack_as(); // minimum TPC crossed rows - if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) + } + if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) { continue; - if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } bool isGoodNegCascadePbPb = std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaBaryonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaMesonToPV; @@ -1058,8 +1119,8 @@ struct HStrangeCorrelationFilter { int compatibleOmegaPlus = 0; float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); - float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * Xictau); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * Omegactau); bool isGoodXiPbPb = std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelection.rejcomp && ctauXi < cascSelection.proplifetime && std::abs(casc.yXi()) < cascSelection.rapCut; @@ -1067,65 +1128,65 @@ struct HStrangeCorrelationFilter { ctauOmega < cascSelection.proplifetime && std::abs(casc.yOmega()) < cascSelection.rapCut; if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 0); + SETBIT(compatibleXiMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 1); + SETBIT(compatibleXiMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 2); + SETBIT(compatibleXiMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 0); + SETBIT(compatibleXiPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 1); + SETBIT(compatibleXiPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 2); + SETBIT(compatibleXiPlus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 0); + SETBIT(compatibleOmegaMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 1); + SETBIT(compatibleOmegaMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 2); + SETBIT(compatibleOmegaMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 0); + SETBIT(compatibleOmegaPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 1); + SETBIT(compatibleOmegaPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 2); + SETBIT(compatibleOmegaPlus, 2); } } float massNSigmaXi = -20.0f; @@ -1144,14 +1205,18 @@ struct HStrangeCorrelationFilter { massNSigmaOmega = (casc.mOmega() - hOmegaMean->Interpolate(casc.pt())) / (hOmegaWidth->Interpolate(casc.pt()) + 1e-6); } } - if (compatibleXiMinus) + if (compatibleXiMinus > 0) { histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), cent); - if (compatibleXiPlus) + } + if (compatibleXiPlus > 0) { histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), cent); - if (compatibleOmegaMinus && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaMinus > 0 && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), cent); - if (compatibleOmegaPlus && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaPlus > 0 && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -1187,24 +1252,30 @@ struct HStrangeCorrelationFilter { casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascCospa || casc.cascradius() < cascSelection.cascRadius || std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascSelection.cascMindcav0topv || - std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) { continue; + } auto bachTrackCast = casc.bachelor_as(); auto posTrackCast = casc.posTrack_as(); auto negTrackCast = casc.negTrack_as(); // minimum TPC crossed rows - if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) + } + if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) { continue; - if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } bool isGoodNegCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaBaryonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaMesonToPV); bool isGoodPosCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && @@ -1216,8 +1287,8 @@ struct HStrangeCorrelationFilter { int compatibleOmegaPlus = 0; float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); - float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * Xictau); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * Omegactau); bool iGoodXiPbPb = std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelection.rejcomp && ctauXi < cascSelection.proplifetime && std::abs(casc.yXi()) < cascSelection.rapCut; @@ -1225,65 +1296,65 @@ struct HStrangeCorrelationFilter { ctauOmega < cascSelection.proplifetime && std::abs(casc.yOmega()) < cascSelection.rapCut; if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 0); + SETBIT(compatibleXiMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 1); + SETBIT(compatibleXiMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 2); + SETBIT(compatibleXiMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 0); + SETBIT(compatibleXiPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 1); + SETBIT(compatibleXiPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 2); + SETBIT(compatibleXiPlus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 0); + SETBIT(compatibleOmegaMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 1); + SETBIT(compatibleOmegaMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 2); + SETBIT(compatibleOmegaMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 0); + SETBIT(compatibleOmegaPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 1); + SETBIT(compatibleOmegaPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 2); + SETBIT(compatibleOmegaPlus, 2); } } float massNSigmaXi = 20.0f; @@ -1309,22 +1380,30 @@ struct HStrangeCorrelationFilter { bool trueOmegaMinus = false; bool trueOmegaPlus = false; cascPhysicalPrimary = casc.isPhysicalPrimary(); - if (casc.pdgCode() == PDG_t::kXiMinus) + if (casc.pdgCode() == PDG_t::kXiMinus) { trueXiMinus = true; - if (casc.pdgCode() == PDG_t::kXiPlusBar) + } + if (casc.pdgCode() == PDG_t::kXiPlusBar) { trueXiPlus = true; - if (casc.pdgCode() == PDG_t::kOmegaMinus) + } + if (casc.pdgCode() == PDG_t::kOmegaMinus) { trueOmegaMinus = true; - if (casc.pdgCode() == PDG_t::kOmegaPlusBar) + } + if (casc.pdgCode() == PDG_t::kOmegaPlusBar) { trueOmegaPlus = true; - if (compatibleXiMinus && (!doTrueSelectionInMass || (trueXiMinus && cascPhysicalPrimary))) + } + if (compatibleXiMinus > 0 && (!doTrueSelectionInMass || (trueXiMinus && cascPhysicalPrimary))) { histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), cent); - if (compatibleXiPlus && (!doTrueSelectionInMass || (trueXiPlus && cascPhysicalPrimary))) + } + if (compatibleXiPlus > 0 && (!doTrueSelectionInMass || (trueXiPlus && cascPhysicalPrimary))) { histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), cent); - if (compatibleOmegaMinus && (!doTrueSelectionInMass || (trueOmegaMinus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaMinus > 0 && (!doTrueSelectionInMass || (trueOmegaMinus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), cent); - if (compatibleOmegaPlus && (!doTrueSelectionInMass || (trueOmegaPlus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaPlus > 0 && (!doTrueSelectionInMass || (trueOmegaPlus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -1352,8 +1431,8 @@ struct HStrangeCorrelationFilter { PROCESS_SWITCH(HStrangeCorrelationFilter, processAssocHadronsMC, "Produce associated Hadron tables for MC", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(context)}; } diff --git a/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx b/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx index b557053295c..fcb3bf21aff 100644 --- a/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx @@ -298,6 +298,7 @@ struct lambdaspincorrelation { std::vector positiveIndex = {}; std::vector negativeIndex = {}; std::vector dcaBetweenDaughter = {}; + std::vector dcaV0ToPV = {}; int numbV0 = 0; // LOGF(info, "event collisions: (%d)", collision.index()); auto centrality = collision.centFT0C(); @@ -355,6 +356,7 @@ struct lambdaspincorrelation { positiveIndex.push_back(postrack1.globalIndex()); negativeIndex.push_back(negtrack1.globalIndex()); v0Cospa.push_back(v0.v0cosPA()); + dcaV0ToPV.push_back(std::abs(v0.dcav0topv())); v0Radius.push_back(v0.v0radius()); dcaPositive.push_back(std::abs(v0.dcapostopv())); dcaNegative.push_back(std::abs(v0.dcanegtopv())); @@ -391,7 +393,7 @@ struct lambdaspincorrelation { lambdaDummy = lambdaMother.at(i5); protonDummy = protonDaughter.at(i5); pionDummy = pionDaughter.at(i5); - lambdaPair(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5)); + lambdaPair(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5), dcaV0ToPV.at(i5)); } } } @@ -410,6 +412,7 @@ struct lambdaspincorrelation { std::vector positiveIndex = {}; std::vector negativeIndex = {}; std::vector dcaBetweenDaughter = {}; + std::vector dcaV0ToPV = {}; int numbV0 = 0; // LOGF(info, "event collisions: (%d)", collision.index()); auto centrality = collision.centFT0C(); @@ -470,6 +473,7 @@ struct lambdaspincorrelation { dcaPositive.push_back(std::abs(v0.dcapostopv())); dcaNegative.push_back(std::abs(v0.dcanegtopv())); dcaBetweenDaughter.push_back(std::abs(v0.dcaV0daughters())); + dcaV0ToPV.push_back(std::abs(v0.dcav0topv())); if (lambdaTag) { v0Status.push_back(0); proton = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassProton); @@ -502,7 +506,7 @@ struct lambdaspincorrelation { lambdaDummy = lambdaMother.at(i5); protonDummy = protonDaughter.at(i5); pionDummy = pionDaughter.at(i5); - lambdaPairmc(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5)); + lambdaPairmc(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5), dcaV0ToPV.at(i5)); } } } @@ -530,6 +534,7 @@ struct lambdaspincorrelation { std::vector positiveIndex = {}; std::vector negativeIndex = {}; std::vector dcaBetweenDaughter = {}; + std::vector dcaV0ToPV = {}; int numbV0 = 0; auto centrality = collision.centFT0C(); @@ -610,6 +615,7 @@ struct lambdaspincorrelation { negativeIndex.push_back(negtrack1.globalIndex()); v0Cospa.push_back(v0.v0cosPA()); + dcaV0ToPV.push_back(std::abs(v0.dcav0topv())); v0Radius.push_back(v0.v0radius()); dcaPositive.push_back(std::abs(v0.dcapostopv())); dcaNegative.push_back(std::abs(v0.dcanegtopv())); @@ -695,7 +701,8 @@ struct lambdaspincorrelation { protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), - negativeIndex.at(i5)); + negativeIndex.at(i5), + dcaV0ToPV.at(i5)); } } } diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index 6a363942d5f..73d4997f821 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx b/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx new file mode 100644 index 00000000000..739e7859c0f --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx @@ -0,0 +1,1175 @@ +// 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 sigmaplusbuilder.cxx +/// \brief Task for Sigma+ -> p + pi0 reconstruction, pi0 reconstructed via one converted photon (PCM) +/// \author Henrik Fribert (TUM) + +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +using TracksFull = soa::Join; +using TracksFullMC = soa::Join; +using CollisionsFull = aod::Collisions; +using CollisionsFullMC = soa::Join; + +struct Sigmaplusbuilder { + + // photon (PCM) selection + Configurable photonMaxMass{"photonMaxMass", 0.20, "Max photon mass (GeV/c^2)"}; + Configurable photonMinRapidity{"photonMinRapidity", -0.8, "Min photon rapidity"}; + Configurable photonMaxRapidity{"photonMaxRapidity", 0.8, "Max photon rapidity"}; + Configurable photonDauEtaMin{"photonDauEtaMin", -0.8, "Min eta of photon daughter tracks"}; + Configurable photonDauEtaMax{"photonDauEtaMax", 0.8, "Max eta of photon daughter tracks"}; + Configurable photonMinRadius{"photonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + Configurable photonMaxRadius{"photonMaxRadius", 115., "Max photon conversion radius (cm)"}; + Configurable photonMinV0cospa{"photonMinV0cospa", 0.80, "Min V0 CosPA"}; + Configurable photonMaxDCAV0Dau{"photonMaxDCAV0Dau", 3.5, "Max DCA between photon daughters (cm)"}; + Configurable photonMaxQt{"photonMaxQt", 0.15, "Max Armenteros qT for photons (GeV/c)"}; + Configurable photonMaxAlpha{"photonMaxAlpha", 1.0, "Max |Armenteros alpha| for photons"}; + Configurable photonMaxTPCNSigmaEl{"photonMaxTPCNSigmaEl", 15, "Max |TPC nSigma_el| for photon daughters"}; + + // proton selection + Configurable protonMinPt{"protonMinPt", 0.3, "Minimum proton pT (GeV/c)"}; + Configurable protonMaxEta{"protonMaxEta", 0.9, "Maximum |eta| for proton track"}; + Configurable protonMaxTPCNSigma{"protonMaxTPCNSigma", 4, "Max |TPC nSigma_pr| for proton"}; + Configurable protonMaxTOFNSigma{"protonMaxTOFNSigma", 4, "Max |TOF nSigma_pr| for proton, if TOF available"}; + Configurable protonPtMinRequireTOF{"protonPtMinRequireTOF", 0.75, "Above this pT, require TOF PID for proton"}; + + // proton-photon candidate selection + Configurable candMaxDcaProtonGamma{"candMaxDcaProtonGamma", 5.0, "Max DCA between proton and photon at the fitted vertex (cm)"}; + Configurable candMinRadius{"candMinRadius", 1.0, "Min candidate decay radius (cm)"}; + Configurable candMaxRadius{"candMaxRadius", 100., "Max candidate decay radius (cm)"}; + + // missing-photon discriminant retry + // resolution-shaped function and tuned parameters from Run 2 used + Configurable discrRetryMaxIter{"discrRetryMaxIter", 10, "Max attempts to recover a negative discriminant by perturbing the flight direction"}; + Configurable discrRetryThetaRange{"discrRetryThetaRange", 0.02, "Max |delta-theta| perturbation of the flight direction per retry (rad)"}; + Configurable discrRetryThetaPar0{"discrRetryThetaPar0", 0.000133299, "par0 of the delta-theta resolution function"}; + Configurable discrRetryThetaPar1{"discrRetryThetaPar1", 0.0016761, "par1 of the delta-theta resolution function"}; + Configurable discrRetryPhiRange{"discrRetryPhiRange", 0.02, "Max |delta-phi| perturbation of the flight direction per retry (rad)"}; + Configurable discrRetryPhiPar0{"discrRetryPhiPar0", 0.000129845, "par0 of the delta-phi resolution function"}; + Configurable discrRetryPhiPar1{"discrRetryPhiPar1", 0.00199688, "par1 of the delta-phi resolution function"}; + + Configurable ccdbPath{"ccdbPath", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Produces sigmaPlusCands; + Produces sigmaPlusCandsMC; + + Service ccdb; + o2::vertexing::DCAFitterN<2> fitter; + int mRunNumber = 0; + float mBz = 0; + TF1 mThetaResoFunc; + TF1 mPhiResoFunc; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Preslice v0PerCollision = aod::v0data::collisionId; + Preslice tracksPerCollision = aod::track::collisionId; + Preslice tracksPerCollisionMC = aod::track::collisionId; + + void init(InitContext const&) + { + ccdb->setURL(ccdbPath); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + + mThetaResoFunc = TF1("thetaResoFunc", "[0]/(abs(x)+[1])", -discrRetryThetaRange, discrRetryThetaRange); + mThetaResoFunc.SetParameters(discrRetryThetaPar0.value, discrRetryThetaPar1.value); + mPhiResoFunc = TF1("phiResoFunc", "[0]/(abs(x)+[1])", -discrRetryPhiRange, discrRetryPhiRange); + mPhiResoFunc.SetParameters(discrRetryPhiPar0.value, discrRetryPhiPar1.value); + + const AxisSpec axisVertexZ{100, -15., 15., "vrtx_{Z} (cm)"}; + + const AxisSpec axisPhotonSel{11, -0.5, 10.5, "selection step"}; + const AxisSpec axisPhotonMass{200, 0., 0.3, "m_{#gamma} (GeV/c^{2})"}; + const AxisSpec axisPhotonPt{100, 0., 5., "#it{p}_{T,#gamma} (GeV/c)"}; + const AxisSpec axisPhotonRadius{200, 0., 200., "R_{conv} (cm)"}; + const AxisSpec axisAlpha{100, -1., 1., "#alpha_{AP}"}; + const AxisSpec axisQt{100, 0., 0.3, "q_{T,AP} (GeV/c)"}; + const AxisSpec axisConvXY{200, -100., 100., "conv. point (cm)"}; + + const AxisSpec axisProtonSel{5, -0.5, 4.5, "selection step"}; + const AxisSpec axisProtonPt{100, 0., 5., "#it{p}_{T,p} (GeV/c)"}; + const AxisSpec axisNSigma{100, -5., 5., "n#sigma"}; + + histos.add("hVertexZ", "hVertexZ", kTH1F, {axisVertexZ}); + + histos.add("Photon/hSelectionCounter", "Photon/hSelectionCounter", kTH1F, {axisPhotonSel}); + auto hPhotonSel = histos.get(HIST("Photon/hSelectionCounter")); + hPhotonSel->GetXaxis()->SetBinLabel(1, "All"); + hPhotonSel->GetXaxis()->SetBinLabel(2, "Mass"); + hPhotonSel->GetXaxis()->SetBinLabel(3, "Rapidity"); + hPhotonSel->GetXaxis()->SetBinLabel(4, "Neg eta"); + hPhotonSel->GetXaxis()->SetBinLabel(5, "Pos eta"); + hPhotonSel->GetXaxis()->SetBinLabel(6, "DCA daughters"); + hPhotonSel->GetXaxis()->SetBinLabel(7, "Radius"); + hPhotonSel->GetXaxis()->SetBinLabel(8, "CosPA"); + hPhotonSel->GetXaxis()->SetBinLabel(9, "Qt"); + hPhotonSel->GetXaxis()->SetBinLabel(10, "Alpha"); + hPhotonSel->GetXaxis()->SetBinLabel(11, "TPC nSigma el"); + + histos.add("Photon/hMass", "Photon/hMass", kTH1F, {axisPhotonMass}); + histos.add("Photon/hPt", "Photon/hPt", kTH1F, {axisPhotonPt}); + histos.add("Photon/hRadius", "Photon/hRadius", kTH1F, {axisPhotonRadius}); + histos.add("Photon/h2ArmenterosPodolanski", "Photon/h2ArmenterosPodolanski", kTH2F, {axisAlpha, axisQt}); + histos.add("Photon/h2ConvPointXY", "Photon/h2ConvPointXY", kTH2F, {axisConvXY, axisConvXY}); + + histos.add("Proton/hSelectionCounter", "Proton/hSelectionCounter", kTH1F, {axisProtonSel}); + auto hProtonSel = histos.get(HIST("Proton/hSelectionCounter")); + hProtonSel->GetXaxis()->SetBinLabel(1, "All"); + hProtonSel->GetXaxis()->SetBinLabel(2, "Pt"); + hProtonSel->GetXaxis()->SetBinLabel(3, "Eta"); + hProtonSel->GetXaxis()->SetBinLabel(4, "TPC nSigma"); + hProtonSel->GetXaxis()->SetBinLabel(5, "TOF nSigma"); + + histos.add("Proton/hPt", "Proton/hPt", kTH1F, {axisProtonPt}); + histos.add("Proton/h2TPCNSigmaVsPt", "Proton/h2TPCNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); + histos.add("Proton/h2TOFNSigmaVsPt", "Proton/h2TOFNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); + + const AxisSpec axisCandSel{7, -0.5, 6.5, "selection step"}; + const AxisSpec axisDca{100, 0., 10., "DCA(p,#gamma) (cm)"}; + const AxisSpec axisCandRadius{200, 0., 200., "R_{dec} (cm)"}; + const AxisSpec axisDiscriminant{200, -1., 1., "discriminant (GeV^{4}/#it{c}^{4})"}; + const AxisSpec axisMassSigma{200, 1.0, 1.4, "m_{p#gamma#gamma} (GeV/#it{c}^{2})"}; + const AxisSpec axisSigmaPt{100, 0., 6., "#it{p}_{T,#Sigma^{+}} (GeV/#it{c})"}; + const AxisSpec axisMomentum{100, 0., 10., "#it{p} (GeV/#it{c})"}; + + histos.add("Candidate/hSelectionCounter", "Candidate/hSelectionCounter", kTH1F, {axisCandSel}); + auto hCandSel = histos.get(HIST("Candidate/hSelectionCounter")); + hCandSel->GetXaxis()->SetBinLabel(1, "All pairs"); + hCandSel->GetXaxis()->SetBinLabel(2, "Vertex fit"); + hCandSel->GetXaxis()->SetBinLabel(3, "DCA(p,#gamma)"); + hCandSel->GetXaxis()->SetBinLabel(4, "Radius"); + hCandSel->GetXaxis()->SetBinLabel(5, "Real root"); + hCandSel->GetXaxis()->SetBinLabel(6, "Valid root"); + hCandSel->GetXaxis()->SetBinLabel(7, "Filled"); + + histos.add("Candidate/hDcaProtonGamma", "Candidate/hDcaProtonGamma", kTH1F, {axisDca}); + histos.add("Candidate/hRadius", "Candidate/hRadius", kTH1F, {axisCandRadius}); + histos.add("Candidate/hDiscriminant", "Candidate/hDiscriminant", kTH1F, {axisDiscriminant}); + histos.add("Candidate/hMassSigmaPlus", "Candidate/hMassSigmaPlus", kTH1F, {axisMassSigma}); + histos.add("Candidate/h2MassVsPt", "Candidate/h2MassVsPt", kTH2F, {axisSigmaPt, axisMassSigma}); + + const AxisSpec axisDiscrIter{discrRetryMaxIter + 2, -0.5, discrRetryMaxIter + 1.5, "discriminant retry iteration"}; + histos.add("Candidate/hDiscriminantRetryIter", "Candidate/hDiscriminantRetryIter", kTH1F, {axisDiscrIter}); + + if (doprocessMc) { + histos.add("Photon/True/hSelectionCounter", "Photon/True/hSelectionCounter", kTH1F, {axisPhotonSel}); + auto hPhotonSelSignal = histos.get(HIST("Photon/True/hSelectionCounter")); + hPhotonSelSignal->GetXaxis()->SetBinLabel(1, "All"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(2, "Mass"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(3, "Rapidity"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(4, "Neg eta"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(5, "Pos eta"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(6, "DCA daughters"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(7, "Radius"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(8, "CosPA"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(9, "Qt"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(10, "Alpha"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(11, "TPC nSigma el"); + + histos.add("Photon/True/hMass", "Photon/True/hMass", kTH1F, {axisPhotonMass}); + histos.add("Photon/True/hPt", "Photon/True/hPt", kTH1F, {axisPhotonPt}); + histos.add("Photon/True/hRadius", "Photon/True/hRadius", kTH1F, {axisPhotonRadius}); + histos.add("Photon/True/h2ArmenterosPodolanski", "Photon/True/h2ArmenterosPodolanski", kTH2F, {axisAlpha, axisQt}); + histos.add("Photon/True/h2ConvPointXY", "Photon/True/h2ConvPointXY", kTH2F, {axisConvXY, axisConvXY}); + + histos.add("Proton/True/hPt", "Proton/True/hPt", kTH1F, {axisProtonPt}); + histos.add("Proton/True/h2TPCNSigmaVsPt", "Proton/True/h2TPCNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); + histos.add("Proton/True/h2TOFNSigmaVsPt", "Proton/True/h2TOFNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); + + histos.add("Candidate/True/hSelectionCounter", "Candidate/True/hSelectionCounter", kTH1F, {axisCandSel}); + auto hCandSelSignal = histos.get(HIST("Candidate/True/hSelectionCounter")); + hCandSelSignal->GetXaxis()->SetBinLabel(1, "All pairs"); + hCandSelSignal->GetXaxis()->SetBinLabel(2, "Vertex fit"); + hCandSelSignal->GetXaxis()->SetBinLabel(3, "DCA(p,#gamma)"); + hCandSelSignal->GetXaxis()->SetBinLabel(4, "Radius"); + hCandSelSignal->GetXaxis()->SetBinLabel(5, "Real root"); + hCandSelSignal->GetXaxis()->SetBinLabel(6, "Valid root"); + hCandSelSignal->GetXaxis()->SetBinLabel(7, "Filled"); + + histos.add("Candidate/True/hDcaProtonGamma", "Candidate/True/hDcaProtonGamma", kTH1F, {axisDca}); + histos.add("Candidate/True/hRadius", "Candidate/True/hRadius", kTH1F, {axisCandRadius}); + const AxisSpec axisVtxRes{200, 0., 20., "|vtx_{fit} - vtx_{MC}| (cm)"}; + histos.add("Candidate/True/hVertexResFromMcTruth", "Candidate/True/hVertexResFromMcTruth", kTH1F, {axisVtxRes}); + const AxisSpec axisMomRes{200, -1., 1., "(p_{fit} - p_{MC}) / p_{MC}"}; + histos.add("Candidate/True/hProtonMomResFromMcTruth", "Candidate/True/hProtonMomResFromMcTruth", kTH1F, {axisMomRes}); + histos.add("Candidate/True/hPhotonMomResFromMcTruth", "Candidate/True/hPhotonMomResFromMcTruth", kTH1F, {axisMomRes}); + const AxisSpec axisProtonFlightAngle{180, 0., 3.15, "angle(p_{proton}, n) (rad)"}; + histos.add("Candidate/True/hProtonFlightAngle", "Candidate/True/hProtonFlightAngle", kTH1F, {axisProtonFlightAngle}); + histos.add("Candidate/True/hDiscriminant", "Candidate/True/hDiscriminant", kTH1F, {axisDiscriminant}); + histos.add("Candidate/True/hDiscriminantRetryIter", "Candidate/True/hDiscriminantRetryIter", kTH1F, {axisDiscrIter}); + histos.add("Candidate/True/hMassSigmaPlus", "Candidate/True/hMassSigmaPlus", kTH1F, {axisMassSigma}); + histos.add("Candidate/True/h2MassVsPt", "Candidate/True/h2MassVsPt", kTH2F, {axisSigmaPt, axisMassSigma}); + + histos.add("MC/hGenSigmaPlusPt", "MC/hGenSigmaPlusPt", kTH1F, {axisSigmaPt}); + + const AxisSpec axisProtonTruthQA{3, -0.5, 2.5, "step"}; + histos.add("MC/hProtonTruthQA", "MC/hProtonTruthQA", kTH1F, {axisProtonTruthQA}); + auto hProtonTruthQA = histos.get(HIST("MC/hProtonTruthQA")); + hProtonTruthQA->GetXaxis()->SetBinLabel(1, "Accepted"); + hProtonTruthQA->GetXaxis()->SetBinLabel(2, "Has mcParticle"); + hProtonTruthQA->GetXaxis()->SetBinLabel(3, "Sigma+ mother"); + + const AxisSpec axisPhotonTruthQA{5, -0.5, 4.5, "step"}; + histos.add("MC/hPhotonTruthQA", "MC/hPhotonTruthQA", kTH1F, {axisPhotonTruthQA}); + auto hPhotonTruthQA = histos.get(HIST("MC/hPhotonTruthQA")); + hPhotonTruthQA->GetXaxis()->SetBinLabel(1, "Accepted"); + hPhotonTruthQA->GetXaxis()->SetBinLabel(2, "Both legs have mcParticle"); + hPhotonTruthQA->GetXaxis()->SetBinLabel(3, "Shared real gamma mother"); + hPhotonTruthQA->GetXaxis()->SetBinLabel(4, "Gamma's mother is pi0"); + hPhotonTruthQA->GetXaxis()->SetBinLabel(5, "Pi0's mother is Sigma+"); + } + + if (doprocessFindable) { + const AxisSpec axisDetectorPresence{3, -0.5, 2.5, "detector"}; + const AxisSpec axisDuplicateTrack{2, -0.5, 1.5, "track"}; + const AxisSpec axisV0Presence{2, -0.5, 1.5, "V0 match"}; + const AxisSpec axisTPCClusters{160, -0.5, 159.5, "TPC clusters"}; + const AxisSpec axisPhotonMomResolution{200, -1., 1., "(#it{p}_{reco,#gamma} - #it{p}_{MC,#gamma})/#it{p}_{MC,#gamma}"}; + const AxisSpec axisPhotonCosPA{200, -1., 1., "cosPA_{#gamma}"}; + const AxisSpec axisPairMass{200, 0., 0.1, "m_{e^{+}e^{-}} (GeV/#it{c}^{2})"}; + histos.add("Findable/hSigmaPlusPt", "Findable/hSigmaPlusPt", kTH1F, {axisSigmaPt}); + histos.add("Findable/h2ProtonPtVsSigmaPlusPt", "Findable/h2ProtonPtVsSigmaPlusPt", kTH2F, {axisSigmaPt, axisMomentum}); + histos.add("Findable/hElectronPt", "Findable/hElectronPt", kTH1F, {axisMomentum}); + histos.add("Findable/hPositronPt", "Findable/hPositronPt", kTH1F, {axisMomentum}); + histos.add("Findable/hElectronPositronMass", "Findable/hElectronPositronMass", kTH1F, {axisPairMass}); + histos.add("Findable/hPhotonConversionRadius", "Findable/hPhotonConversionRadius", kTH1F, {axisPhotonRadius}); + histos.add("Findable/hPhotonMomentumResolution", "Findable/hPhotonMomentumResolution", kTH1F, {axisPhotonMomResolution}); + histos.add("Findable/hPhotonCosPA", "Findable/hPhotonCosPA", kTH1F, {axisPhotonCosPA}); + histos.add("Findable/hConversionPairV0Presence", "Findable/hConversionPairV0Presence", kTH1F, {axisV0Presence}); + histos.add("Findable/hDuplicateConversionTrackCounter", "Findable/hDuplicateConversionTrackCounter", kTH1F, {axisDuplicateTrack}); + histos.add("Findable/hDuplicateElectronTPCNClsFound", "Findable/hDuplicateElectronTPCNClsFound", kTH1F, {axisTPCClusters}); + histos.add("Findable/hDuplicatePositronTPCNClsFound", "Findable/hDuplicatePositronTPCNClsFound", kTH1F, {axisTPCClusters}); + histos.add("Findable/hElectronDetectorPresence", "Findable/hElectronDetectorPresence", kTH1F, {axisDetectorPresence}); + histos.add("Findable/hPositronDetectorPresence", "Findable/hPositronDetectorPresence", kTH1F, {axisDetectorPresence}); + auto hConversionPairV0Presence = histos.get(HIST("Findable/hConversionPairV0Presence")); + hConversionPairV0Presence->GetXaxis()->SetBinLabel(1, "valid pair"); + hConversionPairV0Presence->GetXaxis()->SetBinLabel(2, "in V0"); + auto hDuplicateConversionTrackCounter = histos.get(HIST("Findable/hDuplicateConversionTrackCounter")); + hDuplicateConversionTrackCounter->GetXaxis()->SetBinLabel(1, "e^{-}"); + hDuplicateConversionTrackCounter->GetXaxis()->SetBinLabel(2, "e^{+}"); + auto hElectronDetectorPresence = histos.get(HIST("Findable/hElectronDetectorPresence")); + auto hPositronDetectorPresence = histos.get(HIST("Findable/hPositronDetectorPresence")); + hElectronDetectorPresence->GetXaxis()->SetBinLabel(1, "ITS"); + hElectronDetectorPresence->GetXaxis()->SetBinLabel(2, "TPC"); + hElectronDetectorPresence->GetXaxis()->SetBinLabel(3, "TOF"); + hPositronDetectorPresence->GetXaxis()->SetBinLabel(1, "ITS"); + hPositronDetectorPresence->GetXaxis()->SetBinLabel(2, "TPC"); + hPositronDetectorPresence->GetXaxis()->SetBinLabel(3, "TOF"); + } + } + + // photon (PCM) candidate selection + template + bool selectPhoton(const TV0& v0) + { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + + bool isSignal = false; + if constexpr (IsMC) { + if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { + auto mcPos = posTrack.template mcParticle_as(); + auto mcNeg = negTrack.template mcParticle_as(); + isSignal = findSigmaPlusMotherOfPhoton(mcPos, mcNeg) >= 0; + } + } + + auto fillPhotonStep = [&](int step) { + histos.fill(HIST("Photon/hSelectionCounter"), step); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Photon/True/hSelectionCounter"), step); + } + } + }; + fillPhotonStep(0); + + if (v0.mGamma() < 0 || v0.mGamma() > photonMaxMass) { + return false; + } + fillPhotonStep(1); + + float photonY = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma); + if (photonY < photonMinRapidity || photonY > photonMaxRapidity) { + return false; + } + fillPhotonStep(2); + + if (v0.negativeeta() < photonDauEtaMin || v0.negativeeta() > photonDauEtaMax) { + return false; + } + fillPhotonStep(3); + + if (v0.positiveeta() < photonDauEtaMin || v0.positiveeta() > photonDauEtaMax) { + return false; + } + fillPhotonStep(4); + + if (std::abs(v0.dcaV0daughters()) > photonMaxDCAV0Dau) { + return false; + } + fillPhotonStep(5); + + if (v0.v0radius() < photonMinRadius || v0.v0radius() > photonMaxRadius) { + return false; + } + fillPhotonStep(6); + + if (v0.v0cosPA() < photonMinV0cospa) { + return false; + } + fillPhotonStep(7); + + if (v0.qtarm() > photonMaxQt) { + return false; + } + fillPhotonStep(8); + + if (std::abs(v0.alpha()) > photonMaxAlpha) { + return false; + } + fillPhotonStep(9); + + if (std::abs(posTrack.tpcNSigmaEl()) > photonMaxTPCNSigmaEl || std::abs(negTrack.tpcNSigmaEl()) > photonMaxTPCNSigmaEl) { + return false; + } + fillPhotonStep(10); + + histos.fill(HIST("Photon/hMass"), v0.mGamma()); + histos.fill(HIST("Photon/hPt"), v0.pt()); + histos.fill(HIST("Photon/hRadius"), v0.v0radius()); + histos.fill(HIST("Photon/h2ArmenterosPodolanski"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("Photon/h2ConvPointXY"), v0.x(), v0.y()); + + return true; + } + + // proton candidate selection + template + bool selectProton(const TTrack& track) + { + histos.fill(HIST("Proton/hSelectionCounter"), 0); + + if (track.pt() < protonMinPt) { + return false; + } + histos.fill(HIST("Proton/hSelectionCounter"), 1); + + if (std::abs(track.eta()) > protonMaxEta) { + return false; + } + histos.fill(HIST("Proton/hSelectionCounter"), 2); + + if (std::abs(track.tpcNSigmaPr()) > protonMaxTPCNSigma) { + return false; + } + histos.fill(HIST("Proton/hSelectionCounter"), 3); + + if (track.pt() > protonPtMinRequireTOF) { + if (!track.hasTOF() || std::abs(track.tofNSigmaPr()) > protonMaxTOFNSigma) { + return false; + } + } + histos.fill(HIST("Proton/hSelectionCounter"), 4); + + histos.fill(HIST("Proton/hPt"), track.pt()); + histos.fill(HIST("Proton/h2TPCNSigmaVsPt"), track.pt(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.fill(HIST("Proton/h2TOFNSigmaVsPt"), track.pt(), track.tofNSigmaPr()); + } + + return true; + } + + // small vector helpers used in the Sigma+ reconstruction + static float dot3(const std::array& a, const std::array& b) + { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + static std::array cross3(const std::array& a, const std::array& b) + { + return {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]}; + } + static std::array normalize3(const std::array& a) + { + float norm = std::sqrt(dot3(a, a)); + return {a[0] / norm, a[1] / norm, a[2] / norm}; + } + + // MC truth + template + int findSigmaPlusMotherOfProton(const TMcPart& mcProton) + { + if (std::abs(mcProton.pdgCode()) != PDG_t::kProton) { + return -1; + } + auto const& mothers = mcProton.template mothers_as(); + if (mothers.empty() || std::abs(mothers.front().pdgCode()) != PDG_t::kSigmaPlus) { + return -1; + } + return mothers.front().globalIndex(); + } + + template + int findSigmaPlusMotherOfPhoton(const TMcPart& mcPos, const TMcPart& mcNeg) + { + auto const& posMothers = mcPos.template mothers_as(); + auto const& negMothers = mcNeg.template mothers_as(); + if (posMothers.empty() || negMothers.empty()) { + return -1; + } + auto mcGamma = posMothers.front(); + if (mcGamma.globalIndex() != negMothers.front().globalIndex() || mcGamma.pdgCode() != PDG_t::kGamma) { + return -1; + } + + auto const& pi0Mothers = mcGamma.template mothers_as(); + if (pi0Mothers.empty() || std::abs(pi0Mothers.front().pdgCode()) != PDG_t::kPi0) { + return -1; + } + + auto const& sigmaMothers = pi0Mothers.front().template mothers_as(); + if (sigmaMothers.empty() || std::abs(sigmaMothers.front().pdgCode()) != PDG_t::kSigmaPlus) { + return -1; + } + return sigmaMothers.front().globalIndex(); + } + + template + bool isSigmaPlusToProtonPi0(const TMcPart& mcPart) + { + if (std::abs(mcPart.pdgCode()) != PDG_t::kSigmaPlus) { + return false; + } + int pdgProton = mcPart.pdgCode() > 0 ? PDG_t::kProton : PDG_t::kProtonBar; + bool hasProton = false; + bool hasPi0 = false; + for (const auto& daughter : mcPart.template daughters_as()) { + hasProton |= (daughter.pdgCode() == pdgProton); + hasPi0 |= (std::abs(daughter.pdgCode()) == PDG_t::kPi0); + } + return hasProton && hasPi0; + } + + template + void fillFindableTrackDetectors(const TTrack& track) + { + auto fillDetector = [&](int detector) { + if constexpr (IsElectron) { + histos.fill(HIST("Findable/hElectronDetectorPresence"), detector); + } else { + histos.fill(HIST("Findable/hPositronDetectorPresence"), detector); + } + }; + + if (track.hasITS()) { + fillDetector(0); + } + if (track.hasTPC()) { + fillDetector(1); + } + if (track.hasTOF()) { + fillDetector(2); + } + } + + template + int findSigmaPlusMotherOfConversionElectron(const TMcPart& mcElectron, int& gammaIndex, std::array& conversionVertex) + { + if (std::abs(mcElectron.pdgCode()) != PDG_t::kElectron || mcElectron.getProcess() != TMCProcess::kPPair) { + return -1; + } + + auto const& gammaMothers = mcElectron.template mothers_as(); + if (gammaMothers.empty() || gammaMothers.front().pdgCode() != PDG_t::kGamma) { + return -1; + } + + auto mcGamma = gammaMothers.front(); + if (mcGamma.getProcess() != TMCProcess::kPDecay) { + return -1; + } + + auto const& pi0Mothers = mcGamma.template mothers_as(); + if (pi0Mothers.empty() || std::abs(pi0Mothers.front().pdgCode()) != PDG_t::kPi0) { + return -1; + } + + auto mcPi0 = pi0Mothers.front(); + auto const& sigmaMothers = mcPi0.template mothers_as(); + if (sigmaMothers.empty() || std::abs(sigmaMothers.front().pdgCode()) != PDG_t::kSigmaPlus) { + return -1; + } + + gammaIndex = mcGamma.globalIndex(); + conversionVertex = {mcElectron.vx(), mcElectron.vy(), mcElectron.vz()}; + return sigmaMothers.front().globalIndex(); + } + + // Build a Sigma+ -> p pi0 candidate from a proton track and a PCM photon + template + void buildSigmaPlusCandidate(const TTrack& protonTrack, const TV0& photon, const std::array& pv) + { + auto posTrack = photon.template posTrack_as(); + auto negTrack = photon.template negTrack_as(); + + bool isSignal = false; + std::array mcTrueVtx{}; // Sigma+ decay vertex + std::array mcTrueMomProton{}; // true MC proton momentum + std::array mcTrueMomGamma{}; // true MC momentum of the measured photon + int protonPdgCode = 0; + int protonMotherPdgCode = 0; + int gammaPdgCode = 0; + int gammaMotherPdgCode = 0; + int gammaGMotherPdgCode = 0; + if constexpr (IsMC) { + if (protonTrack.has_mcParticle()) { + auto mcProton = protonTrack.template mcParticle_as(); + protonPdgCode = mcProton.pdgCode(); + auto const& protonMothers = mcProton.template mothers_as(); + if (!protonMothers.empty()) { + protonMotherPdgCode = protonMothers.front().pdgCode(); + } + + int protonSigmaIdx = findSigmaPlusMotherOfProton(mcProton); + + if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { + auto mcPos = posTrack.template mcParticle_as(); + auto mcNeg = negTrack.template mcParticle_as(); + + auto const& posMothers = mcPos.template mothers_as(); + if (!posMothers.empty()) { + auto mcGamma = posMothers.front(); + gammaPdgCode = mcGamma.pdgCode(); + mcTrueMomGamma = {mcGamma.px(), mcGamma.py(), mcGamma.pz()}; + + auto const& gammaMothers = mcGamma.template mothers_as(); + if (!gammaMothers.empty()) { + auto mcPi0 = gammaMothers.front(); + gammaMotherPdgCode = mcPi0.pdgCode(); + + auto const& pi0Mothers = mcPi0.template mothers_as(); + if (!pi0Mothers.empty()) { + gammaGMotherPdgCode = pi0Mothers.front().pdgCode(); + } + } + } + + int photonSigmaIdx = findSigmaPlusMotherOfPhoton(mcPos, mcNeg); + isSignal = (protonSigmaIdx >= 0 && photonSigmaIdx >= 0 && photonSigmaIdx == protonSigmaIdx); + } + + if (isSignal) { + mcTrueVtx = {mcProton.vx(), mcProton.vy(), mcProton.vz()}; + mcTrueMomProton = {mcProton.px(), mcProton.py(), mcProton.pz()}; + } + } + } + + auto fillCandStep = [&](int step) { + histos.fill(HIST("Candidate/hSelectionCounter"), step); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hSelectionCounter"), step); + } + } + }; + fillCandStep(0); // all pairs + + auto protonTrackParCov = getTrackParCov(protonTrack); + + std::array zeroCov{}; + auto photonTrackParCov = o2::track::TrackParCov({photon.x(), photon.y(), photon.z()}, {photon.px(), photon.py(), photon.pz()}, zeroCov, 0, true); + photonTrackParCov.setAbsCharge(0); + photonTrackParCov.setPID(o2::track::PID::Photon); + + int nCand = 0; + try { + nCand = fitter.process(protonTrackParCov, photonTrackParCov); + } catch (...) { + return; + } + if (nCand == 0 || !fitter.propagateTracksToVertex()) { + return; + } + fillCandStep(1); // Vertex fit + + float fitChi2 = fitter.getChi2AtPCACandidate(); + float dcaProtonGamma = std::sqrt(fitChi2); + histos.fill(HIST("Candidate/hDcaProtonGamma"), dcaProtonGamma); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hDcaProtonGamma"), dcaProtonGamma); + } + } + if (dcaProtonGamma > candMaxDcaProtonGamma) { + return; + } + fillCandStep(2); // DCA(p,gamma) + + std::array secVtx = fitter.getPCACandidatePos(); + float radius = std::hypot(secVtx[0], secVtx[1]); + histos.fill(HIST("Candidate/hRadius"), radius); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hRadius"), radius); + float vtxResFromMc = std::hypot(secVtx[0] - mcTrueVtx[0], secVtx[1] - mcTrueVtx[1], secVtx[2] - mcTrueVtx[2]); + histos.fill(HIST("Candidate/True/hVertexResFromMcTruth"), vtxResFromMc); + } + } + if (radius < candMinRadius || radius > candMaxRadius) { + return; + } + fillCandStep(3); // radius + + // flight direction n and the decay-plane basis n, eIn, eOut + std::array flightVec{secVtx[0] - pv[0], secVtx[1] - pv[1], secVtx[2] - pv[2]}; + std::array nHat = normalize3(flightVec); + float flightDistance = std::sqrt(dot3(flightVec, flightVec)); + + std::array pProton; + std::array pGamma1; + fitter.getTrack(0).getPxPyPzGlo(pProton); + fitter.getTrack(1).getPxPyPzGlo(pGamma1); + + if constexpr (IsMC) { + if (isSignal) { + float trueProtonP = std::sqrt(dot3(mcTrueMomProton, mcTrueMomProton)); + float fitProtonP = std::sqrt(dot3(pProton, pProton)); + histos.fill(HIST("Candidate/True/hProtonMomResFromMcTruth"), (fitProtonP - trueProtonP) / trueProtonP); + + float trueGammaP = std::sqrt(dot3(mcTrueMomGamma, mcTrueMomGamma)); + float fitGammaP = std::sqrt(dot3(pGamma1, pGamma1)); + histos.fill(HIST("Candidate/True/hPhotonMomResFromMcTruth"), (fitGammaP - trueGammaP) / trueGammaP); + } + } + + float e1 = std::sqrt(dot3(pGamma1, pGamma1)); // |p_gamma1| + float massPi0 = o2::constants::physics::MassPionNeutral; + + std::array eOut{}; + std::array eIn{}; + float coefA = 0.f, coefB = 0.f, coefK = 0.f, coefL = 0.f; + float pGamma2In = 0.f, pGamma2Out = 0.f, tPerp2 = 0.f; + float discriminant = -1.f; + std::array nHatOrig = nHat; // each retry perturbs around this + constexpr float CoefADegenerateThreshold = 1e-6f; // guards against dividing by a near-zero quadratic coefficient + + if constexpr (IsMC) { + if (isSignal) { + float cosProtonFlight = dot3(pProton, nHatOrig) / std::sqrt(dot3(pProton, pProton)); + float protonFlightAngle = std::acos(std::clamp(cosProtonFlight, -1.f, 1.f)); + histos.fill(HIST("Candidate/True/hProtonFlightAngle"), protonFlightAngle); + } + } + + int discrIter = 0; + for (; discrIter <= discrRetryMaxIter; ++discrIter) { + if (discrIter > 0) { + TVector3 nHatVec(nHatOrig[0], nHatOrig[1], nHatOrig[2]); + float dTheta = mThetaResoFunc.GetRandom(); + float dPhi = mPhiResoFunc.GetRandom(); + nHatVec.SetMagThetaPhi(1., nHatVec.Theta() + dTheta, nHatVec.Phi() + dPhi); + nHat = {static_cast(nHatVec.X()), static_cast(nHatVec.Y()), static_cast(nHatVec.Z())}; + } + + eOut = normalize3(cross3(pProton, nHat)); // normal to the decay plane + eIn = cross3(eOut, nHat); // in-plane, transverse to n + + float pProtonIn = dot3(pProton, eIn); // proton has no out-of-plane component, by construction + float pGamma1Long = dot3(pGamma1, nHat); + float pGamma1In = dot3(pGamma1, eIn); + float pGamma1Out = dot3(pGamma1, eOut); + + // in-plane transverse momentum cancels between p, gamma1, gamma2 + pGamma2In = -(pProtonIn + pGamma1In); + // out-of-plane momentum cancels between gamma1 and gamma2 alone + pGamma2Out = -pGamma1Out; + tPerp2 = pGamma2In * pGamma2In + pGamma2Out * pGamma2Out; + + // m_pi0^2 = 2*(|p_gamma1||p_gamma2| - p_gamma1.p_gamma2), solved for + // the remaining unknown (p_gamma2 along n) -> quadratic coefA*x^2+coefB*x+coefC=0 + float dot1 = pGamma1In * pGamma2In + pGamma1Out * pGamma2Out; + coefK = massPi0 * massPi0 + 2.f * dot1; + coefL = 2.f * pGamma1Long; + + coefA = 4.f * e1 * e1 - coefL * coefL; + if (std::abs(coefA) < CoefADegenerateThreshold) { + continue; + } + coefB = -2.f * coefK * coefL; + float coefC = 4.f * e1 * e1 * tPerp2 - coefK * coefK; + + discriminant = coefB * coefB - 4.f * coefA * coefC; + if (discriminant >= 0.f) { + break; + } + } + + histos.fill(HIST("Candidate/hDiscriminantRetryIter"), discrIter); + histos.fill(HIST("Candidate/hDiscriminant"), discriminant); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hDiscriminantRetryIter"), discrIter); + histos.fill(HIST("Candidate/True/hDiscriminant"), discriminant); + } + } + if (discriminant < 0.f) { + return; + } + fillCandStep(4); // real root + + // two roots from the quadratic, among both we keep the mass closest to the nominal Sigma+ mass + float sqrtDisc = std::sqrt(discriminant); + std::array roots{(-coefB + sqrtDisc) / (2.f * coefA), (-coefB - sqrtDisc) / (2.f * coefA)}; + + bool haveCandidate = false; + float bestMass = -999.f; + std::array bestMomGamma2{}; + for (const float& pGamma2Long : roots) { + std::array pGamma2{ + eIn[0] * pGamma2In + eOut[0] * pGamma2Out + nHat[0] * pGamma2Long, + eIn[1] * pGamma2In + eOut[1] * pGamma2Out + nHat[1] * pGamma2Long, + eIn[2] * pGamma2In + eOut[2] * pGamma2Out + nHat[2] * pGamma2Long}; + float eGamma2 = std::sqrt(tPerp2 + pGamma2Long * pGamma2Long); + float eProton = std::sqrt(dot3(pProton, pProton) + o2::constants::physics::MassProton * o2::constants::physics::MassProton); + std::array pTotal{pProton[0] + pGamma1[0] + pGamma2[0], pProton[1] + pGamma1[1] + pGamma2[1], pProton[2] + pGamma1[2] + pGamma2[2]}; + float eTotal = eProton + e1 + eGamma2; + float mass2 = eTotal * eTotal - dot3(pTotal, pTotal); + if (mass2 < 0.f) { + continue; + } + float mass = std::sqrt(mass2); + if (!haveCandidate || std::abs(mass - o2::constants::physics::MassSigmaPlus) < std::abs(bestMass - o2::constants::physics::MassSigmaPlus)) { + haveCandidate = true; + bestMass = mass; + bestMomGamma2 = pGamma2; + } + } + if (!haveCandidate) { + return; + } + fillCandStep(5); // valid root + + std::array pSigma{pProton[0] + pGamma1[0] + bestMomGamma2[0], pProton[1] + pGamma1[1] + bestMomGamma2[1], pProton[2] + pGamma1[2] + bestMomGamma2[2]}; + float ptSigma = std::hypot(pSigma[0], pSigma[1]); + + histos.fill(HIST("Candidate/hMassSigmaPlus"), bestMass); + histos.fill(HIST("Candidate/h2MassVsPt"), ptSigma, bestMass); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hMassSigmaPlus"), bestMass); + histos.fill(HIST("Candidate/True/h2MassVsPt"), ptSigma, bestMass); + } + } + fillCandStep(6); // filled + + // photon (V0) opening angle: angle between the e+/e- daughter momenta at their own reference point + std::array pPosDau{posTrack.px(), posTrack.py(), posTrack.pz()}; + std::array pNegDau{negTrack.px(), negTrack.py(), negTrack.pz()}; + float photonOpeningAngle = std::acos(std::clamp(dot3(pPosDau, pNegDau) / std::sqrt(dot3(pPosDau, pPosDau) * dot3(pNegDau, pNegDau)), -1.f, 1.f)); + + // photon pointing angle: angle between the fitted photon momentum and the line from its conversion point to the p-gamma decay vertex + std::array convToDecVtx{secVtx[0] - photon.x(), secVtx[1] - photon.y(), secVtx[2] - photon.z()}; + float photonPointingAngle = std::acos(std::clamp(dot3(pGamma1, convToDecVtx) / std::sqrt(dot3(pGamma1, pGamma1) * dot3(convToDecVtx, convToDecVtx)), -1.f, 1.f)); + + // photon DCA to PV: distance from the PV to the line through the conversion point along the photon momentum direction + std::array convPoint{photon.x(), photon.y(), photon.z()}; + std::array photonDir = normalize3({photon.px(), photon.py(), photon.pz()}); + std::array pvToConv{pv[0] - convPoint[0], pv[1] - convPoint[1], pv[2] - convPoint[2]}; + std::array pvToConvCrossDir = cross3(pvToConv, photonDir); + float photonDcaToPV = std::sqrt(dot3(pvToConvCrossDir, pvToConvCrossDir)); + + if constexpr (IsMC) { + sigmaPlusCandsMC(secVtx[0], secVtx[1], secVtx[2], + radius, flightDistance, dcaProtonGamma, fitChi2, + pProton[0], pProton[1], pProton[2], + pGamma1[0], pGamma1[1], pGamma1[2], + bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], + protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), + posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), + photon.mGamma(), photon.alpha(), photon.qtarm(), photon.v0radius(), + photonOpeningAngle, photonPointingAngle, photonDcaToPV, + protonTrack.itsNCls(), protonTrack.tpcNClsFound(), protonTrack.dcaXY(), protonTrack.dcaZ(), + posTrack.itsNCls(), posTrack.tpcNClsFound(), negTrack.itsNCls(), negTrack.tpcNClsFound(), + isSignal, + protonPdgCode, protonMotherPdgCode, + gammaPdgCode, gammaMotherPdgCode, gammaGMotherPdgCode, + mcTrueVtx[0], mcTrueVtx[1], mcTrueVtx[2], + mcTrueMomProton[0], mcTrueMomProton[1], mcTrueMomProton[2], + mcTrueMomGamma[0], mcTrueMomGamma[1], mcTrueMomGamma[2]); + } else { + sigmaPlusCands(secVtx[0], secVtx[1], secVtx[2], + radius, flightDistance, dcaProtonGamma, fitChi2, + pProton[0], pProton[1], pProton[2], + pGamma1[0], pGamma1[1], pGamma1[2], + bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], + protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), + posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), + photon.mGamma(), photon.alpha(), photon.qtarm(), photon.v0radius(), + photonOpeningAngle, photonPointingAngle, photonDcaToPV, + protonTrack.itsNCls(), protonTrack.tpcNClsFound(), protonTrack.dcaXY(), protonTrack.dcaZ(), + posTrack.itsNCls(), posTrack.tpcNClsFound(), negTrack.itsNCls(), negTrack.tpcNClsFound()); + } + } + + void initCCDB(aod::BCs::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = grpmag->getNominalL3Field(); + fitter.setBz(mBz); + LOG(info) << "Task initialized for run " << mRunNumber << " with magnetic field " << mBz << " kZG"; + } + + void processData(CollisionsFull const& collisions, aod::V0Datas const& v0s, TracksFull const& tracks, aod::BCs const&) + { + for (const auto& collision : collisions) { + initCCDB(collision.bc_as()); + histos.fill(HIST("hVertexZ"), collision.posZ()); + std::array pv{collision.posX(), collision.posY(), collision.posZ()}; + + auto v0sThisCollision = v0s.sliceBy(v0PerCollision, collision.globalIndex()); + std::vector acceptedPhotons; + for (const auto& v0 : v0sThisCollision) { + if (selectPhoton(v0)) { + acceptedPhotons.push_back(v0); + } + } + + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + std::vector acceptedProtons; + for (const auto& track : tracksThisCollision) { + if (selectProton(track)) { + acceptedProtons.push_back(track); + } + } + + for (const auto& photon : acceptedPhotons) { + for (const auto& proton : acceptedProtons) { + buildSigmaPlusCandidate(proton, photon, pv); + } + } + } + } + PROCESS_SWITCH(Sigmaplusbuilder, processData, "Process data", true); + + void processMc(CollisionsFullMC const& collisions, aod::V0Datas const& v0s, TracksFullMC const& tracks, aod::BCs const&, aod::McParticles const& mcParticles) + { + for (const auto& collision : collisions) { + initCCDB(collision.bc_as()); + histos.fill(HIST("hVertexZ"), collision.posZ()); + std::array pv{collision.posX(), collision.posY(), collision.posZ()}; + + auto v0sThisCollision = v0s.sliceBy(v0PerCollision, collision.globalIndex()); + std::vector acceptedPhotons; + for (const auto& v0 : v0sThisCollision) { + if (selectPhoton(v0)) { + acceptedPhotons.push_back(v0); + + histos.fill(HIST("MC/hPhotonTruthQA"), 0); + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { + histos.fill(HIST("MC/hPhotonTruthQA"), 1); + auto mcPos = posTrack.template mcParticle_as(); + auto mcNeg = negTrack.template mcParticle_as(); + + auto const& posMothers = mcPos.template mothers_as(); + auto const& negMothers = mcNeg.template mothers_as(); + if (!posMothers.empty() && !negMothers.empty()) { + auto mcGamma = posMothers.front(); + if (mcGamma.globalIndex() == negMothers.front().globalIndex() && mcGamma.pdgCode() == PDG_t::kGamma) { + histos.fill(HIST("MC/hPhotonTruthQA"), 2); + auto const& pi0Mothers = mcGamma.template mothers_as(); + if (!pi0Mothers.empty() && std::abs(pi0Mothers.front().pdgCode()) == PDG_t::kPi0) { + histos.fill(HIST("MC/hPhotonTruthQA"), 3); + auto const& sigmaMothers = pi0Mothers.front().template mothers_as(); + if (!sigmaMothers.empty() && std::abs(sigmaMothers.front().pdgCode()) == PDG_t::kSigmaPlus) { + histos.fill(HIST("MC/hPhotonTruthQA"), 4); + + histos.fill(HIST("Photon/True/hMass"), v0.mGamma()); + histos.fill(HIST("Photon/True/hPt"), v0.pt()); + histos.fill(HIST("Photon/True/hRadius"), v0.v0radius()); + histos.fill(HIST("Photon/True/h2ArmenterosPodolanski"), v0.alpha(), v0.qtarm()); + histos.fill(HIST("Photon/True/h2ConvPointXY"), v0.x(), v0.y()); + } + } + } + } + } + } + } + + auto tracksThisCollision = tracks.sliceBy(tracksPerCollisionMC, collision.globalIndex()); + std::vector acceptedProtons; + for (const auto& track : tracksThisCollision) { + if (selectProton(track)) { + acceptedProtons.push_back(track); + + histos.fill(HIST("MC/hProtonTruthQA"), 0); + if (track.has_mcParticle()) { + histos.fill(HIST("MC/hProtonTruthQA"), 1); + auto mcProton = track.template mcParticle_as(); + if (findSigmaPlusMotherOfProton(mcProton) >= 0) { + histos.fill(HIST("MC/hProtonTruthQA"), 2); + + histos.fill(HIST("Proton/True/hPt"), track.pt()); + histos.fill(HIST("Proton/True/h2TPCNSigmaVsPt"), track.pt(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.fill(HIST("Proton/True/h2TOFNSigmaVsPt"), track.pt(), track.tofNSigmaPr()); + } + } + } + } + } + + for (const auto& photon : acceptedPhotons) { + for (const auto& proton : acceptedProtons) { + buildSigmaPlusCandidate(proton, photon, pv); + } + } + } + + // all generated Sigma+ -> p pi0 decays, regardless of reconstruction + for (const auto& mcPart : mcParticles) { + if (isSigmaPlusToProtonPi0(mcPart)) { + histos.fill(HIST("MC/hGenSigmaPlusPt"), mcPart.pt()); + } + } + } + PROCESS_SWITCH(Sigmaplusbuilder, processMc, "Process MC", false); + + void processFindable(CollisionsFullMC const& collisions, aod::V0Datas const& v0s, TracksFullMC const& tracks, aod::McParticles const&) + { + for (const auto& collision : collisions) { + auto tracksThisCollision = tracks.sliceBy(tracksPerCollisionMC, collision.globalIndex()); + auto v0sThisCollision = v0s.sliceBy(v0PerCollision, collision.globalIndex()); + + for (const auto& protonTrack : tracksThisCollision) { + if (!protonTrack.has_mcParticle()) { + continue; + } + + auto mcProton = protonTrack.template mcParticle_as(); + int sigmaIndex = findSigmaPlusMotherOfProton(mcProton); + if (sigmaIndex < 0) { + continue; + } + + auto const& protonMothers = mcProton.template mothers_as(); + if (protonMothers.empty()) { + continue; + } + auto mcSigmaPlus = protonMothers.front(); + if (std::abs(mcSigmaPlus.y()) > 1) { + continue; + } + histos.fill(HIST("Findable/h2ProtonPtVsSigmaPlusPt"), mcSigmaPlus.pt(), protonTrack.pt()); + std::vector seenElectronMcIds; + std::vector seenElectronTrackIds; + std::vector seenPositronMcIds; + std::vector seenPositronTrackIds; + + for (const auto& electronTrack : tracksThisCollision) { + if (!electronTrack.has_mcParticle()) { + continue; + } + + if (electronTrack.tpcNClsFound() < 90 || electronTrack.sign() > 0) { + continue; + } + + auto mcElectron = electronTrack.template mcParticle_as(); + if (mcElectron.pdgCode() != PDG_t::kElectron) { + continue; + } + + int electronGammaIndex = -1; + std::array electronVertex{}; + if (findSigmaPlusMotherOfConversionElectron(mcElectron, electronGammaIndex, electronVertex) != sigmaIndex) { + continue; + } + + for (const auto& positronTrack : tracksThisCollision) { + if (!positronTrack.has_mcParticle()) { + continue; + } + + if (positronTrack.tpcNClsFound() < 90 || positronTrack.sign() < 0) { + continue; + } + + auto mcPositron = positronTrack.template mcParticle_as(); + if (mcPositron.pdgCode() != PDG_t::kPositron) { + continue; + } + + int positronGammaIndex = -1; + std::array positronVertex{}; + if (findSigmaPlusMotherOfConversionElectron(mcPositron, positronGammaIndex, positronVertex) != sigmaIndex || positronGammaIndex != electronGammaIndex) { + continue; + } + + bool sameConversionPoint = electronVertex[0] == positronVertex[0] && + electronVertex[1] == positronVertex[1] && + electronVertex[2] == positronVertex[2]; + if (!sameConversionPoint) { + continue; + } + + int electronMcId = mcElectron.globalIndex(); + int electronTrackId = electronTrack.globalIndex(); + int positronMcId = mcPositron.globalIndex(); + int positronTrackId = positronTrack.globalIndex(); + + bool seenElectronMc = false; + bool duplicateElectronTrack = false; + for (int iSeen = 0; iSeen < static_cast(seenElectronMcIds.size()); ++iSeen) { + if (seenElectronMcIds[iSeen] == electronMcId) { + seenElectronMc = true; + duplicateElectronTrack |= (seenElectronTrackIds[iSeen] != electronTrackId); + } + } + if (duplicateElectronTrack) { + histos.fill(HIST("Findable/hDuplicateConversionTrackCounter"), 0); + histos.fill(HIST("Findable/hDuplicateElectronTPCNClsFound"), electronTrack.tpcNClsFound()); + } + if (!seenElectronMc) { + seenElectronMcIds.push_back(electronMcId); + seenElectronTrackIds.push_back(electronTrackId); + } + + bool seenPositronMc = false; + bool duplicatePositronTrack = false; + for (int iSeen = 0; iSeen < static_cast(seenPositronMcIds.size()); ++iSeen) { + if (seenPositronMcIds[iSeen] == positronMcId) { + seenPositronMc = true; + duplicatePositronTrack |= (seenPositronTrackIds[iSeen] != positronTrackId); + } + } + if (duplicatePositronTrack) { + histos.fill(HIST("Findable/hDuplicateConversionTrackCounter"), 1); + histos.fill(HIST("Findable/hDuplicatePositronTPCNClsFound"), positronTrack.tpcNClsFound()); + } + if (!seenPositronMc) { + seenPositronMcIds.push_back(positronMcId); + seenPositronTrackIds.push_back(positronTrackId); + } + if (duplicateElectronTrack || duplicatePositronTrack) { + continue; + } + + std::array recoGammaMom{electronTrack.px() + positronTrack.px(), electronTrack.py() + positronTrack.py(), electronTrack.pz() + positronTrack.pz()}; + float recoGammaP = std::sqrt(dot3(recoGammaMom, recoGammaMom)); + constexpr float electronMass = o2::constants::physics::MassElectron; + float electronP2 = electronTrack.px() * electronTrack.px() + electronTrack.py() * electronTrack.py() + electronTrack.pz() * electronTrack.pz(); + float positronP2 = positronTrack.px() * positronTrack.px() + positronTrack.py() * positronTrack.py() + positronTrack.pz() * positronTrack.pz(); + float pairEnergy = std::sqrt(electronP2 + electronMass * electronMass) + std::sqrt(positronP2 + electronMass * electronMass); + float pairMass2 = pairEnergy * pairEnergy - recoGammaP * recoGammaP; + histos.fill(HIST("Findable/hElectronPositronMass"), std::sqrt(std::max(pairMass2, 0.f))); + + auto const& gammaMothers = mcElectron.template mothers_as(); + if (!gammaMothers.empty()) { + auto mcGamma = gammaMothers.front(); + std::array trueGammaMom{mcGamma.px(), mcGamma.py(), mcGamma.pz()}; + float trueGammaP = std::sqrt(dot3(trueGammaMom, trueGammaMom)); + if (trueGammaP > 0.f) { + histos.fill(HIST("Findable/hPhotonMomentumResolution"), (recoGammaP - trueGammaP) / trueGammaP); + } + } + + std::array photonFlightVec{electronVertex[0] - collision.posX(), electronVertex[1] - collision.posY(), electronVertex[2] - collision.posZ()}; + float flightNorm = std::sqrt(dot3(photonFlightVec, photonFlightVec)); + if (flightNorm > 0.f && recoGammaP > 0.f) { + histos.fill(HIST("Findable/hPhotonCosPA"), dot3(photonFlightVec, recoGammaMom) / (flightNorm * recoGammaP)); + } + + histos.fill(HIST("Findable/hSigmaPlusPt"), mcSigmaPlus.pt()); + histos.fill(HIST("Findable/hConversionPairV0Presence"), 0); + for (const auto& v0 : v0sThisCollision) { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + bool sameChargeMatched = posTrack.globalIndex() == positronTrack.globalIndex() && negTrack.globalIndex() == electronTrack.globalIndex(); + if (sameChargeMatched) { + histos.fill(HIST("Findable/hConversionPairV0Presence"), 1); + break; + } + } + histos.fill(HIST("Findable/hElectronPt"), electronTrack.pt()); + histos.fill(HIST("Findable/hPositronPt"), positronTrack.pt()); + histos.fill(HIST("Findable/hPhotonConversionRadius"), std::hypot(electronVertex[0], electronVertex[1])); + fillFindableTrackDetectors(electronTrack); + fillFindableTrackDetectors(positronTrack); + } + } + } + } + } + PROCESS_SWITCH(Sigmaplusbuilder, processFindable, "Process findable MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx index b1c529c2880..94cf60e61d6 100644 --- a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -725,7 +726,7 @@ struct strangederivedbuilder { totalFDDAmplitudeA, totalFDDAmplitudeC, timeZNA, timeZNC, // ZDC info energyCommonZNA, energyCommonZNC); - } else { // We are in Run 2 + } else { // We are in Run 2 products.strangeCentsRun2(collision.centRun2V0M(), collision.centRun2V0A(), collision.centRun2SPDTracklets(), collision.centRun2SPDClusters()); products.strangeEvSelsRun2(collision.sel8(), collision.sel7(), collision.selection_raw(), @@ -809,7 +810,7 @@ struct strangederivedbuilder { collisionEventTime[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); collisionEventTimeErr[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); } else { - collisionEventTime[collision.globalIndex()] = -1e+6; // undefined + collisionEventTime[collision.globalIndex()] = -1e+6; // undefined collisionEventTimeErr[collision.globalIndex()] = -1e-6; // undefined } if (fillOnlySelectedCollisions && !isCollisionAccepted(collision, totalNbrCollisionsPerSelection)) { diff --git a/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx index 112c7d46a5c..14f37772f44 100644 --- a/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx index f1fa21206b1..c81c941d864 100644 --- a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx @@ -75,6 +75,7 @@ #include #include #include +#include #include using std::string; @@ -183,11 +184,11 @@ enum TrkSel { trkSelEta, trkSelPt, trkSelDCA, + trkSelCustomDCA, trkNRowsTPC, trkSelNClsFound, trkSelNClsPID, trkSelTPCBndr, - trkSelCustomDCA, nTrkSel }; @@ -239,51 +240,56 @@ struct FlattenictyPikp { int runNumber{-1}; o2::parameters::GRPMagField* grpmag = nullptr; - Configurable multEst{"multEst", 1, "0: without multiplicity; 1: MultFT0M; 2: MultTPC"}; - Configurable applyCalibGain{"applyCalibGain", false, "equalize detector amplitudes"}; - Configurable applyCalibVtx{"applyCalibVtx", false, "equalize Amp vs vtx"}; - Configurable applyCalibDeDx{"applyCalibDeDx", false, "calibration of dedx signal"}; - Configurable applyCalibDeDxFromCCDB{"applyCalibDeDxFromCCDB", true, "use CCDB-based calibration of dedx signal"}; - Configurable cfgFillTrackQaHist{"cfgFillTrackQaHist", false, "fill track QA histograms"}; - Configurable cfgFillNclVsPhiCutQaHist{"cfgFillNclVsPhiCutQaHist", false, "fill TPC cluster vs geometrical cut QA histograms"}; - Configurable cfgFilldEdxCalibHist{"cfgFilldEdxCalibHist", false, "fill dEdx calibration histograms"}; - Configurable cfgFilldEdxQaHist{"cfgFilldEdxQaHist", false, "fill dEdx QA histograms"}; - Configurable cfgFillDCAxyHist{"cfgFillDCAxyHist", false, "fill nsigma QA histograms"}; - Configurable cfgFillV0Hist{"cfgFillV0Hist", false, "fill V0 histograms"}; - Configurable cfgFillChrgType{"cfgFillChrgType", false, "fill histograms per charge types"}; - Configurable cfgFillChrgTypeV0s{"cfgFillChrgTypeV0s", false, "fill V0s histograms per charge types"}; - Configurable cfgCalibDeDxFunction{"cfgCalibDeDxFunction", "pol8", "Functional form for dEdx calibration"}; - Configurable> paramsFuncMIPposEtaP{"paramsFuncMIPposEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPnegEtaP{"paramsFuncMIPnegEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPallEtaP{"paramsFuncMIPallEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPposEtaN{"paramsFuncMIPposEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPnegEtaN{"paramsFuncMIPnegEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPallEtaN{"paramsFuncMIPallEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUposEtaP{"paramsFuncPlateaUposEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUnegEtaP{"paramsFuncPlateaUnegEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUallEtaP{"paramsFuncPlateaUallEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUposEtaN{"paramsFuncPlateaUposEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUnegEtaN{"paramsFuncPlateaUnegEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUallEtaN{"paramsFuncPlateaUallEtaN", std::vector{-1.f}, "function parameters"}; - Configurable cfgGainEqCcdbPath{"cfgGainEqCcdbPath", "Users/g/gbencedi/flattenicity/GainEq", "CCDB path for gain equalization constants"}; - Configurable cfgVtxEqCcdbPath{"cfgVtxEqCcdbPath", "Users/g/gbencedi/flattenicity/ZvtxEq", "CCDB path for z-vertex equalization constants"}; - Configurable cfgDeDxCalibCcdbPath{"cfgDeDxCalibCcdbPath", "Users/g/gbencedi/flattenicity/dEdxCalib", "CCDB path for dEdx calibration"}; - Configurable cfgStoreThnSparse{"cfgStoreThnSparse", true, "Store histograms as THnSparse"}; + struct : ConfigurableGroup { + Configurable multEst{"multEst", 1, "0: without multiplicity; 1: MultFT0M; 2: MultTPC"}; + Configurable applyCalibGainFromCCDB{"applyCalibGainFromCCDB", false, "equalize detector amplitudes"}; + Configurable applyCalibVtxFromCCDB{"applyCalibVtxFromCCDB", false, "equalize Amp vs vtx"}; + Configurable applyCalibDeDx{"applyCalibDeDx", false, "calibration of dedx signal"}; + Configurable applyCalibDeDxFromCCDB{"applyCalibDeDxFromCCDB", false, "use CCDB-based calibration of dedx signal"}; + Configurable applyDCAParam{"applyDCAParam", false, "use parametrization of DCAxy and DCAz"}; + Configurable applyDCAParamFromCCDB{"applyDCAParamFromCCDB", false, "use CCDB-based parametrization of DCAxy and DCAz"}; + Configurable fillTrackQaHist{"fillTrackQaHist", false, "fill track QA histograms"}; + Configurable fillNclVsPhiCutQaHist{"fillNclVsPhiCutQaHist", false, "fill TPC cluster vs geometrical cut QA histograms"}; + Configurable filldEdxCalibHist{"filldEdxCalibHist", false, "fill dEdx calibration histograms"}; + Configurable filldEdxQaHist{"filldEdxQaHist", false, "fill dEdx QA histograms"}; + Configurable fillDCAxyHist{"fillDCAxyHist", false, "fill nsigma QA histograms"}; + Configurable fillV0Hist{"fillV0Hist", false, "fill V0 histograms"}; + Configurable fillChrgType{"fillChrgType", false, "fill histograms per charge types"}; + Configurable fillChrgTypeV0s{"fillChrgTypeV0s", false, "fill V0s histograms per charge types"}; + Configurable calibDeDxFunction{"calibDeDxFunction", "pol8", "Functional form for dEdx calibration"}; + Configurable> paramsFuncMIPposEtaP{"paramsFuncMIPposEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPnegEtaP{"paramsFuncMIPnegEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPallEtaP{"paramsFuncMIPallEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPposEtaN{"paramsFuncMIPposEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPnegEtaN{"paramsFuncMIPnegEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPallEtaN{"paramsFuncMIPallEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUposEtaP{"paramsFuncPlateaUposEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUnegEtaP{"paramsFuncPlateaUnegEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUallEtaP{"paramsFuncPlateaUallEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUposEtaN{"paramsFuncPlateaUposEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUnegEtaN{"paramsFuncPlateaUnegEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUallEtaN{"paramsFuncPlateaUallEtaN", std::vector{-1.f}, "function parameters"}; + Configurable gainEqCcdbPath{"gainEqCcdbPath", "Users/g/gbencedi/flattenicity/GainEq", "CCDB path for gain equalization constants"}; + Configurable vtxEqCcdbPath{"vtxEqCcdbPath", "Users/g/gbencedi/flattenicity/ZvtxEq", "CCDB path for z-vertex equalization constants"}; + Configurable dEdxCalibCcdbPath{"dEdxCalibCcdbPath", "Users/g/gbencedi/flattenicity/dEdxCalib", "CCDB path for dEdx calibration"}; + Configurable dcaParamCcdbPath{"dcaParamCcdbPath", "Users/g/gbencedi/flattenicity/DCAParam", "CCDB path for DCAxy and DCAz parametrization"}; + Configurable storeThnSparse{"storeThnSparse", true, "Store histograms as THnSparse"}; + } defOpt; struct : ConfigurableGroup { - Configurable cfgCustomTVX{"cfgCustomTVX", false, "Ask for custom TVX instead of sel8"}; - Configurable cfgRemoveNoTimeFrameBorder{"cfgRemoveNoTimeFrameBorder", false, "Bunch crossing is far from Time Frame borders"}; - Configurable cfgRemoveITSROFrameBorder{"cfgRemoveITSROFrameBorder", false, "Bunch crossing is far from ITS RO Frame border"}; - Configurable cfgCutVtxZ{"cfgCutVtxZ", 10.0f, "Accepted z-vertex range"}; - Configurable useZVtxCutMC{"useZVtxCutMC", true, "use Zvtx cut in MC"}; + Configurable customTVX{"customTVX", false, "Ask for custom TVX instead of sel8"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Bunch crossing is far from Time Frame borders"}; + Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Bunch crossing is far from ITS RO Frame border"}; + Configurable cutVtxZ{"cutVtxZ", 10.0f, "Accepted z-vertex range"}; + Configurable zVtxCutMC{"zVtxCutMC", true, "use Zvtx cut in MC"}; Configurable useINELCutMC{"useINELCutMC", true, "use INEL>0 cut in MC"}; - Configurable cfgRemoveNoSameBunchPileup{"cfgRemoveNoSameBunchPileup", true, "Reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable cfgRequireIsGoodZvtxFT0vsPV{"cfgRequireIsGoodZvtxFT0vsPV", true, "Small difference between z-vertex from PV and from FT0"}; - Configurable cfgRequireIsVertexITSTPC{"cfgRequireIsVertexITSTPC", false, "At least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; - Configurable cfgRequirekIsVertexTOFmatched{"cfgRequirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", true, "Reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", true, "Small difference between z-vertex from PV and from FT0"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "At least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; + Configurable requirekIsVertexTOFmatched{"requirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; Configurable useMultMCmidrap{"useMultMCmidrap", true, "use generated Nch in ∣eta∣ < 0.8"}; - Configurable cfgUseInelgt0wTVX{"cfgUseInelgt0wTVX", true, "Use INEL > 0 condition with TVX trigger, i.e. FT0A and FT0C acceptance"}; - Configurable cfgRemoveSplitVertex{"cfgRemoveSplitVertex", true, "Remove split vertices"}; + Configurable useInelgt0wTVX{"useInelgt0wTVX", true, "Use INEL > 0 condition with TVX trigger, i.e. FT0A and FT0C acceptance"}; + Configurable removeSplitVertex{"removeSplitVertex", true, "Remove split vertices"}; } evtSelOpt; struct : ConfigurableGroup { @@ -309,89 +315,91 @@ struct FlattenictyPikp { } binOpt; struct : ConfigurableGroup { - Configurable cfgTrkEtaMax{"cfgTrkEtaMax", 0.8f, "Eta range for tracks"}; - Configurable cfgRapMax{"cfgRapMax", 0.5f, "Maximum range of rapidity for tracks"}; - Configurable cfgTrkPtMin{"cfgTrkPtMin", 0.1f, "Minimum pT of tracks"}; - Configurable cfgApplyNcl{"cfgApplyNcl", false, "Apply cut on TPC clusters"}; - Configurable cfgNclTPCMin{"cfgNclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; - Configurable cfgApplyNclPID{"cfgApplyNclPID", true, "Apply cut on TPC PID clusters"}; - Configurable cfgNclPidTPCMin{"cfgNclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; - Configurable cfgPhiCutPtMin{"cfgPhiCutPtMin", 2.0f, "Minimum pT for phi cut"}; - Configurable cfgTOFBetaPion{"cfgTOFBetaPion", 1.0f, "Minimum beta for TOF pions"}; - Configurable cfgTofBetaPiMax{"cfgTofBetaPiMax", 5E-5, "Maximum beta for TOF pion selection"}; - Configurable cfgRejectTrkAtTPCSector{"cfgRejectTrkAtTPCSector", true, "Reject tracks close to the TPC sector boundaries"}; - Configurable cfgGeoTrkCutMin{"cfgGeoTrkCutMin", "0.06/x+pi/18.0-0.06", "ROOT TF1 formula for minimum phi cut in TPC"}; - Configurable cfgGeoTrkCutMax{"cfgGeoTrkCutMax", "0.1/x+pi/18.0+0.06", "ROOT TF1 formula for maximum phi cut in TPC"}; - Configurable cfgMomMIPMax{"cfgMomMIPMax", 0.6f, "Maximum momentum of MIP pions"}; - Configurable cfgMomMIPMin{"cfgMomMIPMin", 0.4f, "Minimum momentum of MIP pions"}; - Configurable cfgDeDxMIPMax{"cfgDeDxMIPMax", 60.0f, "Maximum range of MIP dedx"}; - Configurable cfgDeDxMIPMin{"cfgDeDxMIPMin", 40.0f, "Maximum range of MIP dedx"}; - Configurable cfgNsigmaMax{"cfgNsigmaMax", 100.0f, "Maximum range of nsgima for tracks"}; - Configurable cfgDcaNsigmaCombinedMax{"cfgDcaNsigmaCombinedMax", 3.0f, "Maximum range of combined nsgima of tracks for DCA"}; - Configurable cfgMomSelPiTOF{"cfgMomSelPiTOF", 0.4f, "Minimum momentum cut for TOF pions"}; - Configurable cfgNsigSelKaTOF{"cfgNsigSelKaTOF", 3.0f, "Nsigma cut for TOF kaons"}; - Configurable cfgBetaPlateuMax{"cfgBetaPlateuMax", 0.1f, "Beta max for Plateau electrons"}; - Configurable cfgApplyCustomDCASel{"cfgApplyCustomDCASel", false, "Apply custom DCA selection"}; - Configurable> cfgDcaXY{"cfgDcaXY", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaXY selection: [0] + [1] * pT^[2]"}; - Configurable> cfgDcaZ{"cfgDcaZ", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaZ selection: [0] + [1] * pT^[2]"}; + Configurable trkEtaMax{"trkEtaMax", 0.8f, "Eta range for tracks"}; + Configurable rapMax{"rapMax", 0.5f, "Maximum range of rapidity for tracks"}; + Configurable trkPtMin{"trkPtMin", 0.1f, "Minimum pT of tracks"}; + Configurable applyNcl{"applyNcl", false, "Apply cut on TPC clusters"}; + Configurable nclTPCMin{"nclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; + Configurable applyNclPID{"applyNclPID", true, "Apply cut on TPC PID clusters"}; + Configurable nclPidTPCMin{"nclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; + Configurable phiCutPtMin{"phiCutPtMin", 2.0f, "Minimum pT for phi cut"}; + Configurable tofBetaPion{"tofBetaPion", 1.0f, "Minimum beta for TOF pions"}; + Configurable tofBetaPiMax{"tofBetaPiMax", 5E-5, "Maximum beta for TOF pion selection"}; + Configurable rejectTrkAtTPCSector{"rejectTrkAtTPCSector", true, "Reject tracks close to the TPC sector boundaries"}; + Configurable geoTrkCutMin{"geoTrkCutMin", "0.06/x+pi/18.0-0.06", "ROOT TF1 formula for minimum phi cut in TPC"}; + Configurable geoTrkCutMax{"geoTrkCutMax", "0.1/x+pi/18.0+0.06", "ROOT TF1 formula for maximum phi cut in TPC"}; + Configurable dEdxMIPnominal{"dEdxMIPnominal", 50.0f, "Nominal value of MIP pions"}; + Configurable momMIPMax{"momMIPMax", 0.6f, "Maximum momentum of MIP pions"}; + Configurable momMIPMin{"momMIPMin", 0.4f, "Minimum momentum of MIP pions"}; + Configurable dEdxMIPMax{"dEdxMIPMax", 60.0f, "Maximum range of MIP dedx"}; + Configurable dEdxMIPMin{"dEdxMIPMin", 40.0f, "Maximum range of MIP dedx"}; + Configurable nsigmaMax{"nsigmaMax", 100.0f, "Maximum range of nsgima for tracks"}; + Configurable dcaNsigmaCombinedMax{"dcaNsigmaCombinedMax", 3.0f, "Maximum range of combined nsgima of tracks for DCA"}; + Configurable momSelPiTOF{"momSelPiTOF", 0.4f, "Minimum momentum cut for TOF pions"}; + Configurable nsigmaSelKaTOF{"nsigmaSelKaTOF", 3.0f, "Nsigma cut for TOF kaons"}; + Configurable betaPlateuMax{"betaPlateuMax", 0.1f, "Beta max for Plateau electrons"}; + Configurable> dcaXY{"dcaXY", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaXY selection: [0] + [1] * pT^[2]"}; + Configurable> dcaZ{"dcaZ", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaZ selection: [0] + [1] * pT^[2]"}; + Configurable nsigmaDCAxy{"nsigmaDCAxy", 1.0f, "Nsigma cut on DCAxy"}; + Configurable nsigmaDCAz{"nsigmaDCAz", 1.0f, "Nsigma cut on DCAz"}; } trkSelOpt; struct : ConfigurableGroup { // common selection - Configurable cfgV0TypeSel{"cfgV0TypeSel", 1, "select on a certain V0 type (leave negative if no selection desired)"}; - Configurable cfgV0Ymax{"cfgV0Ymax", 0.5f, "Maximum rapidity of V0s"}; - Configurable cfgRejectV0sAtTPCSector{"cfgRejectV0sAtTPCSector", true, "Reject V0s close to the TPC sector boundaries"}; - Configurable cfgRequireITS{"cfgRequireITS", true, "Additional cut on the ITS requirement"}; - Configurable cfgNsigmaElTPC{"cfgNsigmaElTPC", 5.0, "max nsigma of TPC for electorn"}; - Configurable cfgNsigmaPiTPC{"cfgNsigmaPiTPC", 5.0, "max nsigma of TPC for pion"}; - Configurable cfgNsigmaPrTPC{"cfgNsigmaPrTPC", 5.0, "max nsigma of TPC for proton"}; - Configurable cfgNsigmaElTOF{"cfgNsigmaElTOF", 3.0, "max nsigma of TOF for electorn"}; - Configurable cfgNsigmaPiTOF{"cfgNsigmaPiTOF", 3.0, "max nsigma of TOF for pion"}; - Configurable cfgNsigmaPrTOF{"cfgNsigmaPrTOF", 3.0, "max nsigma of TOF for proton"}; + Configurable v0TypeSel{"v0TypeSel", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable v0Ymax{"v0Ymax", 0.5f, "Maximum rapidity of V0s"}; + Configurable rejectV0sAtTPCSector{"rejectV0sAtTPCSector", true, "Reject V0s close to the TPC sector boundaries"}; + Configurable v0requireITS{"v0requireITS", true, "Additional cut on the ITS requirement"}; + Configurable nsigmaElTPC{"nsigmaElTPC", 5.0, "max nsigma of TPC for electorn"}; + Configurable nsigmaPiTPC{"nsigmaPiTPC", 5.0, "max nsigma of TPC for pion"}; + Configurable nsigmaPrTPC{"nsigmaPrTPC", 5.0, "max nsigma of TPC for proton"}; + Configurable nsigmaElTOF{"nsigmaElTOF", 3.0, "max nsigma of TOF for electorn"}; + Configurable nsigmaPiTOF{"nsigmaPiTOF", 3.0, "max nsigma of TOF for pion"}; + Configurable nsigmaPrTOF{"nsigmaPrTOF", 3.0, "max nsigma of TOF for proton"}; ConfigurableAxis axisArmPodAlpha{"axisArmPodAlpha", {200, -1.0, 1.0}, "Armenteros-Podolanski alpha"}; ConfigurableAxis axisArmPodqT{"axisArmPodqT", {600, 0.0f, 0.3f}, "Armenteros-Podolanski qT"}; // standad parameters for V0 selection - Configurable cfgV0etamin{"cfgV0etamin", -0.8f, "min eta of V0s"}; - Configurable cfgV0etamax{"cfgV0etamax", +0.8f, "max eta of V0s"}; - Configurable cfgminNCrossedRowsTPC{"cfgminNCrossedRowsTPC", 70, "Additional cut on the minimum number of crossed rows in the TPC"}; - Configurable cfgApplyV0sNclFound{"cfgApplyV0sNclFound", false, "Apply cut on TPC Found clusters"}; - Configurable cfgV0NclTPCMin{"cfgV0NclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; - Configurable cfgApplyV0sNclPID{"cfgApplyV0sNclPID", true, "Apply cut on TPC PID clusters"}; - Configurable cfgV0NclPidTPCMin{"cfgV0NclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; - Configurable cfgmaxChi2PerClusterTPC{"cfgmaxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; - Configurable cfgmaxChi2PerClusterITS{"cfgmaxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; - Configurable cfgminITSnClusters{"cfgminITSnClusters", 4, "minimum number of found ITS clusters"}; - Configurable cfgminNCrossedRowsOverFindableClustersTPC{"cfgminNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; - Configurable cfgDCAv0daughter{"cfgDCAv0daughter", 1.0, "max DCA of V0 daughter tracks (cm)"}; - Configurable cfgv0cospa{"cfgv0cospa", 0.995, "min V0 CosPA"}; - Configurable cfgDCAposToPV{"cfgDCAposToPV", 0.05f, "min DCA Pos To PV (cm)"}; - Configurable cfgDCAnegToPV{"cfgDCAnegToPV", 0.05f, "min DCA Neg To PV (cm)"}; - Configurable cfgv0Rmin{"cfgv0Rmin", 1.2, "min V0 radius (cm)"}; - Configurable cfgv0Rmax{"cfgv0Rmax", 1E5, "max V0 radius (cm)"}; + Configurable v0etamin{"v0etamin", -0.8f, "min eta of V0s"}; + Configurable v0etamax{"v0etamax", +0.8f, "max eta of V0s"}; + Configurable v0minNCrossedRowsTPC{"v0minNCrossedRowsTPC", 70, "Additional cut on the minimum number of crossed rows in the TPC"}; + Configurable applyV0sNclFound{"applyV0sNclFound", false, "Apply cut on TPC Found clusters"}; + Configurable v0NclTPCMin{"v0NclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; + Configurable applyV0sNclPID{"applyV0sNclPID", true, "Apply cut on TPC PID clusters"}; + Configurable v0NclPidTPCMin{"v0NclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; + Configurable v0maxChi2PerClusterTPC{"v0maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable v0maxChi2PerClusterITS{"v0maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; + Configurable v0minITSnClusters{"v0minITSnClusters", 4, "minimum number of found ITS clusters"}; + Configurable v0minNCrossedRowsOverFindableClustersTPC{"v0minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable dcaV0daughter{"dcaV0daughter", 1.0, "max DCA of V0 daughter tracks (cm)"}; + Configurable v0cospa{"v0cospa", 0.995, "min V0 CosPA"}; + Configurable dcaPosToPV{"dcaPosToPV", 0.05f, "min DCA Pos To PV (cm)"}; + Configurable dcaNegToPV{"dcaNegToPV", 0.05f, "min DCA Neg To PV (cm)"}; + Configurable v0Rmin{"v0Rmin", 1.2, "min V0 radius (cm)"}; + Configurable v0Rmax{"v0Rmax", 1E5, "max V0 radius (cm)"}; // parameters for selection KOs - Configurable cfgcTauK0s{"cfgcTauK0s", 20, "v0ctau for K0s"}; - Configurable cfgCosPAK0s{"cfgCosPAK0s", 0.995, "V0 CosPA for K0s"}; - Configurable cfgV0radiusK0s{"cfgV0radiusK0s", 0.5, "v0radius for K0s"}; - Configurable cfgdmassK{"cfgdmassK", 0.01f, "Competing Mass Rejection cut for K0s"}; - Configurable cfgArmPodK0s{"cfgArmPodK0s", 5.0f, "pT * (cut) > |alpha|, Armenteros-Podolanski cut for K0s"}; + Configurable cTauK0s{"cTauK0s", 20, "v0ctau for K0s"}; + Configurable cosPAK0s{"cosPAK0s", 0.995, "V0 CosPA for K0s"}; + Configurable v0radiusK0s{"v0radiusK0s", 0.5, "v0radius for K0s"}; + Configurable dmassK{"dmassK", 0.01f, "Competing Mass Rejection cut for K0s"}; + Configurable armPodK0s{"armPodK0s", 5.0f, "pT * (cut) > |alpha|, Armenteros-Podolanski cut for K0s"}; ConfigurableAxis axisK0sMass{"axisK0sMass", {200, 0.4f, 0.6f}, "K0Short mass binning"}; // parameters for selection Lambda / antiLambda - Configurable cfgcTauLambda{"cfgcTauLambda", 30, "v0ctau for Lambda"}; - Configurable cfgCosPALambda{"cfgCosPALambda", 0.995, "V0 CosPA for Lambda"}; - Configurable cfgV0radiusLambda{"cfgV0radiusLambda", 0.5, "v0radius for Lambda"}; - Configurable cfgdmassL{"cfgdmassL", 0.01f, "Competing Mass Rejection cut for Lambda"}; + Configurable cTauLambda{"cTauLambda", 30, "v0ctau for Lambda"}; + Configurable cosPALambda{"cosPALambda", 0.995, "V0 CosPA for Lambda"}; + Configurable v0radiusLambda{"v0radiusLambda", 0.5, "v0radius for Lambda"}; + Configurable dmassL{"dmassL", 0.01f, "Competing Mass Rejection cut for Lambda"}; ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "Lambda mass binning"}; // parameters for selection Gamma - Configurable cfgdmassG{"cfgdmassG", 0.1f, "max mass for Gammas"}; - Configurable cfgArmPodGammasalpha{"cfgArmPodGammasalpha", 0.45f, "Armenteros-Podolanski alpha cut for Gammas"}; - Configurable cfgArmPodGammasqT{"cfgArmPodGammasqT", 0.01f, "Armenteros-Podolanski qT cut for Gammas"}; + Configurable dmassG{"dmassG", 0.1f, "max mass for Gammas"}; + Configurable armPodGammasalpha{"armPodGammasalpha", 0.45f, "Armenteros-Podolanski alpha cut for Gammas"}; + Configurable armPodGammasqT{"armPodGammasqT", 0.01f, "Armenteros-Podolanski qT cut for Gammas"}; ConfigurableAxis axisGammaMass{"axisGammaMass", {200, 0.0f, 0.5f}, "Gamma mass binning"}; - Configurable cfgdEdxPlateauSel{"cfgdEdxPlateauSel", 50, "dEdx selection sensitivity for electrons"}; + Configurable dEdxPlateauSel{"dEdxPlateauSel", 50, "dEdx selection sensitivity for electrons"}; } v0SelOpt; Service ccdb{}; struct : ConfigurableGroup { - Configurable cfgMagField{"cfgMagField", 99999, "Configurable magnetic field;default CCDB will be queried"}; + Configurable magField{"magField", 99999, "Configurable magnetic field;default CCDB will be queried"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; @@ -408,11 +416,18 @@ struct FlattenictyPikp { bool lCalibLoaded = false; } dedxcalib; + struct DCAParam { + TList* lCalibObjects = nullptr; + TH1F* hDCAxyParam = nullptr; + TH1F* hDCAzParam = nullptr; + bool lCalibLoaded = false; + } dcaparam; + struct : ConfigurableGroup { Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; - 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + Configurable evtRCTFlagCheckerLabel{"evtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable evtRCTFlagCheckerZDCCheck{"evtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable evtRCTFlagCheckerLimitAcceptAsBad{"evtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; } rctCuts; RCTFlagsChecker rctChecker; @@ -479,19 +494,19 @@ struct FlattenictyPikp { void init(InitContext&) { - auto vecParamsMIPposEtaP = (std::vector)paramsFuncMIPposEtaP; - auto vecParamsMIPposEtaN = (std::vector)paramsFuncMIPposEtaN; - auto vecParamsMIPnegEtaP = (std::vector)paramsFuncMIPnegEtaP; - auto vecParamsMIPnegEtaN = (std::vector)paramsFuncMIPnegEtaN; - auto vecParamsMIPallEtaP = (std::vector)paramsFuncMIPallEtaP; - auto vecParamsMIPallEtaN = (std::vector)paramsFuncMIPallEtaN; - - auto vecParamsPLAposEtaP = (std::vector)paramsFuncPlateaUposEtaP; - auto vecParamsPLAposEtaN = (std::vector)paramsFuncPlateaUposEtaN; - auto vecParamsPLAnegEtaP = (std::vector)paramsFuncPlateaUnegEtaP; - auto vecParamsPLAnegEtaN = (std::vector)paramsFuncPlateaUnegEtaN; - auto vecParamsPLAallEtaP = (std::vector)paramsFuncPlateaUallEtaP; - auto vecParamsPLAallEtaN = (std::vector)paramsFuncPlateaUallEtaN; + auto vecParamsMIPposEtaP = (std::vector)defOpt.paramsFuncMIPposEtaP; + auto vecParamsMIPposEtaN = (std::vector)defOpt.paramsFuncMIPposEtaN; + auto vecParamsMIPnegEtaP = (std::vector)defOpt.paramsFuncMIPnegEtaP; + auto vecParamsMIPnegEtaN = (std::vector)defOpt.paramsFuncMIPnegEtaN; + auto vecParamsMIPallEtaP = (std::vector)defOpt.paramsFuncMIPallEtaP; + auto vecParamsMIPallEtaN = (std::vector)defOpt.paramsFuncMIPallEtaN; + + auto vecParamsPLAposEtaP = (std::vector)defOpt.paramsFuncPlateaUposEtaP; + auto vecParamsPLAposEtaN = (std::vector)defOpt.paramsFuncPlateaUposEtaN; + auto vecParamsPLAnegEtaP = (std::vector)defOpt.paramsFuncPlateaUnegEtaP; + auto vecParamsPLAnegEtaN = (std::vector)defOpt.paramsFuncPlateaUnegEtaN; + auto vecParamsPLAallEtaP = (std::vector)defOpt.paramsFuncPlateaUallEtaP; + auto vecParamsPLAallEtaN = (std::vector)defOpt.paramsFuncPlateaUallEtaN; auto addVec = [&](std::vector>& targetVec, const std::string& name, bool isMIP) { if (isMIP) { @@ -528,7 +543,7 @@ struct FlattenictyPikp { ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); ccdb->setFatalWhenNull(false); - rctChecker.init(rctCuts.cfgEvtRCTFlagCheckerLabel, rctCuts.cfgEvtRCTFlagCheckerZDCCheck, rctCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + rctChecker.init(rctCuts.evtRCTFlagCheckerLabel, rctCuts.evtRCTFlagCheckerZDCCheck, rctCuts.evtRCTFlagCheckerLimitAcceptAsBad); if (isCustomTracks.value) { selTrkGlobal = getGlobalTrackSelectionRun3ITSMatch(setITSreq.value); @@ -576,7 +591,7 @@ struct FlattenictyPikp { AxisSpec multAxis{binOpt.axisMultPerc, "multiplicity estimator"}; - switch (multEst) { + switch (defOpt.multEst) { case MultE::CnoMult: break; case MultE::CmultFT0M: @@ -586,12 +601,12 @@ struct FlattenictyPikp { multAxis.name = "multTPC"; break; default: - LOG(fatal) << "No valid option for mult estimator " << multEst; + LOG(fatal) << "No valid option for mult estimator " << defOpt.multEst; } - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector) { - fPhiCutLow = new TF1("fPhiCutLow", trkSelOpt.cfgGeoTrkCutMin.value.c_str(), 0, 100); - fPhiCutHigh = new TF1("fPhiCutHigh", trkSelOpt.cfgGeoTrkCutMax.value.c_str(), 0, 100); + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector) { + fPhiCutLow = new TF1("fPhiCutLow", trkSelOpt.geoTrkCutMin.value.c_str(), 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", trkSelOpt.geoTrkCutMax.value.c_str(), 0, 100); } registryQC.add("Events/hVtxZ", "Measured vertex z position", kTH1F, {vtxzAxis}); @@ -609,6 +624,17 @@ struct FlattenictyPikp { registryQC.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelVtxZ + 1, "Vtx-z pos"); registryQC.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelINELgt0 + 1, "INEL>0"); registryQC.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelRCTFlagChecker + 1, "RCT Flag Checker"); + // Track counter + registryQC.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {kTH1F, {{nTrkSel, 0, nTrkSel}}}); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "Eta"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "Pt"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelDCA + 1, "DCA"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCustomDCA + 1, "Custom DCA sel."); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkNRowsTPC + 1, "trkNRowsTPC"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsFound + 1, "NClsTPCFound"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsPID + 1, "NClsTPCPid"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); // Number of tracks vs centrality registryQC.add("Events/hNchVsCent", "Measured Nch vs Cent; centrality; Nch (|#eta|<0.8)", {kTH2F, {nChAxis, multAxis}}); registryQC.add("Tracks/hPtRes", "#it{p}_{T} resolution;;(#it{p}_{T}_{rec} - #it{p}_{T}_{gen})/#it{p}_{T}_{gen};", kTH2F, {ptAxis, {100, -1.0, 1.0}}); @@ -625,17 +651,6 @@ struct FlattenictyPikp { registryQC.print(); if (doprocessFlat) { - // Track counter - registryData.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {kTH1F, {{nTrkSel, 0, nTrkSel}}}); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "Eta"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "Pt"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelDCA + 1, "DCA"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkNRowsTPC + 1, "trkNRowsTPC"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsFound + 1, "NClsTPCFound"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsPID + 1, "NClsTPCPid"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCustomDCA + 1, "Custom DCA sel."); // V0 counter registryData.add("Tracks/V0qa/hV0Sel", "Number of V0s; Cut; #Tracks Passed Cut", {kTH1F, {{nV0Sel, 0, nV0Sel}}}); registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelAll + 1, "All"); @@ -649,8 +664,8 @@ struct FlattenictyPikp { registryData.add("Events/hFlatVsMultEst", "hFlatVsMultEst", kTH2F, {flatAxis, multAxis}); registryData.add("Tracks/postSel/hPVsPtEta", "; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}); #eta;", {kTH3F, {pAxis, ptAxis, etaAxis}}); - if (cfgFillNclVsPhiCutQaHist || cfgFillTrackQaHist || cfgFilldEdxQaHist || cfgFillDCAxyHist) { - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist || defOpt.fillTrackQaHist || defOpt.filldEdxQaHist || defOpt.fillDCAxyHist) { + if (defOpt.fillNclVsPhiCutQaHist) { registryData.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); registryData.add("Tracks/postSel/hPtPhiNclTPC", "; #{eta}; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); registryData.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #{eta}; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); @@ -659,7 +674,7 @@ struct FlattenictyPikp { registryData.add("Tracks/postSel/hPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTH2F, {ptAxis, clTpcAxis}}); registryData.add("Tracks/postSel/pPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTProfile, {ptAxis}}); } - if (cfgFillTrackQaHist) { + if (defOpt.fillTrackQaHist) { registryData.add("Tracks/postSel/hShTpcClvsPt", "", {kTH2F, {ptAxis, shCluserAxis}}); registryData.add("Tracks/postSel/hNclTPCFoundvsPt", "", {kTH2F, {ptAxis, clTpcAxis}}); registryData.add("Tracks/postSel/hNClTPCPidvsPt", "", {kTH2F, {ptAxis, clTpcAxis}}); @@ -684,8 +699,8 @@ struct FlattenictyPikp { registryData.add("Tracks/postSel/hTOFPvsBeta", "Beta from TOF; #it{p} (GeV/#it{c}); #beta", {kTH2F, {pAxis, {120, 0.0, 1.2}}}); registryData.add("Tracks/postSel/hTOFpi", "Primary Pions from TOF; #eta; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, pAxis, dEdxAxis}}); } - if (cfgFilldEdxQaHist) { - if (cfgStoreThnSparse) { + if (defOpt.filldEdxQaHist) { + if (defOpt.storeThnSparse) { registryData.add("Tracks/postCalib/all/hMIP", "; mult; flat; #eta; #LT dE/dx #GT_{MIP, primary tracks};", {kTHnSparseF, {multAxis, flatAxis, etaAxis, dEdxAxis}}); registryData.add("Tracks/postCalib/all/hPlateau", "; mult; flat; #eta; #LT dE/dx #GT_{Plateau, primary tracks};", {kTHnSparseF, {multAxis, flatAxis, etaAxis, dEdxAxis}}); } else { @@ -701,14 +716,14 @@ struct FlattenictyPikp { registryData.add("Tracks/postCalib/all/hPlateauVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks}; #eta;", {kTH3F, {phiAxis, dEdxAxis, etaAxis}}); registryData.add("Tracks/postCalib/all/hPlateauNClTPCPidvsEta", ";#eta; Ncl pid", {kTH2F, {etaAxis, clTpcAxis}}); registryData.addClone("Tracks/postCalib/all/", "Tracks/preCalib/all/"); - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.addClone("Tracks/postCalib/all/", "Tracks/postCalib/pos/"); registryData.addClone("Tracks/postCalib/all/", "Tracks/postCalib/neg/"); registryData.addClone("Tracks/preCalib/all/", "Tracks/preCalib/pos/"); registryData.addClone("Tracks/preCalib/all/", "Tracks/preCalib/neg/"); } } - if (cfgFillDCAxyHist) { + if (defOpt.fillDCAxyHist) { for (int i = 0; i < Npart; i++) { registryData.add({fmt::format(CpTvsDCAxyF.data(), CspeciesAll[i].data()).c_str(), "; mult; flat; #it{p} (GeV/#it{c}); DCA_{xy} (cm)", {kTHnSparseF, {multAxis, flatAxis, ptAxis, dcaXYAxis}}}); } @@ -737,8 +752,8 @@ struct FlattenictyPikp { // dEdx PID registryData.add({"Tracks/all/hdEdx", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); // Clean samples - if (cfgFillV0Hist) { - if (cfgStoreThnSparse) { + if (defOpt.fillV0Hist) { + if (defOpt.storeThnSparse) { registryData.add({"Tracks/CleanTof/all/hPiTof", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); registryData.add({"Tracks/CleanV0/all/hEV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); registryData.add({"Tracks/CleanV0/all/hPiV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); @@ -751,14 +766,14 @@ struct FlattenictyPikp { } registryData.add("Tracks/CleanTof/all/hBetaVsP", ";Momentum (GeV/#it{c}); #beta", kTH2F, {{{ptAxisV0s}, {120, 0., 1.2}}}); registryData.add("Tracks/CleanTof/all/hTofExpPi", ";Momentum (GeV/#it{c});#it{t}^{#pi}_{Exp}/#it{t}_{TOF}", kTH2F, {{{ptAxisV0s}, {100, 0.2, 1.2}}}); - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.addClone("Tracks/CleanTof/all/", "Tracks/CleanTof/pos/"); registryData.addClone("Tracks/CleanTof/all/", "Tracks/CleanTof/neg/"); registryData.addClone("Tracks/CleanV0/all/", "Tracks/CleanV0/pos/"); registryData.addClone("Tracks/CleanV0/all/", "Tracks/CleanV0/neg/"); } } - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.addClone("Tracks/all/", "Tracks/pos/"); registryData.addClone("Tracks/all/", "Tracks/neg/"); } @@ -784,6 +799,8 @@ struct FlattenictyPikp { // Event loss registryMC.add("Events/hNchVsFlatGenINELgt0", "Gen Nch w/o Evt sel; Gen Nch (|#eta|<0.8); flat", {kTH2F, {nChAxis, flatAxis}}); registryMC.add("Events/hNchVsFlatGenINELgt0wRecEvtSel", "Gen Nch w/ Nrec > 0 + Evt sel; Gen Nch (|#eta|<0.8); flat", {kTH2F, {nChAxis, flatAxis}}); + // Response + registryMC.add("Events/hFlatResponse", "Flattenicity response; flat ture; flat measured", {kTH2F, {flatAxis, flatAxis}}); // Event split registryMC.add("Events/hCentVsFlatRecINELgt0", "Gen evt w/o Evt sel; mult; flat", {kTH2F, {multAxis, flatAxis}}); registryMC.add("Events/hCentVsFlatRecINELgt0wRecEvt", "Gen evt w/ Nrec > 0; mult; flat", {kTH2F, {multAxis, flatAxis}}); @@ -796,7 +813,7 @@ struct FlattenictyPikp { registryMC.add({fmt::format(CpTmcClosureGenPrimF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/o Evt sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); registryMC.add({fmt::format(CpTmcClosureRecF.data(), CspeciesAll[i].data()).c_str(), "Gen Nch w/ Nrec > 0 + Evt. sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); } - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { registryMC.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); registryMC.add("Tracks/postSel/hPtPhiNclTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); registryMC.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); @@ -864,7 +881,7 @@ struct FlattenictyPikp { fv0AmplCorr = {}; auto runnumber = bc.runNumber(); - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector) { + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector) { grpmag = ccdb->getForRun(ccdbConf.grpmagPath, runnumber); if (!grpmag) { LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConf.grpmagPath << " of object GRPMagField and " << ccdbConf.grpPath << " of object GRPObject for run " << runnumber; @@ -872,8 +889,8 @@ struct FlattenictyPikp { magField = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for run " << runnumber << " with magnetic field of " << magField << " kZG"; } - if (applyCalibGain) { - std::string fullPathCalibGain = cfgGainEqCcdbPath; + if (defOpt.applyCalibGainFromCCDB) { + std::string fullPathCalibGain = defOpt.gainEqCcdbPath; fullPathCalibGain += "/FV0"; const auto* objfv0Gain = ccdb->getForRun>(fullPathCalibGain, runnumber); if (!objfv0Gain) { @@ -885,18 +902,17 @@ struct FlattenictyPikp { fv0AmplCorr = *(objfv0Gain); } } - if (applyCalibVtx) { - std::string fullPathCalibVtx = cfgVtxEqCcdbPath; + if (defOpt.applyCalibVtxFromCCDB) { + std::string fullPathCalibVtx = defOpt.vtxEqCcdbPath; fullPathCalibVtx += "/FV0"; zVtxMap = ccdb->getForRun(fullPathCalibVtx, runnumber); } - - if (applyCalibDeDxFromCCDB) { - std::string fullPathCalibDeDxMip = cfgDeDxCalibCcdbPath; + if (defOpt.applyCalibDeDxFromCCDB) { + std::string fullPathCalibDeDxMip = defOpt.dEdxCalibCcdbPath; if (!fullPathCalibDeDxMip.empty()) { fullPathCalibDeDxMip += "/MIP"; } - std::string fullPathCalibDeDxPlateau = cfgDeDxCalibCcdbPath; + std::string fullPathCalibDeDxPlateau = defOpt.dEdxCalibCcdbPath; if (!fullPathCalibDeDxPlateau.empty()) { fullPathCalibDeDxPlateau += "/Plateau"; } @@ -930,13 +946,29 @@ struct FlattenictyPikp { LOGF(fatal, "Could not load hPlateauCalib from %s", fullPathCalibDeDxPlateau.c_str()); } } + if (defOpt.applyDCAParamFromCCDB) { + dcaparam.lCalibObjects = ccdb->getForRun(defOpt.dcaParamCcdbPath, runnumber); + if (dcaparam.lCalibObjects) { + LOG(info) << "CCDB objects loaded successfully"; + dcaparam.hDCAxyParam = dynamic_cast(dcaparam.lCalibObjects->FindObject("hfitDCAxyParams")); + dcaparam.hDCAzParam = dynamic_cast(dcaparam.lCalibObjects->FindObject("hfitDCAzParams")); + dcaparam.lCalibLoaded = true; + if (!dcaparam.hDCAxyParam || !dcaparam.hDCAzParam) { + LOGF(error, "Problem loading CCDB objects! Please check"); + dcaparam.lCalibLoaded = false; + } + } else { + LOGF(fatal, "Could not load DCAParam from %s", defOpt.dcaParamCcdbPath.value.c_str()); + dcaparam.lCalibLoaded = false; + } + } } template std::unique_ptr setFuncPars(T const& vecPars) { static_assert(!std::is_pointer::value, "Pointers to pointers not allowed here"); - std::unique_ptr fCalibDeDxFunc(new TF1("fCalibDeDxFunc", cfgCalibDeDxFunction.value.c_str(), -1., 1.)); + std::unique_ptr fCalibDeDxFunc(new TF1("fCalibDeDxFunc", defOpt.calibDeDxFunction.value.c_str(), -1., 1.)); if (vecPars.size() >= 1) { for (typename T::size_type i = 0; i < vecPars.size(); i++) { fCalibDeDxFunc->SetParameter(i, vecPars[i]); @@ -961,11 +993,11 @@ struct FlattenictyPikp { const float tTOF = track.tofSignal(); const float trkLength = track.length(); const float tExpPiTOF = track.tofExpSignalPi(tTOF); - if (track.p() >= trkSelOpt.cfgMomSelPiTOF && trkLength > Cnull && tTOF > Cnull) { + if (track.p() >= trkSelOpt.momSelPiTOF && trkLength > Cnull && tTOF > Cnull) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[chrg]) + HIST("hTofExpPi"), track.p(), tExpPiTOF / tTOF); - if (std::abs((tExpPiTOF / tTOF) - Cone) < trkSelOpt.cfgTofBetaPiMax) { + if (std::abs((tExpPiTOF / tTOF) - Cone) < trkSelOpt.tofBetaPiMax) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[chrg]) + HIST("hBetaVsP"), track.p(), track.beta()); - // if (std::abs(track.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC && std::abs(track.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + // if (std::abs(track.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC && std::abs(track.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return true; // } } @@ -977,7 +1009,7 @@ struct FlattenictyPikp { template void fillDCA(T const& tracks, C const& collision, aod::BCsWithTimestamps const& /*bcs*/) { - if (trkSelOpt.cfgRejectTrkAtTPCSector) { + if (trkSelOpt.rejectTrkAtTPCSector) { auto bc = collision.template bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -988,27 +1020,10 @@ struct FlattenictyPikp { const float mult = getMult(collision); const float flat = fillFlat(collision); for (const auto& track : tracks) { - if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (!isGoodTrack(track, magField)) { continue; } - if (track.pt() < trkSelOpt.cfgTrkPtMin) { - continue; - } - if (trkSelOpt.cfgApplyNcl && track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { - continue; - } - if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { - continue; - } - float phiModn = track.phi(); - phiMod(phiModn, magField, track.sign()); - if (trkSelOpt.cfgRejectTrkAtTPCSector && (track.pt() >= trkSelOpt.cfgPhiCutPtMin && phiModn < fPhiCutHigh->Eval(track.pt()) && phiModn > fPhiCutLow->Eval(track.pt()))) { - continue; - } - if (!isDCAxyWoCut(track)) { - continue; - } - if (track.hasTOF() && (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.cfgDcaNsigmaCombinedMax))) { + if (track.hasTOF() && (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.dcaNsigmaCombinedMax))) { registryData.fill(HIST(Cprefix) + HIST(CspeciesAll[id]) + HIST(CpTvsDCAxy), mult, flat, track.pt(), track.dcaXY()); } } @@ -1017,7 +1032,7 @@ struct FlattenictyPikp { template void filldEdx(T const& tracks, V const& v0s, C const& collision, aod::BCsWithTimestamps const& bcs) { - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector || applyCalibGain || applyCalibVtx) { + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.template bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -1034,17 +1049,17 @@ struct FlattenictyPikp { for (const auto& track : tracks) { float dEdx = track.tpcSignal(); - if (cfgFillTrackQaHist) { + if (defOpt.fillTrackQaHist) { fillTrackQA(track); } - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } - if (cfgFillTrackQaHist) { + if (defOpt.fillTrackQaHist) { fillTrackQA(track); } - if (cfgFilldEdxCalibHist && cfgFilldEdxQaHist) { - if (cfgFillChrgType) { + if (defOpt.filldEdxCalibHist && defOpt.filldEdxQaHist) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { filldEdxQA(track, collision, dEdx); } else { @@ -1054,41 +1069,41 @@ struct FlattenictyPikp { filldEdxQA(track, collision, dEdx); } } - if (applyCalibDeDx) { - if (cfgFillChrgType) { + if (defOpt.applyCalibDeDx) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { - if (applyCalibDeDxFromCCDB) { - dEdx *= (50.0 / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(track.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdx *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(track.eta()))); } else { - dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + dEdx *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, track)); } - if (cfgFilldEdxQaHist) { + if (defOpt.filldEdxQaHist) { filldEdxQA(track, collision, dEdx); } } else { - if (applyCalibDeDxFromCCDB) { - dEdx *= (50.0 / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(track.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdx *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(track.eta()))); } else { - dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + dEdx *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, track)); } - if (cfgFilldEdxQaHist) { + if (defOpt.filldEdxQaHist) { filldEdxQA(track, collision, dEdx); } } } else { - if (applyCalibDeDxFromCCDB) { - dEdx *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(track.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdx *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(track.eta()))); } else { - dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + dEdx *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, track)); } - if (cfgFilldEdxQaHist) { + if (defOpt.filldEdxQaHist) { filldEdxQA(track, collision, dEdx); } } } // PID TPC dEdx - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hFlatVsPt"), track.eta(), mult, flat, track.p(), track.pt()); registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), dEdx); @@ -1102,24 +1117,24 @@ struct FlattenictyPikp { } // TOF pions - if (cfgFillV0Hist) { + if (defOpt.fillV0Hist) { if (selTOFPi(track)) { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { - if (cfgStoreThnSparse) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kPos]) + HIST("hPiTof"), track.eta(), mult, flat, track.p(), dEdx); } else { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kPos]) + HIST("hPiTof"), track.eta(), track.p(), dEdx); } } else { - if (cfgStoreThnSparse) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kNeg]) + HIST("hPiTof"), track.eta(), mult, flat, track.p(), dEdx); } else { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kNeg]) + HIST("hPiTof"), track.eta(), track.p(), dEdx); } } } else { - if (cfgStoreThnSparse) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kAll]) + HIST("hPiTof"), track.eta(), mult, flat, track.p(), dEdx); } else { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kAll]) + HIST("hPiTof"), track.eta(), track.p(), dEdx); @@ -1130,9 +1145,9 @@ struct FlattenictyPikp { } // V0s - if (cfgFillV0Hist) { + if (defOpt.fillV0Hist) { for (const auto& v0 : v0s) { - if (v0.v0Type() != v0SelOpt.cfgV0TypeSel && v0SelOpt.cfgV0TypeSel > -1) { + if (v0.v0Type() != v0SelOpt.v0TypeSel && v0SelOpt.v0TypeSel > -1) { continue; } if (!isGoodV0Track(v0, tracks, magField)) { @@ -1144,22 +1159,22 @@ struct FlattenictyPikp { float dEdxPos = posTrack.tpcSignal(); float dEdxNeg = negTrack.tpcSignal(); - if (applyCalibDeDx) { - if (cfgFillChrgTypeV0s) { - if (applyCalibDeDxFromCCDB) { - dEdxPos *= (50.0 / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta()))); - dEdxNeg *= (50.0 / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta()))); + if (defOpt.applyCalibDeDx) { + if (defOpt.fillChrgTypeV0s) { + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdxPos *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta()))); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta()))); } else { - dEdxPos *= (50.0 / getCalibration(fDeDxVsEta, posTrack)); - dEdxNeg *= (50.0 / getCalibration(fDeDxVsEta, negTrack)); + dEdxPos *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, posTrack)); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, negTrack)); } } else { - if (applyCalibDeDxFromCCDB) { - dEdxPos *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(posTrack.eta()))); - dEdxNeg *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(negTrack.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdxPos *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(posTrack.eta()))); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(negTrack.eta()))); } else { - dEdxPos *= (50.0 / getCalibration(fDeDxVsEta, posTrack)); - dEdxNeg *= (50.0 / getCalibration(fDeDxVsEta, negTrack)); + dEdxPos *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, posTrack)); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, negTrack)); } } } @@ -1168,39 +1183,39 @@ struct FlattenictyPikp { fillV0QA(v0, posTrack); fillV0QA(v0, negTrack); // float dEdxPosGa{-1.}, dEdxNegGa{-1.}; - if (applyCalibDeDx) { - if (cfgFillChrgTypeV0s) { - if (applyCalibDeDxFromCCDB) { + if (defOpt.applyCalibDeDx) { + if (defOpt.fillChrgTypeV0s) { + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { float dEdxPosGa = dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta())); float dEdxNegGa = dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta())); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } else { float dEdxPosGa = getCalibration(fEDeDxVsEta, posTrack); float dEdxNegGa = getCalibration(fEDeDxVsEta, negTrack); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } } else { - if (applyCalibDeDxFromCCDB) { + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { float dEdxPosGa = dedxcalib.hPlateauCalibAll->GetBinContent(dedxcalib.hPlateauCalibAll->FindBin(posTrack.eta())); float dEdxNegGa = dedxcalib.hPlateauCalibAll->GetBinContent(dedxcalib.hPlateauCalibAll->FindBin(negTrack.eta())); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } else { float dEdxPosGa = getCalibration(fEDeDxVsEta, posTrack); float dEdxNegGa = getCalibration(fEDeDxVsEta, negTrack); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } } } - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hEV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hEV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1208,7 +1223,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hEV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hEV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hEV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1220,8 +1235,8 @@ struct FlattenictyPikp { if (selectTypeV0s(collision, v0, posTrack, negTrack) == kKz) { // K0S -> pi + pi fillV0QA(v0, posTrack); fillV0QA(v0, negTrack); - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1229,7 +1244,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1241,8 +1256,8 @@ struct FlattenictyPikp { if (selectTypeV0s(collision, v0, posTrack, negTrack) == kLam) { // L -> p + pi- fillV0QA(v0, negTrack); fillV0QA(v0, posTrack); - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1250,7 +1265,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1262,8 +1277,8 @@ struct FlattenictyPikp { if (selectTypeV0s(collision, v0, posTrack, negTrack) == kaLam) { // antiLambda -> pbar + pi+ fillV0QA(v0, posTrack); fillV0QA(v0, negTrack); - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1271,7 +1286,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hPV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1333,7 +1348,7 @@ struct FlattenictyPikp { if (!particle.isPhysicalPrimary()) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } nCharged++; @@ -1374,7 +1389,7 @@ struct FlattenictyPikp { template int countTracks(T const& tracks, C const& collision, aod::BCsWithTimestamps const& /*bcs*/, float mult) { - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector || applyCalibGain || applyCalibVtx) { + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.template bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -1385,7 +1400,7 @@ struct FlattenictyPikp { auto nTrk = 0; for (auto const& track : tracks) { - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } nTrk++; @@ -1414,7 +1429,7 @@ struct FlattenictyPikp { template inline void fillNclVsPhiCutQaHist(T const& track, const float phimodn) { - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtPhi"), track.pt(), phimodn); registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtPhiNclTPC"), track.eta(), track.pt(), phimodn, track.tpcNClsFound()); registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtPhiNclPIDTPC"), track.eta(), track.pt(), phimodn, track.tpcNClsPID()); @@ -1425,54 +1440,62 @@ struct FlattenictyPikp { } } - template - bool isGoodTrack(T const& track, const int magfield) + template + bool isGoodTrack(T const& track, const float magfield) { - registryData.fill(HIST("Tracks/hTrkSel"), trkSelAll); - if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelAll); + if (std::abs(track.eta()) > trkSelOpt.trkEtaMax) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelEta); - if (track.pt() < trkSelOpt.cfgTrkPtMin) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelEta); + if (track.pt() < trkSelOpt.trkPtMin) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelPt); - if (!isDCAxyCut(track)) { - return false; + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelPt); + if constexpr (selDCA) { + if (!isDCAxyCut(track)) { + return false; + } + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelDCA); + if (defOpt.applyDCAParam) { + if (defOpt.applyDCAParamFromCCDB) { + if (!isDCAParamCut(track)) { + return false; + } + } else { + if (std::fabs(track.dcaXY()) > trkSelOpt.dcaXY.value[0] + trkSelOpt.dcaXY.value[1] * std::pow(track.pt(), trkSelOpt.dcaXY.value[2]) || std::fabs(track.dcaZ()) > trkSelOpt.dcaZ.value[0] + trkSelOpt.dcaZ.value[1] * std::pow(track.pt(), trkSelOpt.dcaZ.value[2])) { + return false; + } + } + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); + } } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelDCA); if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); - if (trkSelOpt.cfgApplyNcl && track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); + if (trkSelOpt.applyNcl && track.tpcNClsFound() < trkSelOpt.nclTPCMin) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); - if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { + if (trkSelOpt.applyNclPID && track.tpcNClsPID() < trkSelOpt.nclPidTPCMin) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); float phimodn = track.phi(); phiMod(phimodn, magfield, track.sign()); - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { fillNclVsPhiCutQaHist(track, phimodn); } - if (trkSelOpt.cfgRejectTrkAtTPCSector && (track.pt() >= trkSelOpt.cfgPhiCutPtMin && phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt()))) { + if (trkSelOpt.rejectTrkAtTPCSector && (track.pt() >= trkSelOpt.phiCutPtMin && phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt()))) { return false; } - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { fillNclVsPhiCutQaHist(track, phimodn); } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); - if (trkSelOpt.cfgApplyCustomDCASel) { - if (std::fabs(track.dcaXY()) > trkSelOpt.cfgDcaXY.value[0] + trkSelOpt.cfgDcaXY.value[1] * std::pow(track.pt(), trkSelOpt.cfgDcaXY.value[2]) || std::fabs(track.dcaZ()) > trkSelOpt.cfgDcaZ.value[0] + trkSelOpt.cfgDcaZ.value[1] * std::pow(track.pt(), trkSelOpt.cfgDcaZ.value[2])) { - return false; - } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); - } + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); return true; } @@ -1493,30 +1516,30 @@ struct FlattenictyPikp { bool isMassL = false; bool isMassAL = false; - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.cfgdmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) < v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.dmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) < v0SelOpt.dmassG) { isMassG = true; } - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0SelOpt.cfgdmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0SelOpt.dmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.dmassG) { isMassK0s = true; } - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.cfgdmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.dmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.dmassG) { isMassL = true; } - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.cfgdmassK && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.dmassK && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.dmassG) { isMassAL = true; } // Gamma selection if (isMassG) { - if (std::abs(RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma)) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (std::abs(v0.alpha()) < v0SelOpt.cfgArmPodGammasalpha && v0.qtarm() < v0SelOpt.cfgArmPodGammasqT) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaEl()) < v0SelOpt.cfgNsigmaElTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaEl()) < v0SelOpt.cfgNsigmaElTOF) { + if (std::abs(RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma)) < v0SelOpt.v0Ymax) { // rapidity cut + if (std::abs(v0.alpha()) < v0SelOpt.armPodGammasalpha && v0.qtarm() < v0SelOpt.armPodGammasqT) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaEl()) < v0SelOpt.nsigmaElTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaEl()) < v0SelOpt.nsigmaElTOF) { return kGa; } } - if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaEl()) < v0SelOpt.cfgNsigmaElTPC) { - if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaEl()) < v0SelOpt.cfgNsigmaElTOF) { + if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaEl()) < v0SelOpt.nsigmaElTPC) { + if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaEl()) < v0SelOpt.nsigmaElTOF) { return kGa; } } @@ -1525,16 +1548,16 @@ struct FlattenictyPikp { } // K0S selection, K0S -> pi + pi if (isMassK0s) { - if (std::abs(v0.yK0Short()) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0SelOpt.cfgcTauK0s) { // ctau cut - if (v0.v0cosPA() >= v0SelOpt.cfgCosPAK0s && v0.v0radius() >= v0SelOpt.cfgV0radiusK0s && v0.qtarm() * v0SelOpt.cfgArmPodK0s > std::abs(v0.alpha())) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + if (std::abs(v0.yK0Short()) < v0SelOpt.v0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0SelOpt.cTauK0s) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cosPAK0s && v0.v0radius() >= v0SelOpt.v0radiusK0s && v0.qtarm() * v0SelOpt.armPodK0s > std::abs(v0.alpha())) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return kKz; } } - if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { - if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC) { + if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return kKz; } } @@ -1544,11 +1567,11 @@ struct FlattenictyPikp { } // Lambda selection, L -> p + pi- if (isMassL) { - if (std::abs(v0.yLambda()) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cfgcTauLambda) { // ctau cut - if (v0.v0cosPA() >= v0SelOpt.cfgCosPALambda && v0.v0radius() >= v0SelOpt.cfgV0radiusLambda) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPr()) < v0SelOpt.cfgNsigmaPrTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPr()) < v0SelOpt.cfgNsigmaPrTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + if (std::abs(v0.yLambda()) < v0SelOpt.v0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cTauLambda) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cosPALambda && v0.v0radius() >= v0SelOpt.v0radiusLambda) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPr()) < v0SelOpt.nsigmaPrTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPr()) < v0SelOpt.nsigmaPrTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return kLam; } } @@ -1558,11 +1581,11 @@ struct FlattenictyPikp { } // antiLambda -> pbar + pi+ if (isMassAL) { - if (std::abs(v0.yLambda()) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cfgcTauLambda) { // ctau cut - if (v0.v0cosPA() >= v0SelOpt.cfgCosPALambda && v0.v0radius() >= v0SelOpt.cfgV0radiusLambda) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPr()) < v0SelOpt.cfgNsigmaPrTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPr()) < v0SelOpt.cfgNsigmaPrTOF) { + if (std::abs(v0.yLambda()) < v0SelOpt.v0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cTauLambda) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cosPALambda && v0.v0radius() >= v0SelOpt.v0radiusLambda) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPr()) < v0SelOpt.nsigmaPrTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPr()) < v0SelOpt.nsigmaPrTOF) { return kaLam; } } @@ -1574,7 +1597,7 @@ struct FlattenictyPikp { } template - bool isGoodV0Track(T1 const& v0, T2 const& /*track*/, const int magfield) + bool isGoodV0Track(T1 const& v0, T2 const& /*track*/, const float magfield) { const auto& posTrack = v0.template posTrack_as(); const auto& negTrack = v0.template negTrack_as(); @@ -1589,22 +1612,22 @@ struct FlattenictyPikp { float negTrackPhiModn = negTrack.phi(); phiMod(posTrackPhiModn, magfield, posTrack.sign()); phiMod(negTrackPhiModn, magfield, negTrack.sign()); - if (v0SelOpt.cfgRejectV0sAtTPCSector) { - if ((posTrack.pt() >= trkSelOpt.cfgPhiCutPtMin && posTrackPhiModn < fPhiCutHigh->Eval(posTrack.pt()) && posTrackPhiModn > fPhiCutLow->Eval(posTrack.pt())) && (negTrack.pt() >= trkSelOpt.cfgPhiCutPtMin && negTrackPhiModn < fPhiCutHigh->Eval(negTrack.pt()) && negTrackPhiModn > fPhiCutLow->Eval(negTrack.pt()))) { + if (v0SelOpt.rejectV0sAtTPCSector) { + if ((posTrack.pt() >= trkSelOpt.phiCutPtMin && posTrackPhiModn < fPhiCutHigh->Eval(posTrack.pt()) && posTrackPhiModn > fPhiCutLow->Eval(posTrack.pt())) && (negTrack.pt() >= trkSelOpt.phiCutPtMin && negTrackPhiModn < fPhiCutHigh->Eval(negTrack.pt()) && negTrackPhiModn > fPhiCutLow->Eval(negTrack.pt()))) { return false; } } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelRejectV0sAtTPCSector); // V0 topological selections - if (v0.v0cosPA() < v0SelOpt.cfgv0cospa) { + if (v0.v0cosPA() < v0SelOpt.v0cospa) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelCosPA); - if (v0.v0radius() < v0SelOpt.cfgv0Rmin || v0.v0radius() > v0SelOpt.cfgv0Rmax) { + if (v0.v0radius() < v0SelOpt.v0Rmin || v0.v0radius() > v0SelOpt.v0Rmax) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelV0radius); - if (std::abs(v0.dcapostopv()) < v0SelOpt.cfgDCAposToPV || std::abs(v0.dcanegtopv()) < v0SelOpt.cfgDCAnegToPV) { + if (std::abs(v0.dcapostopv()) < v0SelOpt.dcaPosToPV || std::abs(v0.dcanegtopv()) < v0SelOpt.dcaNegToPV) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDCAposToPV); @@ -1613,7 +1636,7 @@ struct FlattenictyPikp { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDaughters); - if (v0.dcaV0daughters() > v0SelOpt.cfgDCAv0daughter) { + if (v0.dcaV0daughters() > v0SelOpt.dcaV0daughter) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDCAv0daughter); @@ -1627,38 +1650,38 @@ struct FlattenictyPikp { template bool isGoodV0DaughterTrack(const T& track) { - if (track.eta() < v0SelOpt.cfgV0etamin || track.eta() > v0SelOpt.cfgV0etamax) { + if (track.eta() < v0SelOpt.v0etamin || track.eta() > v0SelOpt.v0etamax) { return false; } if (!track.hasTPC()) { return false; } - if (track.tpcNClsCrossedRows() < v0SelOpt.cfgminNCrossedRowsTPC) { + if (track.tpcNClsCrossedRows() < v0SelOpt.v0minNCrossedRowsTPC) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < v0SelOpt.cfgminNCrossedRowsOverFindableClustersTPC) { + if (track.tpcCrossedRowsOverFindableCls() < v0SelOpt.v0minNCrossedRowsOverFindableClustersTPC) { return false; } - if (v0SelOpt.cfgApplyV0sNclFound) { - if (track.tpcNClsFound() < v0SelOpt.cfgV0NclTPCMin) { + if (v0SelOpt.applyV0sNclFound) { + if (track.tpcNClsFound() < v0SelOpt.v0NclTPCMin) { return false; } } - if (v0SelOpt.cfgApplyV0sNclPID) { - if (track.tpcNClsPID() < v0SelOpt.cfgV0NclPidTPCMin) { + if (v0SelOpt.applyV0sNclPID) { + if (track.tpcNClsPID() < v0SelOpt.v0NclPidTPCMin) { return false; } } - if (track.tpcChi2NCl() > v0SelOpt.cfgmaxChi2PerClusterTPC) { + if (track.tpcChi2NCl() > v0SelOpt.v0maxChi2PerClusterTPC) { return false; } - if (v0SelOpt.cfgRequireITS && (!track.hasITS())) { + if (v0SelOpt.v0requireITS && (!track.hasITS())) { return false; } - if (v0SelOpt.cfgRequireITS && track.itsNCls() < v0SelOpt.cfgminITSnClusters) { + if (v0SelOpt.v0requireITS && track.itsNCls() < v0SelOpt.v0minITSnClusters) { return false; } - if (track.itsChi2NCl() > v0SelOpt.cfgmaxChi2PerClusterITS) { + if (track.itsChi2NCl() > v0SelOpt.v0maxChi2PerClusterITS) { return false; } return true; @@ -1690,11 +1713,11 @@ struct FlattenictyPikp { } registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTOFPvsBeta"), track.p(), track.beta()); - if (track.beta() > trkSelOpt.cfgTOFBetaPion && track.beta() < trkSelOpt.cfgTOFBetaPion + 0.05) { // TOF pions + if (track.beta() > trkSelOpt.tofBetaPion && track.beta() < trkSelOpt.tofBetaPion + 0.05) { // TOF pions registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTOFpi"), track.eta(), track.p(), track.tpcSignal()); } - if (std::abs(track.eta()) < trkSelOpt.cfgTrkEtaMax) { + if (std::abs(track.eta()) < trkSelOpt.trkEtaMax) { if (isDCAxyWoCut(track)) { registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtVsWOcutDCA"), track.pt(), track.dcaXY()); } @@ -1709,9 +1732,9 @@ struct FlattenictyPikp { const float mult = getMult(collision); const float flat = fillFlat(collision); if constexpr (fillHist) { - if (track.p() >= trkSelOpt.cfgMomMIPMin && track.p() <= trkSelOpt.cfgMomMIPMax) { - if (dEdx > trkSelOpt.cfgDeDxMIPMin && dEdx < trkSelOpt.cfgDeDxMIPMax) { // MIP pions - if (cfgStoreThnSparse) { + if (track.p() >= trkSelOpt.momMIPMin && track.p() <= trkSelOpt.momMIPMax) { + if (dEdx > trkSelOpt.dEdxMIPMin && dEdx < trkSelOpt.dEdxMIPMax) { // MIP pions + if (defOpt.storeThnSparse) { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIP"), mult, flat, track.eta(), dEdx); } else { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIP"), track.eta(), dEdx); @@ -1721,9 +1744,9 @@ struct FlattenictyPikp { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIPVsPhiVsEta"), track.phi(), dEdx, track.eta()); registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIPNClTPCPidvsEta"), track.eta(), track.tpcNClsPID()); } - if (dEdx > trkSelOpt.cfgDeDxMIPMax + 10. && dEdx < trkSelOpt.cfgDeDxMIPMax + 30.) { // Plateau electrons - if (std::abs(track.beta() - 1) < trkSelOpt.cfgBetaPlateuMax) { - if (cfgStoreThnSparse) { + if (dEdx > trkSelOpt.dEdxMIPMax + 10. && dEdx < trkSelOpt.dEdxMIPMax + 30.) { // Plateau electrons + if (std::abs(track.beta() - 1) < trkSelOpt.betaPlateuMax) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateau"), mult, flat, track.eta(), dEdx); } else { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateau"), track.eta(), dEdx); @@ -1744,7 +1767,7 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelAll); } - if (evtSelOpt.cfgCustomTVX) { + if (evtSelOpt.customTVX) { if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; } @@ -1756,43 +1779,43 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelSel8); } - if (evtSelOpt.cfgRemoveITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + if (evtSelOpt.removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelNoITSROFrameBorder); } - if (evtSelOpt.cfgRemoveNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (evtSelOpt.removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkNoTimeFrameBorder); } - if (evtSelOpt.cfgRemoveNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + if (evtSelOpt.removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkNoSameBunchPileup); } - if (evtSelOpt.cfgRequireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (evtSelOpt.requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkIsGoodZvtxFT0vsPV); } - if (evtSelOpt.cfgRequireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + if (evtSelOpt.requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkIsVertexITSTPC); } - if (evtSelOpt.cfgRequirekIsVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + if (evtSelOpt.requirekIsVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkIsVertexTOFmatched); } - if (std::abs(collision.posZ()) > evtSelOpt.cfgCutVtxZ) { + if (std::abs(collision.posZ()) > evtSelOpt.cutVtxZ) { return false; } if constexpr (fillHist) { @@ -1914,7 +1937,7 @@ struct FlattenictyPikp { float getMult(C const& collision) { float val = -999.0; - switch (multEst) { + switch (defOpt.multEst) { case MultE::CnoMult: return val; break; @@ -1929,7 +1952,7 @@ struct FlattenictyPikp { if constexpr (!isMC) { return collision.multTPC(); } else { - LOG(fatal) << "No valid multiplicity estimator: " << multEst; + LOG(fatal) << "No valid multiplicity estimator: " << defOpt.multEst; return val; } break; @@ -1996,13 +2019,13 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("FV0/hFV0amp"), chv0, amplCh); registryQC.fill(HIST("FV0/pFV0amp"), chv0, amplCh); - if (applyCalibGain) { + if (defOpt.applyCalibGainFromCCDB) { registryQC.fill(HIST("FV0/hFV0ampCorr"), chv0, amplCh / fv0AmplCorr[chv0]); registryQC.fill(HIST("FV0/pFV0ampCorr"), chv0, amplCh / fv0AmplCorr[chv0]); } } if (amplCh > Cnull) { - if (applyCalibGain) { // equalize gain channel-by-channel + if (defOpt.applyCalibGainFromCCDB) { // equalize gain channel-by-channel amplCh /= fv0AmplCorr[chv0]; } if (chv0phi > Cnull) { @@ -2018,7 +2041,7 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("FV0/hFV0AmplvsVtxzWoCalib"), collision.posZ(), rhoLatticeFV0[chv0phi]); } - if (applyCalibVtx) { + if (defOpt.applyCalibVtxFromCCDB) { rhoLatticeFV0[chv0phi] *= zVtxMap->GetBinContent(zVtxMap->GetXaxis()->FindBin(chv0phi), zVtxMap->GetYaxis()->FindBin(collision.posZ())); if constexpr (fillHist) { registryQC.fill(HIST("FV0/hFV0AmplvsVtxzCalib"), collision.posZ(), rhoLatticeFV0[chv0phi]); @@ -2034,6 +2057,27 @@ struct FlattenictyPikp { return oneMinusFlat; } + template + bool isDCAParamCut(T const& track) const + { + const float dcaXY = track.dcaXY(); + const float dcaZ = track.dcaZ(); + const float pt = track.pt(); + float selDCAxy = 0.f; + float selDCAz = 0.f; + + if (dcaparam.lCalibLoaded) { + selDCAxy = dcaparam.hDCAxyParam->GetBinContent(1) + dcaparam.hDCAxyParam->GetBinContent(2) / std::pow(std::abs(pt), dcaparam.hDCAxyParam->GetBinContent(3)); + selDCAxy *= trkSelOpt.nsigmaDCAxy.value; + selDCAz = dcaparam.hDCAzParam->GetBinContent(1) + dcaparam.hDCAzParam->GetBinContent(2) / std::pow(std::abs(pt), dcaparam.hDCAzParam->GetBinContent(3)); + selDCAz *= trkSelOpt.nsigmaDCAz.value; + if (std::abs(dcaXY) > selDCAxy || std::abs(dcaZ) > selDCAz) { + return false; + } + } + return true; + } + template bool isDCAxyCut(T const& track) const { @@ -2088,7 +2132,7 @@ struct FlattenictyPikp { auto v0sPerCollision = v0s.sliceBy(perColV0s, collision.globalIndex()); v0sPerCollision.bindExternalIndices(&tracks); filldEdx(tracksPerCollision, v0sPerCollision, collision, bcs); - if (cfgFillDCAxyHist) { + if (defOpt.fillDCAxyHist) { static_for<0, 4>([&](auto i) { fillDCA(tracksPerCollision, collision, bcs); }); @@ -2248,10 +2292,10 @@ struct FlattenictyPikp { if (!isChrgParticle(mcParticle.pdgCode())) { return; } - if (std::abs(mcParticle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(mcParticle.eta()) > trkSelOpt.trkEtaMax) { return; } - if (mcParticle.pt() < trkSelOpt.cfgTrkPtMin) { + if (mcParticle.pt() < trkSelOpt.trkPtMin) { return; } if (!isPID(mcParticle)) { @@ -2356,7 +2400,7 @@ struct FlattenictyPikp { { LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); auto multMC = -1.; - if (evtSelOpt.useMultMCmidrap || multEst == CtwoInt) { // use generated Nch in ∣eta∣ < 0.8 + if (evtSelOpt.useMultMCmidrap || defOpt.multEst == CtwoInt) { // use generated Nch in ∣eta∣ < 0.8 multMC = countPart(particles); } else { multMC = getMultMC(mcCollision); // using McCentFT0Ms @@ -2367,7 +2411,7 @@ struct FlattenictyPikp { // Loop on rec collisions // Obtain here: Numerator of tracking efficiency; Secondary contamination correction for (const auto& collision : collisions) { - if (trkSelOpt.cfgRejectTrkAtTPCSector || applyCalibGain || applyCalibVtx) { + if (trkSelOpt.rejectTrkAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -2376,7 +2420,7 @@ struct FlattenictyPikp { } } registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0"), getMult(collision), fillFlat(collision)); // Evt split den - if (evtSelOpt.cfgRemoveSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { + if (evtSelOpt.removeSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { continue; } registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvt"), getMult(collision), fillFlat(collision)); // Evt split num, w/ Nrec > 0 @@ -2388,10 +2432,10 @@ struct FlattenictyPikp { if (!particle.isPhysicalPrimary()) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { @@ -2410,6 +2454,7 @@ struct FlattenictyPikp { registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvtSel"), multRecGt1, flatRec); // Evt split num, w/ Nrec > 0 + Evt. sel registryMC.fill(HIST("Events/hNchGenVsCent"), multMC, multRecGt1); registryMC.fill(HIST("Events/hNchVsFlatGenINELgt0wRecEvtSel"), multMC, flatMC); // Evt loss num, w/ Nrec > 0 + Evt. sel + registryMC.fill(HIST("Events/hFlatResponse"), flatMC, flatRec); // Obtain here: Denominator of tracking efficiency; Numerator event and signal loss for (const auto& particle : particles) { @@ -2419,10 +2464,10 @@ struct FlattenictyPikp { if (!particle.isPhysicalPrimary()) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { @@ -2447,24 +2492,7 @@ struct FlattenictyPikp { if (!track.has_collision()) { continue; } - if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { - continue; - } - if (track.pt() < trkSelOpt.cfgTrkPtMin) { - continue; - } - if (trkSelOpt.cfgApplyNcl && track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { - continue; - } - if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { - continue; - } - float phiModn = track.phi(); - phiMod(phiModn, magField, track.sign()); - if (trkSelOpt.cfgRejectTrkAtTPCSector && (track.pt() >= trkSelOpt.cfgPhiCutPtMin && phiModn < fPhiCutHigh->Eval(track.pt()) && phiModn > fPhiCutLow->Eval(track.pt()))) { - continue; - } - if (!isDCAxyWoCut(track)) { + if (!isGoodTrack(track, magField)) { continue; } if (!track.has_mcParticle()) { @@ -2478,10 +2506,10 @@ struct FlattenictyPikp { if (!isChrgParticle(particle.pdgCode())) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { // for checking purposes only: use gen Nch, gen Flat @@ -2505,10 +2533,10 @@ struct FlattenictyPikp { registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyAll), multRecGt1, flatRec, track.pt(), track.dcaXY()); } }); - if (isDCAxyCut(track)) { + if (isGoodTrack(track, magField)) { static_for<0, 4>([&](auto i) { constexpr int Cidx = i.value; - if (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.cfgDcaNsigmaCombinedMax)) { + if (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.dcaNsigmaCombinedMax)) { if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { if (particle.isPhysicalPrimary()) { registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CdEdxMcRecPrimSel), track.eta(), multRecGt1, flatRec, track.p(), track.tpcSignal()); @@ -2537,10 +2565,10 @@ struct FlattenictyPikp { if (!isChrgParticle(particle.pdgCode())) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { @@ -2553,7 +2581,7 @@ struct FlattenictyPikp { // Obtain here: Denominator of signal loss and event loss; MC closure // registryMC.fill(HIST("Events/hEvtMcGen"), 0.5); - if (evtSelOpt.useZVtxCutMC && std::abs(mcCollision.posZ()) > evtSelOpt.cfgCutVtxZ) { + if (evtSelOpt.zVtxCutMC && std::abs(mcCollision.posZ()) > evtSelOpt.cutVtxZ) { return; } registryMC.fill(HIST("Events/hVtxZGen"), mcCollision.posZ()); @@ -2564,7 +2592,7 @@ struct FlattenictyPikp { } } registryMC.fill(HIST("Events/hEvtMcGen"), 2.5); - if (evtSelOpt.cfgUseInelgt0wTVX && !isInelGt0wTVX(particles)) { // TVX trigger: FT0A + FT0C acceptance + if (evtSelOpt.useInelgt0wTVX && !isInelGt0wTVX(particles)) { // TVX trigger: FT0A + FT0C acceptance return; } registryMC.fill(HIST("Events/hEvtMcGen"), 3.5); @@ -2574,10 +2602,10 @@ struct FlattenictyPikp { if (!isChrgParticle(particle.pdgCode())) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { diff --git a/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx b/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx index 0518ebe9f9f..ddd61749b7e 100644 --- a/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx @@ -257,7 +257,7 @@ struct NchStudypp { histos.add("hgendndetaVsMultEta05BeforeEvtSel", "hgendndetaBeforeEvtSel vs multiplicity in eta<0.5", kTH2F, {axisEta, multAxis}); histos.add("hgendndetaVsMultEta05AfterEvtSel", "hgendndetaAfterEvtSel vs multiplicity in eta<0.5", kTH2F, {axisEta, multAxis}); histos.add("hGenCent", "Centrality of generated MC events", kTH1F, {axisCent}); - histos.add("hGenAssoRecCent", "Centrality of selected MC events", kTH1F, {axisCent}); + histos.add("hGenAssocRecCent", "Centrality of selected MC events", kTH1F, {axisCent}); histos.add("hgendndetaBeforeEvtSel", "Eta of all generated particles", kTH1F, {axisEta}); histos.add("hgendndetaAfterEvtSel", "Eta of generated particles after EvtSel", kTH1F, {axisEta}); histos.add("hgendndetaVscentBeforeEvtSel", "hgendndetaBeforeEvtSel vs centrality", kTH2F, {axisEta, centAxis}); diff --git a/PWGLF/Tasks/Nuspex/CMakeLists.txt b/PWGLF/Tasks/Nuspex/CMakeLists.txt index 91617ea0567..b34ef39cf73 100644 --- a/PWGLF/Tasks/Nuspex/CMakeLists.txt +++ b/PWGLF/Tasks/Nuspex/CMakeLists.txt @@ -14,6 +14,11 @@ o2physics_add_dpl_workflow(nuclei-batask PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(antitriton-analysis + SOURCES antitritonAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(hypertritonanalysis SOURCES hypertritonAnalysis.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore @@ -70,7 +75,7 @@ o2physics_add_dpl_workflow(spectra-tpc-tiny COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(nuclei-tpcspectra - SOURCES nucleitpcpbpb.cxx + SOURCES nucleitpcPbPb.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx b/PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx new file mode 100644 index 00000000000..63bdfebde78 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx @@ -0,0 +1,483 @@ +// 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 antitritonAnalysis.cxx +/// \brief Analysis of (anti)tritons, based on PWGCF/Femto3D/DataModel/singletrackselector.h +/// \author Nikita Gladin + +#include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include "PWGCF/Femto3D/DataModel/PIDutils.h" +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" + +#include "Common/DataModel/PIDResponseITS.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct AntitritonAnalysis { + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryTrue{"registryTrue", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service pdgDB{}; + float particleMass = 0.f; + + Configurable isMC{"isMC", false, ""}; + + Configurable removeSameBunchPileup{"removeSameBunchPileup", false, ""}; + Configurable requestGoodZvtxFT0vsPV{"requestGoodZvtxFT0vsPV", false, ""}; + Configurable requestVertexITSTPC{"requestVertexITSTPC", false, ""}; + Configurable requestVertexTOFmatched{"requestVertexTOFmatched", 0, "0 -> no selection; 1 -> vertex is matched to TOF or TRD; 2 -> matched to both;"}; + Configurable requestNoCollInTimeRangeStandard{"requestNoCollInTimeRangeStandard", false, ""}; + Configurable requestIsGoodITSLayersAll{"requestIsGoodITSLayersAll", false, "cut time intervals with dead ITS staves"}; + Configurable> irCut{"irCut", std::pair{0.f, 100.f}, "[min., max.] IR range to keep events within"}; + Configurable> occupancyCut{"occupancyCut", std::pair{0, 10000}, "[min., max.] occupancy range to keep events within"}; + + Configurable vertexZ{"vertexZ", 10.0, "abs vertexZ value limit"}; + Configurable minP{"minP", 0.0, "lower mometum limit"}; + Configurable maxP{"maxP", 100.0, "upper mometum limit"}; + Configurable eta{"eta", 100.0, "abs eta value limit"}; + Configurable y{"y", 100.0, "abs y value limit"}; + Configurable> dcaXY{"dcaXY", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaXY value limit; formula: [0] + [1]*pT^[2]"}; + Configurable> dcaZ{"dcaZ", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaZ value limit; formula: [0] + [1]*pT^[2]"}; + Configurable minTpcNClsFound{"minTpcNClsFound", 0, "minimum allowed number of TPC clasters"}; + Configurable tpcChi2NCl{"tpcChi2NCl", 100.0, "upper limit for chi2 value of a fit over TPC clasters"}; + Configurable tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0, "lower limit of TPC CrossedRows/FindableCls value"}; + Configurable maxTpcFractionSharedCls{"maxTpcFractionSharedCls", 0.4, "maximum fraction of TPC shared clasters"}; + Configurable minItsNCls{"minItsNCls", 0, "minimum allowed number of ITS clasters for a track"}; + Configurable itsChi2NCl{"itsChi2NCl", 100.0, "upper limit for chi2 value of a fit over ITS clasters for a track"}; + Configurable particlePDG{"particlePDG", o2::constants::physics::Pdg::kTriton, "PDG code of a particle to perform PID for"}; + Configurable> tpcNSigma{"tpcNSigma", std::vector{-4.0f, 4.0f}, "Nsigma range in TPC before the TOF is used"}; + Configurable> itsNSigma{"itsNSigma", std::vector{-10.0f, 10.0f}, "Nsigma range in ITS to use along with TPC"}; + Configurable pidTrshld{"pidTrshld", 0.0, "value of momentum from which the PID is done with TOF (before that only TPC is used)"}; + Configurable massCuttrshld{"massCuttrshld", 0.0, "value of momentum from which the mass cut is done with TOF"}; + Configurable> itsNsigNL{"itsNsigNL", std::vector{-100.0f, 100.0f}, "Nsigma p-dependent cut in ITS ; formula: [0] + [1]*pT"}; + + Configurable> tofNSigma{"tofNSigma", std::vector{-4.0f, 4.0f}, "Nsigma range in TOF"}; + Configurable> tpcNSigmaResidual{"tpcNSigmaResidual", std::vector{-5.0f, 5.0f}, "residual TPC Nsigma cut to use with the TOF"}; + + Configurable> particlePDGtoReject{"particlePDGtoReject", std::vector{PDG_t::kProton}, "PDG codes of perticles that will be rejected with TPC"}; + Configurable> rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-0.0f, 0.0f}, "TOF rejection Nsigma range for particles specified with PDG to be rejected"}; + Configurable> rejectWithinNsigmaTPC{"rejectWithinNsigmaTPC", std::vector{-0.0f, 0.0f}, "TPC rejection Nsigma range for particles specified with PDG to be rejected"}; + + Configurable> centCut{"centCut", std::pair{0.f, 100.f}, "[min., max.] centrality range to keep tracks within"}; + + Configurable> dcaBinning{"dcaBinning", std::vector{501, 0.5f, 1}, "setup for variable binning (geometric progression is used): 1st (int) -- N_bins (must be odd, otherwise will be increased by 1); 2nd (float) -- abs value of the edge of axises in histos (-2nd, +2nd); 3d (int) -- desired ratio between w_bin at the edges and at 0;"}; + Configurable> tofMass{"tofMass", std::vector{3.0f, 3.0f}, "TOF Mass bounds"}; + + std::pair> itsCuts; + std::pair> tpcCuts; + std::pair> tofCuts; + + Filter pFilter = o2::aod::singletrackselector::p > minP&& o2::aod::singletrackselector::p < maxP; + Filter etaFilter = nabs(o2::aod::singletrackselector::eta) < eta; + Filter tpcTrkFilter = o2::aod::singletrackselector::tpcNClsFound >= minTpcNClsFound && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcChi2NCl) < tpcChi2NCl && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcCrossedRowsOverFindableCls) > tpcCrossedRowsOverFindableCls; + Filter itsTrkFilter = o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedItsChi2NCl) < itsChi2NCl; + Filter vertexFilter = nabs(o2::aod::singletrackselector::posZ) < vertexZ; + + struct HistSet { + std::shared_ptr eta; + std::shared_ptr etaToY; + std::shared_ptr y; + std::shared_ptr phi; + std::shared_ptr p; + std::shared_ptr pt; + std::shared_ptr dcaxyToP; + std::shared_ptr dcaxyToPt; + std::shared_ptr dcazToP; + std::shared_ptr dcazToPt; + std::shared_ptr tpcClusters; + std::shared_ptr itsClusters; + std::shared_ptr tpcSignal; + std::shared_ptr tofSignal; + std::shared_ptr massTOF; + std::shared_ptr nsigmaITS; + std::shared_ptr nsigmaTPC; + std::shared_ptr nsigmaTOF; + std::shared_ptr tofOverTPC; + std::shared_ptr innerParamToP; + std::shared_ptr ptGenPtRec; + std::shared_ptr dcaxyDcazToPt; + std::shared_ptr dcaxyToDcaz; + std::shared_ptr origin; + }; + + static inline const std::vector stageDirs = { + "init", + "No_Cuts", + "ITS_Cuts", + "TPC_Cuts", + "TOF_Cuts", + "ITSTPC_Cut", + "PID_Cuts", + "TOFmass_Cut", + "Rejection_Cut", + "TPCLinear_Cut", + }; + + // signDirs[0] = "t" for sign > 0 (triton), signDirs[1] = "at" for sign < 0 (antitriton). + static inline const std::array signDirs = {"t", "at"}; + + std::vector> hSets; + std::vector> hSetsTrue; + + HistSet makeHistSet(HistogramRegistry& reg, const std::string& dir, int pdgForPid = 0) + { + HistSet h; + + h.eta = reg.add((dir + "/eta").c_str(), "#eta;#eta;Entries", kTH1F, {{200, -2.5, 2.5}}); + h.y = reg.add((dir + "/y").c_str(), "y;y;Entries", kTH1F, {{200, -2.5, 2.5}}); + h.etaToY = reg.add((dir + "/eta_to_y").c_str(), "#eta;y;Entries", kTH2F, {{200, -2.5, 2.5}, {200, -2.5, 2.5}}); + h.phi = reg.add((dir + "/phi").c_str(), "#phi;#phi;Entries", kTH1F, {{200, 0., o2::constants::math::TwoPI}}); + h.p = reg.add((dir + "/p").c_str(), "p;p (GeV/#it{c});Entries", kTH1F, {{100, 0., 5.}}); + h.pt = reg.add((dir + "/pt").c_str(), "p_{T};p_{T} (GeV/#it{c});Entries", kTH1F, {{100, 0., 5.}}); + h.dcaxyToP = reg.add((dir + "/dcaxy_to_p").c_str(), "DCA_{xy} vs p;p (GeV/#it{c});DCA_{xy} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.dcaxyToPt = reg.add((dir + "/dcaxy_to_pt").c_str(), "DCA_{xy} vs p_{T};p_{T} (GeV/#it{c});DCA_{xy} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.dcazToP = reg.add((dir + "/dcaz_to_p").c_str(), "DCA_{z} vs p;p (GeV/#it{c});DCA_{z} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.dcazToPt = reg.add((dir + "/dcaz_to_pt").c_str(), "DCA_{z} vs p_{T};p_{T} (GeV/#it{c});DCA_{z} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.tpcClusters = reg.add((dir + "/TPCClusters").c_str(), "TPC Clusters;N_{TPC clusters};Entries", kTH1F, {{163, -0.5, 162.5}}); + h.itsClusters = reg.add((dir + "/ITSClusters").c_str(), "ITS Clusters;N_{ITS clusters};Entries", kTH1F, {{10, -0.5, 9.5}}); + h.tpcSignal = reg.add((dir + "/TPCSignal").c_str(), "TPC Signal;#it{p}_{inner} (GeV/#it{c});dE/dx in TPC (arbitrary units)", kTH2F, {{200, 0., 5.0}, {1000, 0., 1000.0}}); + h.tofSignal = reg.add((dir + "/TOFSignal").c_str(), "TOF Signal;#it{p} (GeV/#it{c});#beta", kTH2F, {{200, 0., 5.0}, {100, 0., 1.5}}); + h.massTOF = reg.add((dir + "/mTOF").c_str(), "m_{TOF};p_{T} (GeV/#it{c});m_{TOF}(GeV/#it{c}^{2})", kTH2F, {{120, 0., 6.}, {1000, -1.5, 5.0}}); + h.innerParamToP = reg.add((dir + "/ip_to_p").c_str(), ";#it{p} (GeV/#it{c});ip_to_p", kTH2F, {{100, 0., 5.0}, {100, 0.0, 2.0}}); + h.ptGenPtRec = reg.add((dir + "/ptgenptrec").c_str(), ";#it{p_{T, rec}} (GeV/#it{c});#it{p_{T, rec}} - #it{p_{T, gen}}(GeV/#it{c})", kTH2F, {{100, 0., 5.0}, {100, -2.5, 2.5}}); + h.dcaxyDcazToPt = reg.add( + (dir + "/dcaxy_dcaz_to_pt").c_str(), + "DCA_{xy} vs DCA_{z} vs p_{T};DCA_{xy} (cm);DCA_{z} (cm);p_{T} (GeV/#it{c})", + kTH3F, + { + {101, -0.5, 0.5}, // x axis: DCA_xy + {101, -0.5, 0.5}, // y axis: DCA_z + {20, 0., 5.0} // z axis: pT + }); + h.dcaxyToDcaz = reg.add( + (dir + "/dcaxy_to_dcaz").c_str(), + "DCA_{z} vs DCA_{xy};DCA_{xy} (cm);DCA_{z} (cm);Counts", + kTH2F, + { + {501, -0.5, 0.5}, // x axis: DCAxy + {501, -0.5, 0.5} // y axis: DCAz + }); + h.origin = reg.add((dir + "/origin").c_str(), "MC origin;origin (-1: unmatched, 0: primary, 1: weak decay, 2: material);Entries", kTH1F, {{4, -1.5, 2.5}}); + + if (pdgForPid != 0) { + h.tofOverTPC = reg.add((dir + Form("/TOFoverTPC_PDG%i", pdgForPid)).c_str(), "n#sigma_{TOF};n#sigma_{TPC};", kTH2F, {{100, -10., 10.}, {100, -10., 10.}}); + h.nsigmaITS = reg.add((dir + Form("/nsigmaITS_PDG%i", pdgForPid)).c_str(), Form("n#sigma_{ITS};p (GeV/#it{c});n#sigma_{ITS}"), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + h.nsigmaTPC = reg.add((dir + Form("/nsigmaTPC_PDG%i", pdgForPid)).c_str(), Form("n#sigma_{TPC};p (GeV/#it{c});n#sigma_{TPC}"), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + h.nsigmaTOF = reg.add((dir + Form("/nsigmaTOF_PDG%i", pdgForPid)).c_str(), Form("n#sigma_{TOF};p (GeV/#it{c});n#sigma_{TOF}"), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + } + + return h; + } + + template + static float getMassTOF(const TrackType& track) + { + const float beta = track.beta(); + if (beta <= 0.f || beta >= 1.f) { + return -1.f; + } + return track.p() * std::sqrt(1.f / (beta * beta) - 1.f); + } + + template + void fillHistSet(HistSet& h, const TrackType& track, int pdg) + { + const auto rapidity = track.rapidity(particleMass); + h.eta->Fill(track.eta()); + h.etaToY->Fill(track.eta(), rapidity); + h.y->Fill(rapidity); + h.phi->Fill(track.phi()); + h.p->Fill(track.p()); + h.pt->Fill(track.pt()); + h.dcaxyToP->Fill(track.p(), track.dcaXY()); + h.dcaxyToPt->Fill(track.pt(), track.dcaXY()); + h.dcazToP->Fill(track.p(), track.dcaZ()); + h.dcazToPt->Fill(track.pt(), track.dcaZ()); + h.dcaxyDcazToPt->Fill(track.dcaXY(), track.dcaZ(), track.pt()); + h.dcaxyToDcaz->Fill(track.dcaXY(), track.dcaZ()); + h.tpcClusters->Fill(track.tpcNClsFound()); + h.itsClusters->Fill(track.itsNCls()); + h.nsigmaITS->Fill(track.p(), o2::aod::singletrackselector::getITSNsigma(track, pdg)); + h.nsigmaTPC->Fill(track.p(), o2::aod::singletrackselector::getTPCNsigma(track, pdg)); + h.nsigmaTOF->Fill(track.p(), o2::aod::singletrackselector::getTOFNsigma(track, pdg)); + h.tofOverTPC->Fill(o2::aod::singletrackselector::getTPCNsigma(track, pdg), o2::aod::singletrackselector::getTOFNsigma(track, pdg)); + } + + template + void fillHistSetExtra(HistSet& h, const TrackType& track) + { + h.tpcSignal->Fill(track.tpcInnerParam(), track.tpcSignal()); + h.tofSignal->Fill(track.p(), track.beta()); + h.massTOF->Fill(track.pt(), getMassTOF(track)); + h.innerParamToP->Fill(track.p(), track.tpcInnerParam() / track.p()); + if constexpr (HasMC) { + h.ptGenPtRec->Fill(track.pt(), track.pt() - track.pt_MC()); + } + } + + template + void fillSet(HistSet& set, HistSet& mcSet, const TrackType& track, int pdg) + { + fillHistSet(set, track, pdg); + if constexpr (FillExtra) { + fillHistSetExtra(set, track); + } + + if constexpr (HasMC) { + if ((std::abs(track.pdgCode()) == pdg) && (track.pdgCode() / std::abs(track.pdgCode()) == track.sign())) { + mcSet.origin->Fill(track.origin()); + fillHistSet(mcSet, track, pdg); + if constexpr (FillExtra) { + fillHistSetExtra(mcSet, track); + } + } + } + } + + void init(o2::framework::InitContext&) + { + + if (isMC.value) { + o2::aod::ITSResponse::setMCDefaultParameters(); // set MC parametrisation for the ITS PID + } + + particleMass = static_cast(pdgDB->Mass(particlePDG.value)); + + itsCuts = std::make_pair(particlePDG.value, itsNSigma); + tpcCuts = std::make_pair(particlePDG.value, tpcNSigma); + tofCuts = std::make_pair(particlePDG.value, tofNSigma); + + int nBins = static_cast(dcaBinning.value[0]); // number of bins -- must be odd otherwise will be increased by 1 + if ((nBins & 1) == 0) { // bin count must be odd + nBins += 1; + } + + auto dcaBins = (static_cast(dcaBinning.value[2]) != 1.0) + ? calc_var_bins(nBins + 1, dcaBinning.value[1], static_cast(dcaBinning.value[2])) + : calc_const_bins(nBins, -dcaBinning.value[1], dcaBinning.value[1]); + auto constBinsP = calc_const_bins(100, 0., 5.0); + + hSets.resize(stageDirs.size()); + hSetsTrue.resize(stageDirs.size()); + for (size_t i = 0; i < stageDirs.size(); i++) { + for (size_t s = 0; s < signDirs.size(); s++) { + const std::string dir = stageDirs[i] + "/" + signDirs[s]; + hSets[i][s] = makeHistSet(registry, dir, particlePDG.value); + hSetsTrue[i][s] = makeHistSet(registryTrue, dir + "/true", particlePDG.value); + } + } + + const AxisSpec axisMult{5001, -0.5, 5000.5, "mult."}; + const AxisSpec axisPerc{101, -0.5, 100.5, "percentile"}; + registry.add("posZ", "posZ", kTH1F, {{300, -16., 16., "posZ"}}); + registry.add("mult", "mult", kTH1F, {axisMult}); + registry.add("MultVsCent", "MultVsCent", kTH2F, {axisMult, axisPerc}); + registry.add("IRvsOccupancy", "IRvsOccupancy", kTH2I, {{10000, 0, 10000, "Occupancy"}, {50, 0, 50, "IR, kHz"}}); + } + + template + void fillHistograms(ColsType const& collisions, TracksType const& tracks) + { + for (const auto& track : tracks) { + const int signIdx = (-track.sign() + 1) / 2; // 0: triton, 1: antitriton + fillSet(hSets[1][signIdx], hSetsTrue[1][signIdx], track, particlePDG.value); // nocuts + } + for (const auto& collision : collisions) { + if (removeSameBunchPileup && !collision.isNoSameBunchPileup()) { + continue; + } + if (requestGoodZvtxFT0vsPV && !collision.isGoodZvtxFT0vsPV()) { + continue; + } + if (requestVertexITSTPC && !collision.isVertexITSTPC()) { + continue; + } + if (requestVertexTOFmatched > collision.isVertexTOForTRDmatched()) { + continue; + } + if (requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) { + continue; + } + if (requestIsGoodITSLayersAll && !collision.isGoodITSLayersAll()) { + continue; + } + if (collision.multPerc() < centCut.value.first || collision.multPerc() >= centCut.value.second) { + continue; + } + if (collision.hadronicRate() < irCut.value.first || collision.hadronicRate() >= irCut.value.second) { + continue; + } + if (collision.occupancy() < occupancyCut.value.first || collision.occupancy() >= occupancyCut.value.second) { + continue; + } + + registry.fill(HIST("posZ"), collision.posZ()); + registry.fill(HIST("mult"), collision.mult()); + registry.fill(HIST("MultVsCent"), collision.mult(), collision.multPerc()); + registry.fill(HIST("IRvsOccupancy"), collision.occupancy(), collision.hadronicRate()); + } + + for (const auto& track : tracks) { + const auto& coll = track.template singleCollSel_as(); + const int signIdx = (-track.sign() + 1) / 2; // 0: triton, 1: antitriton + + if (removeSameBunchPileup && !coll.isNoSameBunchPileup()) { + continue; + } + if (requestGoodZvtxFT0vsPV && !coll.isGoodZvtxFT0vsPV()) { + continue; + } + if (requestVertexITSTPC && !coll.isVertexITSTPC()) { + continue; + } + if (requestVertexTOFmatched > coll.isVertexTOForTRDmatched()) { + continue; + } + if (requestNoCollInTimeRangeStandard && !coll.noCollInTimeRangeStandard()) { + continue; + } + if (requestIsGoodITSLayersAll && !coll.isGoodITSLayersAll()) { + continue; + } + if (std::fabs(coll.posZ()) > vertexZ) { + continue; + } + if (coll.multPerc() < centCut.value.first || coll.multPerc() >= centCut.value.second) { + continue; + } + if (coll.hadronicRate() < irCut.value.first || coll.hadronicRate() >= irCut.value.second) { + continue; + } + if (coll.occupancy() < occupancyCut.value.first || coll.occupancy() >= occupancyCut.value.second) { + continue; + } + if (track.tpcFractionSharedCls() > maxTpcFractionSharedCls) { + continue; + } + if (track.itsNCls() < minItsNCls) { + continue; + } + if (std::fabs(track.dcaXY()) > dcaXY.value[0] + dcaXY.value[1] * std::pow(track.pt(), dcaXY.value[2])) { + continue; + } + if (std::fabs(track.dcaZ()) > dcaZ.value[0] + dcaZ.value[1] * std::pow(track.pt(), dcaZ.value[2])) { + continue; + } + + if (o2::aod::singletrackselector::ITSselection(track, itsCuts)) { + fillSet(hSets[2][signIdx], hSetsTrue[2][signIdx], track, particlePDG.value); // ITSCuts + } + if (o2::aod::singletrackselector::TPCselection(track, tpcCuts, itsNSigma.value)) { + fillSet(hSets[3][signIdx], hSetsTrue[3][signIdx], track, particlePDG.value); // TPCCuts + } + if (o2::aod::singletrackselector::TOFselection(track, tofCuts, tpcNSigmaResidual.value)) { + fillSet(hSets[4][signIdx], hSetsTrue[4][signIdx], track, particlePDG.value); // TOFCuts + } + if (o2::aod::singletrackselector::TPCselection(track, tpcCuts, itsNSigma.value)) { + fillSet(hSets[5][signIdx], hSetsTrue[5][signIdx], track, particlePDG.value); // ITSTPC + } + + const bool pidOk = + (track.p() < pidTrshld) + ? o2::aod::singletrackselector::TPCselection(track, tpcCuts, itsNSigma.value) + : o2::aod::singletrackselector::TPCselection(track, std::make_pair(particlePDG.value, tpcNSigmaResidual.value), tpcNSigmaResidual.value); + if (!pidOk) { + continue; + } + if (std::fabs(track.rapidity(particleMass)) > y) { + continue; + } + + fillSet(hSets[6][signIdx], hSetsTrue[6][signIdx], track, particlePDG.value); // PIDcuts + if constexpr (FillExtra) { + if (track.p() >= massCuttrshld && (getMassTOF(track) <= tofMass.value[0] || getMassTOF(track) >= tofMass.value[1])) { + continue; + } + } + fillSet(hSets[7][signIdx], hSetsTrue[7][signIdx], track, particlePDG.value); // masscut + + bool rejectedByPDG = false; + for (const int& pdgToReject : particlePDGtoReject.value) { + if (o2::aod::singletrackselector::TPCselection(track, std::make_pair(pdgToReject, rejectWithinNsigmaTPC.value))) { + rejectedByPDG = true; + break; + } + } + if (rejectedByPDG) { + continue; + } + fillSet(hSets[8][signIdx], hSetsTrue[8][signIdx], track, particlePDG.value); // rd + + if (getITSNsigma(track, particlePDG.value) <= itsNsigNL.value[0] + itsNsigNL.value[1] * track.p()) { + continue; + } + fillSet(hSets[9][signIdx], hSetsTrue[9][signIdx], track, particlePDG.value); // nl + } + } + + void processDefault(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + { + fillHistograms(collisions, tracks); + } + PROCESS_SWITCH(AntitritonAnalysis, processDefault, "process default", true); + + void processExtra(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + { + fillHistograms(collisions, tracks); + } + PROCESS_SWITCH(AntitritonAnalysis, processExtra, "process extra", false); + + void processMC(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + { + fillHistograms(collisions, tracks); + } + PROCESS_SWITCH(AntitritonAnalysis, processMC, "process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx index 2186703599f..aa012ec3dd6 100644 --- a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx +++ b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx @@ -140,6 +140,7 @@ struct DedxPidAnalysis { ZVtxCut, NoSameBunchPileup, GoodZvtxFT0vsPV, + GoodITS, INELgt }; @@ -204,7 +205,7 @@ struct DedxPidAnalysis { "max z distance to IP"}; Configurable etaMin{"etaMin", -0.8f, "etaMin"}; Configurable etaMax{"etaMax", +0.8f, "etaMax"}; - Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + // Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; Configurable nSigmaDCAxy{"nSigmaDCAxy", 3.0, "nSigma DCAxy selection"}; Configurable dcaXYp0{"dcaXYp0", 0.0105f, "DCAxy formula: p0 + p1/pt^p2"}; Configurable dcaXYp1{"dcaXYp1", 0.0350f, "DCAxy p1 parameter"}; @@ -250,6 +251,7 @@ struct DedxPidAnalysis { Configurable nGoodZvtx{"nGoodZvtx", true, "Rejects events with no vertex match between FT0 and PV"}; // Configurable nPileUp{"nPileUp", true, "Rejects events with pileup in the same bunch crossing"}; Configurable nINELSelectionMode{"nINELSelectionMode", 2, "INEL event selection: 1 no sel, 2 INEL>0, 3 INEL>1"}; + Configurable nGoodITS{"nGoodITS", true, "Numbers of inactive chips on all ITS layers are below maximum allowed values"}; Configurable v0SelectionMode{"v0SelectionMode", 3, "V0 Selection base on TPC: 1, TOF:2 ,Both:3"}; Configurable momentumMode{"momentumMode", 2, "1: TPC inner param, 2: Total momentum p"}; Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; @@ -281,10 +283,10 @@ struct DedxPidAnalysis { TrackSelection selectedTracks; selectedTracks.SetPtRange(0.1f, 1e10f); selectedTracks.SetEtaRange(etaMin, etaMax); - selectedTracks.SetRequireITSRefit(true); - selectedTracks.SetRequireTPCRefit(true); + // selectedTracks.SetRequireITSRefit(true); + // selectedTracks.SetRequireTPCRefit(true); selectedTracks.SetMinNCrossedRowsTPC(static_cast(minNCrossedRowsTPC.value)); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC); + // selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC); selectedTracks.SetMaxChi2PerClusterTPC(maxChi2TPC); selectedTracks.SetRequireHitsInITSLayers(1, {0, 1, 2}); selectedTracks.SetMaxChi2PerClusterITS(maxChi2ITS); @@ -310,6 +312,11 @@ struct DedxPidAnalysis { } else { LOGF(info, "GoodZvtxFT0vsPV cut disabled"); } + if (nGoodITS) { + LOGF(info, "Applying GoodITSLayersAll cut"); + } else { + LOGF(info, "GoodITSLayersAll cut disabled"); + } if (nINELSelectionMode == NoSelINEL) { LOGF(info, "Applying just INEL"); label = "INEL"; @@ -760,7 +767,7 @@ struct DedxPidAnalysis { HistType::kTH2F, {{ptAxis}, {dcaAxis}}); // Event Counter - registryDeDx.add("evsel", "events selected", HistType::kTH1F, {{6, 0.5, 6.5, ""}}); + registryDeDx.add("evsel", "events selected", HistType::kTH1F, {{7, 0.5, 7.5, ""}}); auto hstat = registryDeDx.get(HIST("evsel")); auto* x = hstat->GetXaxis(); x->SetBinLabel(AllEv, "AllEv"); @@ -769,6 +776,7 @@ struct DedxPidAnalysis { x->SetBinLabel(NoSameBunchPileup, "NoSameBunchPileup"); x->SetBinLabel(GoodZvtxFT0vsPV, "GoodZvtxFT0vsPV"); x->SetBinLabel(INELgt, label); + x->SetBinLabel(GoodITS, "GoodITSLayersAll"); // Track Prim Counter registryDeDx.add("trackselAll", "track selected all particles", HistType::kTH1F, {{5, 0.5, 5.5, ""}}); @@ -1438,6 +1446,12 @@ struct DedxPidAnalysis { registryDeDx.fill(HIST("evsel"), EvCutLabel::GoodZvtxFT0vsPV); } + if (nGoodITS) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return; + registryDeDx.fill(HIST("evsel"), EvCutLabel::GoodITS); + } + if (nINELSelectionMode == NoSelINEL) { registryDeDx.fill(HIST("evsel"), EvCutLabel::INELgt); } else if (nINELSelectionMode == SelINELgt0) { diff --git a/PWGLF/Tasks/Nuspex/multiplicityPt.cxx b/PWGLF/Tasks/Nuspex/multiplicityPt.cxx index 7f0864b61c1..7e90e8b89d5 100644 --- a/PWGLF/Tasks/Nuspex/multiplicityPt.cxx +++ b/PWGLF/Tasks/Nuspex/multiplicityPt.cxx @@ -121,6 +121,7 @@ struct MultiplicityPt { Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Require good Z vertex FT0 vs PV"}; Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Require vertex ITSTPC"}; Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove no time frame border"}; + Configurable nGoodITS{"nGoodITS", true, "Numbers of inactive chips on all ITS layers are below maximum allowed values"}; // Gen-level event selection Configurable selTVXMC{"selTVXMC", true, "Require TVX-equivalent at gen level"}; @@ -229,7 +230,8 @@ struct MultiplicityPt { kVtxZ, kINELgt0, kRecoColl, - kRecoSelected + kGoodITS, + kRecoSelected, }; // Particle species enum @@ -252,14 +254,14 @@ struct MultiplicityPt { // Setup custom track cuts if (useCustomTrackCuts.value) { customTrackCuts = getGlobalTrackSelectionRun3ITSMatch(itsPattern.value); - customTrackCuts.SetRequireITSRefit(requireITS.value); - customTrackCuts.SetRequireTPCRefit(requireTPC.value); + // customTrackCuts.SetRequireITSRefit(requireITS.value); + // customTrackCuts.SetRequireTPCRefit(requireTPC.value); customTrackCuts.SetMinNClustersITS(minITSnClusters.value); customTrackCuts.SetRequireGoldenChi2(requireGoldenChi2.value); customTrackCuts.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); customTrackCuts.SetMaxChi2PerClusterITS(maxChi2PerClusterITS.value); customTrackCuts.SetMinNCrossedRowsTPC(minNCrossedRowsTPC.value); - customTrackCuts.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC.value); + // customTrackCuts.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC.value); customTrackCuts.SetMaxDcaXYPtDep([](float /*pt*/) { return 10000.f; }); // customTrackCuts.SetMaxDcaZ(maxDcaZ.value); } @@ -305,7 +307,7 @@ struct MultiplicityPt { // ======================================================================== // EVENT COUNTER AND BASIC HISTOGRAMS // ======================================================================== - registry.add("EventCounter", ";;Events", kTH1F, {{8, 0.5, 8.5}}); + registry.add("EventCounter", ";;Events", kTH1F, {{9, 0.5, 9.5}}); { auto h = registry.get(HIST("EventCounter")); h->GetXaxis()->SetBinLabel(kAllGen, "All gen."); @@ -313,6 +315,7 @@ struct MultiplicityPt { h->GetXaxis()->SetBinLabel(kVtxZ, "|Zvtx|GetXaxis()->SetBinLabel(kINELgt0, "INEL>0"); h->GetXaxis()->SetBinLabel(kRecoColl, ">=1 reco coll."); + h->GetXaxis()->SetBinLabel(kGoodITS, "GoodITSLayersAll"); h->GetXaxis()->SetBinLabel(kRecoSelected, ">=1 reco+sel."); } @@ -1064,6 +1067,10 @@ struct MultiplicityPt { if (!isEventSelectedMC(collision)) continue; + if (nGoodITS.value && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + continue; + registry.fill(HIST("EventCounter"), kGoodITS); + registry.fill(HIST("EventCounter"), kRecoSelected); const float centrality = collision.centFT0M(); diff --git a/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx b/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx new file mode 100644 index 00000000000..87799179ec4 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx @@ -0,0 +1,1300 @@ +// 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 nucleitpcPbPb.cxx +/// \brief Nuclei (pion, proton, deuteron, triton, He3, He4) TPC(+TOF) PID +/// analysis for Pb-Pb, including MC efficiency/acceptance, signal-loss, +/// event-loss and DCA-template corrections. +/// \note under work +/// +/// \author Jaideep Tanwar , Panjab University + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using CollisionsFull = soa::Join; +using TracksFull = soa::Join; +using CollisionsFullMC = soa::Join; + +//=================================================================================== +// Static configuration tables (species definitions, PID/quality defaults, and +// track/DCA correction parameters). None of the values below are changed by +// this cleanup -- only the surrounding comments/formatting are. +//=================================================================================== +namespace +{ + +// ---- Particle species definitions ------------------------------------------- +constexpr int NParticles = 6; // pion, proton, deuteron, triton, helion(He3), alpha(He4) +const std::vector particleNames{"pion", "proton", "deuteron", "triton", "helion", "alpha"}; +const std::vector correctedparticleNames{"helion", "antihelion", "alpha", "antialpha"}; +const std::vector particlePdgCodes{211, 2212, o2::constants::physics::kDeuteron, o2::constants::physics::kTriton, o2::constants::physics::kHelium3, o2::constants::physics::kAlpha}; +const std::vector particleMasses{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron, o2::constants::physics::MassTriton, o2::constants::physics::MassHelium3, o2::constants::physics::MassAlpha}; +const std::vector particleCharge{1, 1, 1, 1, 2, 2}; + +// ---- TPC Bethe-Bloch parameterisation defaults (per species) --------------- +constexpr int NBetheParams = 6; +const std::vector hfMothCodes = {511, 521, 531, 541, 5122}; // b-mesons + Lambda_b +const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +const std::array, NParticles> kBetheBlochDefault{{{13.611469, 3.598765, -0.021138, 2.039562, 0.651040, 0.09}, // pion + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // proton + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // deuteron + {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // triton + {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}, // helion + {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}}}; // alpha + +// ---- Track PID/quality selection defaults (per species) -------------------- +constexpr int NTrkSettings = 13; +const std::vector trackPIDsettingsNames{"useBBparams", "minITSnCls", "minITSnClscos", "minTPCnCls", "maxTPCchi2", "minTPCchi2", "maxITSchi2", "maxTPCnSigma", "maxDcaXY", "maxDcaZ", "minITSclsSize", "minTPCnClsCrossedRows", "minReqClusterITSib"}; +const std::array, NParticles> kTrackPIDSettings{{{0, 0, 4, 60, 4.0, 0.5, 100, 2.5, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 75, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}}}; + +constexpr int NTrkSettings2 = 7; +const std::vector trackPIDsettingsNames2{"useITSnsigma", "minITSnsigma", "maxITSnsigma", "fillsparsh", "useTPCnsigmaTOF", "maxTPCnsigmaTOF", "maxTOFnsigma"}; +const std::array, NParticles> kTrackPIDSettings2{{{1, -5, 4, 0, 1, 2, 2}, + {1, -5, 4, 0, 1, 2, 2}, + {1, -5, 4, 0, 1, 2, 2}, + {1, -5, 4, 1, 1, 2, 2}, + {1, -5, 4, 1, 1, 2, 2}, + {1, -5, 4, 1, 1, 2, 2}}}; + +// ---- pT-dependent reconstruction correction parameters for He3/He4 --------- +constexpr int NFittingParticle = 4; +constexpr int NFittingParameters = 4; +const std::vector trackcorrectionNames{"a", "b", "c", "d"}; +const std::array, NFittingParticle> ktrackcorrection{{{0.464215, 0.195771, 0.0183111, 0.0}, // He3 + {0.464215, 0.195771, 0.0183111, 0.0}, // anti-He3 + {0.00765, 0.503791, -1.10517, 0.0}, // He4 + {0.00765, 0.503791, -1.10517, 0.0}}}; // anti-He4 + +// ---- pT-dependent DCA cut parameters ---------------------------------------- +// DCAxy(pt) = p0 * exp( p1 * pt) + p2 +// DCAz(pt) = p0 * exp(-p1 * pt) + p2 +constexpr int NDCATypes = 2; +constexpr int NDCAParameters = 3; +const std::vector dcaNames{"p0", "p1", "p2"}; +const std::vector dcaTypeNames{"DCAxy", "DCAz"}; +const std::array, NDCATypes> kDCAcorrection{{{0.0118, -0.6889, 0.0017}, + {0.1014, 1.7512, 0.0024}}}; + +// ---- MC decay-origin classification ----------------------------------------- +constexpr int DecayTypePrimary = 0; +constexpr int DecayTypeWeak = 1; +constexpr int DecayTypeTransport = 2; + +/// One row of the Bethe-Bloch/PID configuration table, resolved for a given species. +struct PrimParticles { + TString name; + int pdgCode; + int charge; + double mass; + double resolution; + std::vector betheParams; + bool active; + + PrimParticles(const std::string& name_, int pdgCode_, double mass_, int charge_, const LabeledArray& bethe) + : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) + { + resolution = bethe.get(name, "resolution"); + betheParams.clear(); + constexpr unsigned int NSpecies = 5; + for (unsigned int i = 0; i < NSpecies; ++i) { + betheParams.push_back(bethe.get(name, i)); + } + } +}; // struct PrimParticles + +std::vector> hmass; +std::vector> hmassnsigma; + +} // namespace + +//=================================================================================== +struct NucleitpcPbPb { + + Preslice tracksPerCollision = aod::track::collisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histomc{"histomc", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // ---- Event selection configurables ------------------------------------ + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove no same bunch pileup"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Require is good Zvtx FT0 vs PV"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Require is vertex ITS TPC"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove no time frame border"}; + Configurable cfgsel8Require{"cfgsel8Require", true, "sel8 cut require"}; + Configurable cfgZvertex{"cfgZvertex", 10, "Min Z Vertex"}; + + // ---- Track selection configurables ------------------------------------ + Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; + Configurable cfgPassedITSRefit{"cfgPassedITSRefit", true, "Require ITS refit"}; + Configurable cfgPassedTPCRefit{"cfgPassedTPCRefit", true, "Require TPC refit"}; + Configurable cfgetaRequire{"cfgetaRequire", true, "eta cut require"}; + Configurable cfgetaRequireMC{"cfgetaRequireMC", true, "eta cut require for generated particles"}; + Configurable cfgRapidityRequire{"cfgRapidityRequire", true, "Require Rapidity cut"}; + Configurable cfgRapidityRequireMC{"cfgRapidityRequireMC", true, "rapidity cut require for generated particles"}; + Configurable cfgCutEta{"cfgCutEta", 0.9f, "Eta range for tracks"}; + Configurable cfgCutRapiditymin{"cfgCutRapiditymin", -0.5f, "min Rapidity range"}; + Configurable cfgCutRapiditymax{"cfgCutRapiditymax", 0.5f, "max Rapidity range"}; + Configurable cfgtpcNClsFindable{"cfgtpcNClsFindable", 0.8f, "tpcNClsFindable over crossedRows"}; + Configurable centcut{"centcut", 80.0f, "centrality cut"}; + Configurable cfgZvertexRequireMC{"cfgZvertexRequireMC", true, "Pos Z cut in MC"}; + + // ---- Track quality-cut configurables ----------------------------------- + Configurable cfgTPCNClsCrossedRowsRequire{"cfgTPCNClsCrossedRowsRequire", true, "Require TPCNClsCrossedRows Cut"}; + Configurable cfgmaxTPCchi2Require{"cfgmaxTPCchi2Require", true, "Require maxTPCchi2 Cut"}; + Configurable cfgminTPCchi2Require{"cfgminTPCchi2Require", true, "Require minTPCchi2 Cut"}; + Configurable cfgminITSnClsRequire{"cfgminITSnClsRequire", false, "Require minITSnCls Cut"}; + Configurable cfgminITSnClscosRequire{"cfgminITSnClscosRequire", true, "Require minITSnCls / cosh(eta) Cut"}; + Configurable cfgminReqClusterITSibRequire{"cfgminReqClusterITSibRequire", true, " Require min number of clusters required in ITS inner barrel"}; + Configurable cfgmaxITSchi2Require{"cfgmaxITSchi2Require", true, "Require maxITSchi2 Cut"}; + Configurable cfgmaxTPCnSigmaRequire{"cfgmaxTPCnSigmaRequire", true, "Require maxTPCnSigma Cut"}; + Configurable cfgminGetMeanItsClsSizeRequire{"cfgminGetMeanItsClsSizeRequire", true, "Require minGetMeanItsClsSize Cut"}; + Configurable cfgmaxGetMeanItsClsSizeRequire{"cfgmaxGetMeanItsClsSizeRequire", true, "Require maxGetMeanItsClsSize Cut"}; + + // ---- He4-specific configurables ----------------------------------------- + Configurable cfghe3massrejreq{"cfghe3massrejreq", true, "Require mass cut on He4 particles"}; + Configurable cfgminmassrejection{"cfgminmassrejection", 6.5, "Min side of He3 particle rejection"}; + Configurable cfgmaxmassrejection{"cfgmaxmassrejection", 9.138, "Max side of He3 particle rejection"}; + Configurable deuteronsigmarejection{"deuteronsigmarejection", 2.0f, "Deuteron TPC nsigma rejection for He4"}; + + // ---- MC-only configurables ----------------------------------------------- + Configurable cfgmccorrectionhe4Require{"cfgmccorrectionhe4Require", true, "MC correction for pp he4 particle"}; + + // ---- DCA cut configurables ------------------------------------------------- + Configurable cfgUseDCAxyCorrection{"cfgUseDCAxyCorrection", true, "Use pT-dependent DCAxy cut"}; + Configurable cfgUseDCAzCorrection{"cfgUseDCAzCorrection", true, "Use pT-dependent DCAz cut"}; + Configurable cfgMultiplyTransportPt{"cfgMultiplyTransportPt", true, "In the DCA templates (processDCA), double the reconstructed pT for transport (material) secondaries; if false, use pT as reconstructed"}; + + // ---- Misc configurables ----------------------------------------------------- + Configurable cfgDebug{"cfgDebug", 1, "debug level"}; + Configurable cfgRigidityCorrection{"cfgRigidityCorrection", false, "apply rigidity correction"}; + Configurable cfgRequirebetaplot{"cfgRequirebetaplot", true, "Require beta plot"}; + Configurable cfgmass2{"cfgmass2", true, "Fill mass square difference"}; + Configurable cfgFillmass{"cfgFillmass", false, "Fill mass histograms"}; + Configurable cfgFillmassnsigma{"cfgFillmassnsigma", true, "Fill mass vs nsigma histograms"}; + + // ---- Table-valued configurables (species x parameter) ------------------ + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {kBetheBlochDefault[0].data(), NParticles, NBetheParams, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgTrackPIDsettings{"cfgTrackPIDsettings", {kTrackPIDSettings[0].data(), NParticles, NTrkSettings, particleNames, trackPIDsettingsNames}, "track selection and PID criteria"}; + Configurable> cfgTrackPIDsettings2{"cfgTrackPIDsettings2", {kTrackPIDSettings2[0].data(), NParticles, NTrkSettings2, particleNames, trackPIDsettingsNames2}, "track selection and PID criteria"}; + Configurable> cfgktrackcorrection{"cfgktrackcorrection", {ktrackcorrection[0].data(), NFittingParticle, NFittingParameters, correctedparticleNames, trackcorrectionNames}, "fitting parameters"}; + Configurable> cfgDCAcorrection{"cfgDCAcorrection", {kDCAcorrection[0].data(), NDCATypes, NDCAParameters, dcaTypeNames, dcaNames}, "DCA parameters: DCAxy: p0*exp(p1*pt)+p2, DCAz: p0*exp(-p1*pt)+p2"}; + + o2::track::TrackParametrizationWithError mTrackParCov; + + // ---- Binning configuration ----------------------------------------------- + ConfigurableAxis axisMagField{"axisMagField", {10, -10., 10.}, "magnetic field"}; + ConfigurableAxis axisNev{"axisNev", {10, 0., 10.}, "Number of events"}; + ConfigurableAxis axisRigidity{"axisRigidity", {4000, -10., 10.}, "#it{p}^{TPC}/#it{z}"}; + ConfigurableAxis axisdEdx{"axisdEdx", {4000, 0, 4000}, "d#it{E}/d#it{x}"}; + ConfigurableAxis axisCent{"axisCent", {100, 0, 100}, "centrality"}; + ConfigurableAxis axisOccupancy{"axisOccupancy", {5000, 0, 50000}, "axis for Occupancy of event"}; + ConfigurableAxis axisVtxZ{"axisVtxZ", {120, -20, 20}, "z"}; + ConfigurableAxis ptAxis{"ptAxis", {200, 0, 10}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axiseta{"axiseta", {100, -1, 1}, "eta"}; + ConfigurableAxis axisrapidity{"axisrapidity", {100, -2, 2}, "rapidity"}; + ConfigurableAxis axismass{"axismass", {1200, 0, 12}, "mass"}; + ConfigurableAxis axismassnsigma{"axismassnsigma", {1200, 0, 12}, "nsigma mass"}; + ConfigurableAxis nsigmaAxis{"nsigmaAxis", {160, -10, 10}, "n#sigma_{#pi^{+}}"}; + ConfigurableAxis axisDCA{"axisDCA", {400, -10., 10.}, "DCA axis"}; + ConfigurableAxis particleAntiAxis{"particleAntiAxis", {2, -0.5, 1.5}, "Particle/Anti-particle"}; // 0 = particle, 1 = anti-particle + ConfigurableAxis decayTypeAxis{"decayTypeAxis", {3, -0.5, 2.5}, "Decay type"}; // 0 = primary, 1 = from decay, 2 = material + + // ---- CCDB ------------------------------------------------------------------- + Service ccdb; + Configurable bField{"bField", -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"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable pidPath{"pidPath", "", "Path to the PID response object"}; + + std::vector primaryParticles; + std::vector primVtx, cents; + bool collHasCandidate = false; + bool collPassedEvSel = false; + int mRunNumber = 0; + int occupancy = 0; + float dBz = 0.0f; + TRandom3 rand; + + // Species indices into primaryParticles / particlePdgCodes (order fixed by particleNames above). + const float proton = 1; + const float he3 = 4; + const float he4 = 5; + + //---------------------------------------------------------------------------------------------------------------- + void init(InitContext const&) + { + mRunNumber = 0; + dBz = 0; + rand.SetSeed(0); + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + for (int i = 0; i < NParticles; i++) { + primaryParticles.push_back(PrimParticles(particleNames.at(i), particlePdgCodes.at(i), particleMasses.at(i), particleCharge.at(i), cfgBetheBlochParams)); + } + + if (doprocessData) { + histos.add("histNev", "histNev", kTH1F, {axisNev}); + histos.add("histVtxZ", "histVtxZ", kTH1F, {axisVtxZ}); + histos.add("histCentFT0C", "histCentFT0C", kTH1F, {axisCent}); + histos.add("histCentFT0M", "histCentFT0M", kTH1F, {axisCent}); + histos.add("histCentFTOC_cut", "histCentFTOC_cut", kTH1F, {axisCent}); + histos.add("hSpectra", " ", HistType::kTHnSparseF, {ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent}); + histos.add("hSpectratof", " ", HistType::kTHnSparseF, {ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent}); + histos.add("DCAxy_vs_pT_data", "DCA_{xy} vs p_{T} for He3 (Data);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + histos.add("DCAxy_vs_pT_anti_data", "DCA_{xy} vs p_{T} for anti-He3 (Data);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + + hmass.resize(2 * NParticles + 2); + hmassnsigma.resize(2 * NParticles + 2); + + for (int i = 0; i < NParticles; i++) { + TString histName = primaryParticles[i].name; + if (cfgFillmass) { + hmass[2 * i] = histos.add(Form("histmass_pt/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); + hmass[2 * i + 1] = histos.add(Form("histmass_ptanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); + } + } + for (int i = 0; i < NParticles; i++) { + TString histName = primaryParticles[i].name; + if (cfgFillmassnsigma) { + hmassnsigma[2 * i] = histos.add(Form("histmass_nsigma/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}/z^{2}; Centrality(%)", HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}); + hmassnsigma[2 * i + 1] = histos.add(Form("histmass_nsigmaanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}/z^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}); + } + } + + histos.add("histeta", "histeta", kTH1F, {axiseta}); + histos.add("histEvents", "histEvents", kTH2F, {axisCent, axisOccupancy}); + } + + histos.add("dcaZ", "dcaZ", kTH2F, {ptAxis, axisDCA}); + histos.add("dcaXY", "dcaXY", kTH2F, {ptAxis, axisDCA}); + histos.add("Tofsignal", "Tofsignal", kTH2F, {axisRigidity, {4000, 0.2, 1.2, "#beta"}}); + histos.add("Tpcsignal", "Tpcsignal", kTH2F, {axisRigidity, axisdEdx}); + + if (doprocessMC) { + histomc.add("hSpectramc", " ", HistType::kTHnSparseF, {particleAntiAxis, axisCent, ptAxis, ptAxis}); + + // Efficiency x Acceptance + histomc.add("hDenomEffAcc", "Denominator for Efficiency x Acceptance", + {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); + histomc.add("hNumerEffAcc", "Numerator for Efficiency x Acceptance", + {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); + + // Signal loss correction + histomc.add("hSignalLossDenom", "Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); + histomc.add("hSignalLossNumer", "Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); + histomc.add("haSignalLossDenom", "anti particle Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); + histomc.add("haSignalLossNumer", "antiparticle Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); + + // Event loss correction + histomc.add("hEventLossDenom", "Event loss denominator", kTH1F, {axisCent}); + histomc.add("hEventLossNumer", "Event loss numerator", kTH1F, {axisCent}); + + histomc.add("histVtxZgen", "histVtxZgen", kTH1F, {axisVtxZ}); + histomc.add("histVtxZReco", "histVtxZReco", kTH1F, {axisVtxZ}); + + histomc.add("histDeltaPtVsPtGenanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histDeltaPtVsPtGen", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histPIDtrack", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); + histomc.add("histPIDtrackanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); + + // Mass^2/z^2 3D plots for MC (pT, mass^2/z^2, centrality) - separate for particles and anti-particles + histomc.add("hMassVsPtMC", "mass^{2}/z^{2} vs p_{T} (MC Particles);p_{T} (GeV/c);mass^{2}/z^{2};Centrality", + {HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}}); + histomc.add("hMassVsPtAntiMC", "mass^{2}/z^{2} vs p_{T} (MC Anti-particles);p_{T} (GeV/c);mass^{2}/z^{2};Centrality", + {HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}}); + } + + if (doprocessDCA) { + histomc.add("DCAxy_vs_pT_primary", "DCA_{xy} vs p_{T} (primary);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + histomc.add("DCAxy_vs_pT_weakdecay", "DCA_{xy} vs p_{T} (Weak Decay);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + histomc.add("DCAxy_vs_pT_transport", "DCA_{xy} vs p_{T} (Transport);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + histomc.add("DCAxy_vs_pT_anti_primary", "DCA_{xy} vs p_{T} for anti (primary);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + histomc.add("DCAxy_vs_pT_anti_weakdecay", "DCA_{xy} vs p_{T} for anti (Weak Decay);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + histomc.add("DCAxy_vs_pT_anti_transport", "DCA_{xy} vs p_{T} for anti (Transport);p_{T} (GeV/c);DCA_{xy} (cm)", + {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); + } + } + + //==================================================================================== + // processData: reconstructed data, fills TPC(+TOF) PID spectra and DCA/mass QA + //==================================================================================== + void processData(CollisionsFull const& collisions, + TracksFull const& tracks, + aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + initCollision(collision); + + if (!collPassedEvSel) + continue; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + continue; + histos.fill(HIST("histNev"), 2.5); + + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + histos.fill(HIST("histNev"), 3.5); + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + continue; + + histos.fill(HIST("histNev"), 4.5); + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; + histos.fill(HIST("histNev"), 5.5); + histos.fill(HIST("histEvents"), collision.centFT0C(), occupancy); + histos.fill(HIST("histVtxZ"), collision.posZ()); + histos.fill(HIST("histCentFT0C"), collision.centFT0C()); + histos.fill(HIST("histCentFT0M"), collision.centFT0M()); + if (collision.centFT0C() > centcut) + continue; + histos.fill(HIST("histNev"), 6.5); + histos.fill(HIST("histCentFTOC_cut"), collision.centFT0C()); + + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + for (const auto& track : tracksInColl) { + if (!passesBasicRecoTrackCuts(track)) + continue; + + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) + continue; + + float ptMomn = computeSpeciesPt(track, i); + float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) + continue; + + int sign = (track.sign() > 0) ? 1 : ((track.sign() < 0) ? -1 : 0); + float rapidity = getRapidity(track, i); + if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) + continue; + + if (!passesTrackQualityCuts(track, i)) + continue; + if (!passesDCACuts(track, i, ptMomn)) + continue; + + float itsSigma = getITSnSigma(track, primaryParticles.at(i)); + if (itsSigma < cfgTrackPIDsettings2->get(i, "minITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) + continue; + if (itsSigma > cfgTrackPIDsettings2->get(i, "maxITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) + continue; + + histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); + histos.fill(HIST("dcaXY"), ptMomn, track.dcaXY()); + histos.fill(HIST("dcaZ"), ptMomn, track.dcaZ()); + + float tofnsigma = getTOFnSigma(track, primaryParticles.at(i)); + if (track.sign() > 0) { + histos.fill(HIST("DCAxy_vs_pT_data"), ptMomn, track.dcaXY(), collision.centFT0C()); + } else if (track.sign() < 0) { + histos.fill(HIST("DCAxy_vs_pT_anti_data"), ptMomn, track.dcaXY(), collision.centFT0C()); + } + + // He4 selection uses the deuteron TPC nsigma to reject deuterons. + float tpcNsigmaDe = track.tpcNSigmaDe(); + + if (i != he4) { + histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); + if (track.hasTOF()) { + histos.fill(HIST("hSpectratof"), ptMomn, tofnsigma, sign, collision.centFT0C()); + } + } else if (!track.hasTOF()) { + if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { + histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); + } + } else { + // Has TOF - apply He4 mass rejection. + float beta = o2::pid::tof::Beta::GetBeta(track); + const float eps = 1e-6f; + if (beta < eps || beta > 1.0f - eps) + continue; + + float charge = 2.f; // he4 has charge 2 + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) { + continue; // reject He4 mass window + } + if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { + histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); + } + } + + if (std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF")) { + if (i == he4) { + if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { + fillhmassnsigma(track, i, collision.centFT0C()); + } + } else { + fillhmassnsigma(track, i, collision.centFT0C()); + } + } + + if ((std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF")) && cfgTrackPIDsettings2->get(i, "useTPCnsigmaTOF") < 1) + continue; + + if (i == he4) { + if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { + fillhmass(track, i, collision.centFT0C()); + } + } else if (i == proton && (std::abs(tofnsigma) < cfgTrackPIDsettings2->get(i, "maxTOFnsigma"))) { + fillhmassnsigma(track, i, collision.centFT0C()); + } else { + fillhmass(track, i, collision.centFT0C()); + } + + if (cfgRequirebetaplot) { + histos.fill(HIST("Tofsignal"), getRigidity(track) * track.sign(), o2::pid::tof::Beta::GetBeta(track)); + } + } // species loop + + histos.fill(HIST("histeta"), track.eta()); + } // track loop + } // collision loop + } + PROCESS_SWITCH(NucleitpcPbPb, processData, "data analysis", false); + + //==================================================================================== + // processMC: MC reco+gen, for efficiency x acceptance, signal-loss and event-loss + //==================================================================================== + struct McCollInfo { + bool passedEvSel = false; + float centrality = -1.0f; + bool passedEvSelVtZ = false; + }; + std::vector mcCollInfos; + + void processMC(CollisionsFullMC const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& tracks, + aod::McParticles const& particlesMC, + aod::BCsWithTimestamps const&) + { + mcCollInfos.clear(); + mcCollInfos.resize(mcCollisions.size()); + + // ---- Pass 1: store centrality and event-selection flags per MC collision ---- + for (auto const& collision : collisions) { + int mcCollIdx = collision.mcCollisionId(); + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { + continue; + } + + mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); // stored without cuts + + if (!collision.sel8() && cfgsel8Require) + continue; + if (collision.centFT0C() > centcut) + continue; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + continue; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + continue; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; + + mcCollInfos[mcCollIdx].passedEvSel = true; + + if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) + continue; + mcCollInfos[mcCollIdx].passedEvSelVtZ = true; + } + + // ---- Event-loss and signal-loss denominators/numerators ---- + for (size_t i = 0; i < mcCollInfos.size(); i++) { + if (mcCollInfos[i].centrality < 0) + continue; // no matching reconstructed collision found + + histomc.fill(HIST("hEventLossDenom"), mcCollInfos[i].centrality); + if (mcCollInfos[i].passedEvSel) { + histomc.fill(HIST("hEventLossNumer"), mcCollInfos[i].centrality); + } + + for (auto const& mcParticle : particlesMC) { + if (mcParticle.mcCollisionId() != static_cast(i)) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + + int particleType = findParticleTypeIndex(mcParticle.pdgCode()); + if (!speciesEnabled(particleType)) + continue; + + if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { + histomc.fill(HIST("hSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); + } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { + histomc.fill(HIST("haSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); + } + + if (mcCollInfos[i].passedEvSel) { + if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { + histomc.fill(HIST("hSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); + } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { + histomc.fill(HIST("haSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); + } + } + } + } + + // ---- Generated particles: efficiency x acceptance denominator, and reco pass ---- + for (auto const& mcCollision : mcCollisions) { + size_t idx = mcCollision.globalIndex(); + if (idx >= mcCollInfos.size()) + continue; + + float centrality = mcCollInfos[idx].centrality; + bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; + + histomc.fill(HIST("histVtxZgen"), mcCollision.posZ()); + + for (auto const& mcParticle : particlesMC) { + if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + + int pdgCode = mcParticle.pdgCode(); + int particleType = findParticleTypeIndex(pdgCode); + if (!speciesEnabled(particleType)) + continue; + + if (std::abs(mcParticle.eta()) > cfgCutEta && cfgetaRequireMC) + continue; + float rapidity = mcParticle.y(); + if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequireMC) + continue; + + int particleAnti = (pdgCode > 0) ? 0 : 1; + int decayType = classifyDecayType(mcParticle); + if (decayType == DecayTypeTransport) + continue; // transported secondaries are not part of the denominator + + if (passedEvSelVtZ) { + histomc.fill(HIST("hDenomEffAcc"), mcParticle.pt(), centrality, particleAnti, decayType); + } + } + + if (!passedEvSelVtZ) + continue; + + // ---- Find the reconstructed collision matching this MC collision ---- + for (auto const& collision : collisions) { + if (collision.mcCollisionId() != static_cast(idx)) + continue; + + auto bc = collision.bc_as(); + initCCDB(bc); + histomc.fill(HIST("histVtxZReco"), collision.posZ()); + + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + for (auto const& track : tracksInColl) { + if (!track.has_mcParticle()) + continue; // skip un-matched reco tracks + + auto const& matchedMCParticle = track.mcParticle_as(); + if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + + int pdg = matchedMCParticle.pdgCode(); + int decayType = classifyDecayType(matchedMCParticle); + + if (!passesBasicRecoTrackCuts(track)) + continue; + + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) + continue; + if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) + continue; + + float ptReco = computeSpeciesPt(track, i); + ptReco = applyHe34PtCorrection(track, pdg, i, ptReco); + + int particleAnti = (pdg > 0) ? 0 : 1; + + float rapidity = getRapidity(track, i); + if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) + continue; + + if (!passesTrackQualityCuts(track, i)) + continue; + if (!passesDCACuts(track, i, ptReco)) + continue; + + float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + bool passesNsigma = !((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire); + + // Single fill per track: axis 2 (pTReco) always gets the reco pT, + // with all cuts applied except TPC nsigma and hasTOF -- this is + // the denominator population for the TOF matching efficiency. + // Axis 3 (pTOF) gets the same pT value only for tracks that both + // pass the TPC nsigma cut and have TOF -- the numerator + // population -- otherwise it gets a sentinel (-1, landing in the + // pTOF axis underflow bin since ptAxis starts at 0) so it's + // excluded from any real-pT projection of that axis. Filling + // once (not twice) avoids double-counting TOF-matched tracks in + // the pTReco axis relative to non-matched tracks. + bool isTOFmatched = passesNsigma && track.hasTOF(); + float ptTOF = isTOFmatched ? ptReco : -1.0f; + histomc.fill(HIST("hSpectramc"), particleAnti, collision.centFT0C(), ptReco, ptTOF); + + if (!passesNsigma) + continue; + + // Efficiency x Acceptance numerator (only after the TPC nsigma cut). + histomc.fill(HIST("hNumerEffAcc"), ptReco, collision.centFT0C(), particleAnti, decayType); + + if (decayType == DecayTypePrimary) { + histos.fill(HIST("dcaXY"), ptReco, track.dcaXY()); + histos.fill(HIST("dcaZ"), ptReco, track.dcaZ()); + histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); + } + + float ptGen = matchedMCParticle.pt(); + float deltaPt = ptReco - ptGen; + if (pdg == -particlePdgCodes.at(i) && decayType == DecayTypePrimary) { // anti-particle + histomc.fill(HIST("histDeltaPtVsPtGenanti"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrackanti"), ptReco, track.pidForTracking()); + } + if (pdg == particlePdgCodes.at(i) && decayType == DecayTypePrimary) { // particle + histomc.fill(HIST("histDeltaPtVsPtGen"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrack"), ptReco, track.pidForTracking()); + } + + // Mass^2/z^2 for MC, split by particle/anti-particle. + if (track.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(track); + const float eps = 1e-6f; + if (beta >= eps && beta <= 1.0f - eps) { + float charge = (i == he3 || i == he4) ? 2.f : 1.f; + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); + + bool skipHe4 = (std::abs(pdg) == particlePdgCodes.at(5)) && cfghe3massrejreq && + (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection); + + if (!skipHe4 && decayType == DecayTypePrimary) { + if (pdg > 0) { + histomc.fill(HIST("hMassVsPtMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); + } else { + histomc.fill(HIST("hMassVsPtAntiMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); + } + } + } + } + } // species loop + } // track loop + break; // matching reconstructed collision found and processed + } // collision loop + } // mcCollision loop + } + PROCESS_SWITCH(NucleitpcPbPb, processMC, "MC reco+gen analysis with efficiency corrections", false); + + //==================================================================================== + // processDCA: MC reco, builds DCAxy templates (primary / weak-decay / transport) + // used for the secondary-contamination correction. Note: no DCA cut is applied + // here, since the DCA distribution itself is what is being measured. + //==================================================================================== + void processDCA(CollisionsFullMC const& collisions, + aod::McCollisions const& mcCollisions, + aod::McParticles const& particlesMC, + soa::Join const& tracks, + aod::BCsWithTimestamps const&) + { + (void)particlesMC; + mcCollInfos.clear(); + mcCollInfos.resize(mcCollisions.size()); + + for (auto const& collision : collisions) { + int mcCollIdx = collision.mcCollisionId(); + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { + continue; + } + + mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); + + if (!collision.sel8() && cfgsel8Require) + continue; + if (collision.centFT0C() > centcut) + continue; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + continue; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + continue; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; + + mcCollInfos[mcCollIdx].passedEvSel = true; + + if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) + continue; + mcCollInfos[mcCollIdx].passedEvSelVtZ = true; + } + + for (auto const& mcCollision : mcCollisions) { + size_t idx = mcCollision.globalIndex(); + if (idx >= mcCollInfos.size()) + continue; + if (!mcCollInfos[idx].passedEvSelVtZ) + continue; + + for (auto const& collision : collisions) { + if (collision.mcCollisionId() != static_cast(idx)) + continue; + + auto bc = collision.bc_as(); + initCCDB(bc); + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + + for (auto const& track : tracksInColl) { + if (!track.has_mcParticle()) + continue; + + auto const& matchedMCParticle = track.mcParticle_as(); + if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + + int pdg = matchedMCParticle.pdgCode(); + if (!passesBasicRecoTrackCuts(track)) + continue; + + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) + continue; + if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) + continue; + + float ptReco = computeSpeciesPt(track, i); + ptReco = applyHe34PtCorrection(track, pdg, i, ptReco); + + float rapidity = getRapidity(track, i); + if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) + continue; + + if (!passesTrackQualityCuts(track, i)) + continue; + + float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) + continue; + + // Decay-origin classification specific to the DCA-template building: + // physical primaries and weak decays (via getProcess()==kPDecay) are + // distinguished from transport/material secondaries. + int decayType = -999; + if (matchedMCParticle.isPhysicalPrimary()) { + decayType = DecayTypePrimary; + if (matchedMCParticle.has_mothers()) { + for (const auto& motherparticle : matchedMCParticle.mothers_as()) { + if (std::find(hfMothCodes.begin(), hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { + decayType = DecayTypeWeak; + break; + } + } + } + } else if (matchedMCParticle.getProcess() == TMCProcess::kPDecay) { + if (!matchedMCParticle.has_mothers()) { + continue; // secondaries from weak decay without mothers are skipped + } + decayType = DecayTypeWeak; + } else { + decayType = DecayTypeTransport; + } + + // Transport (material) secondaries optionally get their reconstructed + // pT doubled for the DCA template, per cfgMultiplyTransportPt; primary + // and weak-decay secondaries always use pT as reconstructed. + float ptTransport = cfgMultiplyTransportPt ? 2.f * ptReco : ptReco; + + if (pdg == particlePdgCodes.at(i)) { // particle + if (decayType == DecayTypePrimary) { + histomc.fill(HIST("DCAxy_vs_pT_primary"), ptReco, track.dcaXY(), collision.centFT0C()); + } else if (decayType == DecayTypeWeak) { + histomc.fill(HIST("DCAxy_vs_pT_weakdecay"), ptReco, track.dcaXY(), collision.centFT0C()); + } else if (decayType == DecayTypeTransport) { + histomc.fill(HIST("DCAxy_vs_pT_transport"), ptTransport, track.dcaXY(), collision.centFT0C()); + } + } else if (pdg == -particlePdgCodes.at(i)) { // anti-particle + if (decayType == DecayTypePrimary) { + histomc.fill(HIST("DCAxy_vs_pT_anti_primary"), ptReco, track.dcaXY(), collision.centFT0C()); + } else if (decayType == DecayTypeWeak) { + histomc.fill(HIST("DCAxy_vs_pT_anti_weakdecay"), ptReco, track.dcaXY(), collision.centFT0C()); + } else if (decayType == DecayTypeTransport) { + histomc.fill(HIST("DCAxy_vs_pT_anti_transport"), ptTransport, track.dcaXY(), collision.centFT0C()); + } + } + } // species loop + } // track loop + break; // matching reconstructed collision found and processed + } // collision loop + } // mcCollision loop + } + PROCESS_SWITCH(NucleitpcPbPb, processDCA, "MC DCA analysis For secondary correction", false); + + //==================================================================================== + // Shared per-track helper cuts (extracted from the near-identical blocks that used + // to be duplicated across processData / processMC / processDCA). + //==================================================================================== + + /// Basic reconstructed-track quality gate: PV contributor, has TPC, ITS/TPC refit, + /// eta acceptance. Identical requirement in all three process functions. + template + bool passesBasicRecoTrackCuts(T const& track) + { + if (!track.isPVContributor() && cfgUsePVcontributors) + return false; + if (!track.hasTPC()) + return false; + if (!track.passedITSRefit() && cfgPassedITSRefit) + return false; + if (!track.passedTPCRefit() && cfgPassedTPCRefit) + return false; + if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) + return false; + return true; + } + + /// Species-dependent TPC/ITS cluster-quality cuts (no DCA cut here -- processDCA + /// deliberately does not cut on DCA since it is measuring the DCA distribution). + template + bool passesTrackQualityCuts(T const& track, size_t i) + { + if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) + return false; + if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || + track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && + cfgTPCNClsCrossedRowsRequire) + return false; + if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) + return false; + if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) + return false; + if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) + return false; + double cosheta = std::cosh(track.eta()); + if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) + return false; + if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) + return false; + if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) + return false; + if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) + return false; + return true; + } + + /// pT-dependent DCAxy/DCAz cuts: sigma(pt) = p0*exp(+/-p1*pt) + p2, scaled by the + /// per-species sigma factor. Used by processData and processMC (not processDCA). + template + bool passesDCACuts(T const& track, size_t i, float pt) + { + double dcaXYp0 = cfgDCAcorrection->get(0U, "p0"); + double dcaXYp1 = cfgDCAcorrection->get(0U, "p1"); + double dcaXYp2 = cfgDCAcorrection->get(0U, "p2"); + double dcaZp0 = cfgDCAcorrection->get(1U, "p0"); + double dcaZp1 = cfgDCAcorrection->get(1U, "p1"); + double dcaZp2 = cfgDCAcorrection->get(1U, "p2"); + + bool insideDCAxy; + if (cfgUseDCAxyCorrection) { + double sigma = cfgTrackPIDsettings->get(i, "maxDcaXY") * (dcaXYp0 * std::exp(dcaXYp1 * pt) + dcaXYp2); + insideDCAxy = std::abs(track.dcaXY()) <= sigma; + } else { + insideDCAxy = std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY"); + } + + bool insideDCAz; + if (cfgUseDCAzCorrection) { + double sigma = cfgTrackPIDsettings->get(i, "maxDcaZ") * (dcaZp0 * std::exp(-dcaZp1 * pt) + dcaZp2); + insideDCAz = std::abs(track.dcaZ()) <= sigma; + } else { + insideDCAz = std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ"); + } + + return insideDCAxy && insideDCAz; + } + + /// Base candidate pT for species i: He3/He4 have charge 2, so the tracking pT + /// (computed for charge 1) is doubled. + template + float computeSpeciesPt(T const& track, size_t i) + { + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + return (i == he3 || i == he4) ? 2.f * mTrackParCov.getPt() : mTrackParCov.getPt(); + } + + /// MC-only pT correction for He3/He4 reconstructed tracks (empirical a/b/c + /// parameterisation per species/charge, plus an antitriton-mistag correction + /// for He3). No-op when cfgmccorrectionhe4Require is false or species is + /// neither He3 nor He4. + template + float applyHe34PtCorrection(T const& track, int pdg, size_t i, float ptIn) + { + if (!cfgmccorrectionhe4Require) + return ptIn; + + double a = 0, b = 0, c = 0; + int param = -1; + if (i == he3) { + param = (pdg > 0) ? 0 : 1; + } else if (i == he4) { + param = (pdg > 0) ? 2 : 3; + } + if (param >= 0) { + a = cfgktrackcorrection->get(param, "a"); + b = cfgktrackcorrection->get(param, "b"); + c = cfgktrackcorrection->get(param, "c"); + } + + float ptOut = ptIn; + if (std::abs(pdg) == particlePdgCodes.at(5)) { // He4/alpha + ptOut = ptOut + a + b * std::exp(c * ptOut); + } + if (std::abs(pdg) == particlePdgCodes.at(4)) { // He3/helion, antitriton-mistag correction + constexpr int AntiTritonPid = 6; + if (track.pidForTracking() == AntiTritonPid) { + ptOut = ptOut - a + b * ptOut - c * ptOut * ptOut; + } + } + return ptOut; + } + + /// Look up the primaryParticles/particlePdgCodes index matching an (MC) pdg code, + /// or -1 if none of the configured species match. + int findParticleTypeIndex(int pdgCode) + { + for (size_t j = 0; j < primaryParticles.size(); j++) { + if (std::abs(pdgCode) == std::abs(particlePdgCodes.at(j))) + return static_cast(j); + } + return -1; + } + + /// True if particleType is a valid species index with fillsparsh enabled. + bool speciesEnabled(int particleType) + { + return particleType >= 0 && cfgTrackPIDsettings2->get(particleType, "fillsparsh") == 1; + } + + /// Decay-origin classification shared by processMC's generated-particle loop and + /// reconstructed-track loop (identical logic in both places). + template + int classifyDecayType(McPart const& mcPart) + { + int decayType; + if (mcPart.isPhysicalPrimary()) { + decayType = DecayTypePrimary; + if (mcPart.has_mothers()) { + for (const auto& motherparticle : mcPart.template mothers_as()) { + if (std::find(hfMothCodes.begin(), hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { + decayType = DecayTypeWeak; + break; + } + } + } + } else if (mcPart.has_mothers()) { + decayType = DecayTypeWeak; + } else { + decayType = DecayTypeTransport; + } + return decayType; + } + + //==================================================================================== + // CCDB / event / mass-histogram helper functions + //==================================================================================== + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + constexpr float InvalidBField = -990.f; + auto run3grpTimestamp = bc.timestamp(); + dBz = 0; + auto* grpo = ccdb->getForTimeStamp(grpPath, run3grpTimestamp); + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (bField < InvalidBField) { + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + dBz = bField; + } + } else { + auto* grpmag = ccdb->getForTimeStamp(grpmagPath, run3grpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grpTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (bField < InvalidBField) { + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } else { + dBz = bField; + } + } + mRunNumber = bc.runNumber(); + } + + template + void initCollision(const T& collision) + { + collHasCandidate = false; + histos.fill(HIST("histNev"), 0.5); + collPassedEvSel = collision.sel8() && std::abs(collision.posZ()) < cfgZvertex; + occupancy = collision.trackOccupancyInTimeRange(); + if (collPassedEvSel) { + histos.fill(HIST("histNev"), 1.5); + } + primVtx.assign({collision.posX(), collision.posY(), collision.posZ()}); + cents.assign({collision.centFT0A(), collision.centFT0C(), collision.centFT0M()}); + } + + template + void fillhmass(T const& track, int species, float cent) + { + if (!track.hasTOF() || !cfgFillmass) + return; + + float beta{o2::pid::tof::Beta::GetBeta(track)}; + const float eps = 1e-6f; + if (beta < eps || beta > 1.0f - eps) + return; + + float charge = (species == he3 || species == he4) ? 2.f : 1.f; + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + + if (species == he4 && cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) + return; + + float massDiff = cfgmass2 ? (massTOF * massTOF) / (charge * charge) : massTOF / charge; + + float ptMomn = computeSpeciesPt(track, species); + if (track.sign() > 0) { + hmass[2 * species]->Fill(ptMomn, massDiff, cent); + } else if (track.sign() < 0) { + hmass[2 * species + 1]->Fill(ptMomn, massDiff, cent); + } + } + + template + void fillhmassnsigma(T const& track, int species, float cent) + { + if (!track.hasTOF() || !cfgFillmassnsigma) + return; + + float beta{o2::pid::tof::Beta::GetBeta(track)}; + const float eps = 1e-6f; + if (beta < eps || beta > 1.0f - eps) + return; + + float charge = (species == he3 || species == he4) ? 2.f : 1.f; + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); + + if (species == he4 && cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) + return; + + float ptMomn = computeSpeciesPt(track, species); + if (track.sign() > 0) { + hmassnsigma[2 * species]->Fill(ptMomn, massSquareOverChargeSquare, cent); + } else if (track.sign() < 0) { + hmassnsigma[2 * species + 1]->Fill(ptMomn, massSquareOverChargeSquare, cent); + } + } + + //==================================================================================== + // PID / kinematics helper functions + //==================================================================================== + + template + float getTPCnSigma(T const& track, PrimParticles& particle) + { + const float rigidity = getRigidity(track); + if (!track.hasTPC()) + return -999; + if (particle.name == "pion" && cfgTrackPIDsettings->get("pion", "useBBparams") < 1) + return cfgTrackPIDsettings->get("pion", "useBBparams") == 0 ? track.tpcNSigmaPi() : 0; + if (particle.name == "proton" && cfgTrackPIDsettings->get("proton", "useBBparams") < 1) + return cfgTrackPIDsettings->get("proton", "useBBparams") == 0 ? track.tpcNSigmaPr() : 0; + if (particle.name == "deuteron" && cfgTrackPIDsettings->get("deuteron", "useBBparams") < 1) + return cfgTrackPIDsettings->get("deuteron", "useBBparams") == 0 ? track.tpcNSigmaDe() : 0; + if (particle.name == "triton" && cfgTrackPIDsettings->get("triton", "useBBparams") < 1) + return cfgTrackPIDsettings->get("triton", "useBBparams") == 0 ? track.tpcNSigmaTr() : 0; + if (particle.name == "helion" && cfgTrackPIDsettings->get("helion", "useBBparams") < 1) + return cfgTrackPIDsettings->get("helion", "useBBparams") == 0 ? track.tpcNSigmaHe() : 0; + if (particle.name == "alpha" && cfgTrackPIDsettings->get("alpha", "useBBparams") < 1) + return cfgTrackPIDsettings->get("alpha", "useBBparams") == 0 ? track.tpcNSigmaAl() : 0; + + double expBethe{common::BetheBlochAleph(static_cast(particle.charge * rigidity / particle.mass), particle.betheParams[0], particle.betheParams[1], particle.betheParams[2], particle.betheParams[3], particle.betheParams[4])}; + double expSigma{expBethe * particle.resolution}; + return static_cast((track.tpcSignal() - expBethe) / expSigma); + } + + /// TOF n-sigma for the given species, mirroring getTPCnSigma's species + /// dispatch. Returns -999 if the track has no TOF signal. + template + float getTOFnSigma(T const& track, PrimParticles& particle) + { + if (!track.hasTOF()) + return -999; + if (particle.name == "pion") + return track.tofNSigmaPi(); + if (particle.name == "proton") + return track.tofNSigmaPr(); + if (particle.name == "deuteron") + return track.tofNSigmaDe(); + if (particle.name == "triton") + return track.tofNSigmaTr(); + if (particle.name == "helion") + return track.tofNSigmaHe(); + if (particle.name == "alpha") + return track.tofNSigmaAl(); + return -999; // fallback if no match + } + + template + float getITSnSigma(T const& track, PrimParticles& particle) + { + if (!track.hasITS()) + return -999; + o2::aod::ITSResponse itsResponse; + if (particle.name == "pion") + return itsResponse.nSigmaITS(track); + if (particle.name == "proton") + return itsResponse.nSigmaITS(track); + if (particle.name == "deuteron") + return itsResponse.nSigmaITS(track); + if (particle.name == "triton") + return itsResponse.nSigmaITS(track); + if (particle.name == "helion") + return itsResponse.nSigmaITS(track); + if (particle.name == "alpha") + return itsResponse.nSigmaITS(track); + return -999; // fallback if no match + } + + template + float getMeanItsClsSize(T const& track) + { + int sum = 0, n = 0; + constexpr int NITSLayers = 8; + for (int i = 0; i < NITSLayers; i++) { + sum += (track.itsClusterSizes() >> (4 * i) & 15); + if (track.itsClusterSizes() >> (4 * i) & 15) + n++; + } + return n > 0 ? static_cast(sum) / n : 0.f; + } + + template + float getRigidity(T const& track) + { + if (!cfgRigidityCorrection) + return track.tpcInnerParam(); + bool hePID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + return hePID ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + } + + template + float getRapidity(T const& track, int species) + { + using PtEtaPhiMVector = ROOT::Math::LorentzVector>; + int speciesHe3 = 4; + int speciesHe4 = 5; + double momn = (species == speciesHe3 || species == speciesHe4) ? 2 * track.pt() : track.pt(); + PtEtaPhiMVector lorentzVectorParticle(momn, track.eta(), track.phi(), particleMasses[species]); + return lorentzVectorParticle.Rapidity(); + } +}; // end of the task here + +//---------------------------------------------------------------------------------------------------------------- +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx b/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx deleted file mode 100644 index 52dd21fdeef..00000000000 --- a/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx +++ /dev/null @@ -1,1416 +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. - -/// \file nucleitpcpbpb.cxx -/// \brief nuclei analysis -/// \note under work -/// -/// \author Jaideep Tanwar , Panjab University - -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/Core/PID/PIDTOF.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponseITS.h" -#include "Common/DataModel/PIDResponseTOF.h" -#include "Common/DataModel/PIDResponseTPC.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using CollisionsFull = soa::Join; -using TracksFull = soa::Join; -using CollisionsFullMC = soa::Join; -//--------------------------------------------------------------------------------------------------------------------------------- -namespace -{ -static const int nParticles = 6; -static const std::vector particleNames{"pion", "proton", "deuteron", "triton", "helion", "alpha"}; -static const std::vector correctedparticleNames{"helion", "antihelion", "alpha", "antialpha"}; -static const std::vector particlePdgCodes{211, 2212, o2::constants::physics::kDeuteron, o2::constants::physics::kTriton, o2::constants::physics::kHelium3, o2::constants::physics::kAlpha}; -static const std::vector particleMasses{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron, o2::constants::physics::MassTriton, o2::constants::physics::MassHelium3, o2::constants::physics::MassAlpha}; -static const std::vector particleCharge{1, 1, 1, 1, 2, 2}; -const int nBetheParams = 6; -std::vector hfMothCodes = {511, 521, 531, 541, 5122}; // b-mesons + Lambda_b -static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -constexpr double kBetheBlochDefault[nParticles][nBetheParams]{ - {13.611469, 3.598765, -0.021138, 2.039562, 0.651040, 0.09}, // pion - {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // proton - {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // deuteron - {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // triton - {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}, // helion - {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}}; // alpha -const int nTrkSettings = 13; -static const std::vector trackPIDsettingsNames{"useBBparams", "minITSnCls", "minITSnClscos", "minTPCnCls", "maxTPCchi2", "minTPCchi2", "maxITSchi2", "maxTPCnSigma", "maxDcaXY", "maxDcaZ", "minITSclsSize", "minTPCnClsCrossedRows", "minReqClusterITSib"}; -constexpr double kTrackPIDSettings[nParticles][nTrkSettings]{ - {0, 0, 4, 60, 4.0, 0.5, 100, 2.5, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 75, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}}; - -const int nTrkSettings2 = 7; -static const std::vector trackPIDsettingsNames2{"useITSnsigma", "minITSnsigma", "maxITSnsigma", "fillsparsh", "useTPCnsigmaTOF", "maxTPCnsigmaTOF", "maxTOFnsigma"}; -constexpr double kTrackPIDSettings2[nParticles][nTrkSettings2]{ - {1, -5, 4, 0, 1, 2, 2}, - {1, -5, 4, 0, 1, 2, 2}, - {1, -5, 4, 0, 1, 2, 2}, - {1, -5, 4, 1, 1, 2, 2}, - {1, -5, 4, 1, 1, 2, 2}, - {1, -5, 4, 1, 1, 2, 2}}; - -static const int nfittingparticle = 4; -const int nfittingparameters = 4; -static const std::vector trackcorrectionNames{"a", "b", "c", "d"}; -constexpr double ktrackcorrection[nfittingparticle][nfittingparameters]{ - {0.464215, 0.195771, 0.0183111, 0.0}, // He3 - {0.464215, 0.195771, 0.0183111, 0.0}, // anti-He3 - {0.00765, 0.503791, -1.10517, 0.0}, // He4 - {0.00765, 0.503791, -1.10517, 0.0}}; // anti-He4 - -// DCA parameters - simple 2x3 array (DCAxy, DCAz) with p0, p1, p2 -static const int nDCAtypes = 2; -const int nDCAparameters = 3; -static const std::vector dcaNames{"p0", "p1", "p2"}; -static const std::vector dcaTypeNames{"DCAxy", "DCAz"}; -constexpr double kDCAcorrection[nDCAtypes][nDCAparameters]{ - {0.0118, -0.6889, 0.0017}, // DCAxy: p0*exp(p1*pt) + p2 - {0.1014, 1.7512, 0.0024}}; // DCAz: p0*exp(-p1*pt) + p2 - -struct PrimParticles { - TString name; - int pdgCode, charge; - double mass, resolution; - std::vector betheParams; - bool active; - PrimParticles(std::string name_, int pdgCode_, double mass_, int charge_, LabeledArray bethe) : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) - { - resolution = bethe.get(name, "resolution"); - betheParams.clear(); - constexpr unsigned int kNSpecies = 5; - for (unsigned int i = 0; i < kNSpecies; i++) - betheParams.push_back(bethe.get(name, i)); - } -}; // struct PrimParticles - -//---------------------------------------------------------------------------------------------------------------- -std::vector> hmass; -std::vector> hmassnsigma; -} // namespace -//---------------------------------------------------------------------------------------------------------------- -struct NucleitpcPbPb { - - Preslice tracksPerCollision = aod::track::collisionId; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry histomc{"histomc", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - // Event Selection Configurables - Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove no same bunch pileup"}; - Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Require is good Zvtx FT0 vs PV"}; - Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Require is vertex ITS TPC"}; - Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove no time frame border"}; - Configurable cfgsel8Require{"cfgsel8Require", true, "sel8 cut require"}; - Configurable cfgZvertex{"cfgZvertex", 10, "Min Z Vertex"}; - - // Track Selection Configurables - Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; - Configurable cfgPassedITSRefit{"cfgPassedITSRefit", true, "Require ITS refit"}; - Configurable cfgPassedTPCRefit{"cfgPassedTPCRefit", true, "Require TPC refit"}; - Configurable cfgetaRequire{"cfgetaRequire", true, "eta cut require"}; - Configurable cfgetaRequireMC{"cfgetaRequireMC", true, "eta cut require for generated particles"}; - Configurable cfgRapidityRequire{"cfgRapidityRequire", true, "Require Rapidity cut"}; - Configurable cfgRapidityRequireMC{"cfgRapidityRequireMC", true, "rapidity cut require for generated particles"}; - Configurable cfgCutEta{"cfgCutEta", 0.9f, "Eta range for tracks"}; - Configurable cfgCutRapiditymin{"cfgCutRapiditymin", -0.5f, "min Rapidity range"}; - Configurable cfgCutRapiditymax{"cfgCutRapiditymax", 0.5f, "max Rapidity range"}; - Configurable cfgtpcNClsFindable{"cfgtpcNClsFindable", 0.8f, "tpcNClsFindable over crossedRows"}; - Configurable centcut{"centcut", 80.0f, "centrality cut"}; - Configurable cfgZvertexRequireMC{"cfgZvertexRequireMC", true, "Pos Z cut in MC"}; - - // Track Cut Configurables - Configurable cfgTPCNClsCrossedRowsRequire{"cfgTPCNClsCrossedRowsRequire", true, "Require TPCNClsCrossedRows Cut"}; - Configurable cfgmaxTPCchi2Require{"cfgmaxTPCchi2Require", true, "Require maxTPCchi2 Cut"}; - Configurable cfgminTPCchi2Require{"cfgminTPCchi2Require", true, "Require minTPCchi2 Cut"}; - Configurable cfgminITSnClsRequire{"cfgminITSnClsRequire", false, "Require minITSnCls Cut"}; - Configurable cfgminITSnClscosRequire{"cfgminITSnClscosRequire", true, "Require minITSnCls / cosh(eta) Cut"}; - Configurable cfgminReqClusterITSibRequire{"cfgminReqClusterITSibRequire", true, " Require min number of clusters required in ITS inner barrel"}; - Configurable cfgmaxITSchi2Require{"cfgmaxITSchi2Require", true, "Require maxITSchi2 Cut"}; - Configurable cfgmaxTPCnSigmaRequire{"cfgmaxTPCnSigmaRequire", true, "Require maxTPCnSigma Cut"}; - Configurable cfgminGetMeanItsClsSizeRequire{"cfgminGetMeanItsClsSizeRequire", true, "Require minGetMeanItsClsSize Cut"}; - Configurable cfgmaxGetMeanItsClsSizeRequire{"cfgmaxGetMeanItsClsSizeRequire", true, "Require maxGetMeanItsClsSize Cut"}; - - // He4 Configurables - Configurable cfghe3massrejreq{"cfghe3massrejreq", true, "Require mass cut on He4 particles"}; - Configurable cfgminmassrejection{"cfgminmassrejection", 6.5, "Min side of He3 particle rejection"}; - Configurable cfgmaxmassrejection{"cfgmaxmassrejection", 9.138, "Max side of He3 particle rejection"}; - Configurable deuteronsigmarejection{"deuteronsigmarejection", 2.0f, "Deuteron TPC nsigma rejection for He4"}; - - // MC Configurables - Configurable cfgmccorrectionhe4Require{"cfgmccorrectionhe4Require", true, "MC correction for pp he4 particle"}; - - // DCA Configurables - booleans to enable/disable pT-dependent cuts - Configurable cfgUseDCAxyCorrection{"cfgUseDCAxyCorrection", true, "Use pT-dependent DCAxy cut"}; - Configurable cfgUseDCAzCorrection{"cfgUseDCAzCorrection", true, "Use pT-dependent DCAz cut"}; - - Configurable cfgDebug{"cfgDebug", 1, "debug level"}; - Configurable cfgRigidityCorrection{"cfgRigidityCorrection", false, "apply rigidity correction"}; - Configurable cfgRequirebetaplot{"cfgRequirebetaplot", true, "Require beta plot"}; - Configurable cfgmass2{"cfgmass2", true, "Fill mass square difference"}; - Configurable cfgFillmass{"cfgFillmass", false, "Fill mass histograms"}; - Configurable cfgFillmassnsigma{"cfgFillmassnsigma", true, "Fill mass vs nsigma histograms"}; - - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {kBetheBlochDefault[0], nParticles, nBetheParams, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; - Configurable> cfgTrackPIDsettings{"cfgTrackPIDsettings", {kTrackPIDSettings[0], nParticles, nTrkSettings, particleNames, trackPIDsettingsNames}, "track selection and PID criteria"}; - Configurable> cfgTrackPIDsettings2{"cfgTrackPIDsettings2", {kTrackPIDSettings2[0], nParticles, nTrkSettings2, particleNames, trackPIDsettingsNames2}, "track selection and PID criteria"}; - Configurable> cfgktrackcorrection{"cfgktrackcorrection", {ktrackcorrection[0], nfittingparticle, nfittingparameters, correctedparticleNames, trackcorrectionNames}, "fitting parameters"}; - - // DCA correction parameters - simple 2x3 array - Configurable> cfgDCAcorrection{"cfgDCAcorrection", {kDCAcorrection[0], nDCAtypes, nDCAparameters, dcaTypeNames, dcaNames}, "DCA parameters: DCAxy: p0*exp(p1*pt)+p2, DCAz: p0*exp(-p1*pt)+p2"}; - - o2::track::TrackParametrizationWithError mTrackParCov; - // Binning configuration - ConfigurableAxis axisMagField{"axisMagField", {10, -10., 10.}, "magnetic field"}; - ConfigurableAxis axisNev{"axisNev", {10, 0., 10.}, "Number of events"}; - ConfigurableAxis axisRigidity{"axisRigidity", {4000, -10., 10.}, "#it{p}^{TPC}/#it{z}"}; - ConfigurableAxis axisdEdx{"axisdEdx", {4000, 0, 4000}, "d#it{E}/d#it{x}"}; - ConfigurableAxis axisCent{"axisCent", {100, 0, 100}, "centrality"}; - ConfigurableAxis axisOccupancy{"axisOccupancy", {5000, 0, 50000}, "axis for Occupancy of event"}; - ConfigurableAxis axisVtxZ{"axisVtxZ", {120, -20, 20}, "z"}; - ConfigurableAxis ptAxis{"ptAxis", {200, 0, 10}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis axiseta{"axiseta", {100, -1, 1}, "eta"}; - ConfigurableAxis axisrapidity{"axisrapidity", {100, -2, 2}, "rapidity"}; - ConfigurableAxis axismass{"axismass", {1200, 0, 12}, "mass"}; - ConfigurableAxis axismassnsigma{"axismassnsigma", {1200, 0, 12}, "nsigma mass"}; - ConfigurableAxis nsigmaAxis{"nsigmaAxis", {160, -10, 10}, "n#sigma_{#pi^{+}}"}; - ConfigurableAxis axisDCA{"axisDCA", {400, -10., 10.}, "DCA axis"}; - ConfigurableAxis particleAntiAxis{"particleAntiAxis", {2, -0.5, 1.5}, "Particle/Anti-particle"}; // 0 = particle, 1 = anti-particle - ConfigurableAxis decayTypeAxis{"decayTypeAxis", {3, -0.5, 2.5}, "Decay type"}; // 0 = primary, 1 = from decay, 2 = material - - // CCDB - Service ccdb; - Configurable bField{"bField", -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"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable pidPath{"pidPath", "", "Path to the PID response object"}; - - std::vector primaryParticles; - std::vector primVtx, cents; - bool collHasCandidate = false; - bool collPassedEvSel = false; - int mRunNumber = 0; - int occupancy = 0; - float dBz = 0.0f; - TRandom3 rand; - float proton = 1; - float de = 2; - float triton = 3; - float he3 = 4; - float he4 = 5; - - //---------------------------------------------------------------------------------------------------------------- - void init(InitContext const&) - { - mRunNumber = 0; - dBz = 0; - rand.SetSeed(0); - ccdb->setURL(ccdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - for (int i = 0; i < nParticles; i++) { // create primaryParticles - primaryParticles.push_back(PrimParticles(particleNames.at(i), particlePdgCodes.at(i), particleMasses.at(i), particleCharge.at(i), cfgBetheBlochParams)); - } - // create histograms - if (doprocessData) { - histos.add("histNev", "histNev", kTH1F, {axisNev}); - histos.add("histVtxZ", "histVtxZ", kTH1F, {axisVtxZ}); - histos.add("histCentFT0C", "histCentFT0C", kTH1F, {axisCent}); - histos.add("histCentFT0M", "histCentFT0M", kTH1F, {axisCent}); - histos.add("histCentFTOC_cut", "histCentFTOC_cut", kTH1F, {axisCent}); - histos.add("hSpectra", " ", HistType::kTHnSparseF, {ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent}); - histos.add("hSpectratof", " ", HistType::kTHnSparseF, {ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent}); - histos.add("DCAxy_vs_pT_data", "DCA_{xy} vs p_{T} for He3 (Data);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histos.add("DCAxy_vs_pT_anti_data", "DCA_{xy} vs p_{T} for anti-He3 (Data);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - - hmass.resize(2 * nParticles + 2); - hmassnsigma.resize(2 * nParticles + 2); - - for (int i = 0; i < nParticles; i++) { - TString histName = primaryParticles[i].name; - if (cfgFillmass) { - hmass[2 * i] = histos.add(Form("histmass_pt/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); - hmass[2 * i + 1] = histos.add(Form("histmass_ptanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); - } - } - for (int i = 0; i < nParticles; i++) { - TString histName = primaryParticles[i].name; - if (cfgFillmassnsigma) { - hmassnsigma[2 * i] = histos.add(Form("histmass_nsigma/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}/z^{2}; Centrality(%)", HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}); - hmassnsigma[2 * i + 1] = histos.add(Form("histmass_nsigmaanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}/z^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}); - } - } - - histos.add("histeta", "histeta", kTH1F, {axiseta}); - - histos.add("histEvents", "histEvents", kTH2F, {axisCent, axisOccupancy}); - } - - histos.add("dcaZ", "dcaZ", kTH2F, {ptAxis, axisDCA}); - histos.add("dcaXY", "dcaXY", kTH2F, {ptAxis, axisDCA}); - histos.add("Tofsignal", "Tofsignal", kTH2F, {axisRigidity, {4000, 0.2, 1.2, "#beta"}}); - histos.add("Tpcsignal", "Tpcsignal", kTH2F, {axisRigidity, axisdEdx}); - - if (doprocessMC) { - histomc.add("hSpectramc", " ", HistType::kTHnSparseF, {{5, -2.5, 2.5}, axisCent, ptAxis, ptAxis}); - - // Efficiency x Acceptance - histomc.add("hDenomEffAcc", "Denominator for Efficiency x Acceptance", - {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); - histomc.add("hNumerEffAcc", "Numerator for Efficiency x Acceptance", - {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); - - // The Signal loss correction - histomc.add("hSignalLossDenom", "Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); - histomc.add("hSignalLossNumer", "Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); - - histomc.add("haSignalLossDenom", "anti particle Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); - histomc.add("haSignalLossNumer", "antiparticle Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); - - // The event loss correction - histomc.add("hEventLossDenom", "Event loss denominator", kTH1F, {axisCent}); - histomc.add("hEventLossNumer", "Event loss numerator", kTH1F, {axisCent}); - - histomc.add("histVtxZgen", "histVtxZgen", kTH1F, {axisVtxZ}); - histomc.add("histVtxZReco", "histVtxZReco", kTH1F, {axisVtxZ}); - - histomc.add("histDeltaPtVsPtGenanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); - histomc.add("histDeltaPtVsPtGen", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); - histomc.add("histPIDtrack", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); - histomc.add("histPIDtrackanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); - - // Mass²/z² 3D plots for MC (pT, mass²/z², centrality) - separate for particles and anti-particles - histomc.add("hMassVsPtMC", "mass^{2}/z^{2} vs p_{T} (MC Particles);p_{T} (GeV/c);mass^{2}/z^{2};Centrality", - {HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}}); - histomc.add("hMassVsPtAntiMC", "mass^{2}/z^{2} vs p_{T} (MC Anti-particles);p_{T} (GeV/c);mass^{2}/z^{2};Centrality", - {HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}}); - } - - if (doprocessDCA) { - - // NEW: Add DCAxy vs pT histograms for MC - histomc.add("DCAxy_vs_pT_transport", "DCA_{xy} vs p_{T} (Transport);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_primary", "DCA_{xy} vs p_{T} (primary);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_weakdecay", "DCA_{xy} vs p_{T} (Weak Decay);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_total", "DCA_{xy} vs p_{T} (Total);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_anti_total", "DCA_{xy} vs p_{T} for anti (Total);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - } - } - //---------------------------------------------------------------------------------------------------------------- - void processData(CollisionsFull const& collisions, - TracksFull const& tracks, - aod::BCsWithTimestamps const&) - { - // Get DCA parameters from configurable - double dcaXY_p0 = cfgDCAcorrection->get(0U, "p0"); - double dcaXY_p1 = cfgDCAcorrection->get(0U, "p1"); - double dcaXY_p2 = cfgDCAcorrection->get(0U, "p2"); - double dcaZ_p0 = cfgDCAcorrection->get(1U, "p0"); - double dcaZ_p1 = cfgDCAcorrection->get(1U, "p1"); - double dcaZ_p2 = cfgDCAcorrection->get(1U, "p2"); - - for (const auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - initCollision(collision); - - if (!collPassedEvSel) - continue; - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - histos.fill(HIST("histNev"), 2.5); - - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - histos.fill(HIST("histNev"), 3.5); - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) - continue; - - histos.fill(HIST("histNev"), 4.5); - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - histos.fill(HIST("histNev"), 5.5); - histos.fill(HIST("histEvents"), collision.centFT0C(), occupancy); - histos.fill(HIST("histVtxZ"), collision.posZ()); - histos.fill(HIST("histCentFT0C"), collision.centFT0C()); - histos.fill(HIST("histCentFT0M"), collision.centFT0M()); - if (collision.centFT0C() > centcut) - continue; - histos.fill(HIST("histNev"), 6.5); - histos.fill(HIST("histCentFTOC_cut"), collision.centFT0C()); - // new slicing - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - // loop over sliced tracks - for (const auto& track : tracksInColl) { - if (!track.isPVContributor() && cfgUsePVcontributors) - continue; - if (!track.hasTPC()) - continue; - if (!track.passedITSRefit() && cfgPassedITSRefit) - continue; - if (!track.passedTPCRefit() && cfgPassedTPCRefit) - continue; - if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) - continue; - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - float ptMomn; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - ptMomn = (i == he3 || i == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) - continue; - int sign = (track.sign() > 0) ? 1 : ((track.sign() < 0) ? -1 : 0); - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; - if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) - continue; - if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || - track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && - cfgTPCNClsCrossedRowsRequire) - continue; - if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) - continue; - if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) - continue; - if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) - continue; - double cosheta = std::cosh(track.eta()); - if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) - continue; - if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) - continue; - if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) - continue; - if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) - continue; - - // DCAxy cut - bool insideDCAxy = false; - if (cfgUseDCAxyCorrection) { - // Use pT-dependent DCAxy cut - double sigmaFactor = cfgTrackPIDsettings->get(i, "maxDcaXY"); - double sigma_base = dcaXY_p0 * std::exp(dcaXY_p1 * ptMomn) + dcaXY_p2; - double sigma_new = sigmaFactor * sigma_base; - insideDCAxy = (std::abs(track.dcaXY()) <= sigma_new); - } else { - // Use simple DCAxy cut (no pT dependence) - insideDCAxy = (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")); - } - - // DCAz cut - bool insideDCAz = false; - if (cfgUseDCAzCorrection) { - // Use pT-dependent DCAz cut - double sigmaFactorZ = cfgTrackPIDsettings->get(i, "maxDcaZ"); - double sigma_base_z = dcaZ_p0 * std::exp(-dcaZ_p1 * ptMomn) + dcaZ_p2; - double sigma_new_z = sigmaFactorZ * sigma_base_z; - insideDCAz = (std::abs(track.dcaZ()) <= sigma_new_z); - } else { - // Use simple DCAz cut (no pT dependence) - insideDCAz = (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")); - } - - if ((!insideDCAxy || !insideDCAz)) { - continue; - } - - float itsSigma = getITSnSigma(track, primaryParticles.at(i)); - if (itsSigma < cfgTrackPIDsettings2->get(i, "minITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) - continue; - if (itsSigma > cfgTrackPIDsettings2->get(i, "maxITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) - continue; - - histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); - histos.fill(HIST("dcaXY"), ptMomn, track.dcaXY()); - histos.fill(HIST("dcaZ"), ptMomn, track.dcaZ()); - float tofnsigma = -999; - if (i == proton) { - tofnsigma = track.tofNSigmaPr(); - } - if (track.sign() > 0) { - histos.fill(HIST("DCAxy_vs_pT_data"), ptMomn, track.dcaXY(), collision.centFT0C()); - } else if (track.sign() < 0) { - histos.fill(HIST("DCAxy_vs_pT_anti_data"), ptMomn, track.dcaXY(), collision.centFT0C()); - } - // Get deuteron TPC nsigma for He4 selection - float tpcNsigmaDe = -999; - tpcNsigmaDe = track.tpcNSigmaDe(); - - if (i != he4) { - histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); - if (track.hasTOF() && i == proton) { - histos.fill(HIST("hSpectratof"), ptMomn, tofnsigma, sign, collision.centFT0C()); - } - } else { - - if (!track.hasTOF()) { - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); - } - } else { - // Has TOF - apply mass cut - float beta = o2::pid::tof::Beta::GetBeta(track); - const float eps = 1e-6f; - if (beta < eps || beta > 1.0f - eps) - continue; - - float charge = 2.f; // he4 has charge 2 - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - - // Apply mass cut for he4 (mass^2 around 3.73^2 = 13.9) - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) { - continue; // Skip if mass cut fails - } - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); - } - } - } - - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF"))) { - if (i == he4) { - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - fillhmassnsigma(track, i, collision.centFT0C()); - } - } else { - fillhmassnsigma(track, i, collision.centFT0C()); - } - } - - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF")) && cfgTrackPIDsettings2->get(i, "useTPCnsigmaTOF") < 1) - continue; - - if (i == he4) { - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - fillhmass(track, i, collision.centFT0C()); - } - } else { - if (i == proton && (std::abs(tofnsigma) < cfgTrackPIDsettings2->get(i, "maxTOFnsigma"))) { - fillhmassnsigma(track, i, collision.centFT0C()); - } else { - fillhmass(track, i, collision.centFT0C()); - } - } - - if (cfgRequirebetaplot) { - histos.fill(HIST("Tofsignal"), getRigidity(track) * track.sign(), o2::pid::tof::Beta::GetBeta(track)); - } - } // loop primaryParticles - - histos.fill(HIST("histeta"), track.eta()); - } // loop sliced tracks - } // collision loop - } - PROCESS_SWITCH(NucleitpcPbPb, processData, "data analysis", false); - - //---------------------------------------------------------------------------------------------------------------- - // MC particles - Efficiency x Acceptance and Signal Loss calculations - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - struct McCollInfo { - bool passedEvSel = false; - float centrality = -1.0f; - bool passedEvSelVtZ = false; - }; - std::vector mcCollInfos; - - void processMC(CollisionsFullMC const& collisions, - aod::McCollisions const& mcCollisions, - soa::Join const& tracks, - aod::McParticles const& particlesMC, - aod::BCsWithTimestamps const&) - - { - // Get DCA parameters from configurable - double dcaXY_p0 = cfgDCAcorrection->get(0U, "p0"); - double dcaXY_p1 = cfgDCAcorrection->get(0U, "p1"); - double dcaXY_p2 = cfgDCAcorrection->get(0U, "p2"); - double dcaZ_p0 = cfgDCAcorrection->get(1U, "p0"); - double dcaZ_p1 = cfgDCAcorrection->get(1U, "p1"); - double dcaZ_p2 = cfgDCAcorrection->get(1U, "p2"); - - mcCollInfos.clear(); - mcCollInfos.resize(mcCollisions.size()); - - // First pass: Store centrality and apply event selection - for (auto const& collision : collisions) { - int mcCollIdx = collision.mcCollisionId(); - if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { - continue; - } - - // STORE CENTRALITY WITHOUt CUTS - mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); - - if (!collision.sel8() && cfgsel8Require) - continue; - if (collision.centFT0C() > centcut) - continue; - - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) - continue; - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - - // Mark this MC collision as passing event selection - mcCollInfos[mcCollIdx].passedEvSel = true; - - // Apply event selection cuts - if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) - continue; - - mcCollInfos[mcCollIdx].passedEvSelVtZ = true; - } - - // FILL EVENT LOSS AND SIGNAL LOSS: Combined loop per MC collision - for (size_t i = 0; i < mcCollInfos.size(); i++) { - if (mcCollInfos[i].centrality >= 0) { // Only if we found a matching collision - // Event loss denominator (always filled regardless of fillsparsh) - histomc.fill(HIST("hEventLossDenom"), mcCollInfos[i].centrality); - - // Event loss numerator (if passed selection) - if (mcCollInfos[i].passedEvSel) { - histomc.fill(HIST("hEventLossNumer"), mcCollInfos[i].centrality); - } - - // Fill signal loss for all primary particles in this MC collision - for (auto const& mcParticle : particlesMC) { - if (mcParticle.mcCollisionId() != static_cast(i)) { - continue; - } - if (!mcParticle.isPhysicalPrimary()) { - continue; - } - - // Check if this particle type has fillsparsh enabled - int particleType = -1; - for (size_t j = 0; j < primaryParticles.size(); j++) { - if (std::abs(mcParticle.pdgCode()) == std::abs(particlePdgCodes.at(j))) { - particleType = j; - break; - } - } - - // Skip if fillsparsh is not enabled for this particle - if (particleType < 0 || cfgTrackPIDsettings2->get(particleType, "fillsparsh") != 1) - continue; - - // Signal loss denominator - if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { // particle - histomc.fill(HIST("hSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); - } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { // anti-particle - histomc.fill(HIST("haSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); - } - // Signal loss numerator (if event passed selection) - if (mcCollInfos[i].passedEvSel) { - if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { // particle - histomc.fill(HIST("hSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); - } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { // anti-particle - histomc.fill(HIST("haSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); - } - } - } - } - } - - // Process MC collisions for efficiency and reconstructed collisions - for (auto const& mcCollision : mcCollisions) { - size_t idx = mcCollision.globalIndex(); - if (idx >= mcCollInfos.size()) - continue; - - float centrality = mcCollInfos[idx].centrality; - bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; - - // Process generated particles for efficiency denominators - histomc.fill(HIST("histVtxZgen"), mcCollision.posZ()); - - for (auto const& mcParticle : particlesMC) { - if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; - - int pdgCode = mcParticle.pdgCode(); - - // Check which particle type this is - int particleType = -1; - for (size_t j = 0; j < primaryParticles.size(); j++) { - if (std::abs(pdgCode) == std::abs(particlePdgCodes.at(j))) { - particleType = j; - break; - } - } - - // Only process if this particle type has fillsparsh enabled - if (particleType < 0 || cfgTrackPIDsettings2->get(particleType, "fillsparsh") != 1) - continue; - - if (std::abs(mcParticle.eta()) > cfgCutEta && cfgetaRequireMC) - continue; - float rapidity = mcParticle.y(); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequireMC) - continue; - - int decayType = 0; - int particleAnti = (pdgCode > 0) ? 0 : 1; - - if (mcParticle.isPhysicalPrimary()) { - decayType = 0; - if (mcParticle.has_mothers()) { - for (const auto& motherparticle : mcParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), - std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - decayType = 1; - break; - } - } - } - } else if (mcParticle.has_mothers()) { - decayType = 1; - } else { - decayType = 2; - continue; - } - - // Efficiency x Acceptance histograms - Denominator - if (passedEvSelVtZ) { - histomc.fill(HIST("hDenomEffAcc"), mcParticle.pt(), centrality, particleAnti, decayType); - } - } - - // Process reconstructed collisions for this MC collision - if (passedEvSelVtZ) { - // Find the corresponding reconstructed collision - for (auto const& collision : collisions) { - if (collision.mcCollisionId() != static_cast(idx)) - continue; - - auto bc = collision.bc_as(); - initCCDB(bc); - - histomc.fill(HIST("histVtxZReco"), collision.posZ()); - - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - - for (auto const& track : tracksInColl) { - if (!track.has_mcParticle()) - continue; // skip un-matched reco tracks - - auto const& matchedMCParticle = track.mcParticle_as(); - - // Only process particles from this MC collision - if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; - - int pdg = matchedMCParticle.pdgCode(); - - int decayType = 0; - - if (matchedMCParticle.isPhysicalPrimary()) { - decayType = 0; - if (matchedMCParticle.has_mothers()) { - for (const auto& motherparticle : matchedMCParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), - std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - decayType = 1; - break; - } - } - } - } else if (matchedMCParticle.has_mothers()) { - decayType = 1; - } else { - decayType = 2; - } - - if (!track.isPVContributor() && cfgUsePVcontributors) - continue; - - if (!track.hasTPC()) - continue; - if (!track.passedITSRefit() && cfgPassedITSRefit) - continue; - if (!track.passedTPCRefit() && cfgPassedTPCRefit) - continue; - if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) - continue; - - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) - continue; - - // CRITICAL: Only process if fillsparsh is enabled for this particle - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - - float ptReco; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - - ptReco = (std::abs(pdg) == particlePdgCodes.at(4) || std::abs(pdg) == particlePdgCodes.at(5)) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - - int particleAnti = (pdg > 0) ? 0 : 1; - - double a = 0, b = 0, c = 0; - - int param = -1; - if (i == he3) { - param = (pdg > 0) ? 0 : 1; - } else if (i == he4) { - param = (pdg > 0) ? 2 : 3; - } - - if (param >= 0) { - a = cfgktrackcorrection->get(param, "a"); - b = cfgktrackcorrection->get(param, "b"); - c = cfgktrackcorrection->get(param, "c"); - } - - if (std::abs(pdg) == particlePdgCodes.at(5) && cfgmccorrectionhe4Require) { - ptReco = ptReco + a + b * std::exp(c * ptReco); - } - - if (std::abs(pdg) == particlePdgCodes.at(4) && cfgmccorrectionhe4Require) { - int pidGuess = track.pidForTracking(); - int antitriton = 6; - if (pidGuess == antitriton) { - ptReco = ptReco - a + b * ptReco - c * ptReco * ptReco; - } - } - - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; - - if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) - continue; - if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && cfgTPCNClsCrossedRowsRequire) - continue; - if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) - continue; - if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) - continue; - if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) - continue; - double cosheta = std::cosh(track.eta()); - if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) - continue; - if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) - continue; - if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) - continue; - if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) - continue; - - // DCAxy cut - bool insideDCAxy = false; - if (cfgUseDCAxyCorrection) { - // Use pT-dependent DCAxy cut - double sigmaFactor = cfgTrackPIDsettings->get(i, "maxDcaXY"); - double sigma_base = dcaXY_p0 * std::exp(dcaXY_p1 * ptReco) + dcaXY_p2; - double sigma_new = sigmaFactor * sigma_base; - insideDCAxy = (std::abs(track.dcaXY()) <= sigma_new); - } else { - // Use simple DCAxy cut (no pT dependence) - insideDCAxy = (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")); - } - - // DCAz cut - bool insideDCAz = false; - if (cfgUseDCAzCorrection) { - // Use pT-dependent DCAz cut - double sigmaFactorZ = cfgTrackPIDsettings->get(i, "maxDcaZ"); - double sigma_base_z = dcaZ_p0 * std::exp(-dcaZ_p1 * ptReco) + dcaZ_p2; - double sigma_new_z = sigmaFactorZ * sigma_base_z; - insideDCAz = (std::abs(track.dcaZ()) <= sigma_new_z); - } else { - // Use simple DCAz cut (no pT dependence) - insideDCAz = (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")); - } - - if ((!insideDCAxy || !insideDCAz)) { - continue; - } - - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) - continue; - - // Efficiency x Acceptance - Numerator - histomc.fill(HIST("hNumerEffAcc"), ptReco, collision.centFT0C(), particleAnti, decayType); - - // Sparse histogram - float ptTOF = -1.0; - if (track.hasTOF()) { - ptTOF = ptReco; - } - histomc.fill(HIST("hSpectramc"), particleAnti, collision.centFT0C(), ptReco, ptTOF); - - // Basic track histograms - if (decayType == 0) { - histos.fill(HIST("dcaXY"), ptReco, track.dcaXY()); - histos.fill(HIST("dcaZ"), ptReco, track.dcaZ()); - histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); - } - // Delta Pt histograms - float ptGen = matchedMCParticle.pt(); - float deltaPt = ptReco - ptGen; - - if (pdg == -particlePdgCodes.at(i) && decayType == 0) { // Anti-particle - histomc.fill(HIST("histDeltaPtVsPtGenanti"), ptReco, deltaPt); - histomc.fill(HIST("histPIDtrackanti"), ptReco, track.pidForTracking()); - } - - if (pdg == particlePdgCodes.at(i) && decayType == 0) { // Particle - histomc.fill(HIST("histDeltaPtVsPtGen"), ptReco, deltaPt); - histomc.fill(HIST("histPIDtrack"), ptReco, track.pidForTracking()); - } - - // Fill mass²/z² for MC - separate for particles and anti-particles - if (track.hasTOF()) { - float beta = o2::pid::tof::Beta::GetBeta(track); - const float eps = 1e-6f; - if (beta >= eps && beta <= 1.0f - eps) { - float charge = (i == he3 || i == he4) ? 2.f : 1.f; - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); - - // Apply He4 rejection if needed (to match data selection) - bool skipHe4 = false; - if (std::abs(pdg) == particlePdgCodes.at(5)) { // He4 - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) { - skipHe4 = true; - } - } - - if (!skipHe4 && decayType == 0) { - if (pdg > 0) { - histomc.fill(HIST("hMassVsPtMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); - } else { - histomc.fill(HIST("hMassVsPtAntiMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); - } - } - } - } - } - } - break; // Found the matching collision, break out of collision loop - } - } - } - } - PROCESS_SWITCH(NucleitpcPbPb, processMC, "MC reco+gen analysis with efficiency corrections", false); - //=-=-=-==-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - void processDCA(CollisionsFullMC const& collisions, - aod::McCollisions const& mcCollisions, - aod::McParticles const& particlesMC, - soa::Join const& tracks, - aod::BCsWithTimestamps const&) - - { - (void)particlesMC; - mcCollInfos.clear(); - mcCollInfos.resize(mcCollisions.size()); - - // First pass: Store centrality and apply event selection - for (auto const& collision : collisions) { - int mcCollIdx = collision.mcCollisionId(); - if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { - continue; - } - - // STORE CENTRALITY WITHOUT CUTS - mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); - - if (!collision.sel8() && cfgsel8Require) - continue; - if (collision.centFT0C() > centcut) - continue; - - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) - continue; - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - - // Mark this MC collision as passing event selection - mcCollInfos[mcCollIdx].passedEvSel = true; - - // Apply event selection cuts - if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) - continue; - - mcCollInfos[mcCollIdx].passedEvSelVtZ = true; - } - - // Process MC collisions for efficiency and reconstructed collisions - for (auto const& mcCollision : mcCollisions) { - size_t idx = mcCollision.globalIndex(); - if (idx >= mcCollInfos.size()) - continue; - - bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; - - // Process reconstructed collisions for this MC collision - if (passedEvSelVtZ) { - // Find the corresponding reconstructed collision - for (auto const& collision : collisions) { - if (collision.mcCollisionId() != static_cast(idx)) - continue; - - auto bc = collision.bc_as(); - initCCDB(bc); - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - - for (auto const& track : tracksInColl) { - if (!track.has_mcParticle()) - continue; // skip un-matched reco tracks - - auto const& matchedMCParticle = track.mcParticle_as(); - - // Only process particles from this MC collision - if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; - - int pdg = matchedMCParticle.pdgCode(); - - if (!track.isPVContributor() && cfgUsePVcontributors) - continue; - - if (!track.hasTPC()) - continue; - if (!track.passedITSRefit() && cfgPassedITSRefit) - continue; - if (!track.passedTPCRefit() && cfgPassedTPCRefit) - continue; - if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) - continue; - - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) - continue; - - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - - float ptReco; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - - ptReco = (std::abs(pdg) == particlePdgCodes.at(4) || std::abs(pdg) == particlePdgCodes.at(5)) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - - double a = 0, b = 0, c = 0; - - int param = -1; - if (i == he3) { - param = (pdg > 0) ? 0 : 1; - } else if (i == he4) { - param = (pdg > 0) ? 2 : 3; - } - - if (param >= 0) { - a = cfgktrackcorrection->get(param, "a"); - b = cfgktrackcorrection->get(param, "b"); - c = cfgktrackcorrection->get(param, "c"); - } - - if (std::abs(pdg) == particlePdgCodes.at(5) && cfgmccorrectionhe4Require) { - ptReco = ptReco + a + b * std::exp(c * ptReco); - } - - if (std::abs(pdg) == particlePdgCodes.at(4) && cfgmccorrectionhe4Require) { - int pidGuess = track.pidForTracking(); - int antitriton = 6; - if (pidGuess == antitriton) { - ptReco = ptReco - a + b * ptReco - c * ptReco * ptReco; - } - } - - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; - - if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) - continue; - if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && cfgTPCNClsCrossedRowsRequire) - continue; - if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) - continue; - if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) - continue; - if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) - continue; - double cosheta = std::cosh(track.eta()); - if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) - continue; - if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) - continue; - if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) - continue; - if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) - continue; - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) - continue; - - int decayType = -999; // 0 = primary, 1 = weak decay, 2 = material - if (matchedMCParticle.isPhysicalPrimary()) { - // ---- Primary particles ---- - decayType = 0; - if (matchedMCParticle.has_mothers()) { - for (auto& motherparticle : matchedMCParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - decayType = 1; - break; - } - } - } - } else if (matchedMCParticle.getProcess() == TMCProcess::kPDecay) { - // ---- Secondary from weak decay ---- - if (!matchedMCParticle.has_mothers()) { - continue; // skip secondaries from weak decay without mothers - } - decayType = 1; - - // Check if it's from HF decay - for (auto& motherparticle : matchedMCParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - break; - } - } - } else { - // ---- Secondary from material interaction ---- - decayType = 2; - } - - float ptDCA; - - if (i == he3 || i == he4) { - ptDCA = ptReco; - } else { - ptDCA = 2 * ptReco; - } - - if (pdg == particlePdgCodes.at(i)) { // He3 - histomc.fill(HIST("DCAxy_vs_pT_total"), ptDCA, track.dcaXY(), collision.centFT0C()); - if (matchedMCParticle.isPhysicalPrimary()) { - histomc.fill(HIST("DCAxy_vs_pT_primary"), ptDCA, track.dcaXY(), collision.centFT0C()); - } - if (decayType == 2) { // Transport/Material - histomc.fill(HIST("DCAxy_vs_pT_transport"), ptDCA, track.dcaXY(), collision.centFT0C()); - } else if (decayType == 1) { // Weak decay (including HF) - histomc.fill(HIST("DCAxy_vs_pT_weakdecay"), ptDCA, track.dcaXY(), collision.centFT0C()); - } - } else if (pdg == -particlePdgCodes.at(i)) { // anti-He3 - histomc.fill(HIST("DCAxy_vs_pT_anti_total"), ptDCA, track.dcaXY(), collision.centFT0C()); - } - } - } - break; // Found the matching collision, break out of collision loop - } - } - } - } - PROCESS_SWITCH(NucleitpcPbPb, processDCA, "MC DCA analysis For secondary correction", false); - //=-=-=-==-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - constexpr float kInvalidBField = -990.f; - auto run3grpTimestamp = bc.timestamp(); - dBz = 0; - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grpTimestamp); - o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - if (bField < kInvalidBField) { - // Fetch magnetic field from ccdb for current collision - dBz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; - } else { - dBz = bField; - } - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grpTimestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grpTimestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - if (bField < kInvalidBField) { - // Fetch magnetic field from ccdb for current collision - dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; - } else { - dBz = bField; - } - } - mRunNumber = bc.runNumber(); - } - //---------------------------------------------------------------------------------------------------------------- - template - void initCollision(const T& collision) - { - collHasCandidate = false; - histos.fill(HIST("histNev"), 0.5); - collPassedEvSel = collision.sel8() && std::abs(collision.posZ()) < cfgZvertex; - occupancy = collision.trackOccupancyInTimeRange(); - if (collPassedEvSel) { - histos.fill(HIST("histNev"), 1.5); - } - primVtx.assign({collision.posX(), collision.posY(), collision.posZ()}); - cents.assign({collision.centFT0A(), collision.centFT0C(), collision.centFT0M()}); - } - //---------------------------------------------------------------------------------------------------------------- - template - void fillhmass(T const& track, int species, float cent) - { - if (!track.hasTOF() || !cfgFillmass) - return; - - float beta{o2::pid::tof::Beta::GetBeta(track)}; - const float eps = 1e-6f; - if (beta < eps || beta > 1.0f - eps) - return; - float charge = (species == he3 || species == he4) ? 2.f : 1.f; - float p = getRigidity(track); // assuming this is the momentum from inner TPC - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - float massDiff = 0.0; - if (species != he4) { - if (cfgmass2) { - // Compare squared masses - massDiff = (massTOF * massTOF) / (charge * charge); - } else { - // Compare linear masses - massDiff = massTOF / charge; - } - } - if (species == he4) { - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) - return; - if (cfgmass2) { - // Compare squared masses - massDiff = (massTOF * massTOF) / (charge * charge); - } else { - // Compare linear masses - massDiff = massTOF / charge; - } - } - - float ptMomn; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - ptMomn = (species == he3 || species == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - if (track.sign() > 0) { - hmass[2 * species]->Fill(ptMomn, massDiff, cent); - } else if (track.sign() < 0) { - hmass[2 * species + 1]->Fill(ptMomn, massDiff, cent); - } - } - //---------------------------------------------------------------------------------------------------------------- - template - void fillhmassnsigma(T const& track, int species, float cent) - { - if (!track.hasTOF() || !cfgFillmassnsigma) - return; - - float beta{o2::pid::tof::Beta::GetBeta(track)}; - const float eps = 1e-6f; - if (beta < eps || beta > 1.0f - eps) - return; - - float charge = (species == he3 || species == he4) ? 2.f : 1.f; - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - - // Calculate mass²/z² - float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); - - // Apply helium-4 rejection if needed - if (species == he4) { - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) - return; - } - - float ptMomn; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - ptMomn = (species == he3 || species == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - - // Fill histogram: mass²/z² vs pT vs centrality - if (track.sign() > 0) { - hmassnsigma[2 * species]->Fill(ptMomn, massSquareOverChargeSquare, cent); - } else if (track.sign() < 0) { - hmassnsigma[2 * species + 1]->Fill(ptMomn, massSquareOverChargeSquare, cent); - } - } - //---------------------------------------------------------------------------------------------------------------- - template - float getTPCnSigma(T const& track, PrimParticles& particle) - { - const float rigidity = getRigidity(track); - if (!track.hasTPC()) - return -999; - if (particle.name == "pion" && cfgTrackPIDsettings->get("pion", "useBBparams") < 1) - return cfgTrackPIDsettings->get("pion", "useBBparams") == 0 ? track.tpcNSigmaPi() : 0; - if (particle.name == "proton" && cfgTrackPIDsettings->get("proton", "useBBparams") < 1) - return cfgTrackPIDsettings->get("proton", "useBBparams") == 0 ? track.tpcNSigmaPr() : 0; - if (particle.name == "deuteron" && cfgTrackPIDsettings->get("deuteron", "useBBparams") < 1) - return cfgTrackPIDsettings->get("deuteron", "useBBparams") == 0 ? track.tpcNSigmaDe() : 0; - if (particle.name == "triton" && cfgTrackPIDsettings->get("triton", "useBBparams") < 1) - return cfgTrackPIDsettings->get("triton", "useBBparams") == 0 ? track.tpcNSigmaTr() : 0; - if (particle.name == "helion" && cfgTrackPIDsettings->get("helion", "useBBparams") < 1) - return cfgTrackPIDsettings->get("helion", "useBBparams") == 0 ? track.tpcNSigmaHe() : 0; - if (particle.name == "alpha" && cfgTrackPIDsettings->get("alpha", "useBBparams") < 1) - return cfgTrackPIDsettings->get("alpha", "useBBparams") == 0 ? track.tpcNSigmaAl() : 0; - - double expBethe{common::BetheBlochAleph(static_cast(particle.charge * rigidity / particle.mass), particle.betheParams[0], particle.betheParams[1], particle.betheParams[2], particle.betheParams[3], particle.betheParams[4])}; - double expSigma{expBethe * particle.resolution}; - float sigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); - return sigmaTPC; - } - //---------------------------------------------------------------------------------------------------------------- - template - float getITSnSigma(T const& track, PrimParticles& particle) - { - if (!track.hasITS()) - return -999; - o2::aod::ITSResponse itsResponse; - if (particle.name == "pion") - return itsResponse.nSigmaITS(track); - if (particle.name == "proton") - return itsResponse.nSigmaITS(track); - if (particle.name == "deuteron") - return itsResponse.nSigmaITS(track); - if (particle.name == "triton") - return itsResponse.nSigmaITS(track); - if (particle.name == "helion") - return itsResponse.nSigmaITS(track); - if (particle.name == "alpha") - return itsResponse.nSigmaITS(track); - return -999; // fallback if no match - } - //---------------------------------------------------------------------------------------------------------------- - template - float getMeanItsClsSize(T const& track) - { - int sum = 0, n = 0; - constexpr int kNITSLayers = 8; - for (int i = 0; i < kNITSLayers; i++) { - sum += (track.itsClusterSizes() >> (4 * i) & 15); - if (track.itsClusterSizes() >> (4 * i) & 15) - n++; - } - return n > 0 ? static_cast(sum) / n : 0.f; - } - //---------------------------------------------------------------------------------------------------------------- - template - float getRigidity(T const& track) - { - if (!cfgRigidityCorrection) - return track.tpcInnerParam(); - bool hePID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; - return hePID ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); - } - - //---------------------------------------------------------------------------------------------------------------- - template - float getRapidity(T const& track, int species) - { - using PtEtaPhiMVector = ROOT::Math::LorentzVector>; - double momn; - int speciesHe3 = 4; - int speciesHe4 = 5; - if (species == speciesHe3 || species == speciesHe4) { - momn = 2 * track.pt(); - } else { - momn = track.pt(); - } - PtEtaPhiMVector lorentzVectorParticle(momn, track.eta(), track.phi(), particleMasses[species]); - return lorentzVectorParticle.Rapidity(); - } -}; // end of the task here -//---------------------------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------------------------- -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Nuspex/piKpRAA.cxx b/PWGLF/Tasks/Nuspex/piKpRAA.cxx index 2ca5f0ec7e9..4ce6a377592 100644 --- a/PWGLF/Tasks/Nuspex/piKpRAA.cxx +++ b/PWGLF/Tasks/Nuspex/piKpRAA.cxx @@ -143,6 +143,7 @@ struct PiKpRAA { Configurable maxPt{"maxPt", 10000000000.0, "maximum pt of the tracks"}; Configurable nSigmaDCAxy{"nSigmaDCAxy", 1.0, "nSigma DCAxy selection"}; Configurable nSigmaDCAz{"nSigmaDCAz", 1.0, "nSigma DCAz selection"}; + Configurable particleVtxSel{"particleVtxSel", 5.0, "selection on the distance between particle creation vtx"}; Configurable minNCrossedRows{"minNCrossedRows", 70, "minimum number of crossed rows"}; Configurable minNcl{"minNcl", 135, "minimum number of clusters for primary-particle selection"}; @@ -499,7 +500,15 @@ struct PiKpRAA { } if (doprocessSim) { - registry.add("zPosMC", "Generated Events With at least One Rec. Collision + Sel. criteria;;Entries;", kTH1F, {axisZpos}); + registry.add("EventCounterMC", ";;Events", kTH1F, {{5, 0, 5}}); + registry.add("zPosMC", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evy. Sel.;;Entries;", kTH1F, {axisZpos}); + registry.add("zPosMCAll", "All MC Events;;Entries;", kTH1F, {axisZpos}); + registry.add("EtaMCParAllMCColl", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Pion", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Kaon", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Proton", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Electron", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Rest", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); registry.add("dcaVsPtPiDec", "Secondary pions from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); registry.add("dcaVsPtPrDec", "Secondary protons from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); registry.add("dcaVsPtPiMat", "Secondary pions from material interactions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); @@ -508,11 +517,9 @@ struct PiKpRAA { registry.add("DCAzVsPtWithSelection", ";#it{p}_{T} (GeV/#it{c});DCA_{z} (cm);", kTH2F, {{axisPtFineFixedWidth}, {axisDCAxy}}); registry.add("CentralityVsBCVsFT0VsTVXVsEvSel", "All=1 | BC=2 | FT0=3 | TVX=4 | EvSel=5;;Status;", kTH2F, {{axisCent}, {5, 0.5, 5.5}}); - - // MC events passing the TVX requirement - registry.add("NchMCcentVsTVX", ";Passed(=1.5) NOT Passed(=0.5);", kTH2F, {axisNch, {2, 0, 2}}); - - registry.add("NumberOfRecoCollisions", "Number of times Gen. Coll.are reconstructed;N;Entries", kTH1F, {{10, -0.5, 9.5}}); + registry.add("NumOfRecColl", "Num. of times a MC evt. is reconstructed;N;Entries", kTH1F, {{5, -0.5, 4.5}}); + registry.add("NumOfRecCollVsNContri", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{5, -0.5, 4.5}, axisNch}); + registry.add("NumOfRecCollVsNContriWithEvtSel", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors WITH EVT SEL;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{5, -0.5, 4.5}, axisNch}); // Pt resolution registry.add("PtResolution", "p_{T} resolution;;(pt_{rec} - pt_{gen})/pt_{gen};", kTH2F, {axisPt, {100, -1.0, 1.0}}); @@ -535,13 +542,15 @@ struct PiKpRAA { registry.add("NchMCVsCent", "Generated Nch v.s. Centrality (At least Once Rec. Coll. + Sel. criteria);;Gen. Nch MC", kTH2F, {axisCent, axisNch}); // Needed to measure Event Loss - registry.add("NchMC_WithRecoEvt", "Generated Nch of Evts With at least one Rec. Coll. + Sel. criteria;Gen. Nch MC;Entries", kTH1F, {axisNch}); - registry.add("NchMC_AllGen", "Generated Nch of All Gen. Evts.;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithRecoEvt", "Gen Nch from MC event associated with the Rec. Coll (with largest Num. of contributors) + Evt. Sel.;Gen Nch MC;Entries", kTH1F, {axisNch}); + registry.add("NchMC_AllGen", "Gen Nch of ALL MC events;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithRecColl", "Gen Nch from MC event associated with a Rec. Coll (at least once);Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithOnlyRecColl", "Gen Nch from MC event associated with a ONLY ONE Rec. Coll from last Num. of Contributors;Gen. Nch;Entries", kTH1F, {axisNch}); // Needed to measure Event Splitting - registry.add("Centrality_WRecoEvt", "Generated Events With at least One Rec. Collision And NO Sel. criteria;;Entries", kTH1F, {axisCent}); - registry.add("Centrality_WRecoEvtWSelCri", "Generated Events With at least One Rec. Collision + Sel. criteria;;Entries", kTH1F, {axisCent}); - registry.add("Centrality_AllRecoEvt", "Generated Events Irrespective of the number of times it was reconstructed + Evt. Selections;;Entries", kTH1F, {axisCent}); + registry.add("Centrality_WRecoEvt", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evt. Sel.;;Entries", kTH1F, {axisCent}); + registry.add("Centrality_WRecoEvtWSelCri", "From the association between the MC event & the Rec. Coll with largest number of PV contributors + Evt. Sel.;;Entries", kTH1F, {axisCent}); + registry.add("Centrality_AllRecoEvt", "All Rec. Coll. Irrespective of the times it was reconstructed + Evt. Sel.;;Entries", kTH1F, {axisCent}); // Needed to calculate the numerator of the Signal Loss correction registry.add("PtPiVsNchMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;Gen. Nch;", kTH2F, {axisPt, axisNch}); @@ -560,6 +569,13 @@ struct PiKpRAA { registry.add("MCclosure_PtPiVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); registry.add("MCclosure_PtKaVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); registry.add("MCclosure_PtPrVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); + + auto hMcCouter = registry.get(HIST("EventCounterMC")); + auto* xMcCounter = hMcCouter->GetXaxis(); + xMcCounter->SetBinLabel(1, "All MC Coll"); + xMcCounter->SetBinLabel(2, "Rec Coll with nContributors > 0"); + xMcCounter->SetBinLabel(3, "Rec Coll With largest nContributors"); + xMcCounter->SetBinLabel(4, "Rec TVX-triggered Coll"); } LOG(info) << "\trequireGoodRct=" << requireGoodRct.value; @@ -1228,15 +1244,16 @@ struct PiKpRAA { const auto& kLowEta = (std::vector)vecLowEta; const auto& kHighEta = (std::vector)vecUpEta; + registry.fill(HIST("EventCounterMC"), 0.5); //--------------------------- - // Only INEL > 0 generated collisions - // By counting number of primary charged particles in |eta| < 1 + // Nch counters in different pseudorapidity intervals //--------------------------- int nChMC{0}; int nChMCTPCAcc{0}; int nChFT0A{0}; int nChFT0C{0}; + for (const auto& particle : mcParticles) { auto charge{0.}; @@ -1266,7 +1283,28 @@ struct PiKpRAA { continue; } + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + const float eta{particle.eta()}; + registry.fill(HIST("EtaMCParAllMCColl"), eta); + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("EtaMCParAllMCColl_Pion"), eta); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("EtaMCParAllMCColl_Kaon"), eta); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("EtaMCParAllMCColl_Proton"), eta); + } else if (particle.pdgCode() == PDG_t::kElectron || particle.pdgCode() == PDG_t::kPositron) { + registry.fill(HIST("EtaMCParAllMCColl_Electron"), eta); + } else { + registry.fill(HIST("EtaMCParAllMCColl_Rest"), eta); + } // TVX requirement if (eta > KminFT0A && eta < KmaxFT0A) { @@ -1290,25 +1328,23 @@ struct PiKpRAA { } //--------------------------- - // Select only events with at least one charged particle in the FT0A and FT0C acceptances? + // Selects MC events with at least one charged particle in the FT0A & FT0C //--------------------------- if (selTVXMC) { if (!(nChFT0A > KzeroInt && nChFT0C > KzeroInt)) { - registry.fill(HIST("NchMCcentVsTVX"), nChMC, 0.5); return; } - registry.fill(HIST("NchMCcentVsTVX"), nChMC, 1.5); } //--------------------------- - // Select only MC events with |Vtx Z| < 10 cm? + // Selects MC events with |Zvtx| < zVtx_Cut //--------------------------- if (isZvtxPosSelMC && (std::fabs(mccollision.posZ()) > posZcut)) { return; } //--------------------------- - // Select only INEL > 0 generated events? + // Selects INEL > 0 MC evets //--------------------------- if (selINELgt0) { if (!(nChMC > KzeroInt)) { @@ -1318,9 +1354,9 @@ struct PiKpRAA { //--------------------------- // All Generated events irrespective of whether there is an associated reconstructed collision - // Consequently, the centrality being a reconstructed quantity, might not always be available + // Consequently, the centrality being a reconstructed quantity, is not always be available // Therefore it is expressed as a function of the generated pT and the generated Nch in ∣eta∣ < 0.8 - // This is used for the denominator of the signal loss correction + // This is used for the denominator of the SIGNAL LOSS correction // Also for MC closure: True Pt vs Generated Nch //--------------------------- for (const auto& particle : mcParticles) { @@ -1346,7 +1382,7 @@ struct PiKpRAA { continue; } - // Select particle based on its charge + // Selects particle based on its charge if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { continue; } @@ -1354,39 +1390,45 @@ struct PiKpRAA { continue; } - // Is it a primary particle? - bool isPrimary{true}; + // Selects only primary particles if (!particle.isPhysicalPrimary()) { - isPrimary = false; - } - - if (isPrimary) { - if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { - registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); - registry.fill(HIST("MCclosure_PtMCPiVsNchMC"), particle.pt(), nChMCTPCAcc); - } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { - registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); - registry.fill(HIST("MCclosure_PtMCKaVsNchMC"), particle.pt(), nChMCTPCAcc); - } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { - registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); - registry.fill(HIST("MCclosure_PtMCPrVsNchMC"), particle.pt(), nChMCTPCAcc); - } else { - continue; - } + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); + registry.fill(HIST("MCclosure_PtMCPiVsNchMC"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); + registry.fill(HIST("MCclosure_PtMCKaVsNchMC"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); + registry.fill(HIST("MCclosure_PtMCPrVsNchMC"), particle.pt(), nChMCTPCAcc); + } else { + continue; } } // Loop over Generated Particles //--------------------------- - // This is used for the denominator of the event loss correction + // This is used for the denominator of the EVENT LOSS correction // Only charge particles within tpcNchAcceptance and without pT selection //--------------------------- registry.fill(HIST("NchMC_AllGen"), nChMCTPCAcc); + registry.fill(HIST("zPosMCAll"), mccollision.posZ()); //--------------------------- - // How many times the Generated evet was reconstrued? + // How many times was the MC event reconstrued? //--------------------------- const auto& nRecColls{collisions.size()}; - registry.fill(HIST("NumberOfRecoCollisions"), nRecColls); + registry.fill(HIST("NumOfRecColl"), nRecColls); //--------------------------- // Only Generated evets with at least one reconstrued collision @@ -1394,11 +1436,96 @@ struct PiKpRAA { if (nRecColls > KzeroInt) { //--------------------------- - // Looks for the collision with the largest number of contributors - // The selected collisions is identified with its index (bestCollisionIndex) + // Looks for the collision with the largest number of tracks contributing to the PV reconstruction + // The selected collision is identified by its global index (bestCollisionIndex) //--------------------------- int biggestNContribs{-1}; int bestCollisionIndex{-1}; + + for (const auto& collision : collisions) { + + registry.fill(HIST("NumOfRecCollVsNContri"), nRecColls, collision.numContrib()); + + //--------------------------- + // Gets the index of the collision with the largest number of contributors + //--------------------------- + if (biggestNContribs < collision.numContrib()) { + biggestNContribs = collision.numContrib(); + bestCollisionIndex = collision.globalIndex(); + } + + //--------------------------- + // This is only for QA + //--------------------------- + int mcNchInTPCAcc{0}; + for (const auto& particle : mcParticles) { + + auto charge{0.}; + // Get the MC particle + const auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + const float eta{particle.eta()}; + if (std::abs(eta) < tpcNchAcceptance) { + mcNchInTPCAcc++; + } + } + + //--------------------------- + // All collisions with N contributors > 0 + //--------------------------- + if (collision.numContrib() > KzeroInt) { + registry.fill(HIST("EventCounterMC"), 1.5); + // To calculate the amount of charged-primary MC particles (|eta|<0.5) + // that belongs to a MC event that was reconstructed at least once + registry.fill(HIST("NchMC_WithRecColl"), mcNchInTPCAcc); + } + + //--------------------------- + // Records only one collision with the largest number of contributors + //--------------------------- + if (bestCollisionIndex == collision.globalIndex()) { + registry.fill(HIST("EventCounterMC"), 2.5); + // To calculate the amount of charged-primary MC particles (|eta|<0.5) + // that belongs to a MC event that was reconstructed + // and only from the with the largest number of contributors + registry.fill(HIST("NchMC_WithOnlyRecColl"), mcNchInTPCAcc); + } + + //--------------------------- + // TVX-triggered collision + //--------------------------- + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("EventCounterMC"), 3.5); + } + } + + //--------------------------- + // Needed to calculate denominator of the EVENT SPLITTING correction + // MC Collisions that are reconstructed more than one will be stored here + //--------------------------- for (const auto& collision : collisions) { float centrality{-999.0}; @@ -1412,55 +1539,91 @@ struct PiKpRAA { centrality = -999.0; } - if (selHasFT0 && !collision.has_foundFT0()) { - continue; - } + //--------------------------- + // Event Selection + // Applied manually to avoid double filling the EventCounter + //--------------------------- - if (biggestNContribs < collision.numContrib()) { - biggestNContribs = collision.numContrib(); - bestCollisionIndex = collision.globalIndex(); + // Has BC? + if (selHasBC) { + if (!collision.has_foundBC()) { + continue; + } } - if (selHasBC && !collision.has_foundBC()) { - continue; + // Has FT0 information? + if (selHasFT0) { + if (!collision.has_foundFT0()) { + continue; + } } - if (useSel8 && !collision.sel8()) { - continue; + // Use sel8? + if (useSel8) { + if (!collision.sel8()) { + continue; + } } // kIsTriggerTVX - if (selTriggerTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { - continue; + if (selTriggerTVX) { + if (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + continue; + } } // kNoITSROFrameBorder - if (selNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - continue; + if (selNoITSROFrameBorder) { + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } } // kNoTimeFrameBorder - if (selNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - continue; + if (selNoTimeFrameBorder) { + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } } // Zvtx - if (isZvtxPosSel && std::fabs(collision.posZ()) > posZcut) { - continue; + if (isZvtxPosSel) { + if (std::fabs(collision.posZ()) > posZcut) { + continue; + } } - if (selIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - continue; + // Short distance between FT0 & PV vertices + if (selIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } } - if (selNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - continue; + if (selNoSameBunchPileup) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + } + + if (isCentSel) { + if (centrality < minCentCut || centrality > maxCentCut) { + continue; + } + } + + if (selINELgt0) { + if (!collision.isInelGt0()) { + continue; + } } //--------------------------- - // Needed to calculate denominator of the Event Splitting correction + // Needed to calculate denominator of the EVENT SPLITTING correction + // MC Collisions that are reconstructed more than one will be stored here //--------------------------- registry.fill(HIST("Centrality_AllRecoEvt"), centrality); + registry.fill(HIST("NumOfRecCollVsNContriWithEvtSel"), nRecColls, collision.numContrib()); } //--------------------------- @@ -1506,9 +1669,6 @@ struct PiKpRAA { } } - //--------------------------- - // Needed to construct the correlation between MC Nch v.s. centrality - //--------------------------- registry.fill(HIST("Centrality_WRecoEvt"), centrality); registry.fill(HIST("zPosMC"), mccollision.posZ()); @@ -1585,9 +1745,12 @@ struct PiKpRAA { return; } - registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); - registry.fill(HIST("NchMCVsCent"), centrality, nChMCTPCAcc); - registry.fill(HIST("NchMC_WithRecoEvt"), nChMCTPCAcc); // Numerator of event loss correction + //--------------------------- + // Needed to construct the correlation between MC Nch v.s. centrality + //--------------------------- + registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); // To calculate numerator of EVENT SPLITTING + registry.fill(HIST("NchMCVsCent"), centrality, nChMCTPCAcc); // Needed for the mapping betwee MC Nch and centrality + registry.fill(HIST("NchMC_WithRecoEvt"), nChMCTPCAcc); // Numerator of EVENT LOSS correction registry.fill(HIST("zPos"), collision.posZ()); registry.fill(HIST("Centrality"), centrality); @@ -1644,24 +1807,29 @@ struct PiKpRAA { } // Is it a primary particle? - bool isPrimary{true}; if (!particle.isPhysicalPrimary()) { - isPrimary = false; - } - - if (isPrimary) { - if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { - registry.fill(HIST("PtPiVsCentMC_WithRecoEvt"), particle.pt(), centrality); // Denominator of tracking efficiency - registry.fill(HIST("PtPiVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); // Numerator of signal loss - } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { - registry.fill(HIST("PtKaVsCentMC_WithRecoEvt"), particle.pt(), centrality); - registry.fill(HIST("PtKaVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); - } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { - registry.fill(HIST("PtPrVsCentMC_WithRecoEvt"), particle.pt(), centrality); - registry.fill(HIST("PtPrVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); - } else { - continue; - } + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsCentMC_WithRecoEvt"), particle.pt(), centrality); // Denominator of tracking efficiency + registry.fill(HIST("PtPiVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); // Numerator of signal loss + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtKaVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtPrVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); + } else { + continue; } } // Loop over generated particles per generated collision @@ -1733,6 +1901,15 @@ struct PiKpRAA { } if (isPrimary && !isDecay && !isMaterial) { + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + if (isPi && !isPr) { registry.fill(HIST("dcaVsPtPi"), track.pt(), track.dcaXY(), centrality); } @@ -1829,12 +2006,16 @@ struct PiKpRAA { registry.fill(HIST("NclVsEtaPID"), track.eta(), track.tpcNClsPID()); registry.fill(HIST("NclVsEtaPIDp"), track.eta(), track.tpcNClsPID()); - bool isPrimary{false}; - if (particle.isPhysicalPrimary()) { - isPrimary = true; + // Rejects non-physical primary particle + if (!particle.isPhysicalPrimary()) { + continue; } - if (!isPrimary) { + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { continue; } @@ -2403,7 +2584,19 @@ struct PiKpRAA { } if (isCentSel) { - if (col.centFT0C() < minCentCut || col.centFT0C() > maxCentCut) { + + float cenT{-999.0}; + if (centralitySelector.value == "FT0C") { + cenT = col.centFT0C(); + } else if (centralitySelector.value == "FT0M") { + cenT = col.centFT0M(); + } else if (centralitySelector.value == "FV0A") { + cenT = col.centFV0A(); + } else { + cenT = -999.0; + } + + if (cenT < minCentCut || cenT > maxCentCut) { return false; } registry.fill(HIST("EventCounter"), EvCutLabel::Centrality); diff --git a/PWGLF/Tasks/QC/mcParticlePrediction.cxx b/PWGLF/Tasks/QC/mcParticlePrediction.cxx index c190fe5a525..41d6e642ecb 100644 --- a/PWGLF/Tasks/QC/mcParticlePrediction.cxx +++ b/PWGLF/Tasks/QC/mcParticlePrediction.cxx @@ -55,10 +55,73 @@ using namespace o2::framework; using namespace o2::pwglf; // Particles -static const std::vector parameterNames{"Enable"}; -static constexpr int nParameters = 1; -static const int defaultParticles[PIDExtended::NIDsTot][nParameters]{{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {1}, {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}}; +static const std::vector parameterNames{"Enable", "SelectPrimaries"}; +static constexpr int nParameters = 2; +static const int defaultParticles[PIDExtended::NIDsTot][nParameters]{{0, 1}, // Electron + {0, 1}, // Muon + {0, 1}, // Pion + {0, 1}, // Kaon + {0, 1}, // Proton + {0, 1}, // Deuteron + {0, 1}, // Triton + {0, 1}, // Helium3 + {0, 1}, // Alpha + {0, 1}, // PI0 + {0, 1}, // Photon + {1, 1}, // K0 + {0, 1}, // Lambda + {0, 1}, // HyperTriton + {0, 1}, // Hyperhydrog4 + {0, 1}, // XiMinus + {0, 1}, // OmegaMinus + {0, 1}, // HyperHelium4 + {0, 1}, // HyperHelium5 + {0, 1}, // Positron + {0, 1}, // MuonPlus + {0, 1}, // PionMinus + {0, 1}, // KaonMinus + {0, 1}, // AntiProton + {0, 1}, // AntiDeuteron + {0, 1}, // AntiTriton + {0, 1}, // AntiHelium3 + {0, 1}, // AntiAlpha + {0, 1}, // AntiLambda + {0, 1}, // AntiHyperTriton + {0, 1}, // AntiHyperhydrog4 + {0, 1}, // XiPlus + {0, 1}, // OmegaPlus + {0, 1}, // AntiHyperHelium4 + {0, 1}, // AntiHyperHelium5 + {0, 1}, // Neutron + {0, 1}, // AntiNeutron + {0, 0}, // Phi + {0, 1}, // BZero + {0, 1}, // BPlus + {0, 1}, // BS + {0, 1}, // D0 + {0, 1}, // DPlus + {0, 1}, // DS + {0, 1}, // DStar + {0, 1}, // ChiC1 + {0, 1}, // JPsi + {0, 1}, // LambdaB0 + {0, 1}, // LambdaCPlus + {0, 1}, // OmegaC0 + {0, 1}, // SigmaC0 + {0, 1}, // SigmaCPlusPlus + {0, 1}, // X3872 + {0, 1}, // Xi0 + {0, 1}, // XiB0 + {0, 1}, // XiCCPlusPlus + {0, 1}, // XiCPlus + {0, 1}, // XiC0 + {0, 0}, // Kstar + {0, 0}, // KstarPM + {0, 1}, // Kshort + {0, 0}, // Xi1530 + {0, 0}}; // Lambda1520 bool enabledParticlesArray[PIDExtended::NIDsTot]; +bool selectPrimariesArray[PIDExtended::NIDsTot]; // Estimators struct Estimators { @@ -156,6 +219,8 @@ std::array, Estimators::nEstimators> hestimatorsRecoEvRecoV std::array, Estimators::nEstimators> hestimatorsRecoEvVsBCId; std::array, Estimators::nEstimators> hvertexPosZ; std::array, PIDExtended::NIDsTot>, Estimators::nEstimators> hpt; +std::array, PIDExtended::NIDsTot>, Estimators::nEstimators> hy; +std::array, PIDExtended::NIDsTot>, Estimators::nEstimators> heta; std::array, PIDExtended::NIDsTot>, Estimators::nEstimators> hyield; struct McParticlePrediction { @@ -165,13 +230,28 @@ struct McParticlePrediction { HistogramRegistry histosRecoEvs{"HistosRecoEvs", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry histosYield{"HistosYield", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry histosPt{"HistosPt", {}, OutputObjHandlingPolicy::AnalysisObject}; - ConfigurableAxis binsEta{"binsEta", {100, -20, 20}, "Binning of the Eta axis"}; - ConfigurableAxis binsVxy{"binsVxy", {100, -10, 10}, "Binning of the production vertex (x and y) axis"}; - ConfigurableAxis binsVz{"binsVz", {100, -10, 10}, "Binning of the production vertex (z) axis"}; - ConfigurableAxis binsPt{"binsPt", {100, 0, 10}, "Binning of the Pt axis"}; - ConfigurableAxis binsImpactParameter{"binsImpactParameter", {400, 0.0, 20.0}, "Binning of the impact parameter axis"}; - ConfigurableAxis binsMultiplicity{"binsMultiplicity", {300, -0.5, 299.5}, "Binning of the Multiplicity axis"}; - ConfigurableAxis binsMultiplicityReco{"binsMultiplicityReco", {1000, -0.5, -0.5 + 10000}, "Binning of the Multiplicity axis"}; + HistogramRegistry histosEta{"HistosEta", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histosY{"HistosY", {}, OutputObjHandlingPolicy::AnalysisObject}; + + struct : ConfigurableGroup { + std::string prefix = "Binning"; // JSON group name + ConfigurableAxis binsEta{"binsEta", {100, -20, 20}, "Binning of the Eta axis"}; + ConfigurableAxis binsY{"binsY", {100, -20, 20}, "Binning of the Y axis"}; + ConfigurableAxis binsVxy{"binsVxy", {100, -10, 10}, "Binning of the production vertex (x and y) axis"}; + ConfigurableAxis binsVz{"binsVz", {100, -10, 10}, "Binning of the production vertex (z) axis"}; + ConfigurableAxis binsPt{"binsPt", {200, 0, 20}, "Binning of the Pt axis"}; + ConfigurableAxis binsImpactParameter{"binsImpactParameter", {400, 0.0, 20.0}, "Binning of the impact parameter axis"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {300, -0.5, 299.5}, "Binning of the Multiplicity axis"}; + ConfigurableAxis binsMultiplicityReco{"binsMultiplicityReco", {1000, -0.5, -0.5 + 10000}, "Binning of the Multiplicity axis"}; + } cfgBinning; + + struct : ConfigurableGroup { + std::string prefix = "Predictions type"; // JSON group name + Configurable enablePt{"enablePt", true, "Produce prediction for pT"}; + Configurable enableY{"enableY", true, "Produce prediction for rapidity"}; + Configurable enableEta{"enableEta", true, "Produce prediction for eta"}; + } cfgPrediction; + Configurable> enabledSpecies{"enabledSpecies", {defaultParticles[0], PIDExtended::NIDsTot, nParameters, PIDExtended::arrayNames(), parameterNames}, "Particles enabled"}; @@ -179,8 +259,9 @@ struct McParticlePrediction { {defaultEstimators[0], Estimators::nEstimators, nParameters, Estimators::arrayNames(), parameterNames}, "Estimators enabled"}; Configurable selectInelGt0{"selectInelGt0", true, "Select only inelastic events"}; - Configurable selectPrimaries{"selectPrimaries", true, "Select only primary particles"}; - Configurable rapidityCut{"rapidityCut", 0.5, "Select only particles within |y| < cut"}; + Configurable selectPrimariesForMultiplicity{"selectPrimariesForMultiplicity", true, "Select only primary particles for multiplicity computation"}; + Configurable rapidityCut{"rapidityCut", 0.5, "Select only particles within |y| < cut for the pT and yield plots"}; + Configurable ptCut{"ptCut", 0.01, "Select only particles within |pt| > cut for the eta and y plots"}; Configurable requireCoincidenceEstimators{"requireCoincidenceEstimators", false, "Asks for a coincidence when two estimators are used"}; Configurable discardkIsGoodZvtxFT0vsPV{"discardkIsGoodZvtxFT0vsPV", false, "Select only collisions with matching BC and MC BC"}; Configurable discardMismatchedBCs{"discardMismatchedBCs", false, "Select only collisions with matching BC and MC BC"}; @@ -195,7 +276,6 @@ struct McParticlePrediction { Configurable enableVsEta05Histograms{"enableVsEta05Histograms", true, "Enables the correlation between ETA05 and other estimators"}; Configurable enableVsEta08Histograms{"enableVsEta08Histograms", true, "Enables the correlation between ETA08 and other estimators"}; Configurable enableVsImpactParameterHistograms{"enableVsImpactParameterHistograms", true, "Enables the correlation between impact parameter and other estimators"}; - Configurable cfgEvtZvtxCut{"cfgEvtZvtxCut", 10.0f, "Evt sel: Max. z-Vertex (cm)"}; Configurable chargetolerance{"chargetolerance", 1e-3, "Tolerance to consider a particle as charged based on its charge"}; Service pdgDB; @@ -204,16 +284,17 @@ struct McParticlePrediction { void init(o2::framework::InitContext&) { mCounter.mPdgDatabase = pdgDB.service; - mCounter.mSelectPrimaries = selectPrimaries.value; - const AxisSpec axisEta{binsEta, "#eta"}; - const AxisSpec axisVx{binsVxy, "Vx"}; - const AxisSpec axisVy{binsVxy, "Vy"}; - const AxisSpec axisVz{binsVz, "Vz"}; - const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec axisImpactParameter{binsImpactParameter, "Impact parameter (fm)"}; - const AxisSpec axisMultiplicity{binsMultiplicity, "Multiplicity (undefined)"}; - const AxisSpec axisMultiplicityReco{binsMultiplicityReco, "Multiplicity Reco. (undefined)"}; - const AxisSpec axisMultiplicityRecoITS{binsMultiplicityReco, "Multiplicity Reco. ITSIB"}; + mCounter.mSelectPrimaries = selectPrimariesForMultiplicity.value; + const AxisSpec axisEta{cfgBinning.binsEta, "#eta"}; + const AxisSpec axisRapidity{cfgBinning.binsY, "#it{y}"}; + const AxisSpec axisVx{cfgBinning.binsVxy, "Vx"}; + const AxisSpec axisVy{cfgBinning.binsVxy, "Vy"}; + const AxisSpec axisVz{cfgBinning.binsVz, "Vz"}; + const AxisSpec axisPt{cfgBinning.binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisImpactParameter{cfgBinning.binsImpactParameter, "Impact parameter (fm)"}; + const AxisSpec axisMultiplicity{cfgBinning.binsMultiplicity, "Multiplicity (undefined)"}; + const AxisSpec axisMultiplicityReco{cfgBinning.binsMultiplicityReco, "Multiplicity Reco. (undefined)"}; + const AxisSpec axisMultiplicityRecoITS{cfgBinning.binsMultiplicityReco, "Multiplicity Reco. ITSIB"}; const AxisSpec axisMultiplicityGenV0s{100, 0, 100, "K0s gen"}; const AxisSpec axisMultiplicityRecoV0s{20, 0, 20, "K0s reco"}; const AxisSpec axisBCID{o2::constants::lhc::LHCMaxBunches, -0.5, -0.5 + o2::constants::lhc::LHCMaxBunches, "BC ID in orbit"}; @@ -224,50 +305,65 @@ struct McParticlePrediction { h->GetXaxis()->SetBinLabel(1, "Read"); h->GetXaxis()->SetBinLabel(2, "INELgt0"); h->GetXaxis()->SetBinLabel(3, "|Z|<10"); - h = histos.add("collisions/reconstructed", "collisions", kTH1D, {{20, -0.5, 19.5}}); - h->GetXaxis()->SetBinLabel(1, "Read"); - h->GetXaxis()->SetBinLabel(2, "has_mcCollision"); - h->GetXaxis()->SetBinLabel(3, "sel8"); - h->GetXaxis()->SetBinLabel(4, "kIsBBT0A"); - h->GetXaxis()->SetBinLabel(5, "kIsBBT0C"); - h->GetXaxis()->SetBinLabel(6, "collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))"); - h->GetXaxis()->SetBinLabel(7, "globalBC == MC globalBC"); - h->GetXaxis()->SetBinLabel(8, "found globalBC == MC globalBC"); - h->GetXaxis()->SetBinLabel(9, "isINELgt0mc"); - h->GetXaxis()->SetBinLabel(10, "VTXz"); - h->GetXaxis()->SetBinLabel(11, "collisionTimeRes"); - h->GetXaxis()->SetBinLabel(11, "collisionTimeRes"); - h->GetXaxis()->SetBinLabel(12, "kIsGoodZvtxFT0vsPV"); - h->GetXaxis()->SetBinLabel(13, "kIsVertexITSTPC"); - h->GetXaxis()->SetBinLabel(14, "kIsVertexTOFmatched"); - h->GetXaxis()->SetBinLabel(15, "kIsVertexTRDmatched"); - - histos.add("collisions/Reco/BCvsMCBC", "BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC}); - histos.add("collisions/Reco/FoundBCvsMCBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC})->GetXaxis()->SetTitle("Found BC ID in orbit"); - histos.add("collisions/Reco/FoundBCvsBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCID})->GetXaxis()->SetTitle("Found BC ID in orbit"); - histos.add("collisions/Reco/collisionTime", "Collision Time", kTH1D, {{1000, -20, 20, "collisionTime"}}); - histos.add("collisions/Reco/collisionTimeRes", "Collision Time Res", kTH1D, {{1600, 0, 1600, "collisionTimeRes (ns)"}}); - histos.add("collisions/Reco/bcMinusfoundBc", "bcMinusfoundBc", kTH1D, {{1600, -1000, 1000, "bc - foundBc (ns)"}}); - histos.add("collisions/Reco/bcMinusfoundBcRatio", "bcMinusfoundBcRatio", kTH1D, {{1600, -40, 40, "(bc - foundBc)/collisionTimeRes"}}); - histos.add("collisions/Reco/bcMinusMcBcRatio", "bcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(bc - mcBc)/collisionTimeRes"}}); - histos.add("collisions/Reco/foundbcMinusMcBcRatio", "foundbcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(foundBc-mcBc)/collisionTimeRes"}}); - histos.add("collisions/Reco/FT0A", "FT0A", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0A (ps)"); - histos.add("collisions/Reco/FT0C", "FT0C", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0C (ps)"); - histos.add("collisions/Reco/FT0AC", "FT0AC", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0AC (ps)"); + if (doprocessReco) { + h = histos.add("collisions/reconstructed", "collisions", kTH1D, {{20, -0.5, 19.5}}); + h->GetXaxis()->SetBinLabel(1, "Read"); + h->GetXaxis()->SetBinLabel(2, "has_mcCollision"); + h->GetXaxis()->SetBinLabel(3, "sel8"); + h->GetXaxis()->SetBinLabel(4, "kIsBBT0A"); + h->GetXaxis()->SetBinLabel(5, "kIsBBT0C"); + h->GetXaxis()->SetBinLabel(6, "collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))"); + h->GetXaxis()->SetBinLabel(7, "globalBC == MC globalBC"); + h->GetXaxis()->SetBinLabel(8, "found globalBC == MC globalBC"); + h->GetXaxis()->SetBinLabel(9, "isINELgt0mc"); + h->GetXaxis()->SetBinLabel(10, "VTXz"); + h->GetXaxis()->SetBinLabel(11, "collisionTimeRes"); + h->GetXaxis()->SetBinLabel(11, "collisionTimeRes"); + h->GetXaxis()->SetBinLabel(12, "kIsGoodZvtxFT0vsPV"); + h->GetXaxis()->SetBinLabel(13, "kIsVertexITSTPC"); + h->GetXaxis()->SetBinLabel(14, "kIsVertexTOFmatched"); + h->GetXaxis()->SetBinLabel(15, "kIsVertexTRDmatched"); + + histos.add("collisions/Reco/BCvsMCBC", "BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC}); + histos.add("collisions/Reco/FoundBCvsMCBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCIDMC})->GetXaxis()->SetTitle("Found BC ID in orbit"); + histos.add("collisions/Reco/FoundBCvsBC", "Found BC vs MC BC", kTH2D, {axisBCID, axisBCID})->GetXaxis()->SetTitle("Found BC ID in orbit"); + histos.add("collisions/Reco/collisionTime", "Collision Time", kTH1D, {{1000, -20, 20, "collisionTime"}}); + histos.add("collisions/Reco/collisionTimeRes", "Collision Time Res", kTH1D, {{1600, 0, 1600, "collisionTimeRes (ns)"}}); + histos.add("collisions/Reco/bcMinusfoundBc", "bcMinusfoundBc", kTH1D, {{1600, -1000, 1000, "bc - foundBc (ns)"}}); + histos.add("collisions/Reco/bcMinusfoundBcRatio", "bcMinusfoundBcRatio", kTH1D, {{1600, -40, 40, "(bc - foundBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/bcMinusMcBcRatio", "bcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(bc - mcBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/foundbcMinusMcBcRatio", "foundbcMinusMcBcRatio", kTH1D, {{1600, -40, 40, "(foundBc-mcBc)/collisionTimeRes"}}); + histos.add("collisions/Reco/FT0A", "FT0A", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0A (ps)"); + histos.add("collisions/Reco/FT0C", "FT0C", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0C (ps)"); + histos.add("collisions/Reco/FT0AC", "FT0AC", kTH1D, {axisFT0})->GetXaxis()->SetTitle("Coll time FT0AC (ps)"); + } + histos.add("particles/eta/charged", "eta", kTH1D, {axisEta}); histos.add("particles/eta/neutral", "eta", kTH1D, {axisEta}); - histos.add("particles/vtx/x", "Vx", kTH1D, {axisVx}); - histos.add("particles/vtx/y", "Vy", kTH1D, {axisVy}); - histos.add("particles/vtx/z", "Vz", kTH1D, {axisVz}); - histos.add("particles/FromCollVsFromMCColl", "FromCollVsFromMCColl", kTH2D, {{binsMultiplicity, "PV contributor particles (good bc)"}, {binsMultiplicityReco, "Particles in MC collision"}}); - histos.add("particles/FromCollVsFromMCCollBad", "FromCollVsFromMCCollBad", kTH2D, {{binsMultiplicity, "PV contributor particles (bad bc)"}, {binsMultiplicityReco, "Particles in MC collision"}}); - histos.add("particles/FromCollVsFromCollBad", "FromCollVsFromCollBad", kTH2D, {{binsMultiplicity, "PV contributor particles (good bc)"}, {binsMultiplicity, "PV contributor particles (bad bc)"}}); - histos.add("particles/FromCollBadOverFromCollVsVsFromMCColl", "FromCollBadOverFromCollVsVsFromMCColl", kTH2D, {{100, 0, 2, "bad/good"}, {binsMultiplicityReco, "Particles in MC collision"}}); - histos.add("V0s/V0RecovsPV", "V0s Reco + Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); - histos.add("V0s/V0RecoAssvsPV", "V0s Reco + Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); - histos.add("V0s/V0AssvsPV", "V0s Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityGenV0s}); - histos.add("V0s/V0RecoAssvsPV_TOFOneLeg", "V0s Reco + Ass + TOF 1 Leg vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); - histos.add("V0s/V0RecoAssvsPV_TOFTwoLegs", "V0s Reco + Ass + TOF 2 Legs vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("particles/eta/undefined", "eta", kTH1D, {axisEta}); + + histos.add("particles/y/charged", "y", kTH1D, {axisRapidity}); + histos.add("particles/y/neutral", "y", kTH1D, {axisRapidity}); + histos.add("particles/y/undefined", "y", kTH1D, {axisRapidity}); + + histos.add("particles/vtx/x", "V_{x}", kTH1D, {axisVx}); + histos.add("particles/vtx/y", "V_{y}", kTH1D, {axisVy}); + histos.add("particles/vtx/z", "V_{z}", kTH1D, {axisVz}); + histos.add("particles/vtx/deltax", "V_{x} - VTX_{x}", kTH1D, {axisVx}); + histos.add("particles/vtx/deltay", "V_{y} - VTX_{y}", kTH1D, {axisVy}); + histos.add("particles/vtx/deltaz", "V_{z} - VTX_{z}", kTH1D, {axisVz}); + histos.add("particles/FromCollVsFromMCColl", "FromCollVsFromMCColl", kTH2D, {{cfgBinning.binsMultiplicity, "PV contributor particles (good bc)"}, {cfgBinning.binsMultiplicityReco, "Particles in MC collision"}}); + histos.add("particles/FromCollVsFromMCCollBad", "FromCollVsFromMCCollBad", kTH2D, {{cfgBinning.binsMultiplicity, "PV contributor particles (bad bc)"}, {cfgBinning.binsMultiplicityReco, "Particles in MC collision"}}); + histos.add("particles/FromCollVsFromCollBad", "FromCollVsFromCollBad", kTH2D, {{cfgBinning.binsMultiplicity, "PV contributor particles (good bc)"}, {cfgBinning.binsMultiplicity, "PV contributor particles (bad bc)"}}); + histos.add("particles/FromCollBadOverFromCollVsVsFromMCColl", "FromCollBadOverFromCollVsVsFromMCColl", kTH2D, {{100, 0, 2, "bad/good"}, {cfgBinning.binsMultiplicityReco, "Particles in MC collision"}}); + + if (doprocessReco) { + histos.add("V0s/V0RecovsPV", "V0s Reco + Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("V0s/V0RecoAssvsPV", "V0s Reco + Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("V0s/V0AssvsPV", "V0s Ass vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityGenV0s}); + histos.add("V0s/V0RecoAssvsPV_TOFOneLeg", "V0s Reco + Ass + TOF 1 Leg vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + histos.add("V0s/V0RecoAssvsPV_TOFTwoLegs", "V0s Reco + Ass + TOF 2 Legs vs PV", kTH2D, {axisMultiplicityRecoITS, axisMultiplicityRecoV0s}); + } for (int i = 0; i < Estimators::nEstimators; i++) { if (enabledEstimators->get(Estimators::estimatorNames[i], "Enable") != 1) { @@ -282,6 +378,8 @@ struct McParticlePrediction { for (int i = 0; i < PIDExtended::NIDsTot; i++) { h->GetXaxis()->SetBinLabel(i + 1, PIDExtended::getName(i)); } + histos.addClone("particles/yields", "particles/idBeforePrimarySelection"); + histos.addClone("particles/yields", "particles/idAfterPrimarySelection"); for (int i = 0; i < Estimators::nEstimators; i++) { if (!enabledEstimatorsArray[i]) { @@ -362,6 +460,7 @@ struct McParticlePrediction { enabledParticlesArray[i] = false; continue; } + selectPrimariesArray[i] = (enabledSpecies->get(PIDExtended::getName(i), "SelectPrimaries") == 1); LOG(info) << "Enabling particle " << i << " " << PIDExtended::getName(i); enabledParticlesArray[i] = true; for (int j = 0; j < Estimators::nEstimators; j++) { @@ -373,16 +472,28 @@ struct McParticlePrediction { axisThisEstimator = axisImpactParameter; } const char* name = Estimators::estimatorNames[j]; - hpt[j][i] = histosPt.add(Form("prediction/pt/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH2D, {axisPt, axisThisEstimator}); - hpt[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); - + if (cfgPrediction.enablePt) { + hpt[j][i] = histosPt.add(Form("prediction/pt/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH2D, {axisPt, axisThisEstimator}); + hpt[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + } + if (cfgPrediction.enableEta) { + heta[j][i] = histosEta.add(Form("prediction/eta/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH2D, {axisEta, axisThisEstimator}); + heta[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + } + if (cfgPrediction.enableY) { + hy[j][i] = histosY.add(Form("prediction/y/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH2D, {axisRapidity, axisThisEstimator}); + hy[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + } hyield[j][i] = histosYield.add(Form("prediction/yield/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH1D, {axisThisEstimator}); hyield[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); + hyield[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s in |y| < %.2f", PIDExtended::getName(i), rapidityCut.value)); } } histos.print(); histosRecoEvs.print(); histosPt.print(); + histosEta.print(); + histosY.print(); histosYield.print(); } @@ -422,6 +533,22 @@ struct McParticlePrediction { if (enabledEstimatorsArray[Estimators::ZNC]) { nMult[Estimators::ZNC] = mCounter.countZNC(mcParticles); } + if (enabledEstimatorsArray[Estimators::ZEM1]) { + LOG(warn) << "Estimator ZEM1 is not implemented yet"; + nMult[Estimators::ZEM1] = 0; + } + if (enabledEstimatorsArray[Estimators::ZEM2]) { + LOG(warn) << "Estimator ZEM2 is not implemented yet"; + nMult[Estimators::ZEM2] = 0; + } + if (enabledEstimatorsArray[Estimators::ZPA]) { + LOG(warn) << "Estimator ZPA is not implemented yet"; + nMult[Estimators::ZPA] = 0; + } + if (enabledEstimatorsArray[Estimators::ZPC]) { + LOG(warn) << "Estimator ZPC is not implemented yet"; + nMult[Estimators::ZPC] = 0; + } if (enabledEstimatorsArray[Estimators::ITSIB] || enableVsITSHistograms) { nMult[Estimators::ITSIB] = mCounter.countITSIB(mcParticles); } @@ -458,7 +585,7 @@ struct McParticlePrediction { } histos.fill(HIST("collisions/generated"), 1); - if (std::abs(mcCollision.posZ()) > cfgEvtZvtxCut) { + if (std::abs(mcCollision.posZ()) > posZCut.value) { return; } histos.fill(HIST("collisions/generated"), 2); @@ -496,54 +623,60 @@ struct McParticlePrediction { continue; } - // if (!particle.isPhysicalPrimary()) { - // continue; - // } + // Count ids before applying the primary selection + histos.fill(HIST("particles/idBeforePrimarySelection"), id); + if (selectPrimariesArray[id] && !particle.isPhysicalPrimary()) { + continue; + } + // Count ids surviving the primary selection + histos.fill(HIST("particles/idAfterPrimarySelection"), id); - TParticlePDG* p = pdgDB->GetParticle(particle.pdgCode()); + const TParticlePDG* p = pdgDB->GetParticle(particle.pdgCode()); if (p) { if (std::abs(p->Charge()) > chargetolerance) { histos.fill(HIST("particles/eta/charged"), particle.eta()); + histos.fill(HIST("particles/y/charged"), particle.y()); } else { histos.fill(HIST("particles/eta/neutral"), particle.eta()); + histos.fill(HIST("particles/y/neutral"), particle.y()); } + } else { + histos.fill(HIST("particles/eta/undefined"), particle.eta()); + histos.fill(HIST("particles/y/undefined"), particle.y()); } - if (std::abs(particle.y()) >= rapidityCut) { - continue; - } - - // Check if particle has daughters (not a final state particle) - auto daughters = particle.daughters_as(); - bool isValid = false; - - if (daughters.size() > 0) { - isValid = true; - for (const auto& daughter : daughters) { - if (!daughter.isPhysicalPrimary()) { - isValid = false; - break; + if (std::abs(particle.pt()) > ptCut.value) { // Fill the eta and rapidity histograms only for particles above the pt cut + for (int i = 0; i < Estimators::nEstimators; i++) { + if (!enabledEstimatorsArray[i]) { + continue; + } + if (heta[i][id]) { + heta[i][id]->Fill(particle.eta(), nMult[i]); + } + if (hy[i][id]) { + hy[i][id]->Fill(particle.y(), nMult[i]); } } - } else { - // Final state particle - check if particle itself is physical primary - isValid = particle.isPhysicalPrimary(); } - - if (!isValid) { + if (std::abs(particle.y()) >= rapidityCut) { continue; } histos.fill(HIST("particles/vtx/x"), particle.vx()); histos.fill(HIST("particles/vtx/y"), particle.vy()); - histos.fill(HIST("particles/vtx/z"), particle.vz() - mcCollision.posZ()); + histos.fill(HIST("particles/vtx/z"), particle.vz()); + histos.fill(HIST("particles/vtx/deltax"), particle.vx() - mcCollision.posX()); + histos.fill(HIST("particles/vtx/deltay"), particle.vy() - mcCollision.posY()); + histos.fill(HIST("particles/vtx/deltaz"), particle.vz() - mcCollision.posZ()); histos.fill(HIST("particles/yields"), id); for (int i = 0; i < Estimators::nEstimators; i++) { if (!enabledEstimatorsArray[i]) { continue; } - hpt[i][id]->Fill(particle.pt(), nMult[i]); + if (hpt[i][id]) { + hpt[i][id]->Fill(particle.pt(), nMult[i]); + } hyield[i][id]->Fill(nMult[i]); } } diff --git a/PWGLF/Tasks/QC/v0cascadesqa.cxx b/PWGLF/Tasks/QC/v0cascadesqa.cxx index ba6ddd38f84..99c7d37699c 100644 --- a/PWGLF/Tasks/QC/v0cascadesqa.cxx +++ b/PWGLF/Tasks/QC/v0cascadesqa.cxx @@ -126,6 +126,8 @@ struct v0cascadesQA { RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + const float ctauxiPDG = 4.91; // from PDG + const float ctauomegaPDG = 2.461; // from PDG struct : ConfigurableGroup { std::string prefix = "v0Selections"; // JSON group name @@ -205,7 +207,7 @@ struct v0cascadesQA { Configurable dcabachtopv{"dcabachtopv", .05, "min DCA Bachelor To PV (cm)"}; Configurable cascradius{"cascradius", 0.5, "minimum Cascade radius (cm)"}; Configurable cascradiusMax{"cascradiusMax", 1E5, "maximum Cascade radius (cm)"}; - Configurable cascProperLifeTime{"cascProperLifeTime", 3, "maximum lifetime (ctau)"}; + Configurable cascProperLifeTime{"cascProperLifeTime", 3, "maximum lifetime (meanctau)"}; // invariant mass selection Configurable v0MassWindow{"v0MassWindow", 0.008, "#Lambda mass (GeV/#it{c}^{2})"}; @@ -877,9 +879,9 @@ struct v0cascadesQA { // // proper lifetime float distOverTotMom = std::sqrt(std::pow(casc.x() - collision.posX(), 2) + std::pow(casc.y() - collision.posY(), 2) + std::pow(casc.z() - collision.posZ(), 2)) / (casc.p() + 1E-10); - if ((cascType == kXiM || cascType == kXiP) && distOverTotMom * o2::constants::physics::MassXiMinus > cascSelections.cascProperLifeTime) + if ((cascType == kXiM || cascType == kXiP) && distOverTotMom * o2::constants::physics::MassXiMinus > (cascSelections.cascProperLifeTime * ctauxiPDG)) return false; - if ((cascType == kOmegaM || cascType == kOmegaP) && distOverTotMom * o2::constants::physics::MassOmegaMinus > cascSelections.cascProperLifeTime) + if ((cascType == kOmegaM || cascType == kOmegaP) && distOverTotMom * o2::constants::physics::MassOmegaMinus > (cascSelections.cascProperLifeTime * ctauomegaPDG)) return false; // rapidity diff --git a/PWGLF/Tasks/Resonances/CMakeLists.txt b/PWGLF/Tasks/Resonances/CMakeLists.txt index eddc93d741b..dd59bcb8ef2 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -328,3 +328,8 @@ o2physics_add_dpl_workflow(lambda1520-analysis-po SOURCES lambda1520analysispo.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cha01710analysis + SOURCES cha01710analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Resonances/cha01710analysis.cxx b/PWGLF/Tasks/Resonances/cha01710analysis.cxx new file mode 100644 index 00000000000..10d32a35f3d --- /dev/null +++ b/PWGLF/Tasks/Resonances/cha01710analysis.cxx @@ -0,0 +1,406 @@ +// 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 cha01710analysis.cxx +/// \brief charged a01710 resonance analysis +/// \author Junlee Kim (jikim1290@gmail.com) + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#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 + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct Cha01710analysis { + enum CentSel { + kFT0C = 0, + kFT0M + }; + + enum V0MassRegion { + kReject = 0, + kSignal, + kSideband + }; + + TRandom* rn = new TRandom(); + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + + Configurable cfgUrl{"cfgUrl", "http://alice-ccdb.cern.ch", "CCDB URL"}; + + struct : ConfigurableGroup { + Configurable cfgCentEst{"cfgCentEst", 1, "0: FT0C, 1: FT0M"}; + Configurable cfgZVertexMax{"cfgZVertexMax", 10.f, "maximum |zPV| (cm)"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8"}; + Configurable cfgRequireGoodZvtx{"cfgRequireGoodZvtx", true, "require kIsGoodZvtxFT0vsPV"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", true, "require kNoSameBunchPileup"}; + } eventCuts; + + struct : ConfigurableGroup { + Configurable cfgV0PtMin{"cfgV0PtMin", 0.f, "minimum K0S pT"}; + Configurable cfgV0PtMax{"cfgV0PtMax", 100.f, "maximum K0S pT"}; + Configurable cfgV0RapidityMax{"cfgV0RapidityMax", 0.5f, "maximum |y(K0S)|"}; + Configurable cfgV0DcaDaughtersMax{"cfgV0DcaDaughtersMax", 1.f, "maximum daughter DCA"}; + Configurable cfgV0CosPAMin{"cfgV0CosPAMin", 0.97f, "minimum V0 cosine pointing angle"}; + Configurable cfgV0RadiusMin{"cfgV0RadiusMin", 0.5f, "minimum V0 radius (cm)"}; + Configurable cfgV0CtauMax{"cfgV0CtauMax", 15.f, "maximum K0S c tau (cm)"}; + Configurable cfgV0DaughterDcaPVMin{"cfgV0DaughterDcaPVMin", 0.06f, "minimum daughter |DCA to PV|"}; + Configurable cfgV0DaughterEtaMax{"cfgV0DaughterEtaMax", 0.8f, "maximum daughter |eta|"}; + Configurable cfgV0DaughterPtMin{"cfgV0DaughterPtMin", 0.1f, "minimum daughter pT"}; + Configurable cfgV0DaughterTPCNClsMin{"cfgV0DaughterTPCNClsMin", 70, "minimum daughter TPC clusters"}; + Configurable cfgV0DaughterTPCNSigmaPiMax{"cfgV0DaughterTPCNSigmaPiMax", 5.f, "maximum daughter |TPC nSigma(pi)|"}; + Configurable cfgV0DaughterTOFNSigmaPiMax{"cfgV0DaughterTOFNSigmaPiMax", 5.f, "maximum daughter |TOF nSigma(pi)|"}; + Configurable cfgKsMassWindow{"cfgKsMassWindow", 0.01, "K short mass window"}; + Configurable cfgRejectLambda{"cfgRejectLambda", true, "reject Lambda/anti-Lambda competitors"}; + Configurable cfgLambdaMassWindow{"cfgLambdaMassWindow", 0.005f, "Lambda rejection window (GeV/c2)"}; + } v0Cuts; + + struct : ConfigurableGroup { + Configurable cfgPtMin{"cfgPtMin", 0.2f, "minimum charged-kaon pT"}; + Configurable cfgEtaMax{"cfgEtaMax", 0.8f, "maximum charged-kaon |eta|"}; + Configurable cfgTPCCrossedRowsMin{"cfgTPCCrossedRowsMin", 70, "minimum crossed TPC rows"}; + Configurable cfgCrossedRowsRatioMin{"cfgCrossedRowsRatioMin", 0.8f, "minimum crossed/findable ratio"}; + Configurable cfgTPCChi2Max{"cfgTPCChi2Max", 4.f, "maximum TPC chi2/cluster"}; + Configurable cfgITSChi2Max{"cfgITSChi2Max", 36.f, "maximum ITS chi2/cluster"}; + Configurable cfgDcaXYMax{"cfgDcaXYMax", 0.5f, "maximum |DCAxy| (cm)"}; + Configurable cfgDcaZMax{"cfgDcaZMax", 2.f, "maximum |DCAz| (cm)"}; + Configurable cfgTPCNSigmaMax{"cfgTPCNSigmaMax", 3.f, "maximum |TPC nSigma(K)| without TOF"}; + Configurable cfgCombinedNSigmaMax{"cfgCombinedNSigmaMax", 3.f, "maximum combined TPC-TOF nSigma(K)"}; + } kaonCuts; + + struct : ConfigurableGroup { + Configurable cfgRequireQVector{"cfgRequireQVector", true, "reject events with an invalid Q-vector"}; + Configurable cfgQvecHarmonic{"cfgQvecHarmonic", 2, "event-plane harmonic"}; + Configurable cfgQvecNumDetectors{"cfgQvecNumDetectors", 7, "number of detectors in the Q-vector table"}; + Configurable cfgQvecDetName{"cfgQvecDetName", "FT0M", "detector used for the event plane"}; + Configurable cfgQvecRefAName{"cfgQvecRefAName", "TPCpos", "event-plane reference A"}; + Configurable cfgQvecRefBName{"cfgQvecRefBName", "TPCneg", "event-plane reference B"}; + Configurable cfgQvecAmplitudeMin{"cfgQvecAmplitudeMin", 1.e-4f, "minimum accepted Q-vector amplitude"}; + } epConfig; + + Configurable cfgMotherRapidityMax{"cfgMotherRapidityMax", 0.5f, "maximum |y(K0S K)|"}; + Configurable cfgNRotations{"cfgNRotations", 3, "number of deterministic rotations per candidate"}; + + ConfigurableAxis cfgAxisMass{"cfgAxisMass", {300, 1.0, 2.5}, "M(K^{0}_{S}K^{#pm}) (GeV/c^{2})"}; + ConfigurableAxis cfgAxisPt{"cfgAxisPt", {200, 0., 20.}, "pT(K^{0}_{S}K^{#pm}) (GeV/c)"}; + ConfigurableAxis cfgAxisCent{"cfgAxisCent", {VARIABLE_WIDTH, 0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 100.}, "FT0M centrality (%)"}; + ConfigurableAxis cfgAxisEP{"cfgAxisEP", {6, 0., constants::math::TwoPI}, "n#Delta#varphi = n(#varphi-#Psi_{n})"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < eventCuts.cfgZVertexMax; + Filter trackFilter = nabs(aod::track::eta) < kaonCuts.cfgEtaMax && aod::track::pt > kaonCuts.cfgPtMin; + + using Collisions = soa::Filtered>; + using Tracks = soa::Filtered>; + using V0s = soa::Join; + + int detId = 0; + int refAId = 4; + int refBId = 5; + int minHarm = 2; + + float centrality = -1.; + float rotmin = 5.0 / 6.0; + float rotmax = 7.0 / 6.0; + + template + int getDetId(T const& name) + { + if (name.value == "FT0C") { + return 0; + } + if (name.value == "FT0A") { + return 1; + } + if (name.value == "FT0M") { + return 2; + } + if (name.value == "FV0A") { + return 3; + } + if (name.value == "TPCpos") { + return 4; + } + if (name.value == "TPCneg") { + return 5; + } + LOGF(warning, "Unknown Q-vector detector %s; using FT0C", name.value.c_str()); + return 0; + } + + void init(InitContext const&) + { + histos.add("Event/hCutFlow", "event cut flow", HistType::kTH1F, {{6, -0.5, 5.5}}); + histos.add("Event/hCentDist", "", HistType::kTH1F, {{120, 0, 120}}); + histos.add("Event/hPVzDist", "", HistType::kTH1F, {{200, -12, 12}}); + + histos.add("EventPlane/hPsiDet", "event plane, detector", HistType::kTH2F, {cfgAxisCent, {180, -constants::math::PI, constants::math::PI}}); + histos.add("EventPlane/hPsiRefA", "event plane, reference A", HistType::kTH2F, {cfgAxisCent, {180, -constants::math::PI, constants::math::PI}}); + histos.add("EventPlane/hPsiRefB", "event plane, reference B", HistType::kTH2F, {cfgAxisCent, {180, -constants::math::PI, constants::math::PI}}); + histos.add("EventPlane/hResolutionDetRefA", "cos[n(PsiDet-PsiRefA)]", HistType::kTH2F, {cfgAxisCent, {102, -1.02, 1.02}}); + histos.add("EventPlane/hResolutionDetRefB", "cos[n(PsiDet-PsiRefB)]", HistType::kTH2F, {cfgAxisCent, {102, -1.02, 1.02}}); + histos.add("EventPlane/hResolutionRefARefB", "cos[n(PsiRefA-PsiRefB)]", HistType::kTH2F, {cfgAxisCent, {102, -1.02, 1.02}}); + + histos.add("V0/hMassBefore", "K0S mass before selection", HistType::kTH2F, {{200, 0.45, 0.55}, cfgAxisPt}); + histos.add("V0/hMassSelected", "selected K0S signal", HistType::kTH2F, {{200, 0.45, 0.55}, cfgAxisPt}); + + histos.add("Kaon/hTPCNSigma", "charged kaon TPC PID", HistType::kTH2F, {cfgAxisPt, {120, -6., 6.}}); + histos.add("Kaon/hTOFNSigma", "charged kaon TOF PID", HistType::kTH2F, {cfgAxisPt, {120, -6., 6.}}); + + histos.add("Pair/hSignalPlus", "K0S K+ same-event versus EP", HistType::kTHnSparseF, {cfgAxisMass, cfgAxisPt, cfgAxisCent, cfgAxisEP}); + histos.add("Pair/hSignalMinus", "K0S K- same-event versus EP", HistType::kTHnSparseF, {cfgAxisMass, cfgAxisPt, cfgAxisCent, cfgAxisEP}); + histos.add("Pair/hSidebandPlus", "K0S-sideband K+ versus EP", HistType::kTHnSparseF, {cfgAxisMass, cfgAxisPt, cfgAxisCent, cfgAxisEP}); + histos.add("Pair/hSidebandMinus", "K0S-sideband K- versus EP", HistType::kTHnSparseF, {cfgAxisMass, cfgAxisPt, cfgAxisCent, cfgAxisEP}); + histos.add("Pair/hRotatedPlus", "rotated K+ background versus EP", HistType::kTH3F, {cfgAxisMass, cfgAxisPt, cfgAxisCent}); + histos.add("Pair/hRotatedMinus", "rotated K- background versus EP", HistType::kTH3F, {cfgAxisMass, cfgAxisPt, cfgAxisCent}); + histos.add("Pair/hMassVsK0SMass", "pair mass versus reconstructed K0S mass", HistType::kTH2F, {cfgAxisMass, {200, 0.43, 0.57}}); + + detId = getDetId(epConfig.cfgQvecDetName); + refAId = getDetId(epConfig.cfgQvecRefAName); + refBId = getDetId(epConfig.cfgQvecRefBName); + if (detId == refAId || detId == refBId || refAId == refBId) { + LOGF(warning, "Q-vector detector names are not distinct; falling back to FT0M, TPCpos, TPCneg"); + detId = 0; + refAId = 4; + refBId = 5; + } + if (epConfig.cfgQvecHarmonic < minHarm) { + LOGF(fatal, "cfgQvecHarmonic must be >= 2"); + } + + ccdb->setURL(cfgUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + template + bool selectEvent(C const& collision) + { + histos.fill(HIST("Event/hCutFlow"), 0.); + if (eventCuts.cfgRequireSel8 && !collision.sel8()) { + return false; + } + histos.fill(HIST("Event/hCutFlow"), 1.); + if (eventCuts.cfgRequireGoodZvtx && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("Event/hCutFlow"), 2.); + if (eventCuts.cfgRequireNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("Event/hCutFlow"), 3.); + + if (epConfig.cfgRequireQVector && + (collision.qvecAmp()[detId] < epConfig.cfgQvecAmplitudeMin || + collision.qvecAmp()[refAId] < epConfig.cfgQvecAmplitudeMin || + collision.qvecAmp()[refBId] < epConfig.cfgQvecAmplitudeMin)) { + return false; + } + histos.fill(HIST("Event/hCutFlow"), 4.); + return true; + } + + template + bool selectKaon(T const& track) + { + if (!track.isPVContributor() || !track.isGlobalTrackWoDCA() || !track.isPrimaryTrack()) { + return false; + } + if (track.tpcNClsCrossedRows() < kaonCuts.cfgTPCCrossedRowsMin || + track.tpcCrossedRowsOverFindableCls() < kaonCuts.cfgCrossedRowsRatioMin || + track.tpcChi2NCl() > kaonCuts.cfgTPCChi2Max || track.itsChi2NCl() > kaonCuts.cfgITSChi2Max || + std::abs(track.dcaXY()) > kaonCuts.cfgDcaXYMax || std::abs(track.dcaZ()) > kaonCuts.cfgDcaZMax) { + return false; + } + histos.fill(HIST("Kaon/hTPCNSigma"), track.pt(), track.tpcNSigmaKa()); + if (track.hasTOF()) { + histos.fill(HIST("Kaon/hTOFNSigma"), track.pt(), track.tofNSigmaKa()); + return std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()) < kaonCuts.cfgCombinedNSigmaMax; + } + return std::abs(track.tpcNSigmaKa()) < kaonCuts.cfgTPCNSigmaMax; + } + + template + bool selectPionDaughter(T const& track) + { + if (!track.hasTPC() || track.tpcNClsFound() < v0Cuts.cfgV0DaughterTPCNClsMin || + track.pt() < v0Cuts.cfgV0DaughterPtMin || std::abs(track.eta()) > v0Cuts.cfgV0DaughterEtaMax || + std::abs(track.tpcNSigmaPi()) > v0Cuts.cfgV0DaughterTPCNSigmaPiMax) { + return false; + } + return true; + } + + template + V0MassRegion selectV0(C const& collision, V const& v0) + { + histos.fill(HIST("V0/hMassBefore"), v0.mK0Short(), v0.pt()); + float ctau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassK0Short; + if (v0.pt() < v0Cuts.cfgV0PtMin || v0.pt() > v0Cuts.cfgV0PtMax || + v0.dcaV0daughters() > v0Cuts.cfgV0DcaDaughtersMax || v0.v0cosPA() < v0Cuts.cfgV0CosPAMin || + v0.v0radius() < v0Cuts.cfgV0RadiusMin || std::abs(ctau) > v0Cuts.cfgV0CtauMax) { + return V0MassRegion::kReject; + } + if (v0Cuts.cfgRejectLambda && + (std::abs(v0.mLambda() - constants::physics::MassLambda0) < v0Cuts.cfgLambdaMassWindow || + std::abs(v0.mAntiLambda() - constants::physics::MassLambda0) < v0Cuts.cfgLambdaMassWindow)) { + return V0MassRegion::kReject; + } + auto pos = v0.template posTrack_as(); + auto neg = v0.template negTrack_as(); + if (!selectPionDaughter(pos) || !selectPionDaughter(neg)) { + return V0MassRegion::kReject; + } + ROOT::Math::PxPyPzMVector k0(v0.px(), v0.py(), v0.pz(), constants::physics::MassK0Short); + if (std::abs(k0.Rapidity()) > v0Cuts.cfgV0RapidityMax) { + return V0MassRegion::kReject; + } + float dm = std::abs(v0.mK0Short() - constants::physics::MassK0Short); + if (dm < v0Cuts.cfgKsMassWindow) { + histos.fill(HIST("V0/hMassSelected"), v0.mK0Short(), v0.pt()); + return V0MassRegion::kSignal; + } + if (dm > v0Cuts.cfgKsMassWindow) { + histos.fill(HIST("V0/hMassSelected"), v0.mK0Short(), v0.pt()); + return V0MassRegion::kSideband; + } + return V0MassRegion::kReject; + } + + template + void fillHistograms(CollisionType const& collision, TracksType const& dTracks, V0Type const& v0s) + { + int harmonic = epConfig.cfgQvecHarmonic; + int qVecDetInd = detId * 4 + 3 + (harmonic - 2) * epConfig.cfgQvecNumDetectors * 4; + int qVecRefAInd = refAId * 4 + 3 + (harmonic - 2) * epConfig.cfgQvecNumDetectors * 4; + int qVecRefBInd = refBId * 4 + 3 + (harmonic - 2) * epConfig.cfgQvecNumDetectors * 4; + + float eventPlaneDet = std::atan2(collision.qvecIm()[qVecDetInd], collision.qvecRe()[qVecDetInd]) / static_cast(harmonic); + float eventPlaneRefA = std::atan2(collision.qvecIm()[qVecRefAInd], collision.qvecRe()[qVecRefAInd]) / static_cast(harmonic); + float eventPlaneRefB = std::atan2(collision.qvecIm()[qVecRefBInd], collision.qvecRe()[qVecRefBInd]) / static_cast(harmonic); + + histos.fill(HIST("EventPlane/hPsiDet"), centrality, eventPlaneDet); + histos.fill(HIST("EventPlane/hPsiRefA"), centrality, eventPlaneRefA); + histos.fill(HIST("EventPlane/hPsiRefB"), centrality, eventPlaneRefB); + histos.fill(HIST("EventPlane/hResolutionDetRefA"), centrality, std::cos(harmonic * (eventPlaneDet - eventPlaneRefA))); + histos.fill(HIST("EventPlane/hResolutionDetRefB"), centrality, std::cos(harmonic * (eventPlaneDet - eventPlaneRefB))); + histos.fill(HIST("EventPlane/hResolutionRefARefB"), centrality, std::cos(harmonic * (eventPlaneRefA - eventPlaneRefB))); + + for (const auto& v0 : v0s) { + auto region = selectV0(collision, v0); + if (region == kReject) { + continue; + } + auto pos = v0.template posTrack_as(); + auto neg = v0.template negTrack_as(); + + ROOT::Math::PxPyPzMVector k0(v0.px(), v0.py(), v0.pz(), constants::physics::MassK0Short); + + for (const auto& track : dTracks) { + if (track.globalIndex() == pos.globalIndex() || track.globalIndex() == neg.globalIndex() || !selectKaon(track)) { + continue; + } + ROOT::Math::PxPyPzMVector kaon(track.px(), track.py(), track.pz(), constants::physics::MassKaonCharged); + auto mother = k0 + kaon; + if (std::abs(mother.Rapidity()) > cfgMotherRapidityMax) { + continue; + } + + float relPhi = TVector2::Phi_0_2pi((mother.Phi() - eventPlaneDet) * harmonic); + histos.fill(HIST("Pair/hMassVsK0SMass"), mother.M(), v0.mK0Short()); + if (region != kSignal) + continue; + if (track.sign() > 0) { + histos.fill(HIST("Pair/hSignalPlus"), mother.M(), mother.Pt(), centrality, relPhi); + } else if (track.sign() < 0) { + histos.fill(HIST("Pair/hSignalMinus"), mother.M(), mother.Pt(), centrality, relPhi); + } + for (int i = 0; i < cfgNRotations; ++i) { + auto randomPhi = rn->Uniform(o2::constants::math::PI * rotmin, o2::constants::math::PI * rotmax); + randomPhi += kaon.Phi(); + auto kaonRot = ROOT::Math::PxPyPzMVector(kaon.Pt() * std::cos(randomPhi), kaon.Pt() * std::sin(randomPhi), track.pz(), o2::constants::physics::MassKaonCharged); + auto motherRot = k0 + kaonRot; + if (std::abs(motherRot.Rapidity()) > cfgMotherRapidityMax) + continue; + + if (track.sign() > 0) { + histos.fill(HIST("Pair/hRotatedPlus"), motherRot.M(), motherRot.Pt(), centrality); + } else if (track.sign() < 0) { + histos.fill(HIST("Pair/hRotatedMinus"), motherRot.M(), motherRot.Pt(), centrality); + } + } + } + } + } + + void processDataSame(Collisions::iterator const& collision, Tracks const& tracks, V0s const& v0s) + { + if (!selectEvent(collision)) { + return; + } + if (eventCuts.cfgCentEst == kFT0M) { + centrality = collision.centFT0M(); + } else if (eventCuts.cfgCentEst == kFT0C) { + centrality = collision.centFT0C(); + } else { + centrality = collision.centFT0M(); + } + + histos.fill(HIST("Event/hCentDist"), centrality); + histos.fill(HIST("Event/hPVzDist"), collision.posZ()); + + fillHistograms(collision, tracks, v0s); + }; + PROCESS_SWITCH(Cha01710analysis, processDataSame, "Process Event for data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx index 8caa58152ca..987e164063f 100644 --- a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx +++ b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx @@ -94,6 +94,7 @@ struct Chargedkstaranalysis { Preslice perCollision = aod::track::collisionId; Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; bool currentIsGen = false; + bool mcClosure = false; struct : ConfigurableGroup { ConfigurableAxis cfgvtxbins{"cfgvtxbins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; ConfigurableAxis cfgmultbins{"cfgmultbins", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Mixing bins - multiplicity"}; @@ -155,8 +156,8 @@ struct Chargedkstaranalysis { // Event Mixing Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; - Service ccdb; - Service pdg; + Service ccdb{}; + Service pdg{}; o2::ccdb::CcdbApi ccdbApi; Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; @@ -226,6 +227,7 @@ struct Chargedkstaranalysis { // MC configurables struct : ConfigurableGroup { Configurable doBkgMc{"doBkgMc", false, "Apply rotation in MC"}; + Configurable doMcClosure{"doMcClosure", true, "Do MC Closure Study in MC"}; } mcCfgs; /// Track selections @@ -300,7 +302,7 @@ struct Chargedkstaranalysis { } kstarCutCfgs; Configurable isQaRequired{"isQaRequired", false, "Fill QA plots"}; - float centrality; + float centrality = 0.f; // PDG code int kPDGK0s = kK0Short; @@ -562,9 +564,12 @@ struct Chargedkstaranalysis { if (!helicityCfgs.qAOptimisation) { 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); + 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); } } @@ -602,7 +607,7 @@ struct Chargedkstaranalysis { std::unordered_map centTruthByAllowed; std::unordered_set refClassIds; std::unordered_map refCentByMcId; - float lMultiplicity; + float lMultiplicity = 0.f; template float getCentrality(CollisionType const& collision) { @@ -624,76 +629,100 @@ struct Chargedkstaranalysis { int ibin = 1; auto applyCut = [&](bool condition) -> bool { - if (!condition) + if (!condition) { return false; - if (!doprocessMC && isQaRequired) + } + if (!doprocessMC && isQaRequired) { histos.fill(HIST("QA/hTrackCutFlow"), ibin); + } ibin++; return true; }; // First bin (before any cuts) - if (!doprocessMC && isQaRequired) + if (!doprocessMC && isQaRequired) { histos.fill(HIST("QA/hTrackCutFlow"), ibin++); + } // Cuts - if (!applyCut(std::abs(track.pt()) >= trackCutCfgs.cMinPtcut)) + if (!applyCut(std::abs(track.pt()) >= trackCutCfgs.cMinPtcut)) { return false; - if (!applyCut(std::abs(track.eta()) <= trackCutCfgs.cMaxEtacut)) + } + if (!applyCut(std::abs(track.eta()) <= trackCutCfgs.cMaxEtacut)) { return false; - if (!applyCut(track.itsNCls() >= trackCutCfgs.cfgITScluster)) + } + if (!applyCut(track.itsNCls() >= trackCutCfgs.cfgITScluster)) { return false; - if (!applyCut(track.tpcNClsFound() >= trackCutCfgs.cfgTPCcluster)) + } + if (!applyCut(track.tpcNClsFound() >= trackCutCfgs.cfgTPCcluster)) { return false; - if (!applyCut(track.tpcCrossedRowsOverFindableCls() >= trackCutCfgs.cfgRatioTPCRowsOverFindableCls)) + } + if (!applyCut(track.tpcCrossedRowsOverFindableCls() >= trackCutCfgs.cfgRatioTPCRowsOverFindableCls)) { return false; - if (!applyCut(track.itsChi2NCl() < trackCutCfgs.cfgITSChi2NCl)) + } + if (!applyCut(track.itsChi2NCl() < trackCutCfgs.cfgITSChi2NCl)) { return false; - if (!applyCut(track.tpcChi2NCl() < trackCutCfgs.cfgTPCChi2NCl)) + } + if (!applyCut(track.tpcChi2NCl() < trackCutCfgs.cfgTPCChi2NCl)) { return false; - - if (!applyCut(!trackCutCfgs.cfgHasITS || track.hasITS())) + } + if (!applyCut(!trackCutCfgs.cfgHasITS || track.hasITS())) { return false; - if (!applyCut(!trackCutCfgs.cfgHasTPC || track.hasTPC())) + } + if (!applyCut(!trackCutCfgs.cfgHasTPC || track.hasTPC())) { return false; - if (!applyCut(!trackCutCfgs.cfgHasTOF || track.hasTOF())) + } + if (!applyCut(!trackCutCfgs.cfgHasTOF || track.hasTOF())) { return false; + } - if (!applyCut(!trackCutCfgs.cfgUseITSRefit || track.passedITSRefit())) + if (!applyCut(!trackCutCfgs.cfgUseITSRefit || track.passedITSRefit())) { return false; - if (!applyCut(!trackCutCfgs.cfgUseTPCRefit || track.passedTPCRefit())) + } + if (!applyCut(!trackCutCfgs.cfgUseTPCRefit || track.passedTPCRefit())) { return false; + } - if (!applyCut(!trackCutCfgs.cfgPVContributor || track.isPVContributor())) + if (!applyCut(!trackCutCfgs.cfgPVContributor || track.isPVContributor())) { return false; - if (!applyCut(!trackCutCfgs.cfgGlobalWoDCATrack || track.isGlobalTrackWoDCA())) + } + if (!applyCut(!trackCutCfgs.cfgGlobalWoDCATrack || track.isGlobalTrackWoDCA())) { return false; - if (!applyCut(!trackCutCfgs.cfgGlobalTrack || track.isGlobalTrack())) + } + if (!applyCut(!trackCutCfgs.cfgGlobalTrack || track.isGlobalTrack())) { return false; - if (!applyCut(!trackCutCfgs.cfgPrimaryTrack || track.isPrimaryTrack())) + } + if (!applyCut(!trackCutCfgs.cfgPrimaryTrack || track.isPrimaryTrack())) { return false; + } - if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cMaxbDCArToPVcut)) + if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cMaxbDCArToPVcut)) { return false; - if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cMaxbDCAzToPVcut)) + } + if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cMaxbDCAzToPVcut)) { return false; + } // pT dependent DCA XY if (trackCutCfgs.cfgpTdepDCAxyCut) { - if (!applyCut(std::abs(track.dcaXY()) <= (0.004 + (0.013 / track.pt())))) + if (!applyCut(std::abs(track.dcaXY()) <= (0.004 + (0.013 / track.pt())))) { return false; + } } else { - if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cfgMaxbDCArToPVcut)) + if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cfgMaxbDCArToPVcut)) { return false; + } } // pT dependent DCA Z if (trackCutCfgs.cfgpTdepDCAzCut) { - if (!applyCut(std::abs(track.dcaZ()) <= (0.004 + (0.013 / track.pt())))) + if (!applyCut(std::abs(track.dcaZ()) <= (0.004 + (0.013 / track.pt())))) { return false; + } } else { - if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cfgMaxbDCAzToPVcut)) + if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cfgMaxbDCAzToPVcut)) { return false; + } } return true; @@ -702,13 +731,15 @@ struct Chargedkstaranalysis { template bool selectionPIDPion(TrackType const& candidate) { - if (std::abs(candidate.tpcNSigmaPi()) >= pidCutCfgs.cfgMaxTPCnSigmaPion) + if (std::abs(candidate.tpcNSigmaPi()) >= pidCutCfgs.cfgMaxTPCnSigmaPion) { return false; - if (pidCutCfgs.cfgTPConly) + } + if (pidCutCfgs.cfgTPConly) { return true; - if (candidate.pt() <= pidCutCfgs.cfgTOFMinPt) + } + if (candidate.pt() <= pidCutCfgs.cfgTOFMinPt) { return true; - + } if (candidate.hasTOF()) { const bool tofPIDPassed = std::abs(candidate.tofNSigmaPi()) < pidCutCfgs.cfgMaxTOFnSigmaPion; const bool combo = (pidCutCfgs.cfgNsigmaCutCombinedPion > 0) && @@ -716,9 +747,8 @@ struct Chargedkstaranalysis { candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < pidCutCfgs.cfgNsigmaCutCombinedPion * pidCutCfgs.cfgNsigmaCutCombinedPion); return tofPIDPassed || combo; - } else { - return pidCutCfgs.cfgTOFVeto; } + return pidCutCfgs.cfgTOFVeto; } template @@ -751,8 +781,9 @@ struct Chargedkstaranalysis { auto mLambda = candidate.mLambda(); auto mALambda = candidate.mAntiLambda(); - if (!doprocessMC && isQaRequired) + if (!doprocessMC && isQaRequired) { histos.fill(HIST("QA/K0sCutCheck"), ibin); + } applyCut(dauDCA <= secondaryCutsCfgs.cSecondaryDauDCAMax); applyCut(dauPosDCAtoPV >= secondaryCutsCfgs.cSecondaryDauPosDCAtoPVMin); @@ -774,26 +805,38 @@ struct Chargedkstaranalysis { template void fillKstarHist(bool isRot, float multiplicity, const T& mother, double cosTheta) { + // 1. Data Path if (!doprocessMC) { - if (isRot) { hChaKstar.fill(HIST("h3ChaKstarInvMassRot"), multiplicity, mother.Pt(), mother.M(), cosTheta); } else { hChaKstar.fill(HIST("h3ChaKstarInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosTheta); } + return; + } + + // 2. MC Generated Path + if (currentIsGen) { + if (isRot) { + histosMc.fill(HIST("h3ChaKstarInvMassRotMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } else { + histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } + return; + } + + // 3. MC Reconstructed Path + if (isRot) { + if (!mcClosure) { + histosMc.fill(HIST("h3ChaKstarInvMassRotMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } else { + histosMc.fill(HIST("h3ChaKstarInvMassRotMcRecClosure"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } } else { - if (currentIsGen) { - if (isRot) { - histosMc.fill(HIST("h3ChaKstarInvMassRotMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } else { - histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } + if (!mcClosure) { + histosMc.fill(HIST("h3ChaKstarInvMassDSMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); } else { - if (isRot) { - histosMc.fill(HIST("h3ChaKstarInvMassRotMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } else { - histosMc.fill(HIST("h3ChaKstarInvMassDSMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } + histosMc.fill(HIST("h3ChaKstarInvMassDSMcRecClosure"), multiplicity, mother.Pt(), mother.M(), cosTheta); } } } @@ -801,14 +844,14 @@ struct Chargedkstaranalysis { template void fillInvMass(const T& mother, float multiplicity, const T& daughter1, const T& daughter2, bool isMix) { - TRandom* rn = new TRandom(); + auto* rn = new TRandom(); rn->SetSeed(0); // Variable declarations ROOT::Math::PxPyPzMVector fourVecDauCM, daughterRot, motherRot, daughterRotCM; ROOT::Math::XYZVectorF beam1CM, beam2CM, zAxisCS, yAxisCS, xAxisCS; ROOT::Math::XYZVectorF v1CM, zaxisHE, yaxisHE, xaxisHE; ROOT::Math::XYZVector randomVec, beamVec, normalVec, normalVecRot, randomVecRot; - float theta2; + float theta2 = 0.0f; // //polarization calculations // zBeam = ROOT::Math::XYZVector(0.f, 0.f, 1.f); // ẑ: beam direction in lab frame @@ -844,7 +887,7 @@ struct Chargedkstaranalysis { auto phiCS = std::atan2(yAxisCS.Dot(v1CM), xAxisCS.Dot(v1CM)); phiCS = RecoDecay::constrainAngle(phiCS, 0.0); - bool doRotation = (!doprocessMC) || (doprocessMC && mcCfgs.doBkgMc); + bool doRotation = !doprocessMC || mcCfgs.doBkgMc; // if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { if (helicityCfgs.activateHelicityFrame) { // helicityVec = mother.Vect(); // 3 vector of mother in COM frame @@ -867,10 +910,11 @@ struct Chargedkstaranalysis { motherRot = daughterRot + daughter2; } ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - if (helicityCfgs.cCosWithKShot) + if (helicityCfgs.cCosWithKShot) { daughterRotCM = boost2(daughter1); - else + } else { daughterRotCM = boost2(daughterRot); + } auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); auto phiHelicityRot = std::atan2(yaxisHE.Dot(daughterRotCM.Vect().Unit()), xaxisHE.Dot(daughterRotCM.Vect().Unit())); @@ -934,10 +978,11 @@ struct Chargedkstaranalysis { motherRot = daughterRot + daughter2; } ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - if (helicityCfgs.cCosWithKShot) + if (helicityCfgs.cCosWithKShot) { daughterRotCM = boost2(daughter1); - else + } else { daughterRotCM = boost2(daughterRot); + } normalVecRot = ROOT::Math::XYZVector(motherRot.Py(), -motherRot.Px(), 0.f); auto cosThetaProductionRot = normalVecRot.Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(normalVecRot.Mag2())); @@ -1002,10 +1047,11 @@ struct Chargedkstaranalysis { } ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - if (helicityCfgs.cCosWithKShot) + if (helicityCfgs.cCosWithKShot) { daughterRotCM = boost2(daughter1); - else + } else { daughterRotCM = boost2(daughterRot); + } auto cosThetaStarRandomRot = randomVecRot.Dot(daughterRotCM.Vect()) / std::sqrt(daughterRotCM.Vect().Mag2()); if (std::abs(motherRot.Rapidity()) < helicityCfgs.rapidityMotherData) { @@ -1057,8 +1103,9 @@ struct Chargedkstaranalysis { } } - if (!trackCut(bTrack) || !selectionPIDPion(bTrack)) + if (!trackCut(bTrack) || !selectionPIDPion(bTrack)) { continue; + } if constexpr (!IsMix) { if (!doprocessMC && isQaRequired) { @@ -1140,8 +1187,9 @@ struct Chargedkstaranalysis { if ((!secondaryCutsCfgs.cfgByPassDauPIDSelection && (!selectionPIDPion(pos) || !selectionPIDPion(neg))) || - !selectionK0s(collision, K0scand)) + !selectionK0s(collision, K0scand)) { continue; + } if constexpr (!IsMix) { if (!doprocessMC && isQaRequired) { @@ -1175,7 +1223,6 @@ struct Chargedkstaranalysis { k0sIndicies.push_back(K0scand.index()); } - // ========================= // Pairing // ========================= @@ -1197,8 +1244,9 @@ struct Chargedkstaranalysis { } if (lResoKstar.Rapidity() > kstarCutCfgs.cKstarMaxRap || - lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) + lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) { continue; + } if constexpr (!IsMix) { if (!doprocessMC && isQaRequired) { @@ -1227,8 +1275,9 @@ struct Chargedkstaranalysis { aod::BCsWithTimestamps const&) { histos.fill(HIST("hEvtSelInfo"), 0.5); - if (!colCuts.isSelected(collision)) // Default event selection + if (!colCuts.isSelected(collision)) { // Default event selection return; + } histos.fill(HIST("hEvtSelInfo"), 1.5); if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(collision)) { return; @@ -1236,11 +1285,13 @@ struct Chargedkstaranalysis { histos.fill(HIST("hEvtSelInfo"), 2.5); lMultiplicity = getCentrality(collision); - if (lMultiplicity < eventCutCfgs.cfgEventCentralityMin || lMultiplicity > eventCutCfgs.cfgEventCentralityMax) + if (lMultiplicity < eventCutCfgs.cfgEventCentralityMin || lMultiplicity > eventCutCfgs.cfgEventCentralityMax) { return; + } histos.fill(HIST("hEvtSelInfo"), 3.5); - if (!collision.isInelGt0()) + if (!collision.isInelGt0()) { return; + } histos.fill(HIST("hEvtSelInfo"), 4.5); colCuts.fillQA(collision); fillHistograms(collision, tracks, v0s); @@ -1265,27 +1316,33 @@ struct Chargedkstaranalysis { for (const auto& [t1, t2] : o2::soa::combinations( o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { // Here t1 corressponds to bachelor track and t2 corressponds to v0s. - if (!trackCut(t1)) + if (!trackCut(t1)) { continue; - if (!selectionPIDPion(t1)) + } + if (!selectionPIDPion(t1)) { continue; + } auto posDauTrack = t2.template posTrack_as(); auto negDauTrack = t2.template negTrack_as(); - if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) // Perhaps it's already applied in trackCut (need to check QA plots) + if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) { // Perhaps it's already applied in trackCut (need to check QA plots) continue; - if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + } + if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) { continue; - if (!selectionK0s(c2, t2)) + } + if (!selectionK0s(c2, t2)) { continue; + } ROOT::Math::PxPyPzMVector lResoSecondary, lDecayDaughter_bach, lResoKstar; lDecayDaughter_bach = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), MassPionCharged); lResoSecondary = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), MassK0Short); lResoKstar = lResoSecondary + lDecayDaughter_bach; - if (lResoKstar.Rapidity() > kstarCutCfgs.cKstarMaxRap || lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) + if (lResoKstar.Rapidity() > kstarCutCfgs.cKstarMaxRap || lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) { continue; + } histos.fill(HIST("hInvmass_KstarME"), c1.centFT0M(), lResoKstar.Pt(), lResoKstar.M()); } } @@ -1301,8 +1358,9 @@ struct Chargedkstaranalysis { // To apply event selection and store the collision IDs of reconstructed events that pass the selection criteria for (const auto& coll : events) { - if (!coll.has_mcCollision()) + if (!coll.has_mcCollision()) { continue; + } const auto mcid = coll.mcCollisionId(); @@ -1313,12 +1371,15 @@ struct Chargedkstaranalysis { histos.fill(HIST("QA/MC/QACent_woCut"), lCentrality); histos.fill(HIST("QA/MC/QAvtxz_woCut"), coll.posZ()); } - if (!colCuts.isSelected(coll)) + if (!colCuts.isSelected(coll)) { continue; - if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(coll)) + } + if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(coll)) { continue; - if (!coll.isInelGt0()) + } + if (!coll.isInelGt0()) { continue; + } colCuts.fillQA(coll); if (doprocessMC && isQaRequired) { @@ -1326,8 +1387,9 @@ struct Chargedkstaranalysis { histos.fill(HIST("QA/MC/QAvtxz_wVtxzCut"), coll.posZ()); } - if (lCentrality < eventCutCfgs.cfgEventCentralityMin || lCentrality > eventCutCfgs.cfgEventCentralityMax) + if (lCentrality < eventCutCfgs.cfgEventCentralityMin || lCentrality > eventCutCfgs.cfgEventCentralityMax) { continue; + } if (doprocessMC && isQaRequired) { histos.fill(HIST("QA/MC/QACent_wCentCut"), lCentrality); @@ -1340,18 +1402,21 @@ struct Chargedkstaranalysis { for (const auto& coll : mccolls) { bool pass = true; - if (cfgTruthIncludeZvtx && std::abs(coll.posZ()) >= eventCutCfgs.confEvtZvtx) + if (cfgTruthIncludeZvtx && std::abs(coll.posZ()) >= eventCutCfgs.confEvtZvtx) { pass = false; + } if (pass && cfgTruthUseInelGt0) { auto partsThisMc = mcParticles.sliceBy(perMCCollision, coll.globalIndex()); // This is to slice all MC particles belonging to the current MC collision. // To check the INEL > 0 - if (!pwglf::isINELgtNmc(partsThisMc, 0, pdg)) + if (!pwglf::isINELgtNmc(partsThisMc, 0, pdg)) { pass = false; + } } - if (!pass) + if (!pass) { continue; + } const auto mcid = coll.globalIndex(); refClassIds.insert(mcid); @@ -1362,12 +1427,15 @@ struct Chargedkstaranalysis { // Calculating the generated Kstar for (const auto& part : mcParticles) { currentIsGen = true; - if (!part.has_mcCollision()) + if (!part.has_mcCollision()) { continue; - if (std::abs(part.pdgCode()) != kKstarPlus) + } + if (std::abs(part.pdgCode()) != kKstarPlus) { continue; - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { continue; + } LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; lResoKstar = LorentzVectorSetXYZM(part.px(), part.py(), part.pz(), MassKPlusStar892); @@ -1384,10 +1452,11 @@ struct Chargedkstaranalysis { if (std::abs(d2.pdgCode()) == kPDGK0s) { bool seenPip = false, seenPim = false; for (const auto& d3 : d2.template daughters_as()) { - if (d3.pdgCode() == +kPiPlus) + if (d3.pdgCode() == +kPiPlus) { seenPip = true; - else if (d3.pdgCode() == -kPiPlus) + } else if (d3.pdgCode() == -kPiPlus) { seenPim = true; + } } if (seenPip && seenPim) { lResoSecondary = LorentzVectorSetXYZM(d2.px(), d2.py(), d2.pz(), MassK0Short); @@ -1397,20 +1466,24 @@ struct Chargedkstaranalysis { } } } - if (hasRightPion && hasK0sToPipi) + if (hasRightPion && hasK0sToPipi) { break; + } } - if (!(hasRightPion && hasK0sToPipi)) + if (!(hasRightPion && hasK0sToPipi)) { continue; + } const auto mcid = part.mcCollisionId(); - if (allowedMcIds.count(mcid) == 0) + if (!allowedMcIds.contains(mcid)) { continue; + } auto iter = centTruthByAllowed.find(mcid); - if (iter == centTruthByAllowed.end()) + if (iter == centTruthByAllowed.end()) { continue; + } const float lCentrality = iter->second; @@ -1429,11 +1502,13 @@ struct Chargedkstaranalysis { currentIsGen = false; auto coll = v0.template collision_as(); - if (!coll.has_mcCollision()) + if (!coll.has_mcCollision()) { continue; + } const auto mcid = coll.mcCollisionId(); - if (allowedMcIds.count(mcid) == 0) + if (!allowedMcIds.contains(mcid)) { continue; // To check the event is allowed or not + } const auto mccoll = coll.template mcCollision_as>(); const float lCentrality = mccoll.centFT0M(); @@ -1441,21 +1516,27 @@ struct Chargedkstaranalysis { if (!secondaryCutsCfgs.cfgByPassDauPIDSelection) { auto posDauTrack = v0.template posTrack_as(); auto negDauTrack = v0.template negTrack_as(); - if (!selectionPIDPion(posDauTrack)) + if (!selectionPIDPion(posDauTrack)) { continue; - if (!selectionPIDPion(negDauTrack)) + } + if (!selectionPIDPion(negDauTrack)) { continue; + } } - if (!selectionK0s(coll, v0)) + if (!selectionK0s(coll, v0)) { continue; + } auto trks = tracks.sliceBy(perCollision, v0.collisionId()); // Grouping the tracks with the v0s, means only those tracks that belong to the same collision as v0 for (const auto& bTrack : trks) { - if (bTrack.collisionId() != v0.collisionId()) + if (bTrack.collisionId() != v0.collisionId()) { continue; - if (!trackCut(bTrack)) + } + if (!trackCut(bTrack)) { continue; - if (!selectionPIDPion(bTrack)) + } + if (!selectionPIDPion(bTrack)) { continue; + } LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; lResoSecondary = LorentzVectorSetXYZM(v0.px(), v0.py(), v0.pz(), MassK0Short); @@ -1464,17 +1545,32 @@ struct Chargedkstaranalysis { const double ptreco = lResoKstar.Pt(); const double yreco = lResoKstar.Rapidity(); - if (std::abs(yreco) > kstarCutCfgs.cKstarMaxRap) + if (std::abs(yreco) > kstarCutCfgs.cKstarMaxRap) { continue; + } + + if (mcCfgs.doMcClosure) { + // For MC clousre test + mcClosure = true; + if (helicityCfgs.cCosWithKShot) { + fillInvMass(lResoKstar, lCentrality, lResoSecondary, lDecayDaughter_bach, eventCutCfgs.confIsMix); + } else { + fillInvMass(lResoKstar, lCentrality, lDecayDaughter_bach, lResoSecondary, eventCutCfgs.confIsMix); + } + } + mcClosure = false; // Since we are doing the MC study and we know about the PDG code of each particle let's try to check the things which we have - if (!v0.has_mcParticle() || !bTrack.has_mcParticle()) + if (!v0.has_mcParticle() || !bTrack.has_mcParticle()) { continue; + } auto mcK0s = v0.template mcParticle_as(); // To get the MC truth particle corressponds to the V0 candidate auto mcPi = bTrack.template mcParticle_as(); - if (std::abs(mcK0s.pdgCode()) != kPDGK0s) + if (std::abs(mcK0s.pdgCode()) != kPDGK0s) { continue; - if (std::abs(mcPi.pdgCode()) != kPiPlus) + } + if (std::abs(mcPi.pdgCode()) != kPiPlus) { continue; + } MCTrueTrackCandidates::iterator kstarFromPi; bool havePiKstar = false; // Loops over all the mother's of pions and check if this pion comming from a kstar @@ -1498,8 +1594,9 @@ struct Chargedkstaranalysis { break; } } - if (shareSameKstar) + if (shareSameKstar) { break; + } } } if (!shareSameKstar) { @@ -1517,20 +1614,25 @@ struct Chargedkstaranalysis { } // To calculate the event losses to store the generated KstartPlus --> To check the number of events remains after passing all the event selection criteria for chk892 for (auto const& part : mcParticles) { - if (!part.has_mcCollision()) + if (!part.has_mcCollision()) { continue; - if (std::abs(part.pdgCode()) != kKstarPlus) + } + if (std::abs(part.pdgCode()) != kKstarPlus) { continue; - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { continue; + } const auto mcid = part.mcCollisionId(); - if (allowedMcIds.count(mcid) == 0) + if (!allowedMcIds.contains(mcid)) { continue; + } auto iter = centTruthByAllowed.find(mcid); - if (iter == centTruthByAllowed.end()) + if (iter == centTruthByAllowed.end()) { continue; + } const float lCentrality = iter->second; @@ -1541,20 +1643,25 @@ struct Chargedkstaranalysis { } // To calculate the denominator -> To check the all the events have chk892 for (auto const& part : mcParticles) { - if (!part.has_mcCollision()) + if (!part.has_mcCollision()) { continue; - if (std::abs(part.pdgCode()) != kKstarPlus) + } + if (std::abs(part.pdgCode()) != kKstarPlus) { continue; - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { continue; + } const auto mcid = part.mcCollisionId(); - if (refClassIds.count(mcid) == 0) + if (!refClassIds.contains(mcid)) { continue; + } auto iter = refCentByMcId.find(mcid); - if (iter == refCentByMcId.end()) + if (iter == refCentByMcId.end()) { continue; + } const float lCentrality = iter->second; @@ -1569,8 +1676,9 @@ struct Chargedkstaranalysis { } for (const auto& mcid : allowedMcIds) { auto iter = centTruthByAllowed.find(mcid); - if (iter == centTruthByAllowed.end()) + if (iter == centTruthByAllowed.end()) { continue; + } const float lCentrality = iter->second; histos.fill(HIST("Correction/EF_num"), lCentrality); @@ -1593,13 +1701,14 @@ struct Chargedkstaranalysis { histos.fill(HIST("Correction/hNEventsMCTruth"), 3.0); } } - if (allowedMcIds.count(mcid)) { + if (allowedMcIds.contains(mcid)) { histos.fill(HIST("Correction/hNEventsMCTruth"), 4.0); } } } PROCESS_SWITCH(Chargedkstaranalysis, processMC, "Process Event for MC", false); }; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; diff --git a/PWGLF/Tasks/Resonances/cksspinalignder.cxx b/PWGLF/Tasks/Resonances/cksspinalignder.cxx index 830d4764f71..c846369135f 100644 --- a/PWGLF/Tasks/Resonances/cksspinalignder.cxx +++ b/PWGLF/Tasks/Resonances/cksspinalignder.cxx @@ -10,20 +10,15 @@ // or submit itself to any jurisdiction. /// \file cksspinalignder.cxx -/// \brief Analysis task for ChargedKStar spin alignment +/// \brief Derived task for charged KStar spin alignment using reduced K0s and pion tables /// /// \author prottay.das@cern.ch #include "PWGLF/DataModel/LFCKSSpinalignmentTables.h" -#include "Common/Core/RecoDecay.h" - -#include -#include #include #include #include -#include #include #include #include @@ -35,22 +30,15 @@ #include #include +#include // IWYU pragma: keep (do not replace with Math/Vector3Dfwd.h) #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include -#include #include -#include -#include // for std::fabs -#include +#include #include -#include #include -#include -#include -#include -#include using namespace o2; using namespace o2::framework; @@ -59,108 +47,65 @@ using namespace o2::soa; struct cksspinalignder { - struct : ConfigurableGroup { - Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; - Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; - } cfgCcdbParam; - - // event sel///////// - Configurable centMin{"centMin", 0, "Minimum Centrality"}; - Configurable centMax{"centMax", 80, "Maximum Centrality"}; - // V0 selection //////////// - Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; - Configurable radiusMin{"radiusMin", 1.2, "Minimum V0 radius"}; - Configurable radiusMax{"radiusMax", 100, "Maximum V0 radius"}; - Configurable dcaPion{"dcaPion", 0.1, "DCA Pion"}; - Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; - Configurable lifetimeMax{"lifetimeMax", 20, "Maximum V0 lifetime"}; - Configurable ptMin{"ptMin", 0.5, "V0 Pt minimum"}; - Configurable ptMax{"ptMax", 10.0, "V0 Pt maximum"}; - Configurable v0eta{"v0eta", 0.8, "Eta cut on lambda"}; - // pion sel///////// - Configurable usePID{"usePID", false, "Enable PID selection using stored bitmask"}; - // Choose which PID bit to require (1..4). If pidExclusive=true -> require ONLY that PID. - Configurable pidChoice{"pidChoice", 2, "PID choice: 1,2,3,4"}; - Configurable pidExclusive{"pidExclusive", false, "If true require ONLY the chosen PID (mask == bit). If false require (mask & bit)!=0"}; - - // Event Mixing - Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; - ConfigurableAxis cfgVtxBins{"cfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; - ConfigurableAxis cfgMultBins{"cfgMultBins", {8, 0.0, 80}, "Mixing bins - centrality"}; - Configurable ptMix{"ptMix", 0.2f, "ME: pT bin width"}; - Configurable etaMix{"etaMix", 0.2f, "ME: eta bin width"}; - Configurable phiMix{"phiMix", 0.3f, "ME: phi bin width"}; - - // THnsparse bining - ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {50, 1.09, 1.14}, "#it{M} (GeV/#it{c}^{2})"}; - ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.0}, "#it{p}_{T}"}; - ConfigurableAxis configThnAxisSA{"configThnAxisSA", {20, -1.0, 1.0}, "cos#it{#theta *}"}; - ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0.0, 80.0}, "Centrality"}; - - // Enable access to the CCDB for the offset and correction constants and save them in dedicated variables. - Service ccdb; - o2::ccdb::CcdbApi ccdbApi; + // Event selection + Configurable centMin{"centMin", 0.0f, "Minimum centrality"}; + Configurable centMax{"centMax", 80.0f, "Maximum centrality"}; + + // K0s selection from stored reduced table + Configurable applyK0sSelection{"applyK0sSelection", true, "Apply additional K0s selection in derived task"}; + Configurable cosPA{"cosPA", 0.995f, "Minimum V0 cosine pointing angle"}; + Configurable radiusMin{"radiusMin", 1.2f, "Minimum V0 radius"}; + Configurable radiusMax{"radiusMax", 100.0f, "Maximum V0 radius"}; + Configurable dcaPion{"dcaPion", 0.1f, "Minimum V0 daughter DCA to PV"}; + Configurable dcaDaughters{"dcaDaughters", 1.0f, "Maximum DCA between V0 daughters"}; + Configurable k0sPtMin{"k0sPtMin", 0.0f, "Minimum K0s pT"}; + Configurable k0sPtMax{"k0sPtMax", 10.0f, "Maximum K0s pT"}; + Configurable k0sEtaMax{"k0sEtaMax", 0.8f, "Maximum K0s eta"}; + Configurable k0sMassMin{"k0sMassMin", 0.45f, "Minimum K0s mass"}; + Configurable k0sMassMax{"k0sMassMax", 0.55f, "Maximum K0s mass"}; + + // Bachelor pion PID + Configurable usePID{"usePID", true, "Apply bachelor pion PID using stored bitmask"}; + Configurable pidChoice{"pidChoice", 4, "PID choice: 1, 2, 3, or 4"}; + Configurable pidExclusive{"pidExclusive", false, "If true require only selected PID bit. If false require selected bit among possible bits"}; + + // Charge selection + Configurable chargeSelection{"chargeSelection", 0, "Bachelor pion charge selection: 0 = both, +1 = K*+, -1 = K*-"}; + + // Event-plane choice + Configurable epChoice{"epChoice", 0, "Event plane: 0 = FT0C, 1 = FT0A, 2 = TPC"}; + + // Event mixing + Configurable nEvtMixing{"nEvtMixing", 5, "Number of mixed events"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {10, -10.0f, 10.0f}, "Mixing bins in z vertex"}; + ConfigurableAxis cfgCentBins{"cfgCentBins", {8, 0.0f, 80.0f}, "Mixing bins in centrality"}; + + // Sparse axes + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {150, 0.75f, 1.05f}, "#it{M}_{K^{0}_{S}#pi} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0f, 10.0f}, "#it{p}_{T}^{K^{0}_{S}#pi} (GeV/#it{c})"}; + ConfigurableAxis configThnAxisSA{"configThnAxisSA", {20, -1.0f, 1.0f}, "cos#it{#theta}^{*}"}; + ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0.0f, 80.0f}, "Centrality (%)"}; + ConfigurableAxis configThnAxisCharge{"configThnAxisCharge", {2, -1.5f, 1.5f}, "Bachelor pion charge"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) { - - histos.add("hCentrality", "Centrality distribution", kTH1F, {{80, 0, 80}}); - histos.add("hKShortMass", "hKShortMass", kTH1F, {{100, 0.45, 0.55}}); - - histos.add("hSparsesame", "hSparsesame", kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisSA, configThnAxisCentrality}); - histos.add("hSparsemix", "hSparsemix", kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisSA, configThnAxisCentrality}); - - ccdb->setURL(cfgCcdbParam.cfgURL); - ccdbApi.init("http://alice-ccdb.cern.ch"); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + histos.add("hCentrality", "Centrality distribution;Centrality (%);Events", kTH1F, {{80, 0.0f, 80.0f}}); + histos.add("hKShortMass", "K^{0}_{S} mass;M_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2});Counts", kTH1F, {{200, 0.4f, 0.6f}}); + + histos.add("hSparsesame", + "Same-event K^{0}_{S}#pi;M_{K^{0}_{S}#pi};p_{T};cos#theta^{*};centrality;charge", + kTHnSparseF, + {configThnAxisInvMass, configThnAxisPt, configThnAxisSA, configThnAxisCentrality, configThnAxisCharge}); + + histos.add("hSparsemix", + "Mixed-event K^{0}_{S}#pi;M_{K^{0}_{S}#pi};p_{T};cos#theta^{*};centrality;charge", + kTHnSparseF, + {configThnAxisInvMass, configThnAxisPt, configThnAxisSA, configThnAxisCentrality, configThnAxisCharge}); } - template - bool selectionV0(T const& candidate) - { - auto kshortPt = std::sqrt(candidate.kShortPx() * candidate.kShortPx() + candidate.kShortPy() * candidate.kShortPy()); - auto px = candidate.kShortPx(); - auto py = candidate.kShortPy(); - auto pz = candidate.kShortPz(); - auto p = std::sqrt(px * px + py * py + pz * pz); - auto kshortEta = 0.5 * std::log((p + pz) / (p - pz)); - - if (std::abs(kshortEta) > v0eta) { - return false; - } - if (candidate.v0Cospa() < cosPA) { - return false; - } - if (candidate.v0Radius() > radiusMax) { - return false; - } - if (candidate.v0Radius() < radiusMin) { - return false; - } - if (candidate.dcaBetweenDaughter() > dcaDaughters) { - return false; - } - if (std::abs(candidate.dcaPositive()) < dcaPion && std::abs(candidate.dcaNegative()) < dcaPion) { - return false; - } - if (candidate.v0Lifetime() > lifetimeMax) { - return false; - } - if (kshortPt < ptMin) { - return false; - } - if (kshortPt > ptMax) { - return false; - } - return true; - } - - // ----- PID via stored bitmask (no selectionPID function needed) ----- - // Assumes your PionTracks table has a uint8_t column named pionPidMask(). - // Bit mapping: PID1=1, PID2=2, PID3=4, PID4=8. + // PID bit mapping from producer static constexpr uint8_t kPID1 = 1u << 0; static constexpr uint8_t kPID2 = 1u << 1; static constexpr uint8_t kPID3 = 1u << 2; @@ -168,8 +113,7 @@ struct cksspinalignder { uint8_t requiredPidBit() const { - const int choice = pidChoice.value; - switch (choice) { + switch (pidChoice.value) { case 1: return kPID1; case 2: @@ -179,8 +123,8 @@ struct cksspinalignder { case 4: return kPID4; default: - LOGF(warn, "pidChoice=%d is invalid. Using PID2.", choice); - return kPID2; + LOGF(warn, "pidChoice=%d is invalid. Using PID4.", pidChoice.value); + return kPID4; } } @@ -190,640 +134,300 @@ struct cksspinalignder { if (!usePID.value) { return true; } - const uint8_t bit = requiredPidBit(); + const uint8_t mask = pion.pionPidMask(); + const uint8_t bit = requiredPidBit(); if (pidExclusive.value) { - return mask == bit; // ONLY chosen PID + return mask == bit; } - return (mask & bit) != 0; // chosen PID (maybe others too) - } - // --------------------------------------------------------------- - std::tuple computePtEtaPhi(float px, float py, float pz) - { - float pt = std::sqrt(px * px + py * py); - float p = std::sqrt(px * px + py * py + pz * pz); - float eta = (p != std::abs(pz)) ? 0.5 * std::log((p + pz) / (p - pz)) : 0.0f; // avoid division by zero - float phi = RecoDecay::constrainAngle(std::atan2(py, px)); - return {pt, eta, phi}; + return (mask & bit) != 0; } - ROOT::Math::PtEtaPhiMVector kshort, pion, chkstar; - ROOT::Math::PtEtaPhiMVector kshortmix, pionmix, chkstarmix; - ROOT::Math::PxPyPzMVector fourVecDauCM, fourVecDauCMmix; - ROOT::Math::XYZVector threeVecDauCM, eventplaneVecNorm, threeVecDauCMmix, eventplaneVecNormmix; - - Filter centralityFilter = (nabs(aod::kshortpionevent::cent) < centMax && nabs(aod::kshortpionevent::cent) > centMin); - - using EventCandidates = soa::Filtered; - - void processSameData(EventCandidates::iterator const& collision, aod::KShortTracks const& V0s, aod::PionTracks const& piontracks) + template + bool passChargeSelection(const TPion& pion) const { - auto centrality = collision.cent(); - histos.fill(HIST("hCentrality"), centrality); - - auto psiFT0C = collision.psiFT0C(); + const int charge = static_cast(pion.charge()); - for (const auto& v0 : V0s) { - if (!selectionV0(v0)) { - continue; - } - auto [kshortPt, kshortEta, kshortPhi] = computePtEtaPhi(v0.kShortPx(), v0.kShortPy(), v0.kShortPz()); - kshort = ROOT::Math::PtEtaPhiMVector(kshortPt, kshortEta, kshortPhi, v0.kShortMass()); - histos.fill(HIST("hKShortMass"), kshort.M()); - - for (const auto& piontrack : piontracks) { - - // PID selection via stored mask - if (!passSelectedPID(piontrack)) { - continue; - } - auto [pionPt, pionEta, pionPhi] = computePtEtaPhi(piontrack.pionBachPx(), piontrack.pionBachPy(), piontrack.pionBachPz()); - pion = ROOT::Math::PtEtaPhiMVector(pionPt, pionEta, pionPhi, o2::constants::physics::MassPionCharged); - - if (piontrack.pionBachIndex() == v0.pionIndex1() || piontrack.pionBachIndex() == v0.pionIndex2()) - continue; // checking if bachelor pion is khort daughter or not -> skip further processing if such is the case + if (charge == 0) { + return false; + } - chkstar = kshort + pion; + if (chargeSelection.value == 0) { + return true; + } - ROOT::Math::Boost boost{chkstar.BoostToCM()}; - fourVecDauCM = boost(kshort); - threeVecDauCM = fourVecDauCM.Vect(); - eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); - auto cosThetaStar = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); + return charge == chargeSelection.value; + } - histos.fill(HIST("hSparsesame"), chkstar.M(), chkstar.Pt(), cosThetaStar, centrality); - } + template + bool selectionV0(const TK0s& candidate) const + { + if (!applyK0sSelection.value) { + return true; } - } - PROCESS_SWITCH(cksspinalignder, processSameData, "Process same data", true); - // Processing Event Mixing - SliceCache cache; - using BinningType = ColumnBinningPolicy; - BinningType colBinning{{cfgVtxBins, cfgMultBins}, true}; - Preslice tracksPerCollisionV0 = aod::kshortpionpair::kshortpioneventId; - Preslice tracksPerCollisionBach = aod::kshortpionpair::kshortpioneventId; + ROOT::Math::PxPyPzMVector k0s(candidate.kShortPx(), + candidate.kShortPy(), + candidate.kShortPz(), + candidate.kShortMass()); - void processMixedData(EventCandidates const& collisions, aod::KShortTracks const& V0s, aod::PionTracks const& piontracks) - { - for (const auto& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing, -1, collisions, collisions)) { - if (collision1.index() == collision2.index()) { - continue; - } - auto centrality = collision1.cent(); - auto psiFT0Cmix = collision1.psiFT0C(); + const float k0sPt = k0s.Pt(); + const float k0sEta = k0s.Eta(); - auto groupV0 = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - auto groupPion = piontracks.sliceBy(tracksPerCollisionBach, collision2.index()); - for (const auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV0, groupPion))) { - if (!selectionV0(t1)) - continue; - auto [kshortPtmix, kshortEtamix, kshortPhimix] = computePtEtaPhi(t1.kShortPx(), t1.kShortPy(), t1.kShortPz()); - kshortmix = ROOT::Math::PtEtaPhiMVector(kshortPtmix, kshortEtamix, kshortPhimix, t1.kShortMass()); + if (std::abs(k0sEta) > k0sEtaMax.value) { + return false; + } - // PID selection via stored mask (on the bachelor pion from the mixed event) - if (!passSelectedPID(t2)) { - continue; - } - auto [pionPtmix, pionEtamix, pionPhimix] = computePtEtaPhi(t2.pionBachPx(), t2.pionBachPy(), t2.pionBachPz()); - pionmix = ROOT::Math::PtEtaPhiMVector(pionPtmix, pionEtamix, pionPhimix, o2::constants::physics::MassPionCharged); + if (candidate.kShortMass() < k0sMassMin.value || + candidate.kShortMass() > k0sMassMax.value) { + return false; + } - chkstarmix = kshortmix + pionmix; + if (candidate.v0Cospa() < cosPA.value) { + return false; + } - ROOT::Math::Boost boost{chkstarmix.BoostToCM()}; - fourVecDauCMmix = boost(kshortmix); - threeVecDauCMmix = fourVecDauCMmix.Vect(); - eventplaneVecNormmix = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0Cmix), -std::cos(2.0 * psiFT0Cmix), 0); - auto cosThetaStarmix = eventplaneVecNormmix.Dot(threeVecDauCMmix) / std::sqrt(threeVecDauCMmix.Mag2()) / std::sqrt(eventplaneVecNormmix.Mag2()); + if (candidate.v0Radius() < radiusMin.value || + candidate.v0Radius() > radiusMax.value) { + return false; + } - histos.fill(HIST("hSparsemix"), chkstarmix.M(), chkstarmix.Pt(), cosThetaStarmix, centrality); - } + if (candidate.dcaBetweenDaughter() > dcaDaughters.value) { + return false; } - } - PROCESS_SWITCH(cksspinalignder, processMixedData, "Process mixed data", true); - - // ===================================================================================== - // MEV2-style mixing for Charged K* : KEEP K0s (from event E) FIXED, MIX bachelor pion - // pion is taken from other events E' but matched in (event class + pion pt/eta/phi) - // ===================================================================================== - - // One status bin (unused dimension, kept for compatibility with linearKey) - static constexpr int N_STATUS = 1; - - // ---------- Binner for bachelor-pion kinematics ---------- - struct MixBinnerPi { - float ptMin, ptMax, ptStep; - float etaMin, etaMax, etaStep; - float phiMin, phiMax, phiStep; - - // Dummy "mass" axis (we keep 1 bin to keep the same 6D infrastructure) - static constexpr float mMin = 0.f; - static constexpr float mMax = 1.f; - static constexpr int nM_ = 1; - static constexpr float mStep = (mMax - mMin) / nM_; - - int nPt_{1}, nEta_{1}, nPhi_{1}; - - MixBinnerPi(float ptMin_, float ptMax_, float ptStep_, - float etaAbsMax_, float etaStep_, - float phiStep_) - : ptMin(ptMin_), ptMax(ptMax_), ptStep(ptStep_), etaMin(-etaAbsMax_), etaMax(+etaAbsMax_), etaStep(etaStep_), phiMin(0.f), phiMax(static_cast(2.0 * TMath::Pi())), phiStep(phiStep_) - { - ptStep = (ptStep > 0.f ? ptStep : 0.2f); - etaStep = (etaStep > 0.f ? etaStep : 0.2f); - phiStep = (phiStep > 0.f ? phiStep : 0.2f); - - nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); - nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); - nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); + + if (candidate.dcaPositive() < dcaPion.value || + candidate.dcaNegative() < dcaPion.value) { + return false; } - inline int nPt() const { return nPt_; } - inline int nEta() const { return nEta_; } - inline int nPhi() const { return nPhi_; } - inline int nM() const { return nM_; } - - inline int binFromValue(float v, float vmin, float step, int nBins) const - { - if (!std::isfinite(v)) - return -1; - const float x = (v - vmin) / step; - int b = static_cast(std::floor(x + 1e-6f)); - if (b < 0) - return -1; - if (b >= nBins) - b = nBins - 1; - return b; + if (k0sPt < k0sPtMin.value || + k0sPt > k0sPtMax.value) { + return false; } - inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } - inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } - inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } - inline int massBin(float m) const { return binFromValue(m, mMin, mStep, nM_); } // always 0 if finite - }; - - // Buffer candidate: one pion stored in a bin - struct BufferCandPi { - int64_t collisionIdx; // to enforce different event - int64_t rowIndex; // row id in PionTracks (for iteratorAt) - uint16_t ptBin, etaBin, phiBin, mBin; - }; - - struct MatchRef { - int64_t collisionIdx; - int64_t rowIndex; - }; - - // Key: (colBin, stat, pt, eta, phi, m) - static inline size_t linearKey(int colBin, int statBin, - int ptBin, int etaBin, int phiBin, int mBin, - int nStat, int nPt, int nEta, int nPhi, int nM) - { - return ((((((static_cast(colBin) * nStat + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin)); + return true; } - // ===================================================================================== - // Mixed-event method: - // PASS 1: build buffer of pions by (event-class bin) + (pi pt/eta/phi bins) - // PASS 2: loop same-event (K0, piSame) pairs; replace piSame by piX from buffer - // keep K0 from current event fixed; use psiFT0C of current event. - // ===================================================================================== - void processMixedDataMEV2_Pion(EventCandidates const& collisions, - aod::KShortTracks const& V0s, - aod::PionTracks const& piontracks) + template + bool k0sBelongsToEvent(const TK0s& k0s, const TCollision& collision) const { - static thread_local std::mt19937 rng(0xBADC0FFE); - - // Build pion binner from your configurables - // Use your own pt range config for bachelor pions if you have it; otherwise reuse ptMin/ptMax - MixBinnerPi mb{ - ptMin, ptMax, /*ptStep*/ ptMix.value, - /*|eta|max*/ v0eta.value, /*etaStep*/ etaMix.value, - /*phiStep*/ phiMix.value}; - - const int nCol = colBinning.getAllBinsCount(); // event-class bins (vz, cent) - const int nStat = N_STATUS; // 1 - const int nPt = mb.nPt(); - const int nEta = mb.nEta(); - const int nPhi = mb.nPhi(); - const int nM = mb.nM(); - - const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM; - std::vector> buffer(nKeys); - - // ---------------- PASS 1: fill 6D buffer with bachelor pions ---------------- - for (auto const& col : collisions) { - const int colBin = colBinning.getBin(std::make_tuple(col.posz(), col.cent())); - if (colBin < 0) - continue; - - auto slicePi = piontracks.sliceBy(tracksPerCollisionBach, col.index()); - - for (auto const& pi : slicePi) { + return k0s.kshortpioneventId() == collision.globalIndex(); + } - // apply configurable PID selection stored in bitmask (your passSelectedPID) - if (!passSelectedPID(pi)) - continue; + template + bool pionBelongsToEvent(const TPion& pion, const TCollision& collision) const + { + return pion.kshortpioneventId() == collision.globalIndex(); + } - auto [pt, eta, phi] = computePtEtaPhi(pi.pionBachPx(), pi.pionBachPy(), pi.pionBachPz()); - phi = RecoDecay::constrainAngle(phi, 0.0F); + template + float getEventPlane(const TCollision& collision) const + { + switch (epChoice.value) { + case 0: + return collision.psiFT0C(); + case 1: + return collision.psiFT0A(); + case 2: + return collision.psiTPC(); + default: + LOGF(warn, "epChoice=%d is invalid. Using FT0C.", epChoice.value); + return collision.psiFT0C(); + } + } - const int ptB = mb.ptBin(pt); - const int etaB = mb.etaBin(eta); - const int phiB = mb.phiBin(phi); - const int mB = 0; // dummy axis has 1 bin - if (ptB < 0 || etaB < 0 || phiB < 0) - continue; + bool computeCosThetaStar(const ROOT::Math::PxPyPzMVector& k0s, + const ROOT::Math::PxPyPzMVector& kstar, + float psi, + float& cosThetaStar) const + { + ROOT::Math::Boost boost{kstar.BoostToCM()}; + ROOT::Math::PxPyPzMVector k0sCM = boost(k0s); + ROOT::Math::XYZVector k0sCMVec = k0sCM.Vect(); - const int stat = 0; - const size_t key = linearKey(colBin, stat, ptB, etaB, phiB, mB, nStat, nPt, nEta, nPhi, nM); + ROOT::Math::XYZVector eventPlaneVector(std::sin(2.0f * psi), + -std::cos(2.0f * psi), + 0.0f); - const int64_t row = static_cast(pi.globalIndex()); + const double denom = + std::sqrt(k0sCMVec.Mag2()) * + std::sqrt(eventPlaneVector.Mag2()); - buffer[key].push_back(BufferCandPi{ - .collisionIdx = static_cast(col.index()), - .rowIndex = row, - .ptBin = static_cast(ptB), - .etaBin = static_cast(etaB), - .phiBin = static_cast(phiB), - .mBin = static_cast(mB)}); - } + if (denom <= 0.0 || !std::isfinite(denom)) { + return false; } - // ---------------- PASS 2: same-event (K0,piSame), replace ONLY pion by piX ---------------- - for (auto const& col1 : collisions) { - const int colBin = colBinning.getBin(std::make_tuple(col1.posz(), col1.cent())); - if (colBin < 0) - continue; + cosThetaStar = + static_cast(eventPlaneVector.Dot(k0sCMVec) / denom); - auto poolK0 = V0s.sliceBy(tracksPerCollisionV0, col1.index()); - auto poolPi = piontracks.sliceBy(tracksPerCollisionBach, col1.index()); - if (poolK0.size() == 0 || poolPi.size() == 0) - continue; + cosThetaStar = std::clamp(cosThetaStar, -1.0f, 1.0f); - const float centrality = col1.cent(); - const float psiFT0Cmix = col1.psiFT0C(); + return true; + } - // Loop over K0s from the *current* event (fixed object) - for (auto const& k0 : poolK0) { - if (!selectionV0(k0)) - continue; + template + bool fillKstarPair(const TK0s& k0sCand, + const TPion& pionCand, + const TCollision& collision, + bool isMixed) + { + if (!selectionV0(k0sCand)) { + return false; + } - // Build K0 4-vector once - auto [kpt, keta, kphi] = computePtEtaPhi(k0.kShortPx(), k0.kShortPy(), k0.kShortPz()); - kphi = RecoDecay::constrainAngle(kphi, 0.0F); - kshortmix = ROOT::Math::PtEtaPhiMVector(kpt, keta, kphi, k0.kShortMass()); + if (!passSelectedPID(pionCand)) { + return false; + } - // Loop over same-event pions to define the "same-event pair" base - for (auto const& piSame : poolPi) { - if (!passSelectedPID(piSame)) - continue; + if (!passChargeSelection(pionCand)) { + return false; + } - // avoid self-combination: bachelor pion can't be a K0 daughter - if (piSame.pionBachIndex() == k0.pionIndex1() || piSame.pionBachIndex() == k0.pionIndex2()) { - continue; - } + // Same-event self-combination rejection: + // bachelor pion must not be one of the K0s daughters. + if (!isMixed) { + if (pionCand.pionBachIndex() == k0sCand.pionIndex1() || + pionCand.pionBachIndex() == k0sCand.pionIndex2()) { + return false; + } + } - // Compute the kinematic bin of THIS pion (this defines where to pick mixed pions) - auto [ppt, peta, pphi] = computePtEtaPhi(piSame.pionBachPx(), piSame.pionBachPy(), piSame.pionBachPz()); - pphi = RecoDecay::constrainAngle(pphi, 0.0F); + ROOT::Math::PxPyPzMVector k0s(k0sCand.kShortPx(), + k0sCand.kShortPy(), + k0sCand.kShortPz(), + k0sCand.kShortMass()); - const int ptB = mb.ptBin(ppt); - const int etaB = mb.etaBin(peta); - const int phiB = mb.phiBin(pphi); - const int mB = 0; - if (ptB < 0 || etaB < 0 || phiB < 0) - continue; + ROOT::Math::PxPyPzMVector pion(pionCand.pionBachPx(), + pionCand.pionBachPy(), + pionCand.pionBachPz(), + o2::constants::physics::MassPionCharged); - const int stat = 0; - const size_t key = linearKey(colBin, stat, ptB, etaB, phiB, mB, nStat, nPt, nEta, nPhi, nM); - auto const& binVec = buffer[key]; - if (binVec.empty()) - continue; + const auto kstar = k0s + pion; - // collect partners from same bin but different collision - std::vector matches; - matches.reserve(binVec.size()); - const int64_t curColIdx = static_cast(col1.index()); + const float mass = kstar.M(); + const float pt = kstar.Pt(); + const float centrality = collision.cent(); + const float charge = static_cast(pionCand.charge()); + const float psi = getEventPlane(collision); - for (auto const& bc : binVec) { - if (bc.collisionIdx == curColIdx) - continue; - matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); - } - if (matches.empty()) - continue; + float cosThetaStar = 0.0f; - // random unique sampling (cap = nEvtMixing) - const int cap = nEvtMixing.value; - if (cap > 0 && cap < static_cast(matches.size())) { - std::uniform_int_distribution dist(0, static_cast(matches.size()) - 1); - std::unordered_set chosen; - chosen.reserve(static_cast(cap) * 2); - while (static_cast(chosen.size()) < cap) - chosen.insert(dist(rng)); - - std::vector subset; - subset.reserve(cap); - for (const int& idx : chosen) - subset.push_back(matches[idx]); - matches.swap(subset); - } else { - std::shuffle(matches.begin(), matches.end(), rng); - } + if (!computeCosThetaStar(k0s, kstar, psi, cosThetaStar)) { + return false; + } - // const float wBase = 1.0f / static_cast(matches.size()); - const float wBase = 1.0; + if (isMixed) { + histos.fill(HIST("hSparsemix"), mass, pt, cosThetaStar, centrality, charge); + } else { + histos.fill(HIST("hSparsesame"), mass, pt, cosThetaStar, centrality, charge); + } - // Replace pion by mixed pion piX, keep k0 fixed - for (auto const& m : matches) { - auto piX = piontracks.iteratorAt(m.rowIndex); // must match PASS 1 rowIndex convention + return true; + } - // safety: PID selection again - if (!passSelectedPID(piX)) - continue; + Filter centralityFilter = + (aod::kshortpionevent::cent >= centMin) && + (aod::kshortpionevent::cent < centMax); - // OPTIONAL keep: also avoid piX being a K0 daughter (same k0 from current event) - if (piX.pionBachIndex() == k0.pionIndex1() || piX.pionBachIndex() == k0.pionIndex2()) { - continue; - } + using EventCandidates = soa::Filtered; - auto [xpt, xeta, xphi] = computePtEtaPhi(piX.pionBachPx(), piX.pionBachPy(), piX.pionBachPz()); - xphi = RecoDecay::constrainAngle(xphi, 0.0F); - pionmix = ROOT::Math::PtEtaPhiMVector(xpt, xeta, xphi, o2::constants::physics::MassPionCharged); + void processSameData(EventCandidates::iterator const& collision, + aod::KShortTracks const& k0sTracks, + aod::PionTracks const& pionTracks) + { + const float centrality = collision.cent(); - chkstarmix = kshortmix + pionmix; + histos.fill(HIST("hCentrality"), centrality); - ROOT::Math::Boost boost{chkstarmix.BoostToCM()}; - fourVecDauCMmix = boost(kshortmix); - threeVecDauCMmix = fourVecDauCMmix.Vect(); + for (const auto& k0sCand : k0sTracks) { + if (!k0sBelongsToEvent(k0sCand, collision)) { + continue; + } - eventplaneVecNormmix = ROOT::Math::XYZVector(std::sin(2.f * psiFT0Cmix), - -std::cos(2.f * psiFT0Cmix), 0.f); + if (!selectionV0(k0sCand)) { + continue; + } - const float cosThetaStarmix = - eventplaneVecNormmix.Dot(threeVecDauCMmix) / - std::sqrt(threeVecDauCMmix.Mag2()) / - std::sqrt(eventplaneVecNormmix.Mag2()); + histos.fill(HIST("hKShortMass"), k0sCand.kShortMass()); - histos.fill(HIST("hSparsemix"), - chkstarmix.M(), chkstarmix.Pt(), cosThetaStarmix, centrality, wBase); - } + for (const auto& pionCand : pionTracks) { + if (!pionBelongsToEvent(pionCand, collision)) { + continue; } + + fillKstarPair(k0sCand, pionCand, collision, false); } } } - PROCESS_SWITCH(cksspinalignder, processMixedDataMEV2_Pion, "Process mixed data MEV4 (keep K0 fixed, replace pion with mixed pion)", true); - - /* -// ---- Configuration knobs (already in your task or add similarly) ---- -// ptMix: step for K0 pT binning, etaMix step for eta, phiMix step for phi -// configThnAxisInvMass etc are your histogram axes (not used for binning here) - -// We can keep one status bin for now -static constexpr int N_STATUS = 1; - -// Binner for K0 kinematics -struct MixBinnerK0 { - float ptMin, ptMax, ptStep; - float etaMin, etaMax, etaStep; - float phiMin, phiMax, phiStep; - - // K0 mass binning (you can widen if you want) - static constexpr float mMin = 0.45f; - static constexpr float mMax = 0.55f; // exclusive-ish - static constexpr int nM_ = 1; - static constexpr float mStep = (mMax - mMin) / nM_; - - int nPt_, nEta_, nPhi_; + PROCESS_SWITCH(cksspinalignder, processSameData, "Process same-event charged KStar", true); - MixBinnerK0(float ptMin_, float ptMax_, float ptStep_, - float etaAbsMax_, float etaStep_, - float phiStep_) - : ptMin(ptMin_), ptMax(ptMax_), ptStep(ptStep_), - etaMin(-etaAbsMax_), etaMax(+etaAbsMax_), etaStep(etaStep_), - phiMin(0.f), phiMax(static_cast(2.0 * TMath::Pi())), phiStep(phiStep_) - { - ptStep = (ptStep > 0.f ? ptStep : 0.1f); - etaStep = (etaStep > 0.f ? etaStep : 0.1f); - phiStep = (phiStep > 0.f ? phiStep : 0.1f); - - nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); - nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); - nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); - } - - inline int nPt() const { return nPt_; } - inline int nEta() const { return nEta_; } - inline int nPhi() const { return nPhi_; } - inline int nM() const { return nM_; } - - inline int binFromValue(float v, float vmin, float step, int nBins) const - { - if (!std::isfinite(v)) return -1; - const float x = (v - vmin) / step; - int b = static_cast(std::floor(x + 1e-6f)); - if (b < 0) return -1; - if (b >= nBins) b = nBins - 1; - return b; - } - - inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } - inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } - inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } - inline int massBin(float m) const { return binFromValue(m, mMin, mStep, nM_); } -}; - - struct BufferCandK0 { - int64_t collisionIdx; // to enforce different event - int64_t rowIndex; // row id in KShortTracks (for iteratorAt) - uint16_t ptBin, etaBin, phiBin, mBin; - }; - - struct MatchRef { - int64_t collisionIdx; - int64_t rowIndex; - }; - - // Key: (colBin, stat, pt, eta, phi, m) - static inline size_t linearKey(int colBin, int statBin, - int ptBin, int etaBin, int phiBin, int mBin, - int nStat, int nPt, int nEta, int nPhi, int nM) - { - return ((((((static_cast(colBin) * nStat + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin)); - } + SliceCache cache; + using BinningType = ColumnBinningPolicy; - void processMixedDataMEV4(EventCandidates const& collisions, - aod::KShortTracks const& V0s, - aod::PionTracks const& piontracks) + template + void fillMixedPairs(const TK0sGroup& k0sGroup, + const TPionGroup& pionGroup, + const TCollision& referenceCollision) { - static thread_local std::mt19937 rng(0xBADC0FFE); - - // Build K0 binner from your configurables - MixBinnerK0 mb{ - ptMin.value, ptMax.value, ptMix.value, - v0eta.value, etaMix.value, - phiMix.value - }; - - const int nCol = colBinning.getAllBinsCount(); - const int nStat = N_STATUS; - const int nPt = mb.nPt(); - const int nEta = mb.nEta(); - const int nPhi = mb.nPhi(); - const int nM = mb.nM(); - - const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM; - std::vector> buffer(nKeys); - - // ---------------- PASS 1: fill 6D buffer with K0s ---------------- - for (auto const& col : collisions) { - const int colBin = colBinning.getBin(std::make_tuple(col.posz(), col.cent())); - if (colBin < 0) continue; - - auto sliceK0 = V0s.sliceBy(tracksPerCollisionV0, col.index()); - - for (auto const& k0 : sliceK0) { - if (!selectionV0(k0)) continue; - - auto [kpt, keta, kphi] = computePtEtaPhi(k0.kShortPx(), k0.kShortPy(), k0.kShortPz()); - kphi = RecoDecay::constrainAngle(kphi, 0.0F); - - const int ptB = mb.ptBin(kpt); - const int etaB = mb.etaBin(keta); - const int phiB = mb.phiBin(kphi); - const int mB = mb.massBin(k0.kShortMass()); - if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) continue; - - const int stat = 0; - const size_t key = linearKey(colBin, stat, ptB, etaB, phiB, mB, nStat, nPt, nEta, nPhi, nM); - - // IMPORTANT: rowIndex must match iteratorAt accessor below. - const int64_t row = static_cast(k0.globalIndex()); // if this fails -> use k0.index() consistently - - buffer[key].push_back(BufferCandK0{ - .collisionIdx = static_cast(col.index()), - .rowIndex = row, - .ptBin = static_cast(ptB), - .etaBin = static_cast(etaB), - .phiBin = static_cast(phiB), - .mBin = static_cast(mB) - }); + for (const auto& k0sCand : k0sGroup) { + for (const auto& pionCand : pionGroup) { + fillKstarPair(k0sCand, pionCand, referenceCollision, true); } } - - // ---------------- PASS 2: build same-event (K0,π) pairs, replace only K0 by K0X ---------------- - for (auto const& col1 : collisions) { - const int colBin = colBinning.getBin(std::make_tuple(col1.posz(), col1.cent())); - if (colBin < 0) continue; - - auto poolK0 = V0s.sliceBy(tracksPerCollisionV0, col1.index()); - auto poolPi = piontracks.sliceBy(tracksPerCollisionBach, col1.index()); - - if (poolK0.size() == 0 || poolPi.size() == 0) continue; // no .empty() in ASoA slice - - const float centrality = col1.cent(); - const float psiFT0Cmix = col1.psiFT0C(); - - // same-event pair loop - for (auto const& k0 : poolK0) { - if (!selectionV0(k0)) continue; - - auto [kpt, keta, kphi] = computePtEtaPhi(k0.kShortPx(), k0.kShortPy(), k0.kShortPz()); - kphi = RecoDecay::constrainAngle(kphi, 0.0F); - - const int ptB = mb.ptBin(kpt); - const int etaB = mb.etaBin(keta); - const int phiB = mb.phiBin(kphi); - const int mB = mb.massBin(k0.kShortMass()); - if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) continue; - - const int stat = 0; - const size_t key = linearKey(colBin, stat, ptB, etaB, phiB, mB, nStat, nPt, nEta, nPhi, nM); - auto const& binVec = buffer[key]; - if (binVec.empty()) continue; - - // pre-collect eligible K0 partners from other events (same bin, different collision) - std::vector matches; - matches.reserve(binVec.size()); - const int64_t curColIdx = static_cast(col1.index()); - - for (auto const& bc : binVec) { - if (bc.collisionIdx == curColIdx) continue; - matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); - } - if (matches.empty()) continue; - - // choose random unique subset of K0 partners - const int cap = nEvtMixing.value; - if (cap > 0 && cap < static_cast(matches.size())) { - std::uniform_int_distribution dist(0, static_cast(matches.size()) - 1); - std::unordered_set chosen; - chosen.reserve(static_cast(cap) * 2); - while (static_cast(chosen.size()) < cap) chosen.insert(dist(rng)); - - std::vector subset; - subset.reserve(cap); - for (const int& idx : chosen) subset.push_back(matches[idx]); - matches.swap(subset); - } else { - std::shuffle(matches.begin(), matches.end(), rng); } - const float wBase = 1.0f / static_cast(matches.size()); - - // Now keep π from SAME event fixed (this is your requirement) - for (auto const& piSame : poolPi) { - if (!passSelectedPID(piSame)) continue; - - // avoid self-combination if you stored K0 daughter indices - if (piSame.pionBachIndex() == k0.pionIndex1() || piSame.pionBachIndex() == k0.pionIndex2()) { - continue; - } - - auto [ppt, peta, pphi] = computePtEtaPhi(piSame.pionBachPx(), piSame.pionBachPy(), piSame.pionBachPz()); - pphi = RecoDecay::constrainAngle(pphi, 0.0F); - pionmix = ROOT::Math::PtEtaPhiMVector(ppt, peta, pphi, o2::constants::physics::MassPionCharged); + void processMixedData(EventCandidates const& collisions, + aod::KShortTracks const& k0sTracks, + aod::PionTracks const& pionTracks) + { + BinningType colBinning{{cfgVtxBins, cfgCentBins}, true}; - // replace K0 by mixed K0X from other event, but keep piSame - for (auto const& m : matches) { - auto k0X = V0s.iteratorAt(m.rowIndex); // if globalIndex fails -> use index consistently in PASS1 + for (const auto& [collision1, collision2] : + selfCombinations(colBinning, nEvtMixing.value, -1, collisions, collisions)) { - if (!selectionV0(k0X)) continue; + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } - auto [xpt, xeta, xphi] = computePtEtaPhi(k0X.kShortPx(), k0X.kShortPy(), k0X.kShortPz()); - xphi = RecoDecay::constrainAngle(xphi, 0.0F); - kshortmix = ROOT::Math::PtEtaPhiMVector(xpt, xeta, xphi, k0X.kShortMass()); + // Direction 1: K0s from event 1 + pion from event 2. + for (const auto& k0sCand : k0sTracks) { + if (!k0sBelongsToEvent(k0sCand, collision1)) { + continue; + } - chkstarmix = kshortmix + pionmix; + for (const auto& pionCand : pionTracks) { + if (!pionBelongsToEvent(pionCand, collision2)) { + continue; + } - ROOT::Math::Boost boost{chkstarmix.BoostToCM()}; - fourVecDauCMmix = boost(kshortmix); - threeVecDauCMmix = fourVecDauCMmix.Vect(); + fillKstarPair(k0sCand, pionCand, collision1, true); + } + } - eventplaneVecNormmix = ROOT::Math::XYZVector(std::sin(2.f * psiFT0Cmix), - -std::cos(2.f * psiFT0Cmix), 0.f); + // Direction 2: K0s from event 2 + pion from event 1. + for (const auto& k0sCand : k0sTracks) { + if (!k0sBelongsToEvent(k0sCand, collision2)) { + continue; + } - const float cosThetaStarmix = - eventplaneVecNormmix.Dot(threeVecDauCMmix) / - std::sqrt(threeVecDauCMmix.Mag2()) / - std::sqrt(eventplaneVecNormmix.Mag2()); + for (const auto& pionCand : pionTracks) { + if (!pionBelongsToEvent(pionCand, collision1)) { + continue; + } - histos.fill(HIST("hSparsemix"), - chkstarmix.M(), chkstarmix.Pt(), cosThetaStarmix, centrality, wBase); - } - } + fillKstarPair(k0sCand, pionCand, collision2, true); + } } } } - PROCESS_SWITCH(cksspinalignder, processMixedDataMEV4, - "Process mixed data MEV4 (replace K0, keep same-event pion)", true); - */ + PROCESS_SWITCH(cksspinalignder, processMixedData, "Process mixed-event charged KStar", true); }; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; diff --git a/PWGLF/Tasks/Resonances/deltaAnalysis.cxx b/PWGLF/Tasks/Resonances/deltaAnalysis.cxx index a1697764db9..db3aa55db1c 100644 --- a/PWGLF/Tasks/Resonances/deltaAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/deltaAnalysis.cxx @@ -10,13 +10,16 @@ // or submit itself to any jurisdiction. /// \file deltaanalysis.cxx -/// \brief Delta(1232) resonance analysis via proton-pion invariant mass reconstruction with advance PID and background rejection cuts +/// \brief Delta(1232) resonance analysis via proton-pion invariant mass reconstruction with advance PID and background rejection cuts also add efficiency correction and acceptance correction /// \author Durgesh Bhatt +#include "PWGLF/DataModel/mcCentrality.h" + #include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -25,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -33,14 +37,20 @@ #include #include #include +#include #include #include +#include + #include #include #include #include #include +#include +#include +#include #include using namespace o2; @@ -52,6 +62,7 @@ namespace { constexpr float massProton = o2::constants::physics::MassProton; constexpr float massPion = o2::constants::physics::MassPionCharged; +constexpr float minAbsCharge = 1e-3f; } // namespace namespace delta_analysis { @@ -73,89 +84,104 @@ struct DeltaAnalysis { SliceCache cache; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // FIX name/configurable: single space between type and name; member name == JSON key; lowerCamelCase - Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted |z-vertex| range [cm]"}; - - Configurable cfgUseNoSameBunchPileupCut{"cfgUseNoSameBunchPileupCut", false, "Apply kNoSameBunchPileup event selection"}; - - Configurable cfgUseGoodZvtxFT0vsPVCut{"cfgUseGoodZvtxFT0vsPVCut", false, "Apply kIsGoodZvtxFT0vsPV event selection"}; - Configurable applyOccupancyInTimeRangeCut{"applyOccupancyInTimeRangeCut", false, "Apply occupancy-in-time-range cut"}; - Configurable cfgOccupancyMin{"cfgOccupancyMin", 0, "Minimum track occupancy in time range"}; - Configurable cfgOccupancyMax{"cfgOccupancyMax", 9999, "Maximum track occupancy in time range"}; - - 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 cfgCutPt{"cfgCutPt", 0.2f, "Minimum pT of daughter track [GeV/c]"}; - Configurable cfgCutEta{"cfgCutEta", 0.8f, "Maximum |eta| of daughter track"}; - // CHANGED: replaced single symmetric cfgCutY with independent cfgMinY / cfgMaxY - Configurable cfgMinY{"cfgMinY", -0.5f, "Minimum rapidity of reconstructed Delta"}; - Configurable cfgMaxY{"cfgMaxY", 0.5f, "Maximum rapidity of reconstructed Delta"}; - - Configurable cfgMinITSClusters{"cfgMinITSClusters", 5, "Minimum ITS clusters"}; - Configurable cfgMinTPCClusters{"cfgMinTPCClusters", 70, "Minimum TPC clusters found"}; - Configurable numberOfInvMassBins{"numberOfInvMassBins", 120, "Number of bins along the invariant mass axis"}; - Configurable cfgMinTPCCrossedRows{"cfgMinTPCCrossedRows", 70, "Minimum TPC crossed pad rows"}; - Configurable cfgMinCrossedRowsOverFindable{"cfgMinCrossedRowsOverFindable", 0.8f, "Minimum ratio crossedRows/findableClusters"}; - Configurable cfgMaxTPCSharedClusters{"cfgMaxTPCSharedClusters", 0, "Maximum TPC shared clusters"}; - Configurable cfgMaxTPCChi2NCl{"cfgMaxTPCChi2NCl", 4.0f, "Maximum TPC chi2/NCl"}; - Configurable cfgMaxITSChi2NCl{"cfgMaxITSChi2NCl", 36.0f, "Maximum ITS chi2/NCl"}; - Configurable requirePrimaryTrack{"requirePrimaryTrack", true, "Require isPrimaryTrack flag"}; - Configurable requireGlobalTrackNoDCA{"requireGlobalTrackNoDCA", true, "Require isGlobalTrackWoDCA flag"}; - Configurable requirePVContributor{"requirePVContributor", true, "Require PV-contributor flag"}; - Configurable cfgLowPtTofNsigmaCut{"cfgLowPtTofNsigmaCut", 3.0f, "Low pt nSigma TOF cut for selecting pions and protons"}; - - Configurable cfgCutDCAz{"cfgCutDCAz", 0.1f, "Maximum |DCAz| for all tracks [cm]"}; - Configurable> protonDCAPtBinEdges{"protonDCAPtBinEdges", {0.0f, 0.5f, 1.0f, 2.0f, 1000.f}, "Proton pT bin edges for DCAxy cut [GeV/c]"}; - Configurable> protonMaxDCAxyPerPtBin{"protonMaxDCAxyPerPtBin", {0.10f, 0.08f, 0.05f, 0.05f}, "Max |DCAxy| for proton per pT bin [cm]"}; - Configurable> pionDCAPtBinEdges{"pionDCAPtBinEdges", {0.0f, 0.5f, 1.0f, 2.0f, 1000.f}, "Pion pT bin edges for DCAxy cut [GeV/c]"}; - Configurable> pionMaxDCAxyPerPtBin{"pionMaxDCAxyPerPtBin", {0.20f, 0.15f, 0.10f, 0.08f}, "Max |DCAxy| for pion per pT bin [cm]"}; - - Configurable useTPCOnlyPID{"useTPCOnlyPID", false, "Use TPC-only PID (ignore TOF even if present)"}; - Configurable requireTOFForProton{"requireTOFForProton", false, "Require TOF signal for proton candidates"}; - Configurable requireTOFForPion{"requireTOFForPion", false, "Require TOF signal for pion candidates"}; - Configurable applyTOFCutWhenAvailableBelowThreshold{"applyTOFCutWhenAvailableBelowThreshold", false, "Apply TOF PID only when TOF information exists below momentum threshold"}; - - Configurable minProtonMomentum{"minProtonMomentum", 0.f, "Minimum proton momentum for TOF PID [GeV/c]"}; - Configurable minTPCNSigmaProton{"minTPCNSigmaProton", -6.0f, "Minimum (lower bound) TPC nSigma for proton"}; - Configurable minTOFNSigmaProton{"minTOFNSigmaProton", -6.0f, "Minimum (lower bound) TOF nSigma for proton"}; - Configurable minCombinedNSigmaProton{"minCombinedNSigmaProton", -6.0f, "Minimum combined nSigma for proton (asymmetric mode)"}; - Configurable maxTPCNSigmaProton{"maxTPCNSigmaProton", 3.0, "Maximum |TPC nSigma| for proton"}; - Configurable combinedNSigmaCutProton{"combinedNSigmaCutProton", 3.0, "Circular TPC+TOF combined nSigma cut for proton. Negative = asymmetric mode."}; - Configurable> protonTPCPIDMomentumBins{"protonTPCPIDMomentumBins", {0.f, 0.5f, 0.7f, 0.8f}, "Proton TPC PID momentum bin edges [GeV/c]"}; - Configurable> protonTPCNSigmaCutPerBin{"protonTPCNSigmaCutPerBin", {5.f, 3.5f, 2.5f}, "Maximum TPC nSigma for proton per momentum bin"}; - Configurable> protonTOFPIDMomentumBins{"protonTOFPIDMomentumBins", {0.f, 999.f}, "Proton TOF PID momentum bin edges [GeV/c]"}; - Configurable> protonTOFNSigmaCutPerBin{"protonTOFNSigmaCutPerBin", {3.0f}, "Maximum TOF nSigma for proton per momentum bin"}; - - Configurable minPionMomentum{"minPionMomentum", 0.f, "Minimum pion momentum for TOF PID [GeV/c]"}; - Configurable minTPCNSigmaPion{"minTPCNSigmaPion", -6.0f, "Minimum (lower bound) TPC nSigma for pion"}; - Configurable minTOFNSigmaPion{"minTOFNSigmaPion", -6.0f, "Minimum (lower bound) TOF nSigma for pion"}; - Configurable minCombinedNSigmaPion{"minCombinedNSigmaPion", -6.0f, "Minimum combined nSigma for pion (asymmetric mode)"}; - Configurable maxTPCNSigmaPion{"maxTPCNSigmaPion", 3.0, "Maximum |TPC nSigma| for pion"}; - Configurable combinedNSigmaCutPion{"combinedNSigmaCutPion", 3.0, "Circular TPC+TOF combined nSigma cut for pion. Negative = asymmetric mode."}; - Configurable> pionTPCPIDMomentumBins{"pionTPCPIDMomentumBins", {0.f, 0.25f, 0.4f, 0.5f}, "Pion TPC PID momentum bin edges [GeV/c]"}; - Configurable> pionTPCNSigmaCutPerBin{"pionTPCNSigmaCutPerBin", {5.f, 3.5f, 2.5f}, "Maximum TPC nSigma for pion per momentum bin"}; - Configurable> pionTOFPIDMomentumBins{"pionTOFPIDMomentumBins", {0.f, 999.f}, "Pion TOF PID momentum bin edges [GeV/c]"}; - Configurable> pionTOFNSigmaCutPerBin{"pionTOFNSigmaCutPerBin", {3.0f}, "Maximum TOF nSigma for pion per momentum bin"}; - - Configurable tpcNSigmaVetoThreshold{"tpcNSigmaVetoThreshold", 3.0f, "Reject track if TPC nSigma of a competing species is below this value"}; - Configurable tofNSigmaVetoThreshold{"tofNSigmaVetoThreshold", 3.0f, "Reject track if TOF nSigma of a competing species is below this value"}; - - Configurable applyDeepAngleCut{"applyDeepAngleCut", false, "Apply minimum opening-angle cut (removes split-track background)"}; - Configurable deepAngleCutValue{"deepAngleCutValue", 0.04, "Minimum opening angle between proton and pion [rad]"}; - - Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per signal event"}; - - Configurable enableRotationalBackground{"enableRotationalBackground", false, "Compute rotational background by rotating pion phi near PI"}; - Configurable numberOfRotations{"numberOfRotations", 10, "Number of pion-phi rotations for background"}; - Configurable rotationAngleWindow{"rotationAngleWindow", 6.f, "Pion rotated by angles within PI +/- PI/rotationAngleWindow"}; - - 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 (%)"}; - 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"}; + // PDG service used only for truth-level charged-particle identification + // (see isChargedPrimaryMC() below). + Service pdgDB{}; + + struct : ConfigurableGroup { + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted |z-vertex| range [cm]"}; + Configurable cfgRequireRecoINELgt0{"cfgRequireRecoINELgt0", true, "Require reconstructed INEL>0 event class (at least one PV track in |eta|<1)"}; + Configurable cfgUseNoSameBunchPileupCut{"cfgUseNoSameBunchPileupCut", false, "Apply kNoSameBunchPileup event selection"}; + Configurable cfgUseGoodZvtxFT0vsPVCut{"cfgUseGoodZvtxFT0vsPVCut", false, "Apply kIsGoodZvtxFT0vsPV event selection"}; + Configurable applyOccupancyInTimeRangeCut{"applyOccupancyInTimeRangeCut", false, "Apply occupancy-in-time-range cut"}; + Configurable cfgOccupancyMin{"cfgOccupancyMin", 0, "Minimum track occupancy in time range"}; + Configurable cfgOccupancyMax{"cfgOccupancyMax", 9999, "Maximum track occupancy in time range"}; + 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"}; + } evSel; + + struct : ConfigurableGroup { + Configurable cfgCutPt{"cfgCutPt", 0.2f, "Minimum pT of daughter track [GeV/c]"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Maximum |eta| of daughter track"}; + Configurable cfgMinY{"cfgMinY", -0.5f, "Minimum rapidity of reconstructed Delta"}; + Configurable cfgMaxY{"cfgMaxY", 0.5f, "Maximum rapidity of reconstructed Delta"}; + Configurable cfgMinITSClusters{"cfgMinITSClusters", 5, "Minimum ITS clusters"}; + Configurable cfgMinTPCClusters{"cfgMinTPCClusters", 70, "Minimum TPC clusters found"}; + Configurable numberOfInvMassBins{"numberOfInvMassBins", 120, "Number of bins along the invariant mass axis"}; + Configurable cfgMinTPCCrossedRows{"cfgMinTPCCrossedRows", 70, "Minimum TPC crossed pad rows"}; + Configurable cfgMinCrossedRowsOverFindable{"cfgMinCrossedRowsOverFindable", 0.8f, "Minimum ratio crossedRows/findableClusters"}; + Configurable cfgMaxTPCSharedClusters{"cfgMaxTPCSharedClusters", 0, "Maximum TPC shared clusters"}; + Configurable cfgMaxTPCChi2NCl{"cfgMaxTPCChi2NCl", 4.0f, "Maximum TPC chi2/NCl"}; + Configurable cfgMaxITSChi2NCl{"cfgMaxITSChi2NCl", 36.0f, "Maximum ITS chi2/NCl"}; + Configurable requirePrimaryTrack{"requirePrimaryTrack", true, "Require isPrimaryTrack flag"}; + Configurable requireGlobalTrackNoDCA{"requireGlobalTrackNoDCA", true, "Require isGlobalTrackWoDCA flag"}; + Configurable requirePVContributor{"requirePVContributor", true, "Require PV-contributor flag"}; + } trackCuts; + + struct : ConfigurableGroup { + Configurable cfgCutDCAz{"cfgCutDCAz", 0.1f, "Maximum |DCAz| for all tracks [cm]"}; + Configurable> protonDCAPtBinEdges{"protonDCAPtBinEdges", {0.0f, 0.5f, 1.0f, 2.0f, 1000.f}, "Proton pT bin edges for DCAxy cut [GeV/c]"}; + Configurable> protonMaxDCAxyPerPtBin{"protonMaxDCAxyPerPtBin", {0.10f, 0.08f, 0.05f, 0.05f}, "Max |DCAxy| for proton per pT bin [cm]"}; + Configurable> pionDCAPtBinEdges{"pionDCAPtBinEdges", {0.0f, 0.5f, 1.0f, 2.0f, 1000.f}, "Pion pT bin edges for DCAxy cut [GeV/c]"}; + Configurable> pionMaxDCAxyPerPtBin{"pionMaxDCAxyPerPtBin", {0.20f, 0.15f, 0.10f, 0.08f}, "Max |DCAxy| for pion per pT bin [cm]"}; + } dcaCuts; + + struct : ConfigurableGroup { + Configurable useTPCOnlyPID{"useTPCOnlyPID", false, "Use TPC-only PID (ignore TOF even if present)"}; + Configurable tpcNSigmaVetoThreshold{"tpcNSigmaVetoThreshold", 3.0f, "Reject track if TPC nSigma of a competing species is below this value"}; + Configurable tofNSigmaVetoThreshold{"tofNSigmaVetoThreshold", 3.0f, "Reject track if TOF nSigma of a competing species is below this value"}; + } pidShared; + + struct : ConfigurableGroup { + Configurable requireTOFForProton{"requireTOFForProton", false, "Require TOF signal for proton candidates"}; + Configurable minProtonMomentum{"minProtonMomentum", 0.f, "Minimum proton momentum for TOF PID [GeV/c]"}; + Configurable minTPCNSigmaProton{"minTPCNSigmaProton", -6.0f, "Minimum (lower bound) TPC nSigma for proton"}; + Configurable minTOFNSigmaProton{"minTOFNSigmaProton", -6.0f, "Minimum (lower bound) TOF nSigma for proton"}; + Configurable minCombinedNSigmaProton{"minCombinedNSigmaProton", -6.0f, "Minimum combined nSigma for proton (asymmetric mode)"}; + Configurable maxTPCNSigmaProton{"maxTPCNSigmaProton", 3.0, "Maximum |TPC nSigma| for proton"}; + Configurable combinedNSigmaCutProton{"combinedNSigmaCutProton", 3.0, "Circular TPC+TOF combined nSigma cut for proton. Negative = asymmetric mode."}; + Configurable> protonTPCPIDMomentumBins{"protonTPCPIDMomentumBins", {0.f, 0.5f, 0.7f, 0.8f}, "Proton TPC PID momentum bin edges [GeV/c]"}; + Configurable> protonTPCNSigmaCutPerBin{"protonTPCNSigmaCutPerBin", {5.f, 3.5f, 2.5f}, "Maximum TPC nSigma for proton per momentum bin"}; + Configurable> protonTOFPIDMomentumBins{"protonTOFPIDMomentumBins", {0.f, 999.f}, "Proton TOF PID momentum bin edges [GeV/c]"}; + Configurable> protonTOFNSigmaCutPerBin{"protonTOFNSigmaCutPerBin", {3.0f}, "Maximum TOF nSigma for proton per momentum bin"}; + } protonPID; + + struct : ConfigurableGroup { + Configurable requireTOFForPion{"requireTOFForPion", false, "Require TOF signal for pion candidates"}; + Configurable minPionMomentum{"minPionMomentum", 0.f, "Minimum pion momentum for TOF PID [GeV/c]"}; + Configurable minTPCNSigmaPion{"minTPCNSigmaPion", -6.0f, "Minimum (lower bound) TPC nSigma for pion"}; + Configurable minTOFNSigmaPion{"minTOFNSigmaPion", -6.0f, "Minimum (lower bound) TOF nSigma for pion"}; + Configurable minCombinedNSigmaPion{"minCombinedNSigmaPion", -6.0f, "Minimum combined nSigma for pion (asymmetric mode)"}; + Configurable maxTPCNSigmaPion{"maxTPCNSigmaPion", 3.0, "Maximum |TPC nSigma| for pion"}; + Configurable combinedNSigmaCutPion{"combinedNSigmaCutPion", 3.0, "Circular TPC+TOF combined nSigma cut for pion. Negative = asymmetric mode."}; + Configurable> pionTPCPIDMomentumBins{"pionTPCPIDMomentumBins", {0.f, 0.25f, 0.4f, 0.5f}, "Pion TPC PID momentum bin edges [GeV/c]"}; + Configurable> pionTPCNSigmaCutPerBin{"pionTPCNSigmaCutPerBin", {5.f, 3.5f, 2.5f}, "Maximum TPC nSigma for pion per momentum bin"}; + Configurable> pionTOFPIDMomentumBins{"pionTOFPIDMomentumBins", {0.f, 999.f}, "Pion TOF PID momentum bin edges [GeV/c]"}; + Configurable> pionTOFNSigmaCutPerBin{"pionTOFNSigmaCutPerBin", {3.0f}, "Maximum TOF nSigma for pion per momentum bin"}; + } pionPID; + + struct : ConfigurableGroup { + Configurable applyDeepAngleCut{"applyDeepAngleCut", false, "Apply minimum opening-angle cut (removes split-track background)"}; + Configurable deepAngleCutValue{"deepAngleCutValue", 0.04, "Minimum opening angle between proton and pion [rad]"}; + } pairCuts; + + struct : ConfigurableGroup { + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per signal event"}; + } mixingCfg; + + struct : ConfigurableGroup { + Configurable enableRotationalBackground{"enableRotationalBackground", false, "Compute rotational background by rotating pion phi near PI"}; + Configurable numberOfRotations{"numberOfRotations", 10, "Number of pion-phi rotations for background"}; + Configurable rotationAngleWindow{"rotationAngleWindow", 6.f, "Pion rotated by angles within PI +/- PI/rotationAngleWindow"}; + } rotBkg; + + 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 (%)"}; + 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; std::vector mProtonTPCMomBins; std::vector mProtonTPCNSigCuts; @@ -181,31 +207,32 @@ struct DeltaAnalysis { << ", bins=" << binsVec.size() << ")"; } }; - chkSz(protonTPCNSigmaCutPerBin, protonTPCPIDMomentumBins, "proton TPC PID"); - chkSz(protonTOFNSigmaCutPerBin, protonTOFPIDMomentumBins, "proton TOF PID"); - chkSz(pionTPCNSigmaCutPerBin, pionTPCPIDMomentumBins, "pion TPC PID"); - chkSz(pionTOFNSigmaCutPerBin, pionTOFPIDMomentumBins, "pion TOF PID"); - chkSz(protonMaxDCAxyPerPtBin, protonDCAPtBinEdges, "proton DCA"); - chkSz(pionMaxDCAxyPerPtBin, pionDCAPtBinEdges, "pion DCA"); - - mProtonTPCMomBins = protonTPCPIDMomentumBins.value; - mProtonTPCNSigCuts = protonTPCNSigmaCutPerBin.value; - mProtonTOFMomBins = protonTOFPIDMomentumBins.value; - mProtonTOFNSigCuts = protonTOFNSigmaCutPerBin.value; - mPionTPCMomBins = pionTPCPIDMomentumBins.value; - mPionTPCNSigCuts = pionTPCNSigmaCutPerBin.value; - mPionTOFMomBins = pionTOFPIDMomentumBins.value; - mPionTOFNSigCuts = pionTOFNSigmaCutPerBin.value; - mProtonDCAPtEdges = protonDCAPtBinEdges.value; - mProtonMaxDCAxy = protonMaxDCAxyPerPtBin.value; - mPionDCAPtEdges = pionDCAPtBinEdges.value; - mPionMaxDCAxy = pionMaxDCAxyPerPtBin.value; + chkSz(protonPID.protonTPCNSigmaCutPerBin, protonPID.protonTPCPIDMomentumBins, "proton TPC PID"); + chkSz(protonPID.protonTOFNSigmaCutPerBin, protonPID.protonTOFPIDMomentumBins, "proton TOF PID"); + chkSz(pionPID.pionTPCNSigmaCutPerBin, pionPID.pionTPCPIDMomentumBins, "pion TPC PID"); + chkSz(pionPID.pionTOFNSigmaCutPerBin, pionPID.pionTOFPIDMomentumBins, "pion TOF PID"); + chkSz(dcaCuts.protonMaxDCAxyPerPtBin, dcaCuts.protonDCAPtBinEdges, "proton DCA"); + chkSz(dcaCuts.pionMaxDCAxyPerPtBin, dcaCuts.pionDCAPtBinEdges, "pion DCA"); + + mProtonTPCMomBins = protonPID.protonTPCPIDMomentumBins.value; + mProtonTPCNSigCuts = protonPID.protonTPCNSigmaCutPerBin.value; + mProtonTOFMomBins = protonPID.protonTOFPIDMomentumBins.value; + mProtonTOFNSigCuts = protonPID.protonTOFNSigmaCutPerBin.value; + mPionTPCMomBins = pionPID.pionTPCPIDMomentumBins.value; + mPionTPCNSigCuts = pionPID.pionTPCNSigmaCutPerBin.value; + mPionTOFMomBins = pionPID.pionTOFPIDMomentumBins.value; + mPionTOFNSigCuts = pionPID.pionTOFNSigmaCutPerBin.value; + mProtonDCAPtEdges = dcaCuts.protonDCAPtBinEdges.value; + mProtonMaxDCAxy = dcaCuts.protonMaxDCAxyPerPtBin.value; + mPionDCAPtEdges = dcaCuts.pionDCAPtBinEdges.value; + mPionMaxDCAxy = dcaCuts.pionMaxDCAxyPerPtBin.value; const AxisSpec ptAxis{200, 0., 10., "p_{T} (GeV/c)"}; - const AxisSpec massAxis{numberOfInvMassBins, 1.0, 8.0, "M_{inv} (GeV/#it{c}^{2})"}; - const AxisSpec centAxis{cfgCentAxis, "Centrality (%)"}; - const AxisSpec vtxAxis{cfgVtxAxis, "Vertex z [cm]"}; - const AxisSpec rapAxis{cfgRapAxis, "Rapidity y"}; + const AxisSpec massAxis{trackCuts.numberOfInvMassBins, 1.0, 8.0, "M_{inv} (GeV/#it{c}^{2})"}; + const AxisSpec centAxis{axes.cfgCentAxis, "Centrality (%)"}; + const AxisSpec centDistAxis{150, 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}"}; const AxisSpec nSigmaTOFaxis{100, -10., 10., "n#sigma^{TOF}"}; const AxisSpec momentumAxis{200, 0., 10., "p (GeV/#it{c})"}; @@ -222,6 +249,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("CentQA/hCentralityVsVtxZ", "Centrality vs vertex z", kTH2F, {vtxAxis, centAxis}); histos.add("CentQA/hCentralityVsOccupancy", "Centrality vs occupancy", kTH2F, {occupancyAxis, centAxis}); @@ -281,7 +309,7 @@ struct DeltaAnalysis { histos.add("Analysis/hDeltaZeroInvMass", "#Delta^{0} (#rightarrow p + #pi^{-}) invariant mass", kTH2F, {ptAxis, massAxis}); histos.add("Analysis/hAntiDeltaZeroInvMass", "#bar{#Delta}^{0} (#rightarrow #bar{p} + #pi^{+}) invariant mass", kTH2F, {ptAxis, massAxis}); - if (enableRotationalBackground) { + if (rotBkg.enableRotationalBackground) { histos.add("Analysis/hDeltaPlusPlusInvMassRot", "#Delta^{++} invariant mass - rotational background", kTH2F, {ptAxis, massAxis}); histos.add("Analysis/hAntiDeltaPlusPlusInvMassRot", "#bar{#Delta}^{++} invariant mass - rotational background", kTH2F, {ptAxis, massAxis}); histos.add("Analysis/hDeltaZeroInvMassRot", "#Delta^{0} invariant mass - rotational background", kTH2F, {ptAxis, massAxis}); @@ -300,7 +328,7 @@ struct DeltaAnalysis { histos.add("THnSparse/hDeltaZero", "THnSparse #Delta^{0} same-event", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("THnSparse/hAntiDeltaZero", "THnSparse #bar{#Delta}^{0} same-event", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); - if (enableRotationalBackground) { + if (rotBkg.enableRotationalBackground) { histos.add("THnSparse/hDeltaPlusPlusRot", "THnSparse #Delta^{++} rotational background", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("THnSparse/hAntiDeltaPlusPlusRot", "THnSparse #bar{#Delta}^{++} rotational background", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("THnSparse/hDeltaZeroRot", "THnSparse #Delta^{0} rotational background", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); @@ -319,20 +347,11 @@ struct DeltaAnalysis { histos.add("THnSparse/hAntiDeltaPlusPlusMC", "THnSparse #bar{#Delta}^{++} MC reconstructed", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("THnSparse/hDeltaZeroMC", "THnSparse #Delta^{0} MC reconstructed", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("THnSparse/hAntiDeltaZeroMC", "THnSparse #bar{#Delta}^{0} MC reconstructed", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); - // CHANGED: generated-particle THnSparse now carries mass at axis 0, followed by pt, cent, rap - histos.add("THnSparse/hDeltaPlusPlusGen", "THnSparse #Delta^{++} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); - histos.add("THnSparse/hAntiDeltaPlusPlusGen", "THnSparse #bar{#Delta}^{++} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); - histos.add("THnSparse/hDeltaZeroGen", "THnSparse #Delta^{0} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); - histos.add("THnSparse/hAntiDeltaZeroGen", "THnSparse #bar{#Delta}^{0} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("Analysis/hDeltaPlusPlusInvMassMC", "#Delta^{++} invariant mass (MC truth-matched)", kTH2F, {ptAxis, massAxis}); histos.add("Analysis/hAntiDeltaPlusPlusInvMassMC", "#bar{#Delta}^{++} invariant mass (MC truth-matched)", kTH2F, {ptAxis, massAxis}); histos.add("Analysis/hDeltaZeroInvMassMC", "#Delta^{0} invariant mass (MC truth-matched)", kTH2F, {ptAxis, massAxis}); histos.add("Analysis/hAntiDeltaZeroInvMassMC", "#bar{#Delta}^{0} invariant mass (MC truth-matched)", kTH2F, {ptAxis, massAxis}); - histos.add("Analysis/hDeltaPlusPlusInvMassGen", "#Delta^{++} invariant mass - generated", kTH2F, {ptAxis, massAxis}); - histos.add("Analysis/hAntiDeltaPlusPlusInvMassGen", "#bar{#Delta}^{++} invariant mass - generated", kTH2F, {ptAxis, massAxis}); - histos.add("Analysis/hDeltaZeroInvMassGen", "#Delta^{0} invariant mass - generated", kTH2F, {ptAxis, massAxis}); - histos.add("Analysis/hAntiDeltaZeroInvMassGen", "#bar{#Delta}^{0} invariant mass - generated", kTH2F, {ptAxis, massAxis}); histos.add("QAChecks/hRecProtonDeltaPlusPlus", "Rec proton from #Delta^{++}", kTH1F, {ptAxis}); histos.add("QAChecks/hRecProtonAntiDeltaPlusPlus", "Rec proton from #bar{#Delta}^{++}", kTH1F, {ptAxis}); @@ -342,16 +361,7 @@ struct DeltaAnalysis { histos.add("QAChecks/hRecPionAntiDeltaPlusPlus", "Rec pion from #bar{#Delta}^{++}", kTH1F, {ptAxis}); histos.add("QAChecks/hRecPionDeltaZero", "Rec pion from #Delta^{0}", kTH1F, {ptAxis}); histos.add("QAChecks/hRecPionAntiDeltaZero", "Rec pion from #bar{#Delta}^{0}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenProtonDeltaPlusPlus", "Gen proton from #Delta^{++}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenProtonAntiDeltaPlusPlus", "Gen proton from #bar{#Delta}^{++}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenProtonDeltaZero", "Gen proton from #Delta^{0}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenProtonAntiDeltaZero", "Gen proton from #bar{#Delta}^{0}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenPionDeltaPlusPlus", "Gen pion from #Delta^{++}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenPionAntiDeltaPlusPlus", "Gen pion from #bar{#Delta}^{++}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenPionDeltaZero", "Gen pion from #Delta^{0}", kTH1F, {ptAxis}); - histos.add("QAChecks/hGenPionAntiDeltaZero", "Gen pion from #bar{#Delta}^{0}", kTH1F, {ptAxis}); - - // reconstructed-level (pre-truth-matching) invariant mass histograms for MC-reconstructed candidates + histos.add("AnalysisMCReco/hDeltaPlusPlusInvMassReco", "#Delta^{++} invariant mass - MC reconstructed (pre-truth-matching)", kTH2F, {ptAxis, massAxis}); histos.add("AnalysisMCReco/hAntiDeltaPlusPlusInvMassReco", "#bar{#Delta}^{++} invariant mass - MC reconstructed (pre-truth-matching)", kTH2F, {ptAxis, massAxis}); histos.add("AnalysisMCReco/hDeltaZeroInvMassReco", "#Delta^{0} invariant mass - MC reconstructed (pre-truth-matching)", kTH2F, {ptAxis, massAxis}); @@ -362,7 +372,6 @@ struct DeltaAnalysis { histos.add("THnSparseMCReco/hDeltaZeroReco", "THnSparse #Delta^{0} MC reconstructed (pre-truth-matching)", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); histos.add("THnSparseMCReco/hAntiDeltaZeroReco", "THnSparse #bar{#Delta}^{0} MC reconstructed (pre-truth-matching)", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); - // detector QA for reconstructed MC tracks,no truth matching required ── histos.add("QAMC/Proton/dcaXYvsPt", "Proton DCA_{xy} vs p_{T} (MC reco, after cuts)", kTH2F, {ptForPIDAxis, dcaXYaxis}); histos.add("QAMC/Proton/dcaZvsPt", "Proton DCA_{z} vs p_{T} (MC reco, after cuts)", kTH2F, {ptForPIDAxis, dcaZaxis}); histos.add("QAMC/Proton/tpcNSigmaVsMomentum", "Proton TPC n#sigma vs p (MC reco, after cuts)", kTH2F, {momentumAxis, nSigmaTPCaxis}); @@ -396,13 +405,112 @@ struct DeltaAnalysis { histos.add("QAMC/Pion/tpcClustersFoundVsPt", "Pion TPC clusters found vs p_{T} (MC reco)", kTH2F, {ptForPIDAxis, tpcClusAxis}); histos.add("QAMC/Pion/dcaXYdist", "Pion DCA_{xy} distribution (MC reco, fine bins)", kTH1F, {dcaXYaxis}); histos.add("QAMC/Pion/dcaZdist", "Pion DCA_{z} distribution (MC reco, fine bins)", kTH1F, {dcaZaxis}); + + histos.add("MCRecoEvent/hRecoEvents", "Reconstructed INEL>0 events (Nrec, MC reco)", kTH1F, {centAxis}); + histos.add("MCRecoEvent/centralitydistribution", "Centrality distribution (MC);vCentFT0M;Entries", kTH1F, {centDistAxis}); + } + + // ── processMCGen(): generated-level Delta spectra + QA ───────────────────────────────── + if (doprocessMCGen) { + histos.add("MCGen/hDeltaPlusPlusGenSparse", "THnSparse #Delta^{++} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + histos.add("MCGen/hAntiDeltaPlusPlusGenSparse", "THnSparse #bar{#Delta}^{++} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + histos.add("MCGen/hDeltaZeroGenSparse", "THnSparse #Delta^{0} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + histos.add("MCGen/hAntiDeltaZeroGenSparse", "THnSparse #bar{#Delta}^{0} generated", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + + histos.add("MCGen/hDeltaPlusPlusInvMassGen", "#Delta^{++} invariant mass - generated", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/hAntiDeltaPlusPlusInvMassGen", "#bar{#Delta}^{++} invariant mass - generated", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/hDeltaZeroInvMassGen", "#Delta^{0} invariant mass - generated", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/hAntiDeltaZeroInvMassGen", "#bar{#Delta}^{0} invariant mass - generated", kTH2F, {ptAxis, massAxis}); + + histos.add("MCGenQA/hGenProtonDeltaPlusPlus", "Gen proton from #Delta^{++}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenProtonAntiDeltaPlusPlus", "Gen proton from #bar{#Delta}^{++}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenProtonDeltaZero", "Gen proton from #Delta^{0}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenProtonAntiDeltaZero", "Gen proton from #bar{#Delta}^{0}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenPionDeltaPlusPlus", "Gen pion from #Delta^{++}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenPionAntiDeltaPlusPlus", "Gen pion from #bar{#Delta}^{++}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenPionDeltaZero", "Gen pion from #Delta^{0}", kTH1F, {ptAxis}); + histos.add("MCGenQA/hGenPionAntiDeltaZero", "Gen pion from #bar{#Delta}^{0}", kTH1F, {ptAxis}); + + // Generated-Delta cut flow. 0=All generated, 1=producedByGenerator, 2=truth vertex-z, + // 3=truth INEL>0, 4=PDG, 5=rapidity, 6=decay channel, 7=final generated histogram. + histos.add("MCGenQA/hGenDeltaCutFlow", "Generated #Delta cut flow", kTH1F, {{8, -0.5f, 7.5f}}); + + histos.add("MCGen/GeneratedDelta_EventAccepted/hDeltaPlusPlusInvMass", "#Delta^{++} generated, event-accepted", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaPlusPlusInvMass", "#bar{#Delta}^{++} generated, event-accepted", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hDeltaZeroInvMass", "#Delta^{0} generated, event-accepted", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaZeroInvMass", "#bar{#Delta}^{0} generated, event-accepted", kTH2F, {ptAxis, massAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hDeltaPlusPlusSparse", "THnSparse #Delta^{++} generated, event-accepted", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaPlusPlusSparse", "THnSparse #bar{#Delta}^{++} generated, event-accepted", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hDeltaZeroSparse", "THnSparse #Delta^{0} generated, event-accepted", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + histos.add("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaZeroSparse", "THnSparse #bar{#Delta}^{0} generated, event-accepted", kTHnSparseF, {massAxis, ptAxis, centAxis, rapAxis}); + } + + // ── processEventFactor(): event-level corrections only (Event Loss / Event Splitting) ── + if (doprocessEventFactor) { + histos.add("EventFactor/hRecoEvents", "Reconstructed INEL>0 events (Nrec)", kTH1F, {centAxis}); + histos.add("EventFactor/hEventsGenAll", "Generated events passing truth |Zvtx| + truth INEL>0 cuts", kTH1F, {centAxis}); + histos.add("EventFactor/hEventsGenAccepted", "Generated events with >=1 accepted reconstructed collision", kTH1F, {centAxis}); + histos.add("EventFactor/hNRecoCollisionsPerMcCollision", "Number of reconstructed collisions per generated collision", kTH1F, {{21, -0.5f, 20.5f}}); + } + + // ── Event-level cut-flow (QA-only) histograms ─────────────────────────────────────────── + // These are pure bookkeeping: they record how many events survive each existing selection + // step (already implemented in passesEventSelectionImpl(), isTruthInelGt0(), and + // processEventFactor()) and do not themselves apply, add, or alter any selection. + { + histos.add("CutFlow/Data/hEventCutFlow", "Data event cut flow", kTH1F, {{9, -0.5f, 8.5f}}); + auto hDataCutFlow = histos.get(HIST("CutFlow/Data/hEventCutFlow")); + hDataCutFlow->GetXaxis()->SetBinLabel(1, "All"); + hDataCutFlow->GetXaxis()->SetBinLabel(2, "sel8"); + hDataCutFlow->GetXaxis()->SetBinLabel(3, "INEL>0"); + hDataCutFlow->GetXaxis()->SetBinLabel(4, "Vz"); + hDataCutFlow->GetXaxis()->SetBinLabel(5, "Occupancy"); + hDataCutFlow->GetXaxis()->SetBinLabel(6, "Centrality"); + hDataCutFlow->GetXaxis()->SetBinLabel(7, "Pileup"); + hDataCutFlow->GetXaxis()->SetBinLabel(8, "GoodZvtx"); + hDataCutFlow->GetXaxis()->SetBinLabel(9, "Accepted"); + } + + if (doprocessMC) { + histos.add("CutFlow/MCReco/hEventCutFlow", "MC reconstructed event cut flow", kTH1F, {{9, -0.5f, 8.5f}}); + auto hMcRecoCutFlow = histos.get(HIST("CutFlow/MCReco/hEventCutFlow")); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(1, "All"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(2, "sel8"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(3, "INEL>0"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(4, "Vz"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(5, "Occupancy"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(6, "Centrality"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(7, "Pileup"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(8, "GoodZvtx"); + hMcRecoCutFlow->GetXaxis()->SetBinLabel(9, "Accepted"); + } + + if (doprocessMCGen) { + histos.add("CutFlow/MCGen/hEventCutFlow", "MC generated event cut flow", kTH1F, {{5, -0.5f, 4.5f}}); + auto hMcGenCutFlow = histos.get(HIST("CutFlow/MCGen/hEventCutFlow")); + hMcGenCutFlow->GetXaxis()->SetBinLabel(1, "All"); + hMcGenCutFlow->GetXaxis()->SetBinLabel(2, "Vz"); + hMcGenCutFlow->GetXaxis()->SetBinLabel(3, "INEL>0"); + hMcGenCutFlow->GetXaxis()->SetBinLabel(4, "Centrality"); + hMcGenCutFlow->GetXaxis()->SetBinLabel(5, "Accepted"); + } + + if (doprocessEventFactor) { + histos.add("CutFlow/EventFactor/hEventAcceptedCutFlow", "Event Loss / Event Splitting: generated-event cut flow", kTH1F, {{6, -0.5f, 5.5f}}); + auto hEventFactorCutFlow = histos.get(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow")); + hEventFactorCutFlow->GetXaxis()->SetBinLabel(1, "All"); + hEventFactorCutFlow->GetXaxis()->SetBinLabel(2, "Vz"); + hEventFactorCutFlow->GetXaxis()->SetBinLabel(3, "INEL>0"); + hEventFactorCutFlow->GetXaxis()->SetBinLabel(4, "HasRecoColl"); + hEventFactorCutFlow->GetXaxis()->SetBinLabel(5, "RecoCollAccepted"); + hEventFactorCutFlow->GetXaxis()->SetBinLabel(6, "EventAccepted"); } } // end init() template float getCentrality(CollisionType const& collision) { - switch (cfgCentralityEstimator) { + switch (evSel.cfgCentralityEstimator) { case delta_analysis::kFT0M: return collision.centFT0M(); case delta_analysis::kFT0A: @@ -418,70 +526,147 @@ struct DeltaAnalysis { } } - // passesEventSelection with optional EventSelection cuts + // INEL>0 (reconstructed): at least one PV-associated track within |eta| < 1. template - bool passesEventSelection(CollisionType const& collision) + bool isRecoInelGt0(CollisionType const& collision) + { + return collision.multNTracksPVeta1() > 0; + } + + // Truth-level charged-primary identification, used only to build the truth-level INEL>0 event + // class (isTruthInelGt0 below). + template + bool isChargedPrimaryMC(McParticleType const& mcPart) + { + if (!mcPart.isPhysicalPrimary()) { + return false; + } + auto* pdgParticle = pdgDB->GetParticle(mcPart.pdgCode()); + if (!pdgParticle) { + return false; + } + return std::abs(pdgParticle->Charge()) > minAbsCharge; + } + + // Truth-level analogue of isRecoInelGt0() above - at least one charged primary within + // |eta| < 1 among the generated particles of a given MC collision. + template + bool isTruthInelGt0(McParticleTableType const& mcParticlesInCollision) + { + for (auto const& mcPart : mcParticlesInCollision) { + if (std::abs(mcPart.eta()) < 1.f && isChargedPrimaryMC(mcPart)) { + return true; + } + } + return false; + } + + struct NoCutFlowTag { + }; + struct DataCutFlowTag { + }; + struct McRecoCutFlowTag { + }; + + template + void fillEventCutFlowBin(float bin) + { + if constexpr (std::is_same_v) { + histos.fill(HIST("CutFlow/Data/hEventCutFlow"), bin); + } else if constexpr (std::is_same_v) { + histos.fill(HIST("CutFlow/MCReco/hEventCutFlow"), bin); + } + // NoCutFlowTag: intentionally does nothing. + } + + template + bool passesEventSelectionImpl(CollisionType const& collision) { + fillEventCutFlowBin(0.f); // All collisions + if (!collision.sel8()) { return false; } - if (std::abs(collision.posZ()) > cfgCutVertex) { + fillEventCutFlowBin(1.f); // sel8 + + if (evSel.cfgRequireRecoINELgt0 && !isRecoInelGt0(collision)) { + return false; + } + fillEventCutFlowBin(2.f); // Reconstructed INEL>0 + + if (std::abs(collision.posZ()) > evSel.cfgCutVertex) { return false; } - if (applyOccupancyInTimeRangeCut) { + fillEventCutFlowBin(3.f); // |Vz| < cfgCutVertex + + if (evSel.applyOccupancyInTimeRangeCut) { const int occ = collision.trackOccupancyInTimeRange(); - if (occ < cfgOccupancyMin || occ > cfgOccupancyMax) { + if (occ < evSel.cfgOccupancyMin || occ > evSel.cfgOccupancyMax) { return false; } } - const float cent = getCentrality(collision); - if (cent < cfgCentMin || cent > cfgCentMax) { - return false; - } + fillEventCutFlowBin(4.f); // Occupancy cut + + // Centrality cut removed: events are no longer rejected based on centrality + // (cfgCentMin / cfgCentMax are intentionally no longer applied here). The + // centrality calculation itself, getCentrality(), cfgCentralityEstimator, and + // all centrality-dependent histograms/infrastructure are left untouched. + fillEventCutFlowBin(5.f); // Centrality range (bin retained for cut-flow numbering; no longer a cut) - if (cfgUseNoSameBunchPileupCut && + if (evSel.cfgUseNoSameBunchPileupCut && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return false; } + fillEventCutFlowBin(6.f); // NoSameBunchPileup - if (cfgUseGoodZvtxFT0vsPVCut && + if (evSel.cfgUseGoodZvtxFT0vsPVCut && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } + fillEventCutFlowBin(7.f); // GoodZvtxFT0vsPV + + fillEventCutFlowBin(8.f); // Final accepted event return true; } + // passesEventSelection with optional EventSelection cuts + template + bool passesEventSelection(CollisionType const& collision) + { + return passesEventSelectionImpl(collision); + } + template bool passesBasicTrackSelection(TrackType const& track) { - if (track.itsNCls() < cfgMinITSClusters) { + if (track.itsNCls() < trackCuts.cfgMinITSClusters) { return false; } - if (track.tpcNClsShared() > cfgMaxTPCSharedClusters) { + if (track.tpcNClsShared() > trackCuts.cfgMaxTPCSharedClusters) { return false; } - if (track.tpcNClsFound() < cfgMinTPCClusters) { + if (track.tpcNClsFound() < trackCuts.cfgMinTPCClusters) { return false; } - if (track.tpcNClsCrossedRows() < cfgMinTPCCrossedRows) { + if (track.tpcNClsCrossedRows() < trackCuts.cfgMinTPCCrossedRows) { return false; } - if (track.tpcNClsCrossedRows() < cfgMinCrossedRowsOverFindable * track.tpcNClsFindable()) { + if (track.tpcNClsCrossedRows() < trackCuts.cfgMinCrossedRowsOverFindable * track.tpcNClsFindable()) { return false; } - if (track.tpcChi2NCl() > cfgMaxTPCChi2NCl) { + if (track.tpcChi2NCl() > trackCuts.cfgMaxTPCChi2NCl) { return false; } - if (track.itsChi2NCl() > cfgMaxITSChi2NCl) { + if (track.itsChi2NCl() > trackCuts.cfgMaxITSChi2NCl) { return false; } - if (requirePrimaryTrack && !track.isPrimaryTrack()) { + if (trackCuts.requirePrimaryTrack && !track.isPrimaryTrack()) { return false; } - if (requireGlobalTrackNoDCA && !track.isGlobalTrackWoDCA()) { + if (trackCuts.requireGlobalTrackNoDCA && !track.isGlobalTrackWoDCA()) { return false; } - if (requirePVContributor && !track.isPVContributor()) { + if (trackCuts.requirePVContributor && !track.isPVContributor()) { return false; } return true; @@ -500,7 +685,7 @@ struct DeltaAnalysis { break; } } - return passed && (std::abs(track.dcaZ()) < cfgCutDCAz); + return passed && (std::abs(track.dcaZ()) < dcaCuts.cfgCutDCAz); } template @@ -516,152 +701,122 @@ struct DeltaAnalysis { break; } } - return passed && (std::abs(track.dcaZ()) < cfgCutDCAz); + return passed && (std::abs(track.dcaZ()) < dcaCuts.cfgCutDCAz); } + // ── PID decision flow ──────────────────────────────────────────────────────────────────────────── template bool passesProtonPID(TrackType const& track, float totalMomentum) { - bool tpcPassed{false}, tofPassed{false}; - const int nTPCBins = static_cast(mProtonTPCMomBins.size()); - const int nTOFBins = static_cast(mProtonTOFMomBins.size()); const float tpcNSigPi = std::abs(track.tpcNSigmaPi()); const float tpcNSigPr = std::abs(track.tpcNSigmaPr()); const float tofNSigPi = std::abs(track.tofNSigmaPi()); const float tofNSigPr = std::abs(track.tofNSigmaPr()); - const float combinedNSigPr = tpcNSigPr * tpcNSigPr + tofNSigPr * tofNSigPr; - const float combinedNSigPi = tpcNSigPi * tpcNSigPi + tofNSigPi * tofNSigPi; - const auto circularCutSq = static_cast(combinedNSigmaCutProton * combinedNSigmaCutProton); - const float circularVetoCutSq = tpcNSigmaVetoThreshold * tpcNSigmaVetoThreshold + tofNSigmaVetoThreshold * tofNSigmaVetoThreshold; + const bool useTOF = !pidShared.useTPCOnlyPID && track.hasTOF(); - if (!useTPCOnlyPID && track.hasTOF()) { - if (combinedNSigmaCutProton < 0 && totalMomentum >= minProtonMomentum) { - if (track.tofNSigmaPr() < minTOFNSigmaProton) { + if (useTOF) { + // Combined TPC+TOF PID - used whenever TOF is available, regardless of momentum. + if (protonPID.combinedNSigmaCutProton < 0) { + // Asymmetric mode: independent TPC and TOF nSigma windows. + if (track.tofNSigmaPr() < protonPID.minTOFNSigmaProton) { return false; } + bool tofPassed = false; + const int nTOFBins = static_cast(mProtonTOFMomBins.size()); for (int i = 0; i < nTOFBins - 1; ++i) { if (totalMomentum >= mProtonTOFMomBins[i] && totalMomentum < mProtonTOFMomBins[i + 1] && - tofNSigPr < mProtonTOFNSigCuts[i] && tofNSigPi > tofNSigmaVetoThreshold) { + tofNSigPr < mProtonTOFNSigCuts[i] && tofNSigPi > pidShared.tofNSigmaVetoThreshold) { tofPassed = true; break; } } - if (track.tpcNSigmaPr() < minCombinedNSigmaProton) { + if (track.tpcNSigmaPr() < protonPID.minCombinedNSigmaProton) { return false; } - if (tpcNSigPr < static_cast(maxTPCNSigmaProton) && tpcNSigPi > tpcNSigmaVetoThreshold) { - tpcPassed = true; - } - } else if (combinedNSigmaCutProton > 0 && totalMomentum >= minProtonMomentum) { - if (combinedNSigPr < circularCutSq && combinedNSigPi > circularVetoCutSq) { - tpcPassed = true; - tofPassed = true; - } - } - // ── Part 2: low-momentum region with TOF available ────────────────── - if (totalMomentum < minProtonMomentum && tpcNSigPr < static_cast(maxTPCNSigmaProton)) { - tpcPassed = true; - if (applyTOFCutWhenAvailableBelowThreshold) { - // TOF is available (track.hasTOF() is true in this branch): require TOF nSigma - tofPassed = (tofNSigPr < cfgLowPtTofNsigmaCut); - } else { - tofPassed = true; - } + const bool tpcPassed = tpcNSigPr < static_cast(protonPID.maxTPCNSigmaProton) && tpcNSigPi > pidShared.tpcNSigmaVetoThreshold; + return tofPassed && tpcPassed; } - } else { - // No TOF available (or useTPCOnlyPID == true) - if (totalMomentum < minProtonMomentum && tpcNSigPr < static_cast(maxTPCNSigmaProton)) { - // ── Part 2: low-momentum, no TOF → TPC-only regardless of configurable ── - tpcPassed = true; - tofPassed = true; - } else { - tofPassed = true; - if (track.tpcNSigmaPr() < minTPCNSigmaProton) { - return false; - } - for (int i = 0; i < nTPCBins - 1; ++i) { - if (totalMomentum >= mProtonTPCMomBins[i] && totalMomentum < mProtonTPCMomBins[i + 1] && - tpcNSigPr < mProtonTPCNSigCuts[i] && tpcNSigPi > tpcNSigmaVetoThreshold) { - tpcPassed = true; - break; - } - } + + // Circular mode: joint TPC+TOF nSigma radius. + const float combinedNSigPr = tpcNSigPr * tpcNSigPr + tofNSigPr * tofNSigPr; + const float combinedNSigPi = tpcNSigPi * tpcNSigPi + tofNSigPi * tofNSigPi; + const auto circularCutSq = static_cast(protonPID.combinedNSigmaCutProton * protonPID.combinedNSigmaCutProton); + const float circularVetoCutSq = pidShared.tpcNSigmaVetoThreshold * pidShared.tpcNSigmaVetoThreshold + + pidShared.tofNSigmaVetoThreshold * pidShared.tofNSigmaVetoThreshold; + return combinedNSigPr < circularCutSq && combinedNSigPi > circularVetoCutSq; + } + + // No usable TOF: above the momentum threshold, TOF is mandatory -> reject. + if (totalMomentum >= protonPID.minProtonMomentum) { + return false; + } + + // TPC-only PID below the momentum threshold, using the momentum-binned TPC cuts. + const int nTPCBins = static_cast(mProtonTPCMomBins.size()); + for (int i = 0; i < nTPCBins - 1; ++i) { + if (totalMomentum >= mProtonTPCMomBins[i] && totalMomentum < mProtonTPCMomBins[i + 1]) { + return tpcNSigPr < mProtonTPCNSigCuts[i] && tpcNSigPi > pidShared.tpcNSigmaVetoThreshold; } } - return tpcPassed && tofPassed; + return false; } template bool passesPionPID(TrackType const& track, float totalMomentum) { - bool tpcPassed{false}, tofPassed{false}; - const int nTPCBins = static_cast(mPionTPCMomBins.size()); - const int nTOFBins = static_cast(mPionTOFMomBins.size()); const float tpcNSigPi = std::abs(track.tpcNSigmaPi()); const float tpcNSigPr = std::abs(track.tpcNSigmaPr()); const float tofNSigPi = std::abs(track.tofNSigmaPi()); const float tofNSigPr = std::abs(track.tofNSigmaPr()); - const float combinedNSigPi = tpcNSigPi * tpcNSigPi + tofNSigPi * tofNSigPi; - const float combinedNSigPr = tpcNSigPr * tpcNSigPr + tofNSigPr * tofNSigPr; - const auto circularCutSq = static_cast(combinedNSigmaCutPion * combinedNSigmaCutPion); - const float circularVetoCutSq = tpcNSigmaVetoThreshold * tpcNSigmaVetoThreshold + tofNSigmaVetoThreshold * tofNSigmaVetoThreshold; - - if (!useTPCOnlyPID && track.hasTOF()) { - if (combinedNSigmaCutPion < 0 && totalMomentum >= minPionMomentum) { - if (track.tofNSigmaPi() < minTOFNSigmaPion) { + + const bool useTOF = !pidShared.useTPCOnlyPID && track.hasTOF(); + + if (useTOF) { + // Combined TPC+TOF PID - used whenever TOF is available, regardless of momentum. + if (pionPID.combinedNSigmaCutPion < 0) { + // Asymmetric mode: independent TPC and TOF nSigma windows. + if (track.tofNSigmaPi() < pionPID.minTOFNSigmaPion) { return false; } + bool tofPassed = false; + const int nTOFBins = static_cast(mPionTOFMomBins.size()); for (int i = 0; i < nTOFBins - 1; ++i) { if (totalMomentum >= mPionTOFMomBins[i] && totalMomentum < mPionTOFMomBins[i + 1] && - tofNSigPi < mPionTOFNSigCuts[i] && tofNSigPr > tofNSigmaVetoThreshold) { + tofNSigPi < mPionTOFNSigCuts[i] && tofNSigPr > pidShared.tofNSigmaVetoThreshold) { tofPassed = true; break; } } - if (track.tpcNSigmaPi() < minCombinedNSigmaPion) { + if (track.tpcNSigmaPi() < pionPID.minCombinedNSigmaPion) { return false; } - if (tpcNSigPi < static_cast(maxTPCNSigmaPion) && tpcNSigPr > tpcNSigmaVetoThreshold) { - tpcPassed = true; - } - } else if (combinedNSigmaCutPion > 0 && totalMomentum >= minPionMomentum) { - if (combinedNSigPi < circularCutSq && combinedNSigPr > circularVetoCutSq) { - tpcPassed = true; - tofPassed = true; - } - } - // ── Part 2: low-momentum region with TOF available ────────────────── - if (totalMomentum < minPionMomentum && tpcNSigPi < static_cast(maxTPCNSigmaPion)) { - tpcPassed = true; - if (applyTOFCutWhenAvailableBelowThreshold) { - // TOF is available (track.hasTOF() is true in this branch): require TOF nSigma - tofPassed = (tofNSigPi < cfgLowPtTofNsigmaCut); - } else { - tofPassed = true; - } + const bool tpcPassed = tpcNSigPi < static_cast(pionPID.maxTPCNSigmaPion) && tpcNSigPr > pidShared.tpcNSigmaVetoThreshold; + return tofPassed && tpcPassed; } - } else { - // No TOF available (or useTPCOnlyPID == true) - if (totalMomentum < minPionMomentum && tpcNSigPi < static_cast(maxTPCNSigmaPion)) { - // ── Part 2: low-momentum, no TOF → TPC-only regardless of configurable ── - tpcPassed = true; - tofPassed = true; - } else { - tofPassed = true; - if (track.tpcNSigmaPi() < minTPCNSigmaPion) { - return false; - } - for (int i = 0; i < nTPCBins - 1; ++i) { - if (totalMomentum >= mPionTPCMomBins[i] && totalMomentum < mPionTPCMomBins[i + 1] && - tpcNSigPi < mPionTPCNSigCuts[i] && tpcNSigPr > tpcNSigmaVetoThreshold) { - tpcPassed = true; - break; - } - } + + // Circular mode: joint TPC+TOF nSigma radius. + const float combinedNSigPi = tpcNSigPi * tpcNSigPi + tofNSigPi * tofNSigPi; + const float combinedNSigPr = tpcNSigPr * tpcNSigPr + tofNSigPr * tofNSigPr; + const auto circularCutSq = static_cast(pionPID.combinedNSigmaCutPion * pionPID.combinedNSigmaCutPion); + const float circularVetoCutSq = pidShared.tpcNSigmaVetoThreshold * pidShared.tpcNSigmaVetoThreshold + + pidShared.tofNSigmaVetoThreshold * pidShared.tofNSigmaVetoThreshold; + return combinedNSigPi < circularCutSq && combinedNSigPr > circularVetoCutSq; + } + + // No usable TOF: above the momentum threshold, TOF is mandatory -> reject. + if (totalMomentum >= pionPID.minPionMomentum) { + return false; + } + + // TPC-only PID below the momentum threshold, using the momentum-binned TPC cuts. + const int nTPCBins = static_cast(mPionTPCMomBins.size()); + for (int i = 0; i < nTPCBins - 1; ++i) { + if (totalMomentum >= mPionTPCMomBins[i] && totalMomentum < mPionTPCMomBins[i + 1]) { + return tpcNSigPi < mPionTPCNSigCuts[i] && tpcNSigPr > pidShared.tpcNSigmaVetoThreshold; } } - return tpcPassed && tofPassed; + return false; } template @@ -680,7 +835,7 @@ struct DeltaAnalysis { histos.fill(HIST("QAafter/Proton/tpcNSigmaKaonContamVsPt"), pt, track.tpcNSigmaKa()); histos.fill(HIST("QAafter/Proton/tpcCrossedRowsVsPt"), pt, track.tpcNClsCrossedRows()); histos.fill(HIST("QAafter/Proton/tpcClustersFoundVsPt"), pt, track.tpcNClsFound()); - if (!useTPCOnlyPID && track.hasTOF()) { + if (!pidShared.useTPCOnlyPID && track.hasTOF()) { const float tofNSigPr = track.tofNSigmaPr(); histos.fill(HIST("QAafter/Proton/tofNSigmaVsMomentum"), totalMomentum, tofNSigPr); histos.fill(HIST("QAafter/Proton/tofNSigmaVsPt"), pt, tofNSigPr); @@ -706,7 +861,7 @@ struct DeltaAnalysis { histos.fill(HIST("QAafter/Pion/tpcNSigmaKaonContamVsPt"), pt, track.tpcNSigmaKa()); histos.fill(HIST("QAafter/Pion/tpcCrossedRowsVsPt"), pt, track.tpcNClsCrossedRows()); histos.fill(HIST("QAafter/Pion/tpcClustersFoundVsPt"), pt, track.tpcNClsFound()); - if (!useTPCOnlyPID && track.hasTOF()) { + if (!pidShared.useTPCOnlyPID && track.hasTOF()) { const float tofNSigPi = track.tofNSigmaPi(); histos.fill(HIST("QAafter/Pion/tofNSigmaVsMomentum"), totalMomentum, tofNSigPi); histos.fill(HIST("QAafter/Pion/tofNSigmaVsPt"), pt, tofNSigPi); @@ -716,7 +871,6 @@ struct DeltaAnalysis { } } - // detector QA for reconstructed MC tracks, no truth matching required ── template void fillQAMCProton(TrackType const& track, float totalMomentum, float centralityPercent) { @@ -733,7 +887,7 @@ struct DeltaAnalysis { histos.fill(HIST("QAMC/Proton/tpcNSigmaKaonContamVsPt"), pt, track.tpcNSigmaKa()); histos.fill(HIST("QAMC/Proton/tpcCrossedRowsVsPt"), pt, track.tpcNClsCrossedRows()); histos.fill(HIST("QAMC/Proton/tpcClustersFoundVsPt"), pt, track.tpcNClsFound()); - if (!useTPCOnlyPID && track.hasTOF()) { + if (!pidShared.useTPCOnlyPID && track.hasTOF()) { const float tofNSigPr = track.tofNSigmaPr(); histos.fill(HIST("QAMC/Proton/tofNSigmaVsMomentum"), totalMomentum, tofNSigPr); histos.fill(HIST("QAMC/Proton/tofNSigmaVsPt"), pt, tofNSigPr); @@ -759,7 +913,7 @@ struct DeltaAnalysis { histos.fill(HIST("QAMC/Pion/tpcNSigmaKaonContamVsPt"), pt, track.tpcNSigmaKa()); histos.fill(HIST("QAMC/Pion/tpcCrossedRowsVsPt"), pt, track.tpcNClsCrossedRows()); histos.fill(HIST("QAMC/Pion/tpcClustersFoundVsPt"), pt, track.tpcNClsFound()); - if (!useTPCOnlyPID && track.hasTOF()) { + if (!pidShared.useTPCOnlyPID && track.hasTOF()) { const float tofNSigPi = track.tofNSigmaPi(); histos.fill(HIST("QAMC/Pion/tofNSigmaVsMomentum"), totalMomentum, tofNSigPi); histos.fill(HIST("QAMC/Pion/tofNSigmaVsPt"), pt, tofNSigPi); @@ -832,7 +986,6 @@ struct DeltaAnalysis { } } - // reconstructed-level (pre-truth-matching) invariant mass ── void fillDeltaHistogramMCReco(int protonSign, int pionSign, float pairPt, float pairMass, float centrality, float rapidity) { if (protonSign > 0) { @@ -856,19 +1009,19 @@ struct DeltaAnalysis { void fillRotationalBackground(int protonSign, int pionSign, float pxProton, float pyProton, float pzProton, float pionPhi, float pionPt, float pzPion, float centrality) { - if (numberOfRotations <= 0) { + if (rotBkg.numberOfRotations <= 0) { return; } - const float weight = 1.f / static_cast(numberOfRotations); - const float rotWindowHalf = o2::constants::math::PI / static_cast(rotationAngleWindow); + const float weight = 1.f / static_cast(rotBkg.numberOfRotations); + const float rotWindowHalf = o2::constants::math::PI / static_cast(rotBkg.rotationAngleWindow); - for (int iRot = 0; iRot < numberOfRotations; ++iRot) { + for (int iRot = 0; iRot < rotBkg.numberOfRotations; ++iRot) { float rotAngle = 0.f; - if (numberOfRotations == 1) { + if (rotBkg.numberOfRotations == 1) { rotAngle = o2::constants::math::PI; } else { rotAngle = (o2::constants::math::PI - rotWindowHalf) + - static_cast(iRot) * (2.f * rotWindowHalf / static_cast(numberOfRotations - 1)); + static_cast(iRot) * (2.f * rotWindowHalf / static_cast(rotBkg.numberOfRotations - 1)); } const float newPhi = RecoDecay::constrainAngle(pionPhi + rotAngle, 0.f); const float pxPionRot = pionPt * std::cos(newPhi); @@ -880,7 +1033,7 @@ struct DeltaAnalysis { const float rotPt = RecoDecay::pt(std::array{pxProton + pxPionRot, pyProton + pyPionRot}); const float rotY = RecoDecay::y( std::array{pxProton + pxPionRot, pyProton + pyPionRot, pzProton + pzPion}, rotMass); - if (rotY < cfgMinY || rotY > cfgMaxY) { + if (rotY < trackCuts.cfgMinY || rotY > trackCuts.cfgMaxY) { continue; } @@ -936,9 +1089,9 @@ struct DeltaAnalysis { } const float mom = RecoDecay::p(track.px(), track.py(), track.pz()); const bool isProton = passesProtonPID(track, mom) && passesProtonDCASelection(track) && - !(requireTOFForProton && !track.hasTOF()); + !(protonPID.requireTOFForProton && !track.hasTOF()); const bool isPion = passesPionPID(track, mom) && passesPionDCASelection(track) && - !(requireTOFForPion && !track.hasTOF()); + !(pionPID.requireTOFForPion && !track.hasTOF()); if (!isProton && !isPion) { continue; } @@ -991,10 +1144,10 @@ struct DeltaAnalysis { } } - if (applyDeepAngleCut) { + if (pairCuts.applyDeepAngleCut) { const float cosAngle = std::clamp( (pxPr * pxPi + pyPr * pyPi + pzPr * pzPi) / (protonCand.mom * pionCand.mom), -1.f, 1.f); - if (std::acos(cosAngle) < static_cast(deepAngleCutValue)) { + if (std::acos(cosAngle) < static_cast(pairCuts.deepAngleCutValue)) { continue; } } @@ -1006,7 +1159,7 @@ struct DeltaAnalysis { const float pairPt = RecoDecay::pt(std::array{pxPr + pxPi, pyPr + pyPi}); const float pairY = RecoDecay::y(std::array{pxPr + pxPi, pyPr + pyPi, pzPr + pzPi}, pairMass); - if (pairY < cfgMinY || pairY > cfgMaxY) { + if (pairY < trackCuts.cfgMinY || pairY > trackCuts.cfgMaxY) { continue; } @@ -1020,7 +1173,7 @@ struct DeltaAnalysis { fillDeltaHistogramMixedEvent(protonCand.sign, pionCand.sign, pairPt, pairMass, centrality, pairY); } else { fillDeltaHistogramSameEvent(protonCand.sign, pionCand.sign, pairPt, pairMass, centrality, pairY); - if (enableRotationalBackground) { + if (rotBkg.enableRotationalBackground) { fillRotationalBackground(protonCand.sign, pionCand.sign, pxPr, pyPr, pzPr, pionCand.phi, pionCand.pt, pzPi, centrality); } @@ -1029,15 +1182,18 @@ struct DeltaAnalysis { } } - Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter acceptanceFilter = (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPt); + Filter collisionFilter = nabs(aod::collision::posZ) < evSel.cfgCutVertex; + Filter acceptanceFilter = (nabs(aod::track::eta) < trackCuts.cfgCutEta && nabs(aod::track::pt) > trackCuts.cfgCutPt); - using EventCandidates = soa::Filtered>; + using EventCandidates = soa::Filtered>; using TrackCandidates = soa::Filtered>; using TrackCandidatesMC = soa::Filtered>; + using EventCandidatesMC = soa::Join; + using McCollisionsCent = soa::Join; Preslice perCol = aod::track::collisionId; Preslice perColMC = aod::track::collisionId; + Preslice perMcCollisionDelta = aod::mcparticle::mcCollisionId; // ── Event-mixing binning policies (one per centrality estimator) ──────────── using BinningTypeFT0M = ColumnBinningPolicy; @@ -1046,17 +1202,17 @@ struct DeltaAnalysis { using BinningTypeFV0A = ColumnBinningPolicy; using BinningTypeNTPV = ColumnBinningPolicy; - BinningTypeFT0M binningFT0M{{cfgVtxAxis, cfgCentAxis}, true}; - BinningTypeFT0A binningFT0A{{cfgVtxAxis, cfgCentAxis}, true}; - BinningTypeFT0C binningFT0C{{cfgVtxAxis, cfgCentAxis}, true}; - BinningTypeFV0A binningFV0A{{cfgVtxAxis, cfgCentAxis}, true}; - BinningTypeNTPV binningNTPV{{cfgVtxAxis, cfgCentAxis}, true}; + BinningTypeFT0M binningFT0M{{axes.cfgVtxAxis, axes.cfgCentAxis}, true}; + BinningTypeFT0A binningFT0A{{axes.cfgVtxAxis, axes.cfgCentAxis}, true}; + BinningTypeFT0C binningFT0C{{axes.cfgVtxAxis, axes.cfgCentAxis}, true}; + BinningTypeFV0A binningFV0A{{axes.cfgVtxAxis, axes.cfgCentAxis}, true}; + BinningTypeNTPV binningNTPV{{axes.cfgVtxAxis, axes.cfgCentAxis}, true}; - SameKindPair pairFT0M{binningFT0M, cfgNoMixedEvents, -1, &cache}; - SameKindPair pairFT0A{binningFT0A, cfgNoMixedEvents, -1, &cache}; - SameKindPair pairFT0C{binningFT0C, cfgNoMixedEvents, -1, &cache}; - SameKindPair pairFV0A{binningFV0A, cfgNoMixedEvents, -1, &cache}; - SameKindPair pairNTPV{binningNTPV, cfgNoMixedEvents, -1, &cache}; + SameKindPair pairFT0M{binningFT0M, mixingCfg.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairFT0A{binningFT0A, mixingCfg.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairFT0C{binningFT0C, mixingCfg.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairFV0A{binningFV0A, mixingCfg.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairNTPV{binningNTPV, mixingCfg.cfgNoMixedEvents, -1, &cache}; std::vector mProtonPool; std::vector mPionPool; @@ -1066,7 +1222,7 @@ struct DeltaAnalysis { aod::BCs const&) { for (auto const& collision : collisions) { - if (!passesEventSelection(collision)) { + if (!passesEventSelectionImpl(collision)) { continue; } const float centrality = getCentrality(collision); @@ -1078,6 +1234,7 @@ struct DeltaAnalysis { histos.fill(HIST("Event/hVtxZ"), collision.posZ()); histos.fill(HIST("Event/hCentrality"), centrality); histos.fill(HIST("Event/hOccupancy"), occupancy); + histos.fill(HIST("Event/centralitydistribution"), collision.centFT0M()); histos.fill(HIST("CentQA/hCentralityVsVtxZ"), collision.posZ(), centrality); histos.fill(HIST("CentQA/hCentralityVsOccupancy"), occupancy, centrality); histos.fill(HIST("CentQA/hEventCountVsCentrality"), centrality); @@ -1116,7 +1273,6 @@ struct DeltaAnalysis { } PROCESS_SWITCH(DeltaAnalysis, processSameEvent, "Process same event", true); - // ── Shared mixed-event logic ───────────────────────────────────────────── template void runMixedEvent(PairType& mixingPair) { @@ -1135,7 +1291,7 @@ struct DeltaAnalysis { void processMixedEvent(EventCandidates const&, TrackCandidates const&) { - switch (cfgCentralityEstimator) { + switch (evSel.cfgCentralityEstimator) { case delta_analysis::kFT0M: runMixedEvent(pairFT0M); break; @@ -1158,22 +1314,31 @@ struct DeltaAnalysis { } PROCESS_SWITCH(DeltaAnalysis, processMixedEvent, "Process mixed event", true); - void processMC(soa::Join const& collisions, aod::BCs const&, TrackCandidatesMC const& tracks, aod::McParticles const& mcParticles) + // ===================================================================================== + // processMC(): RECONSTRUCTED-ONLY. Reconstructs Delta candidates, performs truth matching, + // fills reconstructed QA, fills reconstructed Delta histograms (RecoDelta - the A x eps + // numerator). Nothing generated-only is touched here. UNCHANGED from before the refactor. + // ===================================================================================== + void processMC(EventCandidatesMC const& collisions, aod::BCs const&, TrackCandidatesMC const& tracks, aod::McParticles const& mcParticles) { - constexpr float kGenCentrality = 1.f; - for (auto const& collision : collisions) { - if (!passesEventSelection(collision)) { + if (!passesEventSelectionImpl(collision)) { continue; } + const float centrality = getCentrality(collision); + + // Nrec - "the total number of selected reconstructed INEL>0 events". + histos.fill(HIST("MCRecoEvent/hRecoEvents"), centrality); + histos.fill(HIST("MCRecoEvent/centralitydistribution"), collision.centFT0M()); + histos.fill(HIST("Event/hNcontributor"), collision.numContrib()); histos.fill(HIST("Event/hVtxZ"), collision.posZ()); const uint64_t collIdx = collision.globalIndex(); auto perColTracks = tracks.sliceBy(perColMC, collIdx); perColTracks.bindExternalIndices(&tracks); - + perColTracks.bindExternalIndices(&mcParticles); for (auto const& t0 : perColTracks) { if (!passesBasicTrackSelection(t0) || !t0.has_mcParticle()) { continue; @@ -1216,7 +1381,6 @@ struct DeltaAnalysis { } } - // fill QAMC for every reconstructed MC track passing basic+PID+DCA cuts, irrespective of truth matching. for (auto const& trackForQAMC : perColTracks) { const float momQAMC = RecoDecay::p(trackForQAMC.px(), trackForQAMC.py(), trackForQAMC.pz()); if (!passesBasicTrackSelection(trackForQAMC)) { @@ -1246,7 +1410,6 @@ struct DeltaAnalysis { continue; } - // reconstructed-level (pre-truth-matching) invariant mass. { const std::array, 2> momentaReco = { std::array{t0.px(), t0.py(), t0.pz()}, @@ -1254,7 +1417,7 @@ struct DeltaAnalysis { const float pairMassReco = RecoDecay::m(momentaReco, std::array{massProton, massPion}); const float pairPtReco = RecoDecay::pt(std::array{t0.px() + t1.px(), t0.py() + t1.py()}); const float pairYReco = RecoDecay::y(std::array{t0.px() + t1.px(), t0.py() + t1.py(), t0.pz() + t1.pz()}, pairMassReco); - if (pairYReco >= cfgMinY && pairYReco <= cfgMaxY) { + if (pairYReco >= trackCuts.cfgMinY && pairYReco <= trackCuts.cfgMaxY) { fillDeltaHistogramMCReco(t0.sign(), t1.sign(), pairPtReco, pairMassReco, centrality, pairYReco); } } @@ -1296,26 +1459,67 @@ struct DeltaAnalysis { const float pairMass = RecoDecay::m(momenta, std::array{massProton, massPion}); const float pairPt = RecoDecay::pt(std::array{t0.px() + t1.px(), t0.py() + t1.py()}); const float pairY = RecoDecay::y(std::array{t0.px() + t1.px(), t0.py() + t1.py(), t0.pz() + t1.pz()}, pairMass); - if (pairY < cfgMinY || pairY > cfgMaxY) { + if (pairY < trackCuts.cfgMinY || pairY > trackCuts.cfgMaxY) { continue; } fillDeltaHistogramMC(t0.sign(), t1.sign(), pairPt, pairMass, centrality, pairY); } } + } + PROCESS_SWITCH(DeltaAnalysis, processMC, "Process MC", false); + + void processMCGen(McCollisionsCent::iterator const& mcCollision, + aod::McParticles const& mcParticles, + soa::SmallGroups const& collisions) + { + histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 0.f); // All MC collisions + + if (std::abs(mcCollision.posZ()) > evSel.cfgCutVertex) { + return; + } + histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 1.f); // |Vz| < cfgCutVertex + + const bool truthInelGt0 = isTruthInelGt0(mcParticles); + if (evSel.cfgRequireRecoINELgt0 && !truthInelGt0) { + return; + } + histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 2.f); // Truth INEL>0 + histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 3.f); // Centrality (no cut currently applied) + histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 4.f); // Final generated event + + bool hasAcceptedReco = false; + float genCentrality = mcCollision.centFT0M(); // fallback: MC-truth centrality proxy (see note above) + for (auto const& collision : collisions) { + if (passesEventSelection(collision)) { + hasAcceptedReco = true; + genCentrality = getCentrality(collision); // real reconstructed centrality of an accepted associated collision + break; + } + } for (auto const& mcParticle : mcParticles) { + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 0.f); // bin0: all generated particles + + if (!mcParticle.producedByGenerator()) { + continue; + } + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 1.f); // bin1: producedByGenerator + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 2.f); // bin2: truth vertex-z (event-level, already enforced above) + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 3.f); // bin3: truth INEL>0 (event-level, already enforced above) + const int pdg = mcParticle.pdgCode(); if (std::abs(pdg) != delta_analysis::PdgDeltaPlusPlus && std::abs(pdg) != delta_analysis::PdgDeltaZero) { continue; } - if (mcParticle.y() < cfgMinY || mcParticle.y() > cfgMaxY) { + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 4.f); // bin4: PDG + + if (mcParticle.y() < trackCuts.cfgMinY || mcParticle.y() > trackCuts.cfgMaxY) { continue; } + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 5.f); // bin5: rapidity + const auto daughters = mcParticle.daughters_as(); - // CHANGED: daughter loop is now used only for decay-channel validation / QA - // (hasPr, hasPi, ptPr, ptPi). It no longer accumulates daughter energy for - // the mass calculation. bool hasPr = false, hasPi = false; float ptPr = -999.f, ptPi = -999.f; for (const auto& d : daughters) { @@ -1330,7 +1534,9 @@ struct DeltaAnalysis { if (!hasPr || !hasPi) { continue; } - // CHANGED: genMass is now computed directly from the mother particle's own four-momentum (E, px, py, pz) + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 6.f); // bin6: decay channel + histos.fill(HIST("MCGenQA/hGenDeltaCutFlow"), 7.f); // bin7: final generated histogram + const float eMother = mcParticle.e(); const float pxMother = mcParticle.px(); const float pyMother = mcParticle.py(); @@ -1339,32 +1545,106 @@ struct DeltaAnalysis { const float genMass = std::sqrt(std::max(0.f, mass2)); const float genPt = mcParticle.pt(); const float genY = mcParticle.y(); + + // GeneratedDelta_All if (pdg == delta_analysis::PdgDeltaPlusPlus) { - histos.fill(HIST("Analysis/hDeltaPlusPlusInvMassGen"), genPt, genMass); - // CHANGED: THnSparse Gen fill now carries genMass as the first argument, - // matching the new {massAxis, ptAxis, centAxis, rapAxis} axis order. - histos.fill(HIST("THnSparse/hDeltaPlusPlusGen"), genMass, genPt, kGenCentrality, genY); - histos.fill(HIST("QAChecks/hGenProtonDeltaPlusPlus"), ptPr); - histos.fill(HIST("QAChecks/hGenPionDeltaPlusPlus"), ptPi); + histos.fill(HIST("MCGen/hDeltaPlusPlusInvMassGen"), genPt, genMass); + histos.fill(HIST("MCGen/hDeltaPlusPlusGenSparse"), genMass, genPt, genCentrality, genY); + histos.fill(HIST("MCGenQA/hGenProtonDeltaPlusPlus"), ptPr); + histos.fill(HIST("MCGenQA/hGenPionDeltaPlusPlus"), ptPi); } else if (pdg == -delta_analysis::PdgDeltaPlusPlus) { - histos.fill(HIST("Analysis/hAntiDeltaPlusPlusInvMassGen"), genPt, genMass); - histos.fill(HIST("THnSparse/hAntiDeltaPlusPlusGen"), genMass, genPt, kGenCentrality, genY); - histos.fill(HIST("QAChecks/hGenProtonAntiDeltaPlusPlus"), ptPr); - histos.fill(HIST("QAChecks/hGenPionAntiDeltaPlusPlus"), ptPi); + histos.fill(HIST("MCGen/hAntiDeltaPlusPlusInvMassGen"), genPt, genMass); + histos.fill(HIST("MCGen/hAntiDeltaPlusPlusGenSparse"), genMass, genPt, genCentrality, genY); + histos.fill(HIST("MCGenQA/hGenProtonAntiDeltaPlusPlus"), ptPr); + histos.fill(HIST("MCGenQA/hGenPionAntiDeltaPlusPlus"), ptPi); } else if (pdg == delta_analysis::PdgDeltaZero) { - histos.fill(HIST("Analysis/hDeltaZeroInvMassGen"), genPt, genMass); - histos.fill(HIST("THnSparse/hDeltaZeroGen"), genMass, genPt, kGenCentrality, genY); - histos.fill(HIST("QAChecks/hGenProtonDeltaZero"), ptPr); - histos.fill(HIST("QAChecks/hGenPionDeltaZero"), ptPi); + histos.fill(HIST("MCGen/hDeltaZeroInvMassGen"), genPt, genMass); + histos.fill(HIST("MCGen/hDeltaZeroGenSparse"), genMass, genPt, genCentrality, genY); + histos.fill(HIST("MCGenQA/hGenProtonDeltaZero"), ptPr); + histos.fill(HIST("MCGenQA/hGenPionDeltaZero"), ptPi); } else if (pdg == -delta_analysis::PdgDeltaZero) { - histos.fill(HIST("Analysis/hAntiDeltaZeroInvMassGen"), genPt, genMass); - histos.fill(HIST("THnSparse/hAntiDeltaZeroGen"), genMass, genPt, kGenCentrality, genY); - histos.fill(HIST("QAChecks/hGenProtonAntiDeltaZero"), ptPr); - histos.fill(HIST("QAChecks/hGenPionAntiDeltaZero"), ptPi); + histos.fill(HIST("MCGen/hAntiDeltaZeroInvMassGen"), genPt, genMass); + histos.fill(HIST("MCGen/hAntiDeltaZeroGenSparse"), genMass, genPt, genCentrality, genY); + histos.fill(HIST("MCGenQA/hGenProtonAntiDeltaZero"), ptPr); + histos.fill(HIST("MCGenQA/hGenPionAntiDeltaZero"), ptPi); + } + + // GeneratedDelta_EventAccepted (A x eps denominator) + if (hasAcceptedReco) { + if (pdg == delta_analysis::PdgDeltaPlusPlus) { + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hDeltaPlusPlusInvMass"), genPt, genMass); + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hDeltaPlusPlusSparse"), genMass, genPt, genCentrality, genY); + } else if (pdg == -delta_analysis::PdgDeltaPlusPlus) { + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaPlusPlusInvMass"), genPt, genMass); + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaPlusPlusSparse"), genMass, genPt, genCentrality, genY); + } else if (pdg == delta_analysis::PdgDeltaZero) { + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hDeltaZeroInvMass"), genPt, genMass); + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hDeltaZeroSparse"), genMass, genPt, genCentrality, genY); + } else if (pdg == -delta_analysis::PdgDeltaZero) { + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaZeroInvMass"), genPt, genMass); + histos.fill(HIST("MCGen/GeneratedDelta_EventAccepted/hAntiDeltaZeroSparse"), genMass, genPt, genCentrality, genY); + } } } } - PROCESS_SWITCH(DeltaAnalysis, processMC, "Process MC", false); + PROCESS_SWITCH(DeltaAnalysis, processMCGen, "Process MC truth: generated-level Delta spectra and QA", false); + + void processEventFactor(EventCandidatesMC const& collisions, + McCollisionsCent const& mcCollisions, + aod::McParticles const& mcParticles) + { + // ── Loop A: reconstructed collisions ────────────────────────────────────────────────── + std::unordered_map nRecoCollisionsPerMc; + std::unordered_set acceptedMcCollisionIds; + for (auto const& collision : collisions) { + if (collision.has_mcCollision()) { + ++nRecoCollisionsPerMc[collision.mcCollisionId()]; + } + if (!passesEventSelection(collision)) { + continue; + } + const float centrality = getCentrality(collision); + histos.fill(HIST("EventFactor/hRecoEvents"), centrality); + if (collision.has_mcCollision()) { + acceptedMcCollisionIds.insert(collision.mcCollisionId()); + } + } + + // ── Loop B: generated MC collisions ─────────────────────────────────────────────────── + for (auto const& mcCollision : mcCollisions) { + histos.fill(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow"), 0.f); // All generated MC collisions + + if (std::abs(mcCollision.posZ()) > evSel.cfgCutVertex) { + continue; + } + histos.fill(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow"), 1.f); // |Vz| < cfgCutVertex + + auto mcPartsThisColl = mcParticles.sliceBy(perMcCollisionDelta, mcCollision.globalIndex()); + if (evSel.cfgRequireRecoINELgt0 && !isTruthInelGt0(mcPartsThisColl)) { + continue; + } + histos.fill(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow"), 2.f); // Truth INEL>0 + + const float truthCentrality = mcCollision.centFT0M(); // MC-truth centrality proxy (see note above) + histos.fill(HIST("EventFactor/hEventsGenAll"), truthCentrality); + + const auto itCount = nRecoCollisionsPerMc.find(mcCollision.globalIndex()); + const int nRecoTotal = (itCount != nRecoCollisionsPerMc.end()) ? itCount->second : 0; + histos.fill(HIST("EventFactor/hNRecoCollisionsPerMcCollision"), nRecoTotal); + + if (nRecoTotal > 0) { + histos.fill(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow"), 3.f); // Has associated reconstructed collision + } + + const bool hasAcceptedReco = acceptedMcCollisionIds.contains(mcCollision.globalIndex()); + if (hasAcceptedReco) { + histos.fill(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow"), 4.f); // Associated reco collision passes event selection + histos.fill(HIST("CutFlow/EventFactor/hEventAcceptedCutFlow"), 5.f); // Final EventAccepted + histos.fill(HIST("EventFactor/hEventsGenAccepted"), truthCentrality); + } + } + } + PROCESS_SWITCH(DeltaAnalysis, processEventFactor, "Process Event Loss / Event Splitting factors", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& context) diff --git a/PWGLF/Tasks/Resonances/doublephimeson.cxx b/PWGLF/Tasks/Resonances/doublephimeson.cxx index 043d798ab62..a14647b525a 100644 --- a/PWGLF/Tasks/Resonances/doublephimeson.cxx +++ b/PWGLF/Tasks/Resonances/doublephimeson.cxx @@ -67,13 +67,14 @@ struct doublephimeson { Configurable additionalEvsel{"additionalEvsel", true, "Additional event selection"}; Configurable isDeep{"isDeep", true, "Store deep angle"}; Configurable cutMinNsigmaTPC{"cutMinNsigmaTPC", -2.5, "nsigma cut TPC"}; - Configurable cutNsigmaTPC{"cutNsigmaTPC", 3.0, "nsigma cut TPC"}; - Configurable cutNsigmaTOF{"cutNsigmaTOF", 3.0, "nsigma cut TOF"}; + Configurable cutNsigmaTPC{"cutNsigmaTPC", 2.5, "nsigma cut TPC"}; + Configurable cutNsigmaTOF{"cutNsigmaTOF", 2.5, "nsigma cut TOF"}; Configurable momTOFCut{"momTOFCut", 1.8, "minimum pT cut for madnatory TOF"}; Configurable maxKaonPt{"maxKaonPt", 100.0, "maximum kaon pt cut"}; Configurable cfgCrossPhiLow{"cfgCrossPhiLow", 1.01, "Lower edge of phi mass window for cross-pairing (ghost) veto"}; Configurable cfgCrossPhiHigh{"cfgCrossPhiHigh", 1.03, "Upper edge of phi mass window for cross-pairing (ghost) veto"}; Configurable useParametrized{"useParametrized", false, "Use pT dependent mass peak and width"}; + Configurable useCrossPairRejection{"useCrossPairRejection", true, "Use cross pair phi signal compatibilaty"}; // ------------------------------------------------------------ // pT-dependent phi mass peak and width from single-phi BW fits // @@ -337,17 +338,17 @@ struct doublephimeson { } if (PIDStrategy == 1003) { - if (ptcand < 0.5 && TOFHit != 1 && nsigmaTPC > -2.0 && nsigmaTPC < 2.0) { + if (ptcand < 0.5 && TOFHit != 1 && std::abs(nsigmaTPC) < cutNsigmaTPC) { return true; } - if (ptcand < 0.5 && TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + if (ptcand < 0.5 && TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < cutNsigmaTPC) { return true; } if (ptcand >= 0.5) { - if (TOFHit != 1 && nsigmaTPC > -2.0 && nsigmaTPC < 2.0) { + if (TOFHit != 1 && nsigmaTPC > -2.0 && nsigmaTPC < cutNsigmaTPC) { return true; } - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < cutNsigmaTOF) { return true; } } @@ -1695,7 +1696,6 @@ struct doublephimeson { if (id2 <= id1) { continue; } - const double kplus2pt = std::hypot(t2.phid1Px(), t2.phid1Py()); const double kminus2pt = std::hypot(t2.phid2Px(), t2.phid2Py()); @@ -1736,25 +1736,20 @@ struct doublephimeson { t1.phid1Index() == t2.phid2Index() || t1.phid2Index() == t2.phid1Index() || t1.phid2Index() == t2.phid2Index()) { - // LOGF(info,"track share",t1.phid1Index(),t1.phid2Index(),t2.phid1Index(),t2.phid2Index()); + LOGF(info, "track share %d %d %d %d", t1.phid1Index(), t1.phid2Index(), t2.phid1Index(), t2.phid2Index()); continue; } - const double mCross12 = (k1p + k2m).M(); // K+ from phi1 + K- from phi2 - const double mCross21 = (k2p + k1m).M(); // K+ from phi2 + K- from phi1 - - const bool cross12IsPhiLike = (mCross12 > cfgCrossPhiLow && mCross12 < cfgCrossPhiHigh); - const bool cross21IsPhiLike = (mCross21 > cfgCrossPhiLow && mCross21 < cfgCrossPhiHigh); - if (cross12IsPhiLike || cross21IsPhiLike) { - LOGF(info, - "Best-pairing rejected: mPhi1 = %3.4f, mPhi2 = %3.4f, mCross12 = %3.4f, mCross21 = %3.4f", - phi1.M(), - phi2.M(), - mCross12, - mCross21, - pair.Pt(), - pair.M()); - continue; + auto cross12 = k1p + k2m; + auto cross21 = k2p + k1m; + bool alternativePairValid = cross12.M() > cfgCrossPhiLow && cross12.M() < cfgCrossPhiHigh && cross21.M() > cfgCrossPhiLow && cross21.M() < cfgCrossPhiHigh; + if (alternativePairValid) { + float scoreOriginal = deltaMPhiNominal(phi1.M(), phi2.M()); + float scoreCross = deltaMPhiNominal(cross12.M(), cross21.M()); + if (useCrossPairRejection && (scoreCross < scoreOriginal)) { + LOGF(info, "Best-pairing rejected: original score = %3.4f, cross scoremPhi2 = %3.4f", scoreOriginal, scoreCross); + continue; // another pairing of these four tracks is better + } } histos.fill(HIST("hPhiMass"), phi1.M(), phi2.M(), pair.Pt()); histos.fill(HIST("hPhiMassNormalized"), getNormalizedMPhi(phi1.M(), phi1.Pt()), getNormalizedMPhi(phi2.M(), phi2.Pt()), pair.Pt()); @@ -1808,7 +1803,7 @@ struct doublephimeson { } if (pairPt > minExoticPt) { histos.fill(HIST("hPtCorrelation"), pairPt, ptcorr); - histos.fill(HIST("hMassCent"), p1.M(), p2.M(), collision.centrality()); + // histos.fill(HIST("hMassCent"), p1.M(), p2.M(), collision.centrality()); histos.fill(HIST("SEMassUnlike_AllVars"), M, pairPt, diff --git a/PWGLF/Tasks/Resonances/higherMassResonances.cxx b/PWGLF/Tasks/Resonances/higherMassResonances.cxx index 792916cb6fd..36491e50864 100644 --- a/PWGLF/Tasks/Resonances/higherMassResonances.cxx +++ b/PWGLF/Tasks/Resonances/higherMassResonances.cxx @@ -64,6 +64,7 @@ #include #include #include +#include #include using namespace o2; @@ -156,6 +157,7 @@ struct HigherMassResonances { Configurable cfgETAcut{"cfgETAcut", 0.8f, "Track ETA cut"}; Configurable deltaRDaugherCut{"deltaRDaugherCut", 0.001f, "DeltaR cut on V0 daughters"}; Configurable deltaRK0sCut{"deltaRK0sCut", 0.1f, "Apply deltaR cut between two K0s"}; + Configurable cfgArmenterosCut{"cfgArmenterosCut", 0.2f, "Armenteros-Podolanski cut"}; // Configurable for track selection and multiplicity Configurable cfgPTcut{"cfgPTcut", 0.2f, "Track PT cut"}; @@ -173,7 +175,7 @@ struct HigherMassResonances { Configurable activateHelicityFrame{"activateHelicityFrame", false, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; Configurable activateCollinsSoperFrame{"activateCollinsSoperFrame", false, "Activate the THnSparse with cosThStar w.r.t. Collins soper axis"}; Configurable activateProductionFrame{"activateProductionFrame", false, "Activate the THnSparse with cosThStar w.r.t. production axis"}; - Configurable activateBeamAxisFrame{"activateBeamAxisFrame", true, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; + Configurable activateGJFrame{"activateGJFrame", true, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; Configurable activateRandomFrame{"activateRandomFrame", false, "Activate the THnSparse with cosThStar w.r.t. random axis"}; Configurable cRotations{"cRotations", 3, "Number of random rotations in the rotational background"}; @@ -206,15 +208,21 @@ struct HigherMassResonances { float beamEnergy = 13600.0; double beamMomentum = std::sqrt(beamEnergy * beamEnergy / 4 - o2::constants::physics::MassProton * o2::constants::physics::MassProton); // GeV int noOfDaughters = 2; + float theta2 = 0.0f; + int detId = 0; + int refAId = 0; + int refBId = 0; + float minQvecAmp = 1e-5; + double tolerance = 1e-12; } config; // Service PDGdatabase; + Service pdgDB{}; TRandom* rn = new TRandom(); // variables declaration float multiplicity = 0.0f; - float theta2; - ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, daughterRotCM, mother, motherRot, fourVecDauCM, fourVecDauCM1; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, daughterRotCM, mother, motherRot, fourVecDauCM, fourVecDauCM1, mother2, mother3; ROOT::Math::PxPyPzEVector mother1; ROOT::Math::XYZVector randomVec, beamVec, normalVec; ROOT::Math::XYZVectorF v1CM, zaxisHE, yaxisHE, xaxisHE; @@ -228,10 +236,6 @@ struct HigherMassResonances { bool isMix = false; EventPlaneHelper helperEP; - int detId; - int refAId; - int refBId; - float minQvecAmp = 1e-5; void init(InitContext const&) { @@ -253,7 +257,7 @@ struct HigherMassResonances { AxisSpec axisEvtResPlQA = {102, -1.02, 1.02, ""}; // THnSparses - std::array sparses = {config.activateHelicityFrame, config.activateCollinsSoperFrame, config.activateProductionFrame, config.activateBeamAxisFrame, config.activateRandomFrame}; + std::array sparses = {config.activateHelicityFrame, config.activateCollinsSoperFrame, config.activateProductionFrame, config.activateGJFrame, config.activateRandomFrame}; if (std::accumulate(sparses.begin(), sparses.end(), 0) == 0) { LOGP(fatal, "No output THnSparses enabled"); @@ -267,7 +271,7 @@ struct HigherMassResonances { if (config.activateProductionFrame) { LOGP(info, "THnSparse with cosThStar w.r.t. production axis active."); } - if (config.activateBeamAxisFrame) { + if (config.activateGJFrame) { LOGP(info, "THnSparse with cosThStar w.r.t. beam axis active. (Gottified jackson frame)"); } if (config.activateRandomFrame) { @@ -309,10 +313,11 @@ struct HigherMassResonances { hv0label->GetXaxis()->SetBinLabel(5, "Daughter DCA"); hv0label->GetXaxis()->SetBinLabel(6, "CosPA"); hv0label->GetXaxis()->SetBinLabel(7, "Decay Radius"); - hv0label->GetXaxis()->SetBinLabel(8, "Lifetime"); - hv0label->GetXaxis()->SetBinLabel(9, "CompetingCascade"); - hv0label->GetXaxis()->SetBinLabel(10, "Standard V0"); - hv0label->GetXaxis()->SetBinLabel(11, "Mass Tolerance"); + hv0label->GetXaxis()->SetBinLabel(8, "Armenteros-Podolanski"); + hv0label->GetXaxis()->SetBinLabel(9, "Lifetime"); + hv0label->GetXaxis()->SetBinLabel(10, "CompetingCascade"); + hv0label->GetXaxis()->SetBinLabel(11, "Standard V0"); + hv0label->GetXaxis()->SetBinLabel(12, "Mass Tolerance"); std::shared_ptr hv0DauLabel = rEventSelection.get(HIST("htrackscheck_v0_daughters")); hv0DauLabel->GetXaxis()->SetBinLabel(1, "AllDau Tracks"); @@ -383,6 +388,7 @@ struct HigherMassResonances { rKzeroShort.add("hLT", "hLT", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); rKzeroShort.add("angularSeparation", "Angular distribution between two K0s vs pT", {HistType::kTH1F, {{200, 0.0f, 4.0f}}}); rKzeroShort.add("hDauDeltaR", "Delta R of positive and negative daughers", {HistType::kTHnSparseF, {angleSepAxis, angleSepAxis}}); + rKzeroShort.add("hArmenterosPodolanski", "Armenteros-Podolanski plot", HistType::kTH2D, {AxisSpec{100, -1, 1, "#alpha"}, {200, 0, 0.5, "qtArm"}}); } rKzeroShort.add("NksProduced", "Number of K0s produced", kTH1I, {{15, -0.5, 14.5}}); @@ -394,17 +400,27 @@ struct HigherMassResonances { // rKzeroShort.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {config.axisPtfordEbydx, config.axisdEdx}); } - // For MC + // For Monte Carlo if (doprocessGen || doprocessRec) { hMChists.add("MCcorrections/hGenNo", "Generated collisions before and after event selection", kTH1F, {{5, 0.0f, 5.0f}}); hMChists.add("Genf1710", "Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis, thnAxisPOL}); hMChists.add("Genf1710Calib", "Calibrated Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis, thnAxisPOL}); + hMChists.add("Gen1710PWA", "Gen f_{0}(1710) PWA", kTHnSparseF, {glueballMassAxis, thnAxisPOL, thnAxisPhi}); hMChists.add("Genf17102", "Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis, thnAxisPOL}); hMChists.add("Genf1710Calib2", "Calibrated Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis, thnAxisPOL}); + hMChists.add("Gen1710PWA2", "Gen f_{0}(1710) PWA", kTHnSparseF, {glueballMassAxis, thnAxisPOL, thnAxisPhi}); + hMChists.add("GenThetavsPhi1", "GenThetavsPhi1", kTH2F, {{thnAxisPOL}, {thnAxisPhi}}); + hMChists.add("GenThetavsPhi2", "GenThetavsPhi2", kTH2F, {{thnAxisPOL}, {thnAxisPhi}}); + hMChists.add("Recf1710_pt1", "Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}); hMChists.add("Recf1710Calib_pt1", "Calibrated Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}); + hMChists.add("Recf1710PWA_pt1", "Rec f_{0}(1710) PWA", kTHnSparseF, {glueballMassAxis, thnAxisPOL, thnAxisPhi}); hMChists.add("Recf1710_pt2", "Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}); hMChists.add("Recf1710Calib_pt2", "Calibrated Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}); + hMChists.add("Recf1710PWA_pt2", "Rec f_{0}(1710) PWA", kTHnSparseF, {glueballMassAxis, thnAxisPOL, thnAxisPhi}); + hMChists.add("RecThetavsPhi1", "RecTheta vs Phi1", kTH2F, {{thnAxisPOL}, {thnAxisPhi}}); + hMChists.add("RecThetavsPhi2", "RecTheta vs Phi2", kTH2F, {{thnAxisPOL}, {thnAxisPhi}}); + hMChists.add("h1Recsplit", "Rec p_{T}2", kTH1F, {ptAxis}); hMChists.add("Genf1710_mass", "Gen f_{0}(1710) mass", kTH1F, {glueballMassAxis}); hMChists.add("Genf1710_mass2", "Gen f_{0}(1710) mass", kTH1F, {glueballMassAxis}); @@ -441,9 +457,9 @@ struct HigherMassResonances { } if (doprocessSEEP) { - detId = getdetId(config.cfgDetName); - refAId = getdetId(config.cfgRefAName); - refBId = getdetId(config.cfgRefBName); + config.detId = getdetId(config.cfgDetName); + config.refAId = getdetId(config.cfgRefAName); + config.refBId = getdetId(config.cfgRefBName); hglue.add("EpDet", "", {HistType::kTH2F, {axisCentQA, axisEvtPlQA}}); hglue.add("EpRefA", "", {HistType::kTH2F, {axisCentQA, axisEvtPlQA}}); @@ -460,21 +476,26 @@ struct HigherMassResonances { { if (name.value == "FT0C") { return 0; - } else if (name.value == "FT0A") { + } + if (name.value == "FT0A") { return 1; - } else if (name.value == "FT0M") { + } + if (name.value == "FT0M") { return 2; - } else if (name.value == "FV0A") { + } + if (name.value == "FV0A") { return 3; - } else if (name.value == "TPCPos") { + } + if (name.value == "TPCPos") { return 4; - } else if (name.value == "TPCNeg") { + } + if (name.value == "TPCNeg") { return 5; - } else if (name.value == "TPCTot") { + } + if (name.value == "TPCTot") { return 6; - } else { - return 0; } + return 0; } template @@ -490,8 +511,8 @@ struct HigherMassResonances { // if (config.isSel8 && !collision.sel8()) // return false; - if (fillHist) - rEventSelection.fill(HIST("hEventCut"), 2); + // if (fillHist) + // rEventSelection.fill(HIST("hEventCut"), 2); if (config.isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) return false; @@ -505,8 +526,8 @@ struct HigherMassResonances { // if (config.isNoSameBunchPileup && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup))) // return false; - if (fillHist) - rEventSelection.fill(HIST("hEventCut"), 5); + // if (fillHist) + // rEventSelection.fill(HIST("hEventCut"), 5); if (config.isAllLayersGoodITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return false; @@ -518,8 +539,8 @@ struct HigherMassResonances { // if (config.isApplyOccCut && (std::abs(collision.trackOccupancyInTimeRange()) > config.configOccCut)) // return false; - if (fillHist) - rEventSelection.fill(HIST("hEventCut"), 7); + // if (fillHist) + // rEventSelection.fill(HIST("hEventCut"), 7); if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) return false; @@ -570,8 +591,8 @@ struct HigherMassResonances { // if (config.isSel8 && !collision.sel8()) // return false; - if (fillHist) - rEventSelection.fill(HIST("hEventCut"), 2); + // if (fillHist) + // rEventSelection.fill(HIST("hEventCut"), 2); if (config.isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) return false; @@ -585,8 +606,8 @@ struct HigherMassResonances { // if (config.isNoSameBunchPileup && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup))) // return false; - if (fillHist) - rEventSelection.fill(HIST("hEventCut"), 5); + // if (fillHist) + // rEventSelection.fill(HIST("hEventCut"), 5); if (config.isAllLayersGoodITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return false; @@ -598,8 +619,8 @@ struct HigherMassResonances { // if (config.isApplyOccCut && (std::abs(collision.trackOccupancyInTimeRange()) > config.configOccCut)) // return false; - if (fillHist) - rEventSelection.fill(HIST("hEventCut"), 7); + // if (fillHist) + // rEventSelection.fill(HIST("hEventCut"), 7); if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) return false; @@ -617,9 +638,6 @@ struct HigherMassResonances { template bool selectionV0(Collision const& collision, V0 const& candidate, float /*multiplicity*/) { - // const float qtarm = candidate.qtarm(); - // const float alph = candidate.alpha(); - // float arm = qtarm / alph; const float pT = candidate.pt(); const float tranRad = candidate.v0radius(); const float dcaDaughv0 = candidate.dcaV0daughters(); @@ -634,6 +652,7 @@ struct HigherMassResonances { rKzeroShort.fill(HIST("hLT"), ctauK0s); rKzeroShort.fill(HIST("hDCAV0Daughters"), candidate.dcaV0daughters()); rKzeroShort.fill(HIST("hV0CosPA"), candidate.v0cosPA()); + rKzeroShort.fill(HIST("hArmenterosPodolanski"), candidate.alpha(), candidate.qtarm()); } if (config.qAcorrelation2Dhist) rKzeroShort.fill(HIST("mass_lambda_kshort_before"), candidate.mK0Short(), candidate.mLambda()); @@ -670,9 +689,9 @@ struct HigherMassResonances { } rEventSelection.fill(HIST("htrackscheck_v0"), 6.5); - // if (tranRad > config.confV0TranRadV0Max) { - // return false; - // } + if (candidate.qtarm() < config.cfgArmenterosCut * std::fabs(candidate.alpha())) { + return false; + } rEventSelection.fill(HIST("htrackscheck_v0"), 7.5); if (std::fabs(ctauK0s) > config.cMaxV0LifeTime) { @@ -783,6 +802,124 @@ struct HigherMassResonances { return std::sqrt(d1 * d1 + d2 * d2); } + enum FrameType { kHelicity = 0, + kCollinsSoper = 1, + kProduction = 2, + kGottfriedJackson = 3, + kRandom = 4 }; + + std::pair getCosThetaPhi(const ROOT::Math::PxPyPzMVector& motherVec, const ROOT::Math::PxPyPzMVector& daughterVec, int frame) + { + //---------------------------------------------------------------- + // Boost daughter into mother rest frame + //---------------------------------------------------------------- + ROOT::Math::Boost boost{motherVec.BoostToCM()}; + + auto dauCM = boost(daughterVec); + + // Unit vector of daughter momentum in mother rest frame + auto v1cm = ROOT::Math::XYZVectorF(dauCM.Vect()).Unit(); + + //---------------------------------------------------------------- + // Beam directions boosted into mother rest frame + //---------------------------------------------------------------- + auto beam1cm = ROOT::Math::XYZVectorF((boost(beam1).Vect()).Unit()); + + auto beam2cm = ROOT::Math::XYZVectorF((boost(beam2).Vect()).Unit()); + + double cosTheta = 0.; + double phi = 0.; + + if (frame == kHelicity) { + //============================================================== + // HELICITY FRAME + // z-axis : Mother momentum direction in laboratory frame + // y-axis : Normal to beam plane + // x-axis : Completes right-handed coordinate system + //============================================================== + + auto zaxisHELocal = ROOT::Math::XYZVectorF(motherVec.Vect()).Unit(); + auto yaxisHELocal = ROOT::Math::XYZVectorF(beam1cm.Cross(beam2cm)).Unit(); + auto xaxisHELocal = ROOT::Math::XYZVectorF(yaxisHELocal.Cross(zaxisHELocal)).Unit(); + cosTheta = motherVec.Vect().Dot(dauCM.Vect()) / (std::sqrt(dauCM.Vect().Mag2()) * std::sqrt(motherVec.Vect().Mag2())); + phi = std::atan2(yaxisHELocal.Dot(v1cm), xaxisHELocal.Dot(v1cm)); + phi = RecoDecay::constrainAngle(phi, 0.0); + } else if (frame == kCollinsSoper) { + //============================================================== + // COLLINS-SOPER FRAME + // z-axis : Bisector of the two beam directions + // y-axis : Normal to beam plane + // x-axis : Completes right-handed system + //============================================================== + + auto zAxisCSLocal = ROOT::Math::XYZVectorF((beam1cm.Unit() - beam2cm.Unit())).Unit(); + auto yAxisCSLocal = ROOT::Math::XYZVectorF(beam1cm.Cross(beam2cm)).Unit(); + auto xAxisCSLocal = ROOT::Math::XYZVectorF(yAxisCSLocal.Cross(zAxisCSLocal)).Unit(); + cosTheta = zAxisCSLocal.Dot(v1cm); + phi = std::atan2(yAxisCSLocal.Dot(v1cm), xAxisCSLocal.Dot(v1cm)); + phi = RecoDecay::constrainAngle(phi, 0.0); + } else if (frame == kProduction) { + //============================================================== + // PRODUCTION FRAME + // z-axis : Normal to production plane + // + // Production plane is defined by: + // beam direction + // mother momentum + // Used occasionally in spin-alignment analyses. + //============================================================== + + ROOT::Math::XYZVector normalVecLocal = ROOT::Math::XYZVector(motherVec.Py(), -motherVec.Px(), 0.f); + cosTheta = normalVecLocal.Dot(dauCM.Vect()) / (std::sqrt(dauCM.Vect().Mag2()) * std::sqrt(normalVecLocal.Mag2())); + // for production frame reuse helicity-style azimuthal angle + auto zaxisHELocal = ROOT::Math::XYZVectorF(motherVec.Vect()).Unit(); + auto yaxisHELocal = ROOT::Math::XYZVectorF(beam1cm.Cross(beam2cm)).Unit(); + auto xaxisHELocal = ROOT::Math::XYZVectorF(yaxisHELocal.Cross(zaxisHELocal)).Unit(); + phi = std::atan2(yaxisHELocal.Dot(v1cm), xaxisHELocal.Dot(v1cm)); + phi = RecoDecay::constrainAngle(phi, 0.0); + } else if (frame == kGottfriedJackson) { + // ------------------------------------------------------------------ + // Gottfried-Jackson (GJ') frame + // + // z-axis : beam direction in the mother rest frame + // y-axis : normal to the production plane + // x-axis : right-handed coordinate system + // ------------------------------------------------------------------ + + // z-axis: beam direction boosted into mother rest frame + auto zAxisGJ = beam1cm.Unit(); + + // Mother momentum in LAB (defines production plane) + auto motherLab = ROOT::Math::XYZVectorF(motherVec.Vect()).Unit(); + + // Normal to production plane + auto yAxisGJ = ROOT::Math::XYZVectorF(zAxisGJ.Cross(motherLab)); + + if (yAxisGJ.Mag2() > config.tolerance) + yAxisGJ = yAxisGJ.Unit(); + else + yAxisGJ = ROOT::Math::XYZVectorF(0.f, 1.f, 0.f); + + // Complete right-handed system + ROOT::Math::XYZVectorF xAxisGJ = ROOT::Math::XYZVectorF(yAxisGJ.Cross(zAxisGJ)).Unit(); + + // Daughter direction in mother rest frame + cosTheta = zAxisGJ.Dot(v1cm); + + phi = std::atan2(yAxisGJ.Dot(v1cm), xAxisGJ.Dot(v1cm)); + + phi = RecoDecay::constrainAngle(phi, 0.0); + } else { // kRandom or fallback + auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + ROOT::Math::XYZVector randomVecLocal = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + cosTheta = randomVecLocal.Dot(dauCM.Vect()) / std::sqrt(dauCM.Vect().Mag2()); + phi = phiRandom; + } + + return {cosTheta, phi}; + } + using EventCandidatesDerivedData = soa::Join; using V0CandidatesDerivedData = soa::Join; // using DauTracks = soa::Join; @@ -866,185 +1003,114 @@ struct HigherMassResonances { // zBeam direction in lab frame template - void fillInvMass(const T& mother, float multiplicity, const T& daughter1, const T& daughter2, bool isMix) + void fillInvMass(const T& motherVec, float eventMultiplicity, const T& daughterVec1, const T& daughterVec2, bool isMixed) { - // //polarization calculations - // zBeam = ROOT::Math::XYZVector(0.f, 0.f, 1.f); // ẑ: beam direction in lab frame - - ROOT::Math::Boost boost{mother.BoostToCM()}; // define the boost to the center of mass frame - fourVecDauCM = boost(daughter1); // boost the frame of daughter to the center of mass frame - // threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother - - beam1CM = ROOT::Math::XYZVectorF((boost(beam1).Vect()).Unit()); - beam2CM = ROOT::Math::XYZVectorF((boost(beam2).Vect()).Unit()); - - //========================Helicity and Production frame calculation========================== - // define y = zBeam x z: Normal to the production plane - // ẑ: mother direction in lab, boosted into mother's rest frame - - // auto motherLabDirection = ROOT::Math::XYZVector(0, 0, mother.Vect().Z()); // ẑ axis in lab frame - - // // ŷ = zBeam × ẑ - // auto y_axis = zBeam.Cross(motherLabDirection).Unit(); - - // // x̂ = ŷ × ẑ - // auto x_axis = y_axis.Cross(motherLabDirection).Unit(); - - // // Project daughter momentum onto x–y plane - // auto p_proj_x = threeVecDauCM.Dot(x_axis); - // auto p_proj_y = threeVecDauCM.Dot(y_axis); - - // // Calculate φ in [-π, π] - // auto anglePhi = std::atan2(p_proj_y, p_proj_x); // φ in radians - //============================================================================================= - - v1CM = ROOT::Math::XYZVectorF(boost(daughter1).Vect()).Unit(); - // ROOT::Math::XYZVectorF v2_CM{(boost(daughter1).Vect()).Unit()}; - // using positive sign convention for the first track - // ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1CM : v2_CM); // here selected decay daughter momentum is intested. here you can choose one decay daughter no need to check both case as it is neutral particle for our case - // Helicity Frame - zaxisHE = ROOT::Math::XYZVectorF(mother.Vect()).Unit(); - yaxisHE = ROOT::Math::XYZVectorF(beam1CM.Cross(beam2CM)).Unit(); - xaxisHE = ROOT::Math::XYZVectorF(yaxisHE.Cross(zaxisHE)).Unit(); - - // CosThetaHE = zaxisHE.Dot(v_CM); - - auto anglePhi = std::atan2(yaxisHE.Dot(v1CM), xaxisHE.Dot(v1CM)); - anglePhi = RecoDecay::constrainAngle(anglePhi, 0.0); - // if (anglePhi < 0) { - // anglePhi += o2::constants::math::TwoPI; // ensure phi is in [0, 2pi] - // } - - // CS Frame - zAxisCS = ROOT::Math::XYZVectorF((beam1CM.Unit() - beam2CM.Unit())).Unit(); - yAxisCS = ROOT::Math::XYZVectorF(beam1CM.Cross(beam2CM)).Unit(); - xAxisCS = ROOT::Math::XYZVectorF(yAxisCS.Cross(zAxisCS)).Unit(); - double cosThetaStarCS = zAxisCS.Dot(v1CM); - auto phiCS = std::atan2(yAxisCS.Dot(v1CM), xAxisCS.Dot(v1CM)); - phiCS = RecoDecay::constrainAngle(phiCS, 0.0); - - // if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { if (config.activateHelicityFrame) { - // helicityVec = mother.Vect(); // 3 vector of mother in COM frame - // auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); - auto cosThetaStarHelicity = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); - if (!isMix) { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity, anglePhi); + auto pr = getCosThetaPhi(motherVec, daughterVec1, kHelicity); + if (!isMixed) { + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } for (int i = 0; i < config.cRotations; i++) { - theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - - daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - motherRot = daughterRot + daughter2; + daughterRot = ROOT::Math::PxPyPzMVector(daughterVec1.Px() * std::cos(config.theta2) - daughterVec1.Py() * std::sin(config.theta2), daughterVec1.Px() * std::sin(config.theta2) + daughterVec1.Py() * std::cos(config.theta2), daughterVec1.Pz(), daughterVec1.M()); - ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - daughterRotCM = boost2(daughterRot); + motherRot = daughterRot + daughterVec2; - auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); - auto phiHelicityRot = std::atan2(yaxisHE.Dot(daughterRotCM.Vect().Unit()), xaxisHE.Dot(daughterRotCM.Vect().Unit())); - phiHelicityRot = RecoDecay::constrainAngle(phiHelicityRot, 0.0); - if (motherRot.Rapidity() < config.rapidityMotherData) - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarHelicityRot, phiHelicityRot); + auto prrot = getCosThetaPhi(motherRot, daughterRot, kHelicity); + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) + hglue.fill(HIST("h3glueInvMassRot"), eventMultiplicity, motherRot.Pt(), motherRot.M(), prrot.first, prrot.second); } } else { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity, anglePhi); + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } } } else if (config.activateCollinsSoperFrame) { - if (!isMix) { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarCS, phiCS); + auto pr = getCosThetaPhi(motherVec, daughterVec1, kCollinsSoper); + if (!isMixed) { + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } for (int i = 0; i < config.cRotations; i++) { - theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + daughterRot = ROOT::Math::PxPyPzMVector(daughterVec1.Px() * std::cos(config.theta2) - daughterVec1.Py() * std::sin(config.theta2), daughterVec1.Px() * std::sin(config.theta2) + daughterVec1.Py() * std::cos(config.theta2), daughterVec1.Pz(), daughterVec1.M()); - motherRot = daughterRot + daughter2; + motherRot = daughterRot + daughterVec2; - ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - daughterRotCM = boost2(daughterRot); + auto prrot = getCosThetaPhi(motherRot, daughterRot, kCollinsSoper); - auto cosThetaStarCSrot = zAxisCS.Dot(daughterRotCM.Vect()) / std::sqrt(daughterRotCM.Vect().Mag2()); - auto phiCSrot = std::atan2(yAxisCS.Dot(daughterRotCM.Vect().Unit()), xAxisCS.Dot(daughterRotCM.Vect().Unit())); - phiCSrot = RecoDecay::constrainAngle(phiCSrot, 0.0); - - if (motherRot.Rapidity() < config.rapidityMotherData) - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarCSrot, phiCSrot); + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) + hglue.fill(HIST("h3glueInvMassRot"), eventMultiplicity, motherRot.Pt(), motherRot.M(), prrot.first, prrot.second); } } else { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarCS, phiCS); + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } } } else if (config.activateProductionFrame) { - normalVec = ROOT::Math::XYZVector(mother.Py(), -mother.Px(), 0.f); - auto cosThetaProduction = normalVec.Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(normalVec.Mag2())); - if (!isMix) { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaProduction, anglePhi); + auto pr = getCosThetaPhi(motherVec, daughterVec1, kProduction); + if (!isMixed) { + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } for (int i = 0; i < config.cRotations; i++) { - theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - motherRot = ROOT::Math::PxPyPzMVector(mother.Px() * std::cos(theta2) - mother.Py() * std::sin(theta2), mother.Px() * std::sin(theta2) + mother.Py() * std::cos(theta2), mother.Pz(), mother.M()); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + motherRot = ROOT::Math::PxPyPzMVector(motherVec.Px() * std::cos(config.theta2) - motherVec.Py() * std::sin(config.theta2), motherVec.Px() * std::sin(config.theta2) + motherVec.Py() * std::cos(config.theta2), motherVec.Pz(), motherVec.M()); + auto prrot = getCosThetaPhi(motherRot, daughterVec1, kProduction); if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaProduction, anglePhi); + hglue.fill(HIST("h3glueInvMassRot"), eventMultiplicity, motherRot.Pt(), motherRot.M(), prrot.first, prrot.second); } } } else { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaProduction, anglePhi); + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } } - } else if (config.activateBeamAxisFrame) { - beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); - auto cosThetaStarBeam = beamVec.Dot(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); - if (!isMix) { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam, anglePhi); + } else if (config.activateGJFrame) { + auto pr = getCosThetaPhi(motherVec, daughterVec1, kGottfriedJackson); + if (!isMixed) { + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } for (int i = 0; i < config.cRotations; i++) { - theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - motherRot = ROOT::Math::PxPyPzMVector(mother.Px() * std::cos(theta2) - mother.Py() * std::sin(theta2), mother.Px() * std::sin(theta2) + mother.Py() * std::cos(theta2), mother.Pz(), mother.M()); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + motherRot = ROOT::Math::PxPyPzMVector(motherVec.Px() * std::cos(config.theta2) - motherVec.Py() * std::sin(config.theta2), motherVec.Px() * std::sin(config.theta2) + motherVec.Py() * std::cos(config.theta2), motherVec.Pz(), motherVec.M()); + auto prrot = getCosThetaPhi(motherRot, daughterVec1, kGottfriedJackson); if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarBeam, anglePhi); + hglue.fill(HIST("h3glueInvMassRot"), eventMultiplicity, motherRot.Pt(), motherRot.M(), prrot.first, prrot.second); } } } else { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam, anglePhi); + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } } } else if (config.activateRandomFrame) { - auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); - auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); - - randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); - auto cosThetaStarRandom = randomVec.Dot(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); - if (!isMix) { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom, phiRandom); + auto pr = getCosThetaPhi(motherVec, daughterVec1, kRandom); + if (!isMixed) { + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } for (int i = 0; i < config.cRotations; i++) { - theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - motherRot = ROOT::Math::PxPyPzMVector(mother.Px() * std::cos(theta2) - mother.Py() * std::sin(theta2), mother.Px() * std::sin(theta2) + mother.Py() * std::cos(theta2), mother.Pz(), mother.M()); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + motherRot = ROOT::Math::PxPyPzMVector(motherVec.Px() * std::cos(config.theta2) - motherVec.Py() * std::sin(config.theta2), motherVec.Px() * std::sin(config.theta2) + motherVec.Py() * std::cos(config.theta2), motherVec.Pz(), motherVec.M()); + auto prrot = getCosThetaPhi(motherRot, daughterVec1, kRandom); if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarRandom, phiRandom); + hglue.fill(HIST("h3glueInvMassRot"), eventMultiplicity, motherRot.Pt(), motherRot.M(), prrot.first, prrot.second); } } } else { - if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom, phiRandom); + if (std::abs(motherVec.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), eventMultiplicity, motherVec.Pt(), motherVec.M(), pr.first, pr.second); } } } - // } } void processSE(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, V0TrackCandidate const& V0s) @@ -1059,8 +1125,6 @@ struct HigherMassResonances { multiplicity = collision.centFT0C(); } else if (config.cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } if (!selectionEvent(collision, true)) { @@ -1085,7 +1149,7 @@ struct HigherMassResonances { } std::vector v0indexes; - bool allConditionsMet = 0; + bool allConditionsMet = false; for (const auto& [v1, v2] : combinations(CombinationsFullIndexPolicy(V0s, V0s))) { @@ -1147,7 +1211,7 @@ struct HigherMassResonances { continue; } - allConditionsMet = 1; + allConditionsMet = true; daughter1 = ROOT::Math::PxPyPzMVector(v1.px(), v1.py(), v1.pz(), o2::constants::physics::MassK0Short); // Kshort daughter2 = ROOT::Math::PxPyPzMVector(v2.px(), v2.py(), v2.pz(), o2::constants::physics::MassK0Short); // Kshort @@ -1193,16 +1257,16 @@ struct HigherMassResonances { } for (int i = 0; i < config.cRotations; i++) { - double theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(config.theta2) - daughter1.Py() * std::sin(config.theta2), daughter1.Px() * std::sin(config.theta2) + daughter1.Py() * std::cos(config.theta2), daughter1.Pz(), daughter1.M()); motherRot = daughterRot + daughter2; // double pTcorrRot = std::abs(daughterRot.Pt() + daughter2.Pt()) / motherRot.Pt(); double pTcorrRot = (motherRot.Pt() - daughterRot.Pt() != 0.) ? daughterRot.Pt() / (motherRot.Pt() - daughterRot.Pt()) : 0.; - if (motherRot.Rapidity() < config.rapidityMotherData) + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), deltaMass, deltaRvalue, pTcorrRot); } } @@ -1228,15 +1292,13 @@ struct HigherMassResonances { multiplicity = collision.centFT0C(); } else if (config.cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0C(); // default } if (!selectionEvent(collision, true)) { return; } - if (collision.qvecAmp()[detId] < minQvecAmp || collision.qvecAmp()[refAId] < minQvecAmp || collision.qvecAmp()[refBId] < minQvecAmp) { + if (collision.qvecAmp()[config.detId] < config.minQvecAmp || collision.qvecAmp()[config.refAId] < config.minQvecAmp || collision.qvecAmp()[config.refBId] < config.minQvecAmp) { return; } @@ -1245,10 +1307,11 @@ struct HigherMassResonances { rEventSelection.fill(HIST("hmultiplicity"), multiplicity); } - float eps[3] = {0.}; - eps[0] = helperEP.GetEventPlane(collision.qvecRe()[4 * detId + 3], collision.qvecIm()[4 * detId + 3], 2); - eps[1] = helperEP.GetEventPlane(collision.qvecRe()[4 * refAId + 3], collision.qvecIm()[4 * refAId + 3], 2); - eps[2] = helperEP.GetEventPlane(collision.qvecRe()[4 * refBId + 3], collision.qvecIm()[4 * refBId + 3], 2); + std::array eps{}; + + eps[0] = helperEP.GetEventPlane(collision.qvecRe()[4 * config.detId + 3], collision.qvecIm()[4 * config.detId + 3], 2); + eps[1] = helperEP.GetEventPlane(collision.qvecRe()[4 * config.refAId + 3], collision.qvecIm()[4 * config.refAId + 3], 2); + eps[2] = helperEP.GetEventPlane(collision.qvecRe()[4 * config.refBId + 3], collision.qvecIm()[4 * config.refBId + 3], 2); float resNumA = helperEP.GetResolution(eps[0], eps[1], 2); float resNumB = helperEP.GetResolution(eps[0], eps[2], 2); @@ -1361,13 +1424,13 @@ struct HigherMassResonances { } for (int i = 0; i < config.cRotations; i++) { - double theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(config.theta2) - daughter1.Py() * std::sin(config.theta2), daughter1.Px() * std::sin(config.theta2) + daughter1.Py() * std::cos(config.theta2), daughter1.Pz(), daughter1.M()); motherRot = daughterRot + daughter2; - if (motherRot.Rapidity() < config.rapidityMotherData) { + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { hglue.fill(HIST("h3glueInvMassEPRot"), multiplicity, motherRot.Pt(), motherRot.M(), RecoDecay::constrainAngle(2.0 * motherRot.Phi() - 2.0 * eps[0])); } } @@ -1404,7 +1467,7 @@ struct HigherMassResonances { SameKindPair pair3{binningOnFT0C, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; SameKindPair pair4{binningOnFV0A, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; - auto runMixing = [&](auto& pair, auto multiplicityGetter) { + auto runMixing = [&](const auto& pair, auto multiplicityGetter) { for (const auto& [c1, tracks1, c2, tracks2] : pair) { multiplicity = multiplicityGetter(c1); @@ -1481,11 +1544,11 @@ struct HigherMassResonances { if (config.qAOptimisation) { double deltaRvalue = std::sqrt(TVector2::Phi_mpi_pi(daughter1.phi() - daughter2.phi()) * TVector2::Phi_mpi_pi(daughter1.phi() - daughter2.phi()) + (daughter1.eta() - daughter2.eta()) * (daughter1.eta() - daughter2.eta())); - const double deltaMass = deltaM(t1.mK0Short(), t2.mK0Short()); + const double deltaMassOpt = deltaM(t1.mK0Short(), t2.mK0Short()); // const double ptCorr = std::abs(daughter1.Pt() + daughter2.Pt()) / mother.Pt(); const double ptCorr = (mother.Pt() - daughter1.Pt() != 0.) ? daughter1.Pt() / (mother.Pt() - daughter1.Pt()) : 0.; if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), deltaMass, deltaRvalue, ptCorr); + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), deltaMassOpt, deltaRvalue, ptCorr); } } } @@ -1509,7 +1572,6 @@ struct HigherMassResonances { std::vector passKs; ROOT::Math::PxPyPzMVector lResonanceGen1; ROOT::Math::PxPyPzEVector lResonanceGen; - Service pdgDB; // void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) void processGen(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) @@ -1544,8 +1606,6 @@ struct HigherMassResonances { multiplicityGen = collision.centFT0C(); } else if (config.cSelectMultEstimator == kFV0A) { multiplicityGen = collision.centFV0A(); - } else { - multiplicityGen = collision.centFT0M(); // default } if (!selectionEvent(collision, true)) { @@ -1603,35 +1663,51 @@ struct HigherMassResonances { } } if (static_cast(passKs.size()) == config.noOfDaughters) { - lResonanceGen = ROOT::Math::PxPyPzEVector(mcParticle.pt(), mcParticle.eta(), mcParticle.phi(), mcParticle.e()); + lResonanceGen = ROOT::Math::PxPyPzEVector(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); lResonanceGen1 = daughter1 + daughter2; + mother2 = ROOT::Math::PxPyPzMVector(lResonanceGen1.Px(), lResonanceGen1.Py(), lResonanceGen1.Pz(), lResonanceGen1.M()); + mother3 = ROOT::Math::PxPyPzMVector(lResonanceGen.Px(), lResonanceGen.Py(), lResonanceGen.Pz(), lResonanceGen.M()); + + int frame = -1; + + if (config.activateHelicityFrame) { + frame = kHelicity; + } else if (config.activateCollinsSoperFrame) { + frame = kCollinsSoper; + } else if (config.activateProductionFrame) { + frame = kProduction; + } else if (config.activateGJFrame) { + frame = kGottfriedJackson; + } else if (config.activateRandomFrame) { + frame = kRandom; + } else { + LOGP(fatal, "No reference frame selected"); + } - ROOT::Math::Boost boost{lResonanceGen.BoostToCM()}; - ROOT::Math::Boost boost1{lResonanceGen1.BoostToCM()}; - - fourVecDauCM = boost(daughter1); - fourVecDauCM1 = boost1(daughter1); - - auto helicityGen = lResonanceGen.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(lResonanceGen.Vect().Mag2())); - auto helicityGen1 = lResonanceGen1.Vect().Dot(fourVecDauCM1.Vect()) / (std::sqrt(fourVecDauCM1.Vect().Mag2()) * std::sqrt(lResonanceGen1.Vect().Mag2())); + auto angularVar = getCosThetaPhi(mother3, daughter1, frame); + auto angularVar1 = getCosThetaPhi(mother2, daughter1, frame); - hMChists.fill(HIST("Genf1710"), multiplicityGen, lResonanceGen.pt(), helicityGen); - hMChists.fill(HIST("Genf1710Calib"), genMultiplicity, lResonanceGen.pt(), helicityGen); + hMChists.fill(HIST("Genf1710"), multiplicityGen, lResonanceGen.pt(), angularVar.first); + hMChists.fill(HIST("Genf1710Calib"), genMultiplicity, lResonanceGen.pt(), angularVar.first); hMChists.fill(HIST("Genf1710_mass"), lResonanceGen.M()); hMChists.fill(HIST("GenRapidity"), mcParticle.y()); hMChists.fill(HIST("GenEta"), mcParticle.eta()); hMChists.fill(HIST("GenPhi"), mcParticle.phi()); + hMChists.fill(HIST("Gen1710PWA"), lResonanceGen.M(), angularVar.first, angularVar.second); + hMChists.fill(HIST("GenThetavsPhi1"), angularVar.first, angularVar.second); if (config.isapplyPairRapidityMC && std::abs(lResonanceGen1.Rapidity()) >= config.rapidityMotherData) { continue; } - hMChists.fill(HIST("Genf17102"), multiplicityGen, lResonanceGen1.pt(), helicityGen1); - hMChists.fill(HIST("Genf1710Calib2"), genMultiplicity, lResonanceGen1.pt(), helicityGen1); + hMChists.fill(HIST("Genf17102"), multiplicityGen, lResonanceGen1.pt(), angularVar1.first); + hMChists.fill(HIST("Genf1710Calib2"), genMultiplicity, lResonanceGen1.pt(), angularVar1.first); hMChists.fill(HIST("Genf1710_mass2"), lResonanceGen1.M()); hMChists.fill(HIST("GenRapidity2"), lResonanceGen1.Rapidity()); hMChists.fill(HIST("GenEta2"), lResonanceGen1.Eta()); hMChists.fill(HIST("GenPhi2"), lResonanceGen1.Phi()); + hMChists.fill(HIST("Gen1710PWA2"), lResonanceGen1.M(), angularVar1.first, angularVar1.second); + hMChists.fill(HIST("GenThetavsPhi2"), angularVar1.first, angularVar1.second); } passKs.clear(); // clear the vector for the next iteration } @@ -1662,8 +1738,6 @@ struct HigherMassResonances { multiplicity1 = RecCollision.centFT0C(); } else if (config.cSelectMultEstimator == kFV0A) { multiplicity1 = RecCollision.centFV0A(); - } else { - multiplicity1 = RecCollision.centFT0M(); // default } isSelectedEvent = true; @@ -1682,15 +1756,15 @@ struct HigherMassResonances { return; } - auto multiplicityGen = -1; - multiplicityGen = mcCollision.centFT0M(); - hMChists.fill(HIST("MCcorrections/MultiplicityGen"), multiplicityGen); + auto multiplicityGenEvt = -1.f; + multiplicityGenEvt = mcCollision.centFT0M(); + hMChists.fill(HIST("MCcorrections/MultiplicityGen"), multiplicityGenEvt); hMChists.fill(HIST("MCcorrections/MultiplicityGen2"), multiplicity1); hMChists.fill(HIST("MCcorrections/hMultvsCent"), multiplicity1, multMC); // Event loss if (isSelectedEvent) { - hMChists.fill(HIST("MCcorrections/MultiplicityRec"), multiplicityGen); + hMChists.fill(HIST("MCcorrections/MultiplicityRec"), multiplicityGenEvt); hMChists.fill(HIST("MCcorrections/MultiplicityRec2"), multiplicity1); } @@ -1699,11 +1773,11 @@ struct HigherMassResonances { if (std::abs(mcPart.y()) >= config.rapidityMotherData || std::abs(mcPart.pdgCode()) != config.pdgCodes[config.selectMCparticles]) continue; - hMChists.fill(HIST("MCcorrections/hSignalLossDenominator"), mcPart.pt(), multiplicityGen); + hMChists.fill(HIST("MCcorrections/hSignalLossDenominator"), mcPart.pt(), multiplicityGenEvt); hMChists.fill(HIST("MCcorrections/hSignalLossDenominator2"), mcPart.pt(), multiplicity1); hMChists.fill(HIST("MCcorrections/hSignalLossDenominator3"), mcPart.pt(), multMC); if (isSelectedEvent) { - hMChists.fill(HIST("MCcorrections/hSignalLossNumerator"), mcPart.pt(), multiplicityGen); + hMChists.fill(HIST("MCcorrections/hSignalLossNumerator"), mcPart.pt(), multiplicityGenEvt); hMChists.fill(HIST("MCcorrections/hSignalLossNumerator2"), mcPart.pt(), multiplicity1); hMChists.fill(HIST("MCcorrections/hSignalLossNumerator3"), mcPart.pt(), multMC); } @@ -1753,26 +1827,24 @@ struct HigherMassResonances { const auto& mcCollisionRec = collision.mcCollision_as(); multiplicityRec = mcCollisionRec.centFT0M(); - auto multiplicity = -999.0; + auto eventMultiplicity = -999.0; if (config.cSelectMultEstimator == kFT0M) { - multiplicity = collision.centFT0M(); + eventMultiplicity = collision.centFT0M(); } else if (config.cSelectMultEstimator == kFT0A) { - multiplicity = collision.centFT0A(); + eventMultiplicity = collision.centFT0A(); } else if (config.cSelectMultEstimator == kFT0C) { - multiplicity = collision.centFT0C(); + eventMultiplicity = collision.centFT0C(); } else if (config.cSelectMultEstimator == kFV0A) { - multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default + eventMultiplicity = collision.centFV0A(); } if (!selectionEvent(collision, false)) { return; } - hMChists.fill(HIST("Rec_Multiplicity"), multiplicity); + hMChists.fill(HIST("Rec_Multiplicity"), eventMultiplicity); rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - hMChists.fill(HIST("MC_mult_after_event_sel"), multiplicity); + hMChists.fill(HIST("MC_mult_after_event_sel"), eventMultiplicity); eventCounter++; for (const auto& v01 : V0s) { @@ -1800,21 +1872,23 @@ struct HigherMassResonances { if (!negtrack1.has_mcParticle() || !negtrack2.has_mcParticle()) continue; - double nTPCSigmaPos1[1]{postrack1.tpcNSigmaPi()}; - double nTPCSigmaNeg1[1]{negtrack1.tpcNSigmaPi()}; - double nTPCSigmaPos2[1]{postrack2.tpcNSigmaPi()}; - double nTPCSigmaNeg2[1]{negtrack2.tpcNSigmaPi()}; + double nTPCSigmaPos1 = postrack1.tpcNSigmaPi(); + double nTPCSigmaNeg1 = negtrack1.tpcNSigmaPi(); + double nTPCSigmaPos2 = postrack2.tpcNSigmaPi(); + double nTPCSigmaNeg2 = negtrack2.tpcNSigmaPi(); - if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1[0], v01) || !isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2[0], v02)) { + if (!isSelectedV0Daughter(postrack1, 1, nTPCSigmaPos1, v01) || + !isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2, v02)) { continue; } - if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1[0], v01) || !isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2[0], v02)) { + if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1, v01) || + !isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2, v02)) { continue; } hMChists.fill(HIST("events_checkrec"), 1.5); - if (!selectionV0(collision, v01, multiplicity) || !selectionV0(collision, v02, multiplicity)) { + if (!selectionV0(collision, v01, eventMultiplicity) || !selectionV0(collision, v02, eventMultiplicity)) { continue; } hMChists.fill(HIST("events_checkrec"), 2.5); @@ -1887,37 +1961,42 @@ struct HigherMassResonances { daughter2 = ROOT::Math::PxPyPzMVector(v02.px(), v02.py(), v02.pz(), o2::constants::physics::MassK0Short); mother = daughter1 + daughter2; mother1 = ROOT::Math::PxPyPzEVector(mothertrack1.px(), mothertrack1.py(), mothertrack1.pz(), mothertrack1.e()); + mother2 = ROOT::Math::PxPyPzMVector(mother1.Px(), mother1.Py(), mother1.Pz(), mother1.M()); + + int frame = kHelicity; + + if (config.activateCollinsSoperFrame) { + frame = kCollinsSoper; + } else if (config.activateProductionFrame) { + frame = kProduction; + } else if (config.activateGJFrame) { + frame = kGottfriedJackson; + } else if (config.activateRandomFrame) { + frame = kRandom; + } - ROOT::Math::Boost boost{mother.BoostToCM()}; - ROOT::Math::Boost boost1{mother1.BoostToCM()}; - - fourVecDauCM = boost(daughter1); - fourVecDauCM1 = boost1(daughter1); - - auto helicityRec = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); - - auto helicityRec2 = mother1.Vect().Dot(fourVecDauCM1.Vect()) / (std::sqrt(fourVecDauCM1.Vect().Mag2()) * std::sqrt(mother1.Vect().Mag2())); - - // const double deltaMassRec = deltaM(mctrackv01.mK0Short(), mctrackv02.mK0Short()); - // if (deltaMassRec > config.cMaxDeltaM) { - // continue; - // } + auto angularVar = getCosThetaPhi(mother, daughter1, frame); + auto angularVar1 = getCosThetaPhi(mother2, daughter1, frame); - hMChists.fill(HIST("Recf1710_pt1"), multiplicity, mothertrack1.pt(), mother1.M(), helicityRec2); - hMChists.fill(HIST("Recf1710Calib_pt1"), multiplicityRec, mothertrack1.pt(), mother1.M(), helicityRec2); + hMChists.fill(HIST("Recf1710_pt1"), eventMultiplicity, mothertrack1.pt(), mother1.M(), angularVar1.first); + hMChists.fill(HIST("Recf1710Calib_pt1"), multiplicityRec, mothertrack1.pt(), mother1.M(), angularVar1.first); hMChists.fill(HIST("RecRapidity"), mothertrack1.y()); hMChists.fill(HIST("RecPhi"), mothertrack1.phi()); hMChists.fill(HIST("RecEta"), mothertrack1.eta()); + hMChists.fill(HIST("Recf1710PWA_pt1"), mother1.M(), angularVar1.first, angularVar1.second); + hMChists.fill(HIST("RecThetavsPhi1"), angularVar1.first, angularVar1.second); if (config.isapplyPairRapidityMC && std::abs(mother.Rapidity()) >= config.rapidityMotherData) { continue; } - hMChists.fill(HIST("Recf1710_pt2"), multiplicity, mother.Pt(), mother.M(), helicityRec); - hMChists.fill(HIST("Recf1710Calib_pt2"), multiplicityRec, mother.Pt(), mother.M(), helicityRec); + hMChists.fill(HIST("Recf1710_pt2"), eventMultiplicity, mother.Pt(), mother.M(), angularVar.first); + hMChists.fill(HIST("Recf1710Calib_pt2"), multiplicityRec, mother.Pt(), mother.M(), angularVar.first); hMChists.fill(HIST("RecRapidity2"), mother.Rapidity()); hMChists.fill(HIST("RecPhi2"), mother.Phi()); hMChists.fill(HIST("RecEta2"), mother.Eta()); + hMChists.fill(HIST("Recf1710PWA_pt2"), mother.M(), angularVar.first, angularVar.second); + hMChists.fill(HIST("RecThetavsPhi2"), angularVar.first, angularVar.second); } gindex2.clear(); } @@ -1938,8 +2017,6 @@ struct HigherMassResonances { multiplicity = collision.centFT0C(); } else if (config.cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } if (!selectionEventDerived(collision, true)) { @@ -1952,7 +2029,7 @@ struct HigherMassResonances { } std::vector v0indexes; - bool allConditionsMet = 0; + bool allConditionsMet = false; for (const auto& [v1, v2] : combinations(CombinationsFullIndexPolicy(V0s, V0s))) { @@ -1979,7 +2056,7 @@ struct HigherMassResonances { continue; } - allConditionsMet = 1; + allConditionsMet = true; daughter1 = ROOT::Math::PxPyPzMVector(v1.px(), v1.py(), v1.pz(), o2::constants::physics::MassK0Short); // Kshort daughter2 = ROOT::Math::PxPyPzMVector(v2.px(), v2.py(), v2.pz(), o2::constants::physics::MassK0Short); // Kshort @@ -2022,14 +2099,14 @@ struct HigherMassResonances { } for (int i = 0; i < config.cRotations; i++) { - double theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); + config.theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / config.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / config.rotationalCut); - daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(config.theta2) - daughter1.Py() * std::sin(config.theta2), daughter1.Px() * std::sin(config.theta2) + daughter1.Py() * std::cos(config.theta2), daughter1.Pz(), daughter1.M()); motherRot = daughterRot + daughter2; // double pTcorrRot = std::abs(daughterRot.Pt() + daughter2.Pt()) / motherRot.Pt(); double pTcorrRot = (motherRot.Pt() - daughterRot.Pt() != 0.) ? daughterRot.Pt() / (motherRot.Pt() - daughterRot.Pt()) : 0.; - if (motherRot.Rapidity() < config.rapidityMotherData) + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), deltaMass, deltaRvalue, pTcorrRot); } } @@ -2095,11 +2172,11 @@ struct HigherMassResonances { if (config.qAOptimisation) { double deltaRvalue = std::sqrt(TVector2::Phi_mpi_pi(daughter1.phi() - daughter2.phi()) * TVector2::Phi_mpi_pi(daughter1.phi() - daughter2.phi()) + (daughter1.eta() - daughter2.eta()) * (daughter1.eta() - daughter2.eta())); - const double deltaMass = deltaM(t1.mK0Short(), t2.mK0Short()); + const double deltaMassOpt = deltaM(t1.mK0Short(), t2.mK0Short()); // const double ptCorr = std::abs(daughter1.Pt() + daughter2.Pt()) / mother.Pt(); const double ptCorr = (mother.Pt() - daughter1.Pt() != 0.) ? daughter1.Pt() / (mother.Pt() - daughter1.Pt()) : 0.; if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { - hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), deltaMass, deltaRvalue, ptCorr); + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), deltaMassOpt, deltaRvalue, ptCorr); } } } diff --git a/PWGLF/Tasks/Resonances/kstar892LightIon.cxx b/PWGLF/Tasks/Resonances/kstar892LightIon.cxx index 51d9700d7c4..cdfb55fc3ba 100644 --- a/PWGLF/Tasks/Resonances/kstar892LightIon.cxx +++ b/PWGLF/Tasks/Resonances/kstar892LightIon.cxx @@ -98,6 +98,7 @@ struct Kstar892LightIon { Configurable isVertexTOFMatched{"isVertexTOFMatched", false, "Vertex TOF Matched"}; Configurable isApplyhasFT0{"isApplyhasFT0", false, "Apply has_foundFT0 event selection"}; + Configurable isApplyhasBC{"isApplyhasBC", false, "Apply has_foundBC event selection"}; // check Configurable isApplyMCGenInelgt0{"isApplyMCGenInelgt0", true, "Apply INEL>0 cut in MC Gen Collisions"}; @@ -140,6 +141,9 @@ struct Kstar892LightIon { Configurable pidMode{"pidMode", 0, "0=Combined,1=TPC,2=TOF,3=TOFHIT,4=TOFVeto"}; Configurable misIdStrategy{"misIdStrategy", -1, "-1=Disabled, 0=Standard, 1=PtDependent, 2=PtDependentCompare"}; + Configurable shiftTofNsigmaKa{"shiftTofNsigmaKa", 0.0, "Shift in Nsigma for kaons in TOF"}; + Configurable shiftTofNsigmaPi{"shiftTofNsigmaPi", 0.0, "Shift in Nsigma for pions in TOF"}; + Configurable nsigmaCutTPCPi{"nsigmaCutTPCPi", 3.0, "TPC Nsigma cut for pions"}; Configurable nsigmaCutTPCKa{"nsigmaCutTPCKa", 3.0, "TPC Nsigma cut for kaons"}; Configurable nsigmaCutTOFPi{"nsigmaCutTOFPi", 3.0, "TOF Nsigma cut for pions"}; @@ -286,7 +290,8 @@ struct Kstar892LightIon { std::string("isVertexITSTPC") + check(selectionConfig.isVertexITSTPC.value), std::string("isVertexTOFMatched") + check(selectionConfig.isVertexTOFMatched.value), std::string("INEL > 0") + check(selectionConfig.isApplyINELgt0.value), - std::string("hasFT0") + check(selectionConfig.isApplyhasFT0.value)}; + std::string("hasFT0") + check(selectionConfig.isApplyhasFT0.value), + std::string("hasBC") + check(selectionConfig.isApplyhasBC.value)}; // assign labels for (size_t i = 0; i < eveCutLabels.size(); ++i) { @@ -525,6 +530,16 @@ struct Kstar892LightIon { hMC.add("KinematicsMisId/hOtherMisId_PtDeltaRMass", "#DeltaR vs M(K#pi);#DeltaR;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, 0.0, 5.0}, invmassAxis}); hMC.add("KinematicsMisId/hOtherMisId_PtCentMass", "p_{T} vs Centrality vs M(K#pi);p_{T} (GeV/c);Centrality (%);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, centralityAxis, invmassAxis}); + hMC.add("KinematicsMisId/hK0s_PtDeltaRMass", "#DeltaR vs M(K#pi);#DeltaR;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, 0.0, 5.0}, invmassAxis}); + hMC.add("KinematicsMisId/hK0s_PtCentMass", "p_{T} vs Centrality vs M(K#pi);p_{T} (GeV/c);Centrality (%);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, centralityAxis, invmassAxis}); + + hMC.add("KinematicsMisId/hLambda_PtDeltaRMass", "#DeltaR vs M(K#pi);#DeltaR;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, 0.0, 5.0}, invmassAxis}); + hMC.add("KinematicsMisId/hLambda_PtCentMass", "p_{T} vs Centrality vs M(K#pi);p_{T} (GeV/c);Centrality (%);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, centralityAxis, invmassAxis}); + + hMC.add("KinematicsMisId/hUnknownMisIdMotherPDG", "PDG Code of unknown mothers for fake Kpi pairs;PDG Code", kTH1F, {{100000, -50000.0, 50000.0}}); + hMC.add("KinematicsMisId/hOtherMother_PtDeltaRMass", "#DeltaR vs M(K#pi);#DeltaR;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, 0.0, 5.0}, invmassAxis}); + hMC.add("KinematicsMisId/hOtherMother_PtCentMass", "p_{T} vs Centrality vs M(K#pi);p_{T} (GeV/c);Centrality (%);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, centralityAxis, invmassAxis}); + if (additionalKin) { hMC.add("KinematicsMisId/hTrueKstar_PtOpenAngleMass", "Opening angle vs M(K#pi);Opening angle (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, 0., o2::constants::math::PI}, invmassAxis}); hMC.add("KinematicsMisId/hTrueKstar_PtDeltaPhiMass", "#Delta#phi vs M(K#pi);#Delta#phi (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, -o2::constants::math::PI, o2::constants::math::PI}, invmassAxis}); @@ -573,6 +588,24 @@ struct Kstar892LightIon { hMC.add("KinematicsMisId/hOtherMisId_PtDeltaEtaMass", "#Delta#eta vs M(K#pi);#Delta#eta;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, -2.0, 2.0}, invmassAxis}); hMC.add("KinematicsMisId/hOtherMisId_PtKaonPtMass", "Kaon p_{T} vs M(K#pi);p_{T}^{K} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); hMC.add("KinematicsMisId/hOtherMisId_PtPionPtMass", "Pion p_{T} vs M(K#pi);p_{T}^{#pi} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); + + hMC.add("KinematicsMisId/hK0s_PtOpenAngleMass", "Opening angle vs M(K#pi);Opening angle (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, 0., o2::constants::math::PI}, invmassAxis}); + hMC.add("KinematicsMisId/hK0s_PtDeltaPhiMass", "#Delta#phi vs M(K#pi);#Delta#phi (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, -o2::constants::math::PI, o2::constants::math::PI}, invmassAxis}); + hMC.add("KinematicsMisId/hK0s_PtDeltaEtaMass", "#Delta#eta vs M(K#pi);#Delta#eta;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, -2.0, 2.0}, invmassAxis}); + hMC.add("KinematicsMisId/hK0s_PtKaonPtMass", "Kaon p_{T} vs M(K#pi);p_{T}^{K} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); + hMC.add("KinematicsMisId/hK0s_PtPionPtMass", "Pion p_{T} vs M(K#pi);p_{T}^{#pi} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); + + hMC.add("KinematicsMisId/hLambda_PtOpenAngleMass", "Opening angle vs M(K#pi);Opening angle (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, 0., o2::constants::math::PI}, invmassAxis}); + hMC.add("KinematicsMisId/hLambda_PtDeltaPhiMass", "#Delta#phi vs M(K#pi);#Delta#phi (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, -o2::constants::math::PI, o2::constants::math::PI}, invmassAxis}); + hMC.add("KinematicsMisId/hLambda_PtDeltaEtaMass", "#Delta#eta vs M(K#pi);#Delta#eta;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, -2.0, 2.0}, invmassAxis}); + hMC.add("KinematicsMisId/hLambda_PtKaonPtMass", "Kaon p_{T} vs M(K#pi);p_{T}^{K} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); + hMC.add("KinematicsMisId/hLambda_PtPionPtMass", "Pion p_{T} vs M(K#pi);p_{T}^{#pi} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); + + hMC.add("KinematicsMisId/hOtherMother_PtOpenAngleMass", "Opening angle vs M(K#pi);Opening angle (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, 0., o2::constants::math::PI}, invmassAxis}); + hMC.add("KinematicsMisId/hOtherMother_PtDeltaPhiMass", "#Delta#phi vs M(K#pi);#Delta#phi (rad);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {180, -o2::constants::math::PI, o2::constants::math::PI}, invmassAxis}); + hMC.add("KinematicsMisId/hOtherMother_PtDeltaEtaMass", "#Delta#eta vs M(K#pi);#Delta#eta;M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, {200, -2.0, 2.0}, invmassAxis}); + hMC.add("KinematicsMisId/hOtherMother_PtKaonPtMass", "Kaon p_{T} vs M(K#pi);p_{T}^{K} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); + hMC.add("KinematicsMisId/hOtherMother_PtPionPtMass", "Pion p_{T} vs M(K#pi);p_{T}^{#pi} (GeV/c);M(K#pi) (GeV/c^{2})", kTH3F, {ptAxis, ptAxis, invmassAxis}); } } } @@ -689,6 +722,13 @@ struct Kstar892LightIon { hEventSelection.fill(HIST("hEventCut"), 15); } + if (selectionConfig.isApplyhasBC && !collision.has_foundBC()) { + return false; + } + if (fillHist) { + hEventSelection.fill(HIST("hEventCut"), 16); + } + return true; } @@ -812,10 +852,16 @@ struct Kstar892LightIon { return pid == PIDParticle::kPion ? c.tpcNSigmaPi() : c.tpcNSigmaKa(); } - template + /* template float tofSigma(const T& c, PIDParticle pid) { return pid == PIDParticle::kPion ? c.tofNSigmaPi() : c.tofNSigmaKa(); + } */ + + template + float tofSigma(const T& c, PIDParticle pid) + { + return pid == PIDParticle::kPion ? (c.tofNSigmaPi() - selectionConfig.shiftTofNsigmaPi) : (c.tofNSigmaKa() - selectionConfig.shiftTofNsigmaKa); } template @@ -1198,27 +1244,27 @@ struct Kstar892LightIon { if (track1.sign() < 0) { hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), tofSigma(track1, PIDParticle::kPion), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_p"), track1.tpcNSigmaPi(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_p"), track1.tofNSigmaPi(), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_p"), tofSigma(track1, PIDParticle::kPion), centrality, track1.p()); } else if (track1.sign() > 0) { hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), tofSigma(track1, PIDParticle::kPion), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_p"), track1.tpcNSigmaPi(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_p"), track1.tofNSigmaPi(), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_p"), tofSigma(track1, PIDParticle::kPion), centrality, track1.p()); } - hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); - hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), tofSigma(track1, PIDParticle::kKaon), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track1.tpcNSigmaPi(), tofSigma(track1, PIDParticle::kPion), track1.pt()); hOthers.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), centrality, track1.pt()); hOthers.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), centrality, track1.pt()); @@ -1253,34 +1299,34 @@ struct Kstar892LightIon { if (track1.sign() < 0) { hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); } else if (track1.sign() > 0) { hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); } if (track2.sign() < 0) { hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } else if (track2.sign() > 0) { hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } - hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); - hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), track2.tofNSigmaPi(), track2.pt()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), tofSigma(track1, PIDParticle::kKaon), track1.pt()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), tofSigma(track2, PIDParticle::kPion), track2.pt()); if (track1.hasTOF()) { hOthers.fill(HIST("hTOFBetaKa"), track1.beta()); @@ -1370,27 +1416,27 @@ struct Kstar892LightIon { if (track1.sign() < 0) { hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), tofSigma(track1, PIDParticle::kPion), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_p"), track1.tpcNSigmaPi(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_p"), track1.tofNSigmaPi(), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_p"), tofSigma(track1, PIDParticle::kPion), centrality, track1.p()); } else { hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), tofSigma(track1, PIDParticle::kPion), centrality, track1.pt()); hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_p"), track1.tpcNSigmaPi(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_p"), track1.tofNSigmaPi(), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_p"), tofSigma(track1, PIDParticle::kPion), centrality, track1.p()); } - hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); - hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), tofSigma(track1, PIDParticle::kKaon), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track1.tpcNSigmaPi(), tofSigma(track1, PIDParticle::kPion), track1.pt()); hOthers.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), centrality, track1.pt()); hOthers.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), centrality, track1.pt()); @@ -1425,34 +1471,34 @@ struct Kstar892LightIon { if (track1.sign() < 0) { hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); } else if (track1.sign() > 0) { hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); } if (track2.sign() < 0) { hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } else if (track2.sign() > 0) { hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } - hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); - hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), track2.tofNSigmaPi(), track2.pt()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), tofSigma(track1, PIDParticle::kKaon), track1.pt()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), tofSigma(track2, PIDParticle::kPion), track2.pt()); if (track1.hasTOF()) { hOthers.fill(HIST("hTOFBetaKa"), track1.beta()); @@ -1841,35 +1887,35 @@ struct Kstar892LightIon { if (cQAplots) { if (mctrack2.pdgCode() == PDG_t::kPiPlus) { // pion hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } if (mctrack2.pdgCode() == PDG_t::kKPlus) { // kaon hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); - hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.pt()); hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_p"), track2.tpcNSigmaKa(), centrality, track2.p()); - hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_p"), track2.tofNSigmaKa(), centrality, track2.p()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_p"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.p()); } if (mctrack2.pdgCode() == PDG_t::kPiMinus) { // negative track pion hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } if (mctrack2.pdgCode() == PDG_t::kKMinus) { // negative track kaon hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); - hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.pt()); hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_p"), track2.tpcNSigmaKa(), centrality, track2.p()); - hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_p"), track2.tofNSigmaKa(), centrality, track2.p()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_p"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.p()); } if (std::abs(mctrack1.pdgCode()) == PDG_t::kKPlus && std::abs(mctrack2.pdgCode()) == PDG_t::kPiPlus) { - hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); - hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), track2.tofNSigmaPi(), track2.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), tofSigma(track1, PIDParticle::kKaon), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), tofSigma(track2, PIDParticle::kPion), track2.pt()); } } @@ -1915,24 +1961,24 @@ struct Kstar892LightIon { if (cQAplots) { if (track1.sign() < 0 && track2.sign() > 0) { hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), tofSigma(track1, PIDParticle::kPion), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_p"), track1.tpcNSigmaPi(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), track1.tofNSigmaPi(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), tofSigma(track1, PIDParticle::kPion), centrality, track1.p()); hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_p"), track2.tpcNSigmaKa(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), track2.tofNSigmaKa(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.p()); } else { hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), tofSigma(track1, PIDParticle::kPion), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_p"), track1.tpcNSigmaPi(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), track1.tofNSigmaPi(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), tofSigma(track1, PIDParticle::kPion), centrality, track1.p()); hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_p"), track2.tpcNSigmaKa(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), track2.tofNSigmaKa(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), tofSigma(track2, PIDParticle::kKaon), centrality, track2.p()); } if (track1.hasTOF()) { @@ -1961,24 +2007,24 @@ struct Kstar892LightIon { if (cQAplots) { if (track1.sign() < 0 && track2.sign() > 0) { hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } else { hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.pt()); hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), tofSigma(track2, PIDParticle::kPion), centrality, track2.pt()); hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_p"), track1.tpcNSigmaKa(), centrality, track1.p()); - hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), track1.tofNSigmaKa(), centrality, track1.p()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_p"), tofSigma(track1, PIDParticle::kKaon), centrality, track1.p()); hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_p"), track2.tpcNSigmaPi(), centrality, track2.p()); - hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), track2.tofNSigmaPi(), centrality, track2.p()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_p"), tofSigma(track2, PIDParticle::kPion), centrality, track2.p()); } if (track1.hasTOF()) { @@ -3248,8 +3294,8 @@ struct Kstar892LightIon { } hMC.fill(HIST("KinematicsMisId/hTrueKstar_PtDeltaRMass"), ptPair, dR, mass); hMC.fill(HIST("KinematicsMisId/hTrueKstar_PtCentMass"), ptPair, centrality, mass); - } else if (isFakeKaon || isFakePion) { // Correct identification but from a different mother - if (hasCommonMother) { + } else if (isFakeKaon || isFakePion) { // Incorrect identification + if (hasCommonMother) { // From same mother if (commonMotherPDG == o2::constants::physics::kOmega) { // Omega reflection if (additionalKin) { hMC.fill(HIST("KinematicsMisId/hOmega_PtOpenAngleMass"), ptPair, openAngle, mass); @@ -3310,8 +3356,40 @@ struct Kstar892LightIon { } hMC.fill(HIST("KinematicsMisId/hKstarMisId_PtDeltaRMass"), ptPair, dR, mass); hMC.fill(HIST("KinematicsMisId/hKstarMisId_PtCentMass"), ptPair, centrality, mass); + } else if (commonMotherPDG == PDG_t::kK0Short) { // K0s reflection + if (additionalKin) { + hMC.fill(HIST("KinematicsMisId/hK0s_PtOpenAngleMass"), ptPair, openAngle, mass); + hMC.fill(HIST("KinematicsMisId/hK0s_PtDeltaPhiMass"), ptPair, dPhi, mass); + hMC.fill(HIST("KinematicsMisId/hK0s_PtDeltaEtaMass"), ptPair, dEta, mass); + hMC.fill(HIST("KinematicsMisId/hK0s_PtKaonPtMass"), ptPair, ptK, mass); + hMC.fill(HIST("KinematicsMisId/hK0s_PtPionPtMass"), ptPair, ptPi, mass); + } + hMC.fill(HIST("KinematicsMisId/hK0s_PtDeltaRMass"), ptPair, dR, mass); + hMC.fill(HIST("KinematicsMisId/hK0s_PtCentMass"), ptPair, centrality, mass); + } else if (commonMotherPDG == PDG_t::kLambda0) { // Lambda reflection + if (additionalKin) { + hMC.fill(HIST("KinematicsMisId/hLambda_PtOpenAngleMass"), ptPair, openAngle, mass); + hMC.fill(HIST("KinematicsMisId/hLambda_PtDeltaPhiMass"), ptPair, dPhi, mass); + hMC.fill(HIST("KinematicsMisId/hLambda_PtDeltaEtaMass"), ptPair, dEta, mass); + hMC.fill(HIST("KinematicsMisId/hLambda_PtKaonPtMass"), ptPair, ptK, mass); + hMC.fill(HIST("KinematicsMisId/hLambda_PtPionPtMass"), ptPair, ptPi, mass); + } + hMC.fill(HIST("KinematicsMisId/hLambda_PtDeltaRMass"), ptPair, dR, mass); + hMC.fill(HIST("KinematicsMisId/hLambda_PtCentMass"), ptPair, centrality, mass); + } else { // All other reflections + hMC.fill(HIST("KinematicsMisId/hUnknownMisIdMotherPDG"), commonMotherPDG); + + if (additionalKin) { + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtOpenAngleMass"), ptPair, openAngle, mass); + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtDeltaPhiMass"), ptPair, dPhi, mass); + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtDeltaEtaMass"), ptPair, dEta, mass); + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtKaonPtMass"), ptPair, ptK, mass); + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtPionPtMass"), ptPair, ptPi, mass); + } + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtDeltaRMass"), ptPair, dR, mass); + hMC.fill(HIST("KinematicsMisId/hOtherMother_PtCentMass"), ptPair, centrality, mass); } - } else { // Correct indentification but no common mother + } else { // Incorrect identification but no common mother if (additionalKin) { hMC.fill(HIST("KinematicsMisId/hOtherMisId_PtOpenAngleMass"), ptPair, openAngle, mass); hMC.fill(HIST("KinematicsMisId/hOtherMisId_PtDeltaPhiMass"), ptPair, dPhi, mass); diff --git a/PWGLF/Tasks/Resonances/kstarInOO.cxx b/PWGLF/Tasks/Resonances/kstarInOO.cxx index b2840dca788..0a3e99db80c 100644 --- a/PWGLF/Tasks/Resonances/kstarInOO.cxx +++ b/PWGLF/Tasks/Resonances/kstarInOO.cxx @@ -75,9 +75,6 @@ struct kstarInOO { Configurable cfgEventVtxCut{"cfgEventVtxCut", 10.0, "V_z cut selection"}; Configurable cfgEventMaxEta{"cfgEventMaxEta", 1.0, "set INEL event eta cut"}; ConfigurableAxis cfgCentAxis{"cfgCentAxis", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}, "Binning of the centrality axis"}; - Configurable cfgOccupancySel{"cfgOccupancySel", false, "Occupancy selection"}; - Configurable cfgOccupancyMax{"cfgOccupancyMax", 999999., "maximum occupancy of tracks in neighbouring collisions in a given time range"}; - Configurable cfgOccupancyMin{"cfgOccupancyMin", -100., "minimum occupancy of tracks in neighbouring collisions in a given time range"}; // Track Selection // General @@ -106,9 +103,12 @@ struct kstarInOO { Configurable cfgTrackCirclePIDCut{"cfgTrackCirclePIDCut", true, "Enables PID cut shape circle switch"}; Configurable cfgTrackCircleValue{"cfgTrackCircleValue", 2, "Enables TOF TPC PID circle cut value"}; Configurable cfgTrackTOFHard{"cfgTrackTOFHard", false, "Enables TOF Hard"}; + Configurable isMIDCut{"isMIDCut", false, "Enables Mis-IDentified PID cut"}; Configurable cfgTrackTPCPIDnSig{"cfgTrackTPCPIDnSig", 4.0, "nTPC PID sigma"}; Configurable cfgTrackTOFPIDnSig{"cfgTrackTOFPIDnSig", 4.0, "nTOF PID sigma"}; + Configurable cfgMIDnSig{"cfgMIDnSig", 1.5, "nTPC Mis-IDentification Particle sigma"}; + Configurable cDebugLevel{"cDebugLevel", 0, "Resolution of Debug"}; // Mixing @@ -133,9 +133,8 @@ struct kstarInOO { Configurable cfgEventCutQA{"cfgEventCutsQA", false, "Enable Event QA Hists"}; Configurable cfgTrackCutQA{"cfgTrackCutQA", false, "Enable Track QA Hists"}; Configurable cfgJetQAHistos{"cfgJetQAHistos", false, "Enable Jet QA Histos"}; - Configurable cfgWoJetQA{"cfgWoJetQA", false, "Enable Without Jet QA Histos"}; - Configurable cfgMCHistos{"cfgMCHistos", false, "Enable MC Hists"}; + Configurable cfgMCHistos{"cfgMCHistos", false, "Enable MC Histos"}; Configurable cfgMixedHistos{"cfgMixedHistos", false, "Enable Mixed Histos"}; Configurable cfgJetHistos{"cfgJetHistos", false, "Enable Jet Histos"}; Configurable cfgJetMCHistos{"cfgJetMCHistos", false, "Enable Jet MC Histos"}; @@ -160,9 +159,6 @@ struct kstarInOO { Configurable cfgTriggerMasksTest3{"cfgTriggerMasksTest3", "", "possible JE Trigger masks Test3"}; Configurable cfgForceTrueINELgt{"cfgForceTrueINELgt", true, "Check generated event with True INELgt0"}; - Configurable cfgIsKstar{"cfgIsKstar", false, "Swaps Phi for Kstar analysis"}; - Configurable cfgBR{"cfgBR", false, "Forces Gen. Charged BR Only"}; - std::vector eventSelectionBits; std::vector RealTriggerMaskBits; std::vector triggerMaskBitsTest1; @@ -199,7 +195,6 @@ struct kstarInOO { "kNoITSROFrameBorder", "kNoCollInTimeRangeStandard", "kIsGoodITSLayersAll", - Form("Occupancy < %.0f", cfgOccupancyMax.value), "All passed events"}; for (size_t i = 0; i < eventCutLabels.size(); ++i) { hCutFlow->GetXaxis()->SetBinLabel(i + 1, eventCutLabels[i].c_str()); @@ -224,6 +219,9 @@ struct kstarInOO { histos.add("QA_kaon_TPC_TOF_BC", "QA_kaon_TPC_TOF_BC", {HistType::kTH2F, {pidAxis, pidAxis}}); histos.add("QA_track_pT_BC", "QA_track_pT_BC", kTH1F, {{13, 0.0, 13.0}}); + histos.add("Possible_MID_Pion_TPC", "Possible_MID_Pion_TPC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("Possible_MID_Kaon_TPC", "Possible_MID_Kaon_TPC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("hDCArToPv_AC", "DCArToPv_AC", kTH1F, {axisDCAxy}); histos.add("hDCAzToPv_AC", "DCAzToPv_AC", kTH1F, {axisDCAz}); histos.add("hIsPrim_AC", "hIsPrim_AC", kTH1F, {{2, -0.5, 1.5}}); @@ -252,8 +250,6 @@ struct kstarInOO { histos.add("nGoodJets", "The number of good jets", kTH1F, {{6, -0.5, 5.5}}); histos.add("nJetsPerEvent", "The number of jet per event", kTH1F, {{6, -0.5, 5.5}}); - histos.add("rawDimpT", "rawDimpT", kTH2F, {{1000, 0.0, 10.0}, {100, -0.5, 0.5}}); - histos.add("jetTrackEta", "Jet Track Eta", kTH1F, {{100, -1.0, 1.0}}); histos.add("jetTrackPhi", "Jet Track Phi", kTH1F, {{80, -1.0, 7.0}}); } @@ -262,14 +258,28 @@ struct kstarInOO { histos.add("mcpjet_eta", "MC particle-level Jet Eta", kTH1F, {{100, -1.0, 1.0}}); histos.add("mcpjet_phi", "MC particle-level Jet Phi", kTH1F, {{80, -1.0, 7.0}}); - histos.add("Gen_particle_All_BR", "Generated particle All pT (GeV/c)", kTH1F, {{2000, 0., 100.}}); - histos.add("Gen_particle_BR", "Gen_particle_BR", kTH1F, {minvAxis}); - histos.add("Gen_particle_pT", "Generated particle pT (GeV/c)", kTH1F, {{2000, 0., 100.}}); + histos.add("nJet_6_8", "MC particle-level nJet pT 6 < jet pT < 8 (GeV/c)", kTH1F, {{2000, 0., 100.}}); + + histos.add("Gen_KstarPt_All_BR", "Generated K*0 All pT (GeV/c)", kTH1F, {{2000, 0., 100.}}); + histos.add("Gen_Kstar_BR", "Generated K*0 BR", kTH1F, {minvAxis}); + histos.add("Gen_KstarPt_BR", "Generated K*0 pT (GeV/c)", kTH1F, {{2000, 0., 100.}}); - histos.add("dR_taggedjet_kaon", "dR between tagged jet and kaon wo pT cut", {HistType::kTH2F, {{60, 0., 1.5}, {100, 0., 20.}}}); - histos.add("dR_taggedjet_pion", "dR between tagged jet and pion wo pT cut", {HistType::kTH2F, {{60, 0., 1.5}, {100, 0., 20.}}}); - histos.add("dR_taggedjet_all", "dR between tagged jet and kpi", {HistType::kTH2F, {{60, 0., 1.5}, {100, 0., 20.}}}); - histos.add("dR_taggedjet_all_6_8", "dR between tagged jet and kpi 6 < jet pT < 8", {HistType::kTH2F, {{60, 0., 1.5}, {100, 0., 20.}}}); + histos.add("dR_taggedjet_kaon", "dR between tagged jet and kaon wo pT cut", {HistType::kTH2F, {{100, 0., 3.0}, {150, 0., 30.}}}); + histos.add("dR_taggedjet_pion", "dR between tagged jet and pion wo pT cut", {HistType::kTH2F, {{100, 0., 3.0}, {150, 0., 30.}}}); + histos.add("dR_taggedjet_all", "dR between tagged jet and kpi", {HistType::kTH2F, {{100, 0., 3.0}, {150, 0., 30.}}}); + histos.add("dR_taggedjet_all_6_8", "dR between tagged jet and kpi 6 < jet pT < 8", {HistType::kTH2F, {{100, 0., 3.0}, {150, 0., 30.}}}); + + histos.add("dR_kstar_pion", "dR between kstar and pion", {HistType::kTH2F, {{100, 0., 3.0}, {150, 0., 30.}}}); + histos.add("dR_kstar_kaon", "dR between kstar and kaon", {HistType::kTH2F, {{100, 0., 3.0}, {150, 0., 30.}}}); + + histos.add("Kstar_pT_INJet_6_8", "K*0 pT Inside 6-8 Jet", kTH1F, {{1000, 0., 50.}}); + histos.add("Kstar_pT_INJet_8_10", "K*0 pT Inside 8-10 Jet", kTH1F, {{1000, 0., 50.}}); + histos.add("Kstar_pT_INJet_10_12", "K*0 pT Inside 10-12 Jet", kTH1F, {{1000, 0., 50.}}); + + histos.add("JetpT_8to", "Jet pT 8 to", kTH1F, {{2000, 0., 100.}}); + histos.add("recoveredJetpT_6_8to8", "Recovered Jet pT 6-8 --> 8", kTH1F, {{2000, 0., 100.}}); + histos.add("Kstar_pT_6_8to8_IN_recoveredJet", "K*0 pT In recovered Jet pT 6-8 --> 8", kTH1F, {{1000, 0., 50.}}); + histos.add("Kstar_pT_6_8to8_10_IN_recoveredJet", "K*0 pT In recovered Jet pT 6-8 --> 8-10", kTH1F, {{1000, 0., 50.}}); histos.add("missed_kpi_INJets_6_8", "missed kpi In Jets with 6 < jetPt < 8", {HistType::kTH2F, {{120, 0.0, 1.2}, {100, 0., 20.}}}); histos.add("missed_kpi_INJets_8_10", "missed kpi In Jets with 8 < jetPt < 10", {HistType::kTH2F, {{120, 0.0, 1.2}, {100, 0., 20.}}}); @@ -279,22 +289,14 @@ struct kstarInOO { histos.add("missed_kpi_INJets_25_infinite", "missed kpi In Jets with 25 < jetPt < infinite", {HistType::kTH2F, {{120, 0.0, 1.2}, {100, 0., 20.}}}); histos.add("missed_kpi_INJets_8_infinite", "missed kpi In Jets with 8 < jetPt < infinite", {HistType::kTH2F, {{120, 0.0, 1.2}, {100, 0., 20.}}}); - histos.add("recoveredJetpT_6_8to8_10", "recovered Jet pT", kTH1F, {{2000, 0., 100.}}); - histos.add("recoveredJetpT_6_8to8_10_kstarSpectra", "Kstar pT within the recovered Jet pT", kTH1F, {{2000, 0., 100.}}); - - histos.add("normalJetpT_8_kstarSpectra", "kstar pT in Jet > 8GeV/c", kTH1F, {{2000, 0., 100.}}); - histos.add("normalJetpT_6_8_kstarSpectra", "6 GeV/c < kstar pT in Jet < 8 GeV/c", kTH1F, {{2000, 0., 100.}}); - histos.add("normalJetpT_8_10_kstarSpectra", "8 GeV/c < kstar pT in Jet < 10 GeV/c", kTH1F, {{2000, 0., 100.}}); - histos.add("normalJetpT_10_12_kstarSpectra", "10 GeV/c < kstar pT in Jet < 12 GeV/c", kTH1F, {{2000, 0., 100.}}); - histos.add("JetMigration", "bin to bin migration", {HistType::kTH2F, {{150, 0.0, 15.0, "True jet pT (GeV/c)"}, {150, 0., 15., "Recovered jet pT (GeV/c)"}}}); } //////////////////////////////////// histos.add("nEvents", "nEvents", kTH1F, {{7, 0.0, 7.0}}); histos.add("hUSS_KPi", "hUSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); - histos.add("hUSS_PiK", "hUSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); histos.add("hLSS_KPi", "hLSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hUSS_PiK", "hUSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); histos.add("hLSS_PiK", "hLSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); if (cfgMixedHistos) { @@ -457,57 +459,50 @@ struct kstarInOO { } // pion pid Selection } // fill QA - enum class objectType { MB, + enum class objectType { Inclusive, Jets, - MBRecParticle, - JetsRecParticle }; + RecoParticle, + JetsRecoParticle }; template - void fillMinv(objectType type, const TrackType& trk1, const TrackType& trk2, const ROOT::Math::PxPyPzMVector& lReso, double centrality, double jetpt, bool IsMix, bool flip) + void fillMinv(objectType type, const TrackType& trk1, const TrackType& trk2, const ROOT::Math::PxPyPzMVector& lReso, double centrality, double jetpt, bool flip) { double conjugate = trk1.sign() * trk2.sign(); switch (type) { - case objectType::MB: - if (IsMix && cfgMixedHistos) { - if (conjugate < 0) { - if (!flip) - histos.fill(HIST("hUSS_KPi_Mix"), centrality, lReso.Pt(), lReso.M()); - else - histos.fill(HIST("hUSS_PiK_Mix"), centrality, lReso.Pt(), lReso.M()); + case objectType::Inclusive: + if (conjugate < 0) { + if (!flip) { + histos.fill(HIST("hUSS_KPi"), centrality, lReso.Pt(), lReso.M()); + } else { + histos.fill(HIST("hUSS_PiK"), centrality, lReso.Pt(), lReso.M()); } - } else { - if (conjugate < 0) { - if (!flip) - histos.fill(HIST("hUSS_KPi"), centrality, lReso.Pt(), lReso.M()); - else - histos.fill(HIST("hUSS_PiK"), centrality, lReso.Pt(), lReso.M()); - } else if (conjugate > 0) { - if (!flip) - histos.fill(HIST("hLSS_KPi"), centrality, lReso.Pt(), lReso.M()); - else - histos.fill(HIST("hLSS_PiK"), centrality, lReso.Pt(), lReso.M()); + } else if (conjugate > 0) { + if (!flip) { + histos.fill(HIST("hLSS_KPi"), centrality, lReso.Pt(), lReso.M()); + } else { + histos.fill(HIST("hLSS_PiK"), centrality, lReso.Pt(), lReso.M()); } } break; case objectType::Jets: - if (!IsMix && cfgJetHistos) { + if (cfgJetHistos) { if (conjugate < 0) { - if (!flip) + if (!flip) { histos.fill(HIST("hUSS_KPi_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); - else + } else { histos.fill(HIST("hUSS_PiK_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); - } else { - if (conjugate > 0) { - if (!flip) - histos.fill(HIST("hLSS_KPi_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); - else - histos.fill(HIST("hLSS_PiK_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); + } + } else if (conjugate > 0) { + if (!flip) { + histos.fill(HIST("hLSS_KPi_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); + } else { + histos.fill(HIST("hLSS_PiK_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); } } } break; - case objectType::MBRecParticle: + case objectType::RecoParticle: if (cfgMCHistos) { if (conjugate < 0) { histos.fill(HIST("hUSS_TrueRec"), centrality, lReso.Pt(), lReso.M()); @@ -515,7 +510,7 @@ struct kstarInOO { } break; - case objectType::JetsRecParticle: + case objectType::JetsRecoParticle: if (cfgJetMCHistos) { if (conjugate < 0) { histos.fill(HIST("hUSS_TrueRec_INSIDE"), centrality, jetpt, lReso.Pt(), lReso.M()); @@ -527,68 +522,71 @@ struct kstarInOO { //====================================================================== template - std::pair eventSelection(const EventType event, const bool QA) + std::pair eventSelection(const EventType& event, const bool QA) { if (cfgEventCutQA && QA) { fillQA(false, event, 1); histos.fill(HIST("hEvent_Cut"), 0); } - if (!event.sel8()) + if (!event.sel8()) { return {false, 1}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 1); } - if (std::abs(event.posZ()) > cfgEventVtxCut) + if (std::abs(event.posZ()) > cfgEventVtxCut) { return {false, 2}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 2); } - if (!event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + if (!event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return {false, 3}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 3); } - if (!event.selection_bit(aod::evsel::kNoSameBunchPileup)) + if (!event.selection_bit(aod::evsel::kNoSameBunchPileup)) { return {false, 4}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 4); } - if (!event.selection_bit(aod::evsel::kNoTimeFrameBorder)) + if (!event.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return {false, 5}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 5); } - if (!event.selection_bit(aod::evsel::kNoITSROFrameBorder)) + if (!event.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return {false, 6}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 6); } - if (!event.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) + if (!event.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) { return {false, 7}; + } if (cfgEventCutQA && QA) { histos.fill(HIST("hEvent_Cut"), 7); } - if (!event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + if (!event.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { return {false, 8}; - if (cfgEventCutQA && QA) { - histos.fill(HIST("hEvent_Cut"), 8); } - if (cfgOccupancySel && (event.trackOccupancyInTimeRange() > cfgOccupancyMax || event.trackOccupancyInTimeRange() < cfgOccupancyMin)) - return {false, 9}; if (cfgEventCutQA && QA) { - histos.fill(HIST("hEvent_Cut"), 9); + histos.fill(HIST("hEvent_Cut"), 8); } if (cfgEventCutQA && QA) { fillQA(true, event, 1); - histos.fill(HIST("hEvent_Cut"), 10); + histos.fill(HIST("hEvent_Cut"), 9); } - return {true, 11}; + return {true, 10}; }; template - std::pair JetEventSelection(const EventType event, const bool QA) + std::pair JetEventSelection(const EventType& event, const bool QA) { if (cfgEventCutQA && QA) { fillQA(false, event, 1); @@ -597,8 +595,9 @@ struct kstarInOO { if (!jetderiveddatautilities::selectCollision(event, eventSelectionBits)) { // sel8 return {false, 1}; } - if (std::abs(event.posZ()) > cfgEventVtxCut) + if (std::abs(event.posZ()) > cfgEventVtxCut) { return {false, 2}; + } if (cfgEventCutQA && QA) { fillQA(true, event, 1); @@ -607,38 +606,51 @@ struct kstarInOO { }; template - bool trackSelection(const TracksType track, const bool QA) + bool trackSelection(const TracksType& track, const bool QA) { if (cfgTrackCutQA && QA) { fillQA(false, track, 2); } - if (cfgTrackGlobalSel && !track.isGlobalTrack()) + if (cfgTrackGlobalSel && !track.isGlobalTrack()) { return false; - if (track.pt() < cfgTrackMinPt) + } + if (track.pt() < cfgTrackMinPt) { return false; - if (std::abs(track.eta()) > cfgTrackMaxEta) + } + if (std::abs(track.eta()) > cfgTrackMaxEta) { return false; - if (std::abs(track.dcaXY()) > cfgTrackMaxDCArToPVcut) + } + if (std::abs(track.dcaXY()) > cfgTrackMaxDCArToPVcut) { return false; - if (std::abs(track.dcaZ()) > cfgTrackMaxDCAzToPVcut) + } + if (std::abs(track.dcaZ()) > cfgTrackMaxDCAzToPVcut) { return false; - if (cfgTrackPrimaryTrack && !track.isPrimaryTrack()) + } + if (cfgTrackPrimaryTrack && !track.isPrimaryTrack()) { return false; - if (cfgTrackGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + } + if (cfgTrackGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { return false; - if (cfgTrackFindableTPCClusters > 0 && track.tpcNClsFindable() < cfgTrackFindableTPCClusters) + } + if (cfgTrackFindableTPCClusters > 0 && track.tpcNClsFindable() < cfgTrackFindableTPCClusters) { return false; - if (track.tpcNClsCrossedRows() < cfgTrackTPCCrossedRows) + } + if (track.tpcNClsCrossedRows() < cfgTrackTPCCrossedRows) { return false; - if (cfgTrackRowsOverFindable > 0 && track.tpcCrossedRowsOverFindableCls() > cfgTrackRowsOverFindable) + } + if (cfgTrackRowsOverFindable > 0 && track.tpcCrossedRowsOverFindableCls() > cfgTrackRowsOverFindable) { return false; - if (track.tpcChi2NCl() > cfgTrackTPCChi2) + } + if (track.tpcChi2NCl() > cfgTrackTPCChi2) { return false; - if (track.itsChi2NCl() > cfgTrackITSChi2) + } + if (track.itsChi2NCl() > cfgTrackITSChi2) { return false; - if (cfgTrackConnectedToPV && !track.isPVContributor()) + } + if (cfgTrackConnectedToPV && !track.isPVContributor()) { return false; + } if (cfgTrackCutQA && QA) { fillQA(true, track, 2); @@ -646,6 +658,24 @@ struct kstarInOO { return true; }; + template + bool isMIDPion(const TrackPID& candidate, const bool QA) + { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("Possible_MID_Pion_TPC"), candidate.tpcNSigmaKa(), candidate.tofNSigmaKa()); + } + return std::abs(candidate.tpcNSigmaKa()) < cfgMIDnSig && std::abs(candidate.tpcNSigmaPi()) < cfgMIDnSig; + } + + template + bool isMIDKaon(const TrackPID& candidate, const bool QA) + { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("Possible_MID_Kaon_TPC"), candidate.tpcNSigmaPi(), candidate.tofNSigmaPi()); + } + return std::abs(candidate.tpcNSigmaPi()) < cfgMIDnSig && std::abs(candidate.tpcNSigmaKa()) < cfgMIDnSig; + } + template bool trackPIDKaon(const TrackPID& candidate, const bool QA) { @@ -659,23 +689,27 @@ struct kstarInOO { // TPC if (cfgTrackSquarePIDCut) { - if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) + if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) { tpcPIDPassed = true; - if (candidate.hasTOF()) { - if (std::abs(candidate.tofNSigmaKa()) < cfgTrackTOFPIDnSig) { - tofPIDPassed = true; - } - } else { - if (!cfgTrackTOFHard) { - tofPIDPassed = true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < cfgTrackTOFPIDnSig) { + tofPIDPassed = true; + } } else { - tofPIDPassed = false; + if (!cfgTrackTOFHard) { + tofPIDPassed = true; + } else { + tofPIDPassed = false; + } } - } + } // TPCPID cut } // end of square cut + if (cfgTrackCirclePIDCut) { - if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) + if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) { tpcpid = std::abs(candidate.tpcNSigmaKa()); + } tofpid = 0; if (candidate.hasTOF()) { @@ -693,9 +727,8 @@ struct kstarInOO { // TPC & TOF if (tpcPIDPassed && tofPIDPassed) { - if (cfgTrackCutQA && QA) { - fillQA(true, candidate, 3); - } + // if (cfgTrackCutQA && QA) + // fillQA(true, candidate, 3); return true; } return false; @@ -714,23 +747,28 @@ struct kstarInOO { // TPC if (cfgTrackSquarePIDCut) { - if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) + if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) { tpcPIDPassed = true; - if (candidate.hasTOF()) { - if (std::abs(candidate.tofNSigmaPi()) < cfgTrackTOFPIDnSig) { - tofPIDPassed = true; - } - } else { - if (!cfgTrackTOFHard) { - tofPIDPassed = true; + + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cfgTrackTOFPIDnSig) { + tofPIDPassed = true; + } } else { - tofPIDPassed = false; + if (!cfgTrackTOFHard) { + tofPIDPassed = true; + } else { + tofPIDPassed = false; + } } - } + } // TPCPID cut + } // end of square cut + if (cfgTrackCirclePIDCut) { - if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) + if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) { tpcpid = std::abs(candidate.tpcNSigmaPi()); + } tofpid = 0; if (candidate.hasTOF()) { @@ -748,9 +786,8 @@ struct kstarInOO { // TPC & TOF if (tpcPIDPassed && tofPIDPassed) { - if (cfgTrackCutQA && QA) { - fillQA(true, candidate, 4); - } + // if (cfgTrackCutQA && QA) + // fillQA(true, candidate, 4); return true; } return false; @@ -759,12 +796,27 @@ struct kstarInOO { template ROOT::Math::PxPyPzMVector minvReconstruction(const TracksType& trk1, const TracksType& trk2, const bool QA, const bool flip) { - if (!trackSelection(trk1, false) || !trackSelection(trk2, false)) + if (!trackSelection(trk1, false) || !trackSelection(trk2, false)) { return {}; - if (!trackPIDKaon(trk1, QA) || !trackPIDPion(trk2, QA)) + } + if (!trackPIDKaon(trk1, QA) || !trackPIDPion(trk2, QA)) { return {}; - if (trk1.globalIndex() >= trk2.globalIndex()) + } + if (trk1.globalIndex() >= trk2.globalIndex()) { + return {}; + } + + if (isMIDCut && isMIDPion(trk1, QA)) { return {}; + } + if (isMIDCut && isMIDKaon(trk2, QA)) { + return {}; + } + + if (cfgTrackCutQA && QA) { + fillQA(true, trk1, 3); + fillQA(true, trk2, 4); + } ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; if (!flip) { @@ -776,8 +828,9 @@ struct kstarInOO { } lResonance = lDecayDaughter1 + lDecayDaughter2; - if (std::abs(lResonance.Eta()) > cfgTrackMaxEta) + if (std::abs(lResonance.Eta()) > cfgTrackMaxEta) { return {}; + } return {lResonance}; } // minvReconstruction @@ -786,8 +839,9 @@ struct kstarInOO { ROOT::Math::PxPyPzMVector TrueReconstruction(const TracksType& trk1, const TracksType& trk2) { double conjugate = trk1.sign() * trk2.sign(); - if (conjugate > 0) + if (conjugate > 0) { return {}; + } auto particle1 = trk1.mcParticle(); auto particle2 = trk2.mcParticle(); @@ -813,17 +867,21 @@ struct kstarInOO { mothers2PDG.push_back(particle2_mom.pdgCode()); } - if (mothers1PDG[0] != Kstar0PDG) + if (mothers1PDG[0] != Kstar0PDG) { return {}; // mother not K*0 - if (mothers2PDG[0] != Kstar0PDG) + } + if (mothers2PDG[0] != Kstar0PDG) { return {}; // mothers not K*0 - if (mothers1[0] != mothers2[0]) + } + if (mothers1[0] != mothers2[0]) { return {}; // Kaon and pion not from the same K*0 - - if (std::abs(particle1.pdgCode()) != PionPDG && std::abs(particle1.pdgCode()) != KaonPDG) + } + if (std::abs(particle1.pdgCode()) != PionPDG && std::abs(particle1.pdgCode()) != KaonPDG) { return {}; - if (std::abs(particle2.pdgCode()) != PionPDG && std::abs(particle2.pdgCode()) != KaonPDG) + } + if (std::abs(particle2.pdgCode()) != PionPDG && std::abs(particle2.pdgCode()) != KaonPDG) { return {}; + } double track1_mass, track2_mass; if (std::abs(particle1.pdgCode()) == PionPDG) { @@ -847,16 +905,18 @@ struct kstarInOO { lTrueDaughter2 = ROOT::Math::PxPyPzMVector(particle2.px(), particle2.py(), particle2.pz(), track2_mass); lTrueReso = lTrueDaughter1 + lTrueDaughter2; - if (lTrueReso.M() < 0) + if (lTrueReso.M() < 0) { return {}; - if (std::abs(lTrueReso.Eta()) > cfgTrackMaxEta) + } + if (std::abs(lTrueReso.Eta()) > cfgTrackMaxEta) { return {}; + } return {lTrueReso}; } // TrueReconstruction template - void TrackSlicing(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool IsMix, const bool QA) + void TrackSlicing(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool QA) { auto tracks1 = kaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto tracks2 = pion->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); @@ -865,46 +925,49 @@ struct kstarInOO { for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { for (bool flip : {false, true}) { auto lReso = minvReconstruction(trk1, trk2, QA, flip); - if (lReso.M() < 0) + if (lReso.M() < 0) { continue; + } - fillMinv(objectType::MB, trk1, trk2, lReso, centrality, -1.0, IsMix, flip); + fillMinv(objectType::Inclusive, trk1, trk2, lReso, centrality, -1.0, flip); } // flip } // for } // TrackSlicing template - void TrackSlicingMC(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool IsMix, const bool QA) + void TrackSlicingMC(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool QA) { auto tracks1 = kaonMC->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); auto tracks2 = pionMC->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); auto centrality = collision1.centFT0C(); for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) + if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) { continue; + } for (bool flip : {false, true}) { auto lReso = minvReconstruction(trk1, trk2, QA, flip); - if (lReso.M() < 0) + if (lReso.M() < 0) { continue; - - fillMinv(objectType::MB, trk1, trk2, lReso, centrality, -1.0, IsMix, flip); + } + fillMinv(objectType::Inclusive, trk1, trk2, lReso, centrality, -1.0, flip); } // flip //============================ //| True Reconstruction //============================ auto lTrueReso = TrueReconstruction(trk1, trk2); - fillMinv(objectType::MBRecParticle, trk1, trk2, lTrueReso, centrality, -1.0, IsMix, false); + fillMinv(objectType::RecoParticle, trk1, trk2, lTrueReso, centrality, -1.0, false); } // tracks } // TrackSlicingMC template - double DistinguishJets(const JetType& jets, ROOT::Math::PxPyPzMVector lResonance) + double DistinguishJets(const JetType& jets, ROOT::Math::PxPyPzMVector& lResonance) { - if (cDebugLevel > 0) + if (cDebugLevel > 0) { LOG(info) << "Found multiple jets to the same phi."; + } double bestR = 0; double bestJetpT = 0; @@ -924,7 +987,7 @@ struct kstarInOO { } template - void JetTrackSlicing(aod::JetCollision const& collision, TracksType const& jetTracks, const JetType& chargedjets, const bool IsMix, const bool QA) + void JetTrackSlicing(aod::JetCollision const& collision, TracksType const& jetTracks, const JetType& chargedjets, const bool QA) { //============= //| Inclusive @@ -936,10 +999,11 @@ struct kstarInOO { for (bool flip : {false, true}) { auto lResonance = minvReconstruction(trk1, trk2, QA, flip); - if (lResonance.M() < 0) + if (lResonance.M() < 0) { continue; + } - fillMinv(objectType::MB, trk1, trk2, lResonance, centrality, -1.0, IsMix, flip); + fillMinv(objectType::Inclusive, trk1, trk2, lResonance, centrality, -1.0, flip); //======== //| Jets @@ -947,13 +1011,13 @@ struct kstarInOO { bool jetFlag = false; int goodjets = 0; double jetpt = 0; - double R = 0; + double dR = 0; for (auto const& jet : chargedjets) { - double phidiff = TVector2::Phi_mpi_pi(jet.phi() - lResonance.Phi()); - double etadiff = jet.eta() - lResonance.Eta(); - R = TMath::Sqrt((etadiff * etadiff) + (phidiff * phidiff)); + double dphi = TVector2::Phi_mpi_pi(jet.phi() - lResonance.Phi()); + double deta = jet.eta() - lResonance.Eta(); + dR = TMath::Sqrt((deta * deta) + (dphi * dphi)); - if (R < cfgJetR) { + if (dR < cfgJetR) { jetFlag = true; jetpt = jet.pt(); goodjets++; @@ -970,14 +1034,14 @@ struct kstarInOO { } if (jetFlag) { - fillMinv(objectType::Jets, trk1, trk2, lResonance, centrality, jetpt, IsMix, flip); + fillMinv(objectType::Jets, trk1, trk2, lResonance, centrality, jetpt, flip); } // jetFlag } // flip } // jetTracks } // JetTrackSlicing template - void JetTrackSlicingMC(aod::JetCollision const& collision, TracksType const& jetTracks, const JetType& mcdjets, const bool IsMix, const bool QA) + void JetTrackSlicingMC(aod::JetCollision const& collision, TracksType const& jetTracks, const JetType& mcdjets, const bool QA) { //============================ //| MB: Track Reconstruction @@ -987,15 +1051,17 @@ struct kstarInOO { auto trk1 = track1.template track_as(); auto trk2 = track2.template track_as(); - if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) + if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) { continue; + } for (bool flip : {false, true}) { auto lResonance = minvReconstruction(trk1, trk2, QA, flip); - if (lResonance.M() < 0) + if (lResonance.M() < 0) { continue; + } - fillMinv(objectType::MB, trk1, trk2, lResonance, centrality, -1.0, IsMix, flip); + fillMinv(objectType::Inclusive, trk1, trk2, lResonance, centrality, -1.0, flip); //============================== //| Jets: Track Reconstruction //============================== @@ -1022,7 +1088,7 @@ struct kstarInOO { } if (jetFlag) { - fillMinv(objectType::Jets, trk1, trk2, lResonance, centrality, jetpt, IsMix, flip); + fillMinv(objectType::Jets, trk1, trk2, lResonance, centrality, jetpt, flip); } // jetFlag } // filp } // Tracks loop @@ -1041,8 +1107,9 @@ struct kstarInOO { { if (cDebugLevel > 0) { nJetEvents++; - if ((nJetEvents + 1) % 10000 == 0) + if ((nJetEvents + 1) % 10000 == 0) { LOG(info) << "Processed Jet Data Events: " << nJetEvents; + } } histos.fill(HIST("nEvents"), 0.5); // Raw event @@ -1053,13 +1120,16 @@ struct kstarInOO { break; } } - if (!INELgt0) + if (!INELgt0) { return; + } histos.fill(HIST("nEvents"), 1.5); // INEL>0 event auto [goodEv, code] = JetEventSelection(collision, true); - if (!goodEv) + // auto [goodEv, code] = eventSelection(collision, true); + if (!goodEv) { return; + } histos.fill(HIST("nEvents"), 2.5); // After selection // Trigger before we start jet finding @@ -1097,32 +1167,29 @@ struct kstarInOO { } if (!RT) { return; - } else if (RT && (VTtest1 || VTtest2 || VTtest3)) { + } + if (VTtest1 || VTtest2 || VTtest3) { return; } } // Trigger cut histos.fill(HIST("nEvents"), 3.5); // After trigger cut - std::vector jetpT{}; - std::vector jetEta{}; - std::vector jetPhi{}; bool HasJets = false; int nJets = 0; for (auto chargedjet : chargedjets) { - if (std::abs(chargedjet.eta()) > cfgJetMaxEta - cfgJetdR) - return; + if (std::abs(chargedjet.eta()) > (cfgJetMaxEta - cfgJetdR)) { + continue; + } - jetpT.push_back(chargedjet.pt()); - jetEta.push_back(chargedjet.eta()); - jetPhi.push_back(chargedjet.phi()); nJets++; if (cfgJetQAHistos) { histos.fill(HIST("JetpT"), chargedjet.pt()); histos.fill(HIST("JetEta"), chargedjet.eta()); histos.fill(HIST("JetPhi"), chargedjet.phi()); } - if (chargedjet.pt() > cfgJetpT) + if (chargedjet.pt() > cfgJetpT) { HasJets = true; + } } if (cfgJetQAHistos) { histos.fill(HIST("nJetsPerEvent"), nJets); @@ -1132,24 +1199,26 @@ struct kstarInOO { //| Has Jets //==================== if (cfgReqJets) { - if (!HasJets) + if (!HasJets) { return; + } } histos.fill(HIST("nEvents"), 4.5); // Has jets + // Just for checking track QA plot for (auto& jetTrack : jetTracks) { auto originTrack = jetTrack.track_as(); - if (!trackSelection(originTrack, true)) + if (!trackSelection(originTrack, true)) { continue; + } if (cfgJetQAHistos) { - histos.fill(HIST("rawDimpT"), jetTrack.pt(), jetTrack.pt() - originTrack.pt()); histos.fill(HIST("jetTrackEta"), jetTrack.eta()); histos.fill(HIST("jetTrackPhi"), jetTrack.phi()); } } // jetTrack loop - JetTrackSlicing(collision, jetTracks, chargedjets, false, true); + JetTrackSlicing(collision, jetTracks, chargedjets, true); } // ProcessDataJets PROCESS_SWITCH(kstarInOO, processDataJets, "process Data Jets", false); @@ -1163,8 +1232,9 @@ struct kstarInOO { { if (cDebugLevel > 0) { nJetMCEvents++; - if ((nJetMCEvents + 1) % 10000 == 0) + if ((nJetMCEvents + 1) % 10000 == 0) { LOG(info) << "Processed Jet MC Events: " << nJetMCEvents; + } } histos.fill(HIST("nEvents"), 0.5); // Gen event @@ -1175,13 +1245,15 @@ struct kstarInOO { break; } } // jetTrack loop - if (!INELgt0) + if (!INELgt0) { return; + } histos.fill(HIST("nEvents"), 1.5); // INEL>0 event auto [goodEv, code] = JetEventSelection(collision, true); - if (!goodEv) + if (!goodEv) { return; + } histos.fill(HIST("nEvents"), 2.5); // Inclusive event // The trigger option doesn't work @@ -1189,19 +1261,13 @@ struct kstarInOO { // return; // histos.fill(HIST("nEvents"), 3.5); // Events for Inclusive - std::vector mcdjetpT{}; - std::vector mcdjetEta{}; - std::vector mcdjetPhi{}; - bool HasJets = false; int nJets = 0; for (auto mcdjet : mcdjets) { - if (std::abs(mcdjet.eta()) > cfgJetMaxEta - cfgJetdR) - return; + if (std::abs(mcdjet.eta()) > cfgJetMaxEta - cfgJetdR) { + continue; + } - mcdjetpT.push_back(mcdjet.pt()); - mcdjetEta.push_back(mcdjet.eta()); - mcdjetPhi.push_back(mcdjet.phi()); nJets++; if (cfgJetQAHistos) { histos.fill(HIST("JetpT"), mcdjet.pt()); @@ -1211,11 +1277,10 @@ struct kstarInOO { if (mcdjet.pt() > cfgJetpT) { HasJets = true; } - } + } // mcdjets if (cfgJetQAHistos) { histos.fill(HIST("nJetsPerEvent"), nJets); } - //==================== //| Has Jets //==================== @@ -1226,7 +1291,7 @@ struct kstarInOO { } histos.fill(HIST("nEvents"), 3.5); // Jet event - // JetTrackSlicingMC(collision, jetTracks, mcdjets, false, true); + // JetTrackSlicingMC(collision, jetTracks, mcdjets, true); // Instead of using "JetTrackSlicingMC", Once we have to test showing the distribution each condition for (auto& [track1, track2] : combinations(o2::soa::CombinationsUpperIndexPolicy(jetTracks, jetTracks))) { @@ -1243,17 +1308,18 @@ struct kstarInOO { histos.fill(HIST("hEffRecTest0_pT"), lResonanceTest1.Pt()); } - if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) + if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) { continue; + } if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest1_pT"), lResonanceTest1.Pt()); } - ////////////////////////////// ////////////////////////////// if (cfgReqMcEffTrackQA) { // false, true - if (!trackSelection(trk1, true) || !trackSelection(trk2, false)) + if (!trackSelection(trk1, true) || !trackSelection(trk2, false)) { continue; + } } ////////////////////////////// ////////////////////////////// @@ -1261,15 +1327,14 @@ struct kstarInOO { if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest2_pT"), lResonanceTest1.Pt()); } - if (cfgReqMcEffPID) { // false, true - if (!trackPIDKaon(trk1, true) || !trackPIDPion(trk2, true)) + if (!trackPIDKaon(trk1, true) || !trackPIDPion(trk2, true)) { continue; + } } if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest3_pT"), lResonanceTest1.Pt()); } - auto particle1 = trk1.mcParticle(); auto particle2 = trk2.mcParticle(); //////////////////////////////////////////////////////////////////////// @@ -1293,6 +1358,7 @@ struct kstarInOO { if (cfgJetMCHistos) { histos.fill(HIST("hMotherPdg1"), std::abs(mothers1PDG[0])); } + std::vector mothers2{}; std::vector mothers2PDG{}; for (auto& particle2_mom : particle2.template mothers_as()) { @@ -1302,30 +1368,30 @@ struct kstarInOO { if (cfgJetMCHistos) { histos.fill(HIST("hMotherPdg2"), std::abs(mothers2PDG[0])); } - - if (mothers1[0] != mothers2[0]) + if (mothers1[0] != mothers2[0]) { continue; // Kaon and pion not from the same K*0 - + } if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest5_pT"), lResonanceTest1.Pt()); } - - if (std::abs(particle1.pdgCode()) != KaonPDG) // kaon + // kaon + if (std::abs(particle1.pdgCode()) != KaonPDG) { continue; + } if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest6_pT"), lResonanceTest1.Pt()); } - - if (std::abs(particle2.pdgCode()) != PionPDG) // pion + // pion + if (std::abs(particle2.pdgCode()) != PionPDG) { continue; - + } if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest7_pT"), lResonanceTest1.Pt()); } - - if (std::abs(mothers1PDG[0]) != Kstar0PDG) + if (std::abs(mothers1PDG[0]) != Kstar0PDG) { continue; // mother not K*0 + } if (cfgJetMCHistos) { histos.fill(HIST("hEffRecTest8_pT"), lResonanceTest1.Pt()); if (lResonanceTest1.Pt() < 0.4) { @@ -1334,13 +1400,12 @@ struct kstarInOO { } } - if (std::abs(mothers2PDG[0]) != Kstar0PDG) + if (std::abs(mothers2PDG[0]) != Kstar0PDG) { continue; // mothers not K*0 - + } if (cfgJetMCHistos) { histos.fill(HIST("hEffRec_pT"), lResonanceTest1.Pt()); } - } // track loop } // process loop PROCESS_SWITCH(kstarInOO, processMCJets, "process MC Jets", false); @@ -1355,8 +1420,9 @@ struct kstarInOO { { if (cDebugLevel > 0) { nEvents++; - if ((nEvents + 1) % 10000 == 0) + if ((nEvents + 1) % 10000 == 0) { LOG(info) << "Processed Data Events: " << nEvents; + } } histos.fill(HIST("nEvents"), 0.5); @@ -1367,23 +1433,25 @@ struct kstarInOO { break; } } - if (!INELgt0) + if (!INELgt0) { return; + } histos.fill(HIST("nEvents"), 1.5); auto [goodEv, code] = eventSelection(collision, true); - if (!goodEv) + if (!goodEv) { return; + } histos.fill(HIST("nEvents"), 2.5); // for trackQA plot for (const auto& track : tracks) { - if (!trackSelection(track, true)) + if (!trackSelection(track, true)) { continue; + } } - TrackSlicing(collision, tracks, collision, tracks, false, true); - + TrackSlicing(collision, tracks, collision, tracks, true); } // processSameEvents PROCESS_SWITCH(kstarInOO, processDataSameEvent, "process Data Same Event", false); @@ -1401,27 +1469,33 @@ struct kstarInOO { for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { if (cDebugLevel > 0) { nEventsMix++; - if ((nEventsMix + 1) % 10000 == 0) + if ((nEventsMix + 1) % 10000 == 0) { LOG(info) << "Processed DATA Mixed Events : " << nEventsMix; + } } auto [goodEv1, code1] = eventSelection(collision1, false); auto [goodEv2, code2] = eventSelection(collision2, false); bool VtxMixFlag = false; bool CentMixFlag = false; // bool OccupanacyMixFlag = false; - if (std::abs(collision1.posZ() - collision2.posZ()) <= cfgVtxMixCut) // set default to maybe 10 + if (std::abs(collision1.posZ() - collision2.posZ()) <= cfgVtxMixCut) { // set default to maybe 10 VtxMixFlag = true; - if (std::abs(collision1.centFT0C() - collision2.centFT0C()) <= cfgVtxMixCut) // set default to maybe 10 + } + if (std::abs(collision1.centFT0C() - collision2.centFT0C()) <= cfgVtxMixCut) { // set default to maybe 10 CentMixFlag = true; + } - if (!goodEv1 || !goodEv2) + if (!goodEv1 || !goodEv2) { continue; - if (!CentMixFlag) + } + if (!CentMixFlag) { continue; - if (!VtxMixFlag) + } + if (!VtxMixFlag) { continue; + } - TrackSlicing(collision1, tracks1, collision2, tracks2, true, false); + TrackSlicing(collision1, tracks1, collision2, tracks2, false); } } PROCESS_SWITCH(kstarInOO, processDataMixedEvent, "process DATA Mixed Event", false); @@ -1451,22 +1525,25 @@ struct kstarInOO { break; } } - if (!INELgt0) + if (!INELgt0) { return; + } histos.fill(HIST("nEvents"), 1.5); auto [goodEv, code] = eventSelection(collision, true); // sel8 & vtx - if (!goodEv) + if (!goodEv) { return; + } histos.fill(HIST("nEvents"), 2.5); // for trackQA plot for (const auto& track : tracks) { - if (!trackSelection(track, true)) + if (!trackSelection(track, true)) { continue; + } } - TrackSlicingMC(collision, tracks, collision, tracks, false, true); + TrackSlicingMC(collision, tracks, collision, tracks, true); } // processSameEvents_MC PROCESS_SWITCH(kstarInOO, processSameEventMC, "process Same Event MC", false); @@ -1484,8 +1561,9 @@ struct kstarInOO { for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { if (cDebugLevel > 0) { nEventsMCMix++; - if ((nEventsMCMix + 1) % 10000 == 0) + if ((nEventsMCMix + 1) % 10000 == 0) { LOG(info) << "Processed Mixed Events: " << nEventsMCMix; + } } auto [goodEv1, code1] = eventSelection(collision1, false); auto [goodEv2, code2] = eventSelection(collision2, false); @@ -1493,7 +1571,7 @@ struct kstarInOO { continue; } - TrackSlicingMC(collision1, tracks1, collision2, tracks2, true, false); + TrackSlicingMC(collision1, tracks1, collision2, tracks2, false); } // mixing } // processMixedEvent_MC PROCESS_SWITCH(kstarInOO, processMixedEventMC, "process Mixed Event MC", false); @@ -1508,22 +1586,24 @@ struct kstarInOO { { if (cDebugLevel > 0) { ++nEventsGen; - if (nEventsGen % 10000 == 0) + if (nEventsGen % 10000 == 0) { LOG(info) << "Processed MC (GEN) Events: " << nEventsGen; + } } if (cfgMCHistos) { histos.fill(HIST("nEvents_Gen"), 0.5); // Gen events } - //======================= //| Event & Signal loss //======================= bool INELgt0 = false; for (auto& particle : mcParticles) { - if (std::abs(particle.eta()) > cfgEventMaxEta) + if (std::abs(particle.eta()) > cfgEventMaxEta) { continue; - if (particle.pt() <= 0.0) + } + if (particle.pt() <= 0.0) { continue; + } INELgt0 = true; break; } @@ -1535,15 +1615,17 @@ struct kstarInOO { if (cfgMCHistos) { histos.fill(HIST("nEvents_Gen"), 1.5); // INEL>0 Gen events & EL: denominator } - - if (std::abs(collision.posZ()) > cfgEventVtxCut) + if (std::abs(collision.posZ()) > cfgEventVtxCut) { return; + } for (auto& particle : mcParticles) { - if (std::abs(particle.pdgCode()) != Kstar0PDG) + if (std::abs(particle.pdgCode()) != Kstar0PDG) { continue; - if (std::abs(particle.eta()) > cfgTrackMaxEta) + } + if (std::abs(particle.eta()) > cfgTrackMaxEta) { continue; + } if (cfgMCHistos) { histos.fill(HIST("hGen_pT_Kstar"), particle.pt()); // SL: denominator @@ -1563,33 +1645,37 @@ struct kstarInOO { bool hasGoodEv = false; for (auto& recocoll : recocolls) { // poorly reconstructed auto [goodEv, code] = eventSelection(recocoll, true); - if (recocoll.posZ() > cfgEventVtxCut) + if (recocoll.posZ() > cfgEventVtxCut) { goodEv = false; - if (!goodEv) + } + if (!goodEv) { continue; + } hasGoodEv = true; centrality = recocoll.centFT0C(); break; } // recocolls - if (!hasGoodEv) + if (!hasGoodEv) { return; + } if (cfgMCHistos) { histos.fill(HIST("nEvents_Gen"), 2.5); // EL: numerator } - for (auto& particle : mcParticles) { - if (std::abs(particle.pdgCode()) != Kstar0PDG) + if (std::abs(particle.pdgCode()) != Kstar0PDG) { continue; // Not K*0 - if (std::abs(particle.eta()) > cfgTrackMaxEta) + } + if (std::abs(particle.eta()) > cfgTrackMaxEta) { continue; - if (particle.pt() < cfgTrackMinPt) + } + if (particle.pt() < cfgTrackMinPt) { continue; + } if (cfgMCHistos) { histos.fill(HIST("hRec_pT_Kstar"), centrality, particle.pt()); // SL: numerator // eff: denominator } - } // loop over particles } // processGen PROCESS_SWITCH(kstarInOO, processGen, "process Generated Particles", false); @@ -1604,8 +1690,9 @@ struct kstarInOO { { if (cDebugLevel > 0) { ++nprocessGenEvents; - if (nprocessGenEvents % 10000 == 0) + if (nprocessGenEvents % 10000 == 0) { LOG(info) << "Processed MC (GEN) Events: " << nprocessGenEvents; + } } if (cfgJetMCHistos) { histos.fill(HIST("nEvents_Gen"), 0.5); @@ -1615,10 +1702,12 @@ struct kstarInOO { //======================= bool INELgt0 = false; for (auto& particle : mcParticles) { - if (std::abs(particle.eta()) > cfgEventMaxEta) + if (std::abs(particle.eta()) > cfgEventMaxEta) { continue; - if (particle.pt() <= 0.0) + } + if (particle.pt() <= 0.0) { continue; + } INELgt0 = true; break; } @@ -1630,15 +1719,17 @@ struct kstarInOO { if (cfgJetMCHistos) { histos.fill(HIST("nEvents_Gen"), 1.5); // EL: denominator } - - if (std::abs(collision.posZ()) > cfgEventVtxCut) + if (std::abs(collision.posZ()) > cfgEventVtxCut) { return; + } for (auto& particle : mcParticles) { - if (std::abs(particle.pdgCode()) != Kstar0PDG) + if (std::abs(particle.pdgCode()) != Kstar0PDG) { continue; - if (std::abs(particle.eta()) > cfgTrackMaxEta) + } + if (std::abs(particle.eta()) > cfgTrackMaxEta) { continue; + } if (cfgJetMCHistos) { histos.fill(HIST("hGen_pT_Kstar"), particle.pt()); // SL: denominator @@ -1656,23 +1747,28 @@ struct kstarInOO { if (goodEv) { goodEv = jetderiveddatautilities::selectTrigger(recocoll, RealTriggerMaskBits); } - if (std::abs(recocoll.posZ()) > cfgEventVtxCut) + if (std::abs(recocoll.posZ()) > cfgEventVtxCut) { goodEv = false; + } - if (!goodEv) + if (!goodEv) { return; + } } // reco.coll if (cfgJetMCHistos) { histos.fill(HIST("nEvents_Gen"), 2.5); // EL: numerator } for (auto& particle : mcParticles) { - if (std::abs(particle.pdgCode()) != Kstar0PDG) + if (std::abs(particle.pdgCode()) != Kstar0PDG) { continue; - if (std::abs(particle.eta()) > cfgTrackMaxEta) + } + if (std::abs(particle.eta()) > cfgTrackMaxEta) { continue; - if (particle.pt() < cfgTrackMinPt) + } + if (particle.pt() < cfgTrackMinPt) { continue; + } /* // Not Yet if (cfg_Force_BR) { @@ -1698,7 +1794,6 @@ struct kstarInOO { if (cfgJetMCHistos) { histos.fill(HIST("hRec_pT_Kstar"), particle.pt()); // SL: numerator and eff: denominator } - } // loop over particles } // end of process PROCESS_SWITCH(kstarInOO, processGenJets, "Process Generated Particles Inclusive&Jets", false); @@ -1708,85 +1803,78 @@ struct kstarInOO { { if (cDebugLevel > 0) { ++ndRtest; - if (ndRtest % 10000 == 0) + if (ndRtest % 10000 == 0) { LOG(info) << "Processed dR test: " << ndRtest; + } } bool INELgt0 = false; for (auto& mcpjet : mcpjets) { - if (std::abs(mcpjet.eta()) > cfgEventMaxEta) + if (std::abs(mcpjet.eta()) > cfgEventMaxEta) { continue; - if (mcpjet.pt() <= 0.0) + } + if (mcpjet.pt() <= 0.0) { continue; + } INELgt0 = true; break; } // Selection event through mcpjet loop - if (!INELgt0) + if (!INELgt0) { return; - - if (std::abs(collision.posZ()) > cfgEventVtxCut) + } + if (std::abs(collision.posZ()) > cfgEventVtxCut) { return; + } histos.fill(HIST("nEvents"), 0.5); for (auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.eta()) > cfgTrackMaxEta) + if (std::abs(mcParticle.eta()) > cfgTrackMaxEta) { continue; - if (!mcParticle.has_daughters()) + } + if (!mcParticle.has_daughters()) { continue; - - ROOT::Math::PxPyPzEVector lResonance; - lResonance = ROOT::Math::PxPyPzEVector(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); - - int GenPID = 0; - if (!cfgIsKstar) - GenPID = 333; - else - GenPID = 313; - - if (std::abs(mcParticle.pdgCode()) != GenPID) + } + if (std::abs(mcParticle.pdgCode()) != Kstar0PDG) { continue; + } if (cfgJetdRHistos) { - histos.fill(HIST("Gen_particle_All_BR"), mcParticle.pt()); + histos.fill(HIST("Gen_KstarPt_All_BR"), mcParticle.pt()); } - + // 4vector: K*0 + ROOT::Math::PxPyPzEVector lResonance = ROOT::Math::PxPyPzEVector(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); bool skip = false; int daughter_kaon = 0; int daughter_pion = 0; - if (!cfgIsKstar) { - for (auto& daughter : mcParticle.daughters_as()) { - if (std::abs(daughter.pdgCode()) != KaonPDG) - skip = true; - } - } else { - for (auto& daughter : mcParticle.daughters_as()) { - if (std::abs(daughter.pdgCode()) == KaonPDG) - ++daughter_kaon; - else if (std::abs(daughter.pdgCode()) == PionPDG) - ++daughter_pion; + for (auto& daughter : mcParticle.daughters_as()) { + if (std::abs(daughter.pdgCode()) == KaonPDG) { + ++daughter_kaon; + } else if (std::abs(daughter.pdgCode()) == PionPDG) { + ++daughter_pion; } - if (daughter_kaon != 1 || daughter_pion != 1) - skip = true; - } // K*(892) - - if (skip && cfgBR) + } + if (daughter_kaon != 1 || daughter_pion != 1) { + skip = true; + } + if (skip) { continue; + } if (cfgJetdRHistos) { - histos.fill(HIST("Gen_particle_BR"), lResonance.M()); - histos.fill(HIST("Gen_particle_pT"), mcParticle.pt()); + histos.fill(HIST("Gen_Kstar_BR"), lResonance.M()); + histos.fill(HIST("Gen_KstarPt_BR"), mcParticle.pt()); } //================== // Distinguish Jets double bestR = 999; - double bestJetpT = 0; - double bestJetPhi = 0; - double bestJetEta = 0; + ROOT::Math::PxPyPzEVector bestJet; + for (auto& mcpjet : mcpjets) { - if (mcpjet.pt() < cfgJetpT) + if (mcpjet.pt() < cfgJetpT) { continue; + } if (cfgJetdRHistos) { histos.fill(HIST("mcpjet_eta"), mcpjet.eta()); @@ -1796,123 +1884,135 @@ struct kstarInOO { double dphi = TVector2::Phi_mpi_pi(mcpjet.phi() - lResonance.Phi()); double deta = mcpjet.eta() - lResonance.Eta(); - double R = TMath::Sqrt((dphi * dphi) + (deta * deta)); - if (R < bestR) { - bestR = R; - bestJetpT = mcpjet.pt(); - bestJetPhi = mcpjet.phi(); - bestJetEta = mcpjet.eta(); - } + double dR = TMath::Sqrt((dphi * dphi) + (deta * deta)); + if (dR < bestR) { + bestR = dR; + bestJet = ROOT::Math::PxPyPzEVector(mcpjet.px(), mcpjet.py(), mcpjet.pz(), mcpjet.energy()); + } // bestR } // mcpJets - if (bestR > cfgJetdR) + if (bestR > cfgJetdR) { continue; + } + + if (bestJet.Pt() > 6.0 && bestJet.Pt() < 8.0) { + if (cfgJetdRHistos) { + histos.fill(HIST("nJet_6_8"), bestJet.Pt()); + } + } //================== // daughters - double missing_pt = 0; - double dR_kaon, dR_pion; - bool kaon_out = false; - bool pion_out = false; - for (auto& daughter : mcParticle.daughters_as()) { - if (cfgIsKstar) { - if (std::abs(daughter.pdgCode()) == KaonPDG) { + double dR_kaon = 0; + double dR_pion = 0; + double dR_k_kstar = 0; + double dR_pi_kstar = 0; + bool isKaonInJet = false; + bool isPionInJet = false; + ROOT::Math::PxPyPzEVector Daughter, missing_daughter; - double dphi_kaon = TVector2::Phi_mpi_pi(bestJetPhi - daughter.phi()); - double deta_kaon = bestJetEta - daughter.eta(); - dR_kaon = TMath::Sqrt((dphi_kaon * dphi_kaon) + (deta_kaon * deta_kaon)); - - if (bestR < cfgJetdR) { - if (cfgJetdRHistos) { - histos.fill(HIST("dR_taggedjet_kaon"), dR_kaon, lResonance.Pt()); - histos.fill(HIST("dR_taggedjet_all"), dR_kaon, lResonance.Pt()); - } - if (dR_kaon > cfgJetdR) { - kaon_out = true; - missing_pt += daughter.pt(); - } - } // INSIDE Jets - } // kaon daughter - if (std::abs(daughter.pdgCode()) == PionPDG) { + for (auto& daughter : mcParticle.daughters_as()) { + Daughter = ROOT::Math::PxPyPzEVector(daughter.px(), daughter.py(), daughter.pz(), daughter.energy()); + + if (std::abs(daughter.pdgCode()) == KaonPDG) { + //=============== + // K*0 and kaon + double dphi_k_kstar = TVector2::Phi_mpi_pi(lResonance.Phi() - Daughter.Phi()); + double deta_k_kstar = lResonance.Eta() - Daughter.Eta(); + dR_k_kstar = TMath::Sqrt((dphi_k_kstar * dphi_k_kstar) + (deta_k_kstar * deta_k_kstar)); + + // Jet and kaon + double dphi_kaon = TVector2::Phi_mpi_pi(bestJet.Phi() - Daughter.Phi()); + double deta_kaon = bestJet.Eta() - Daughter.Eta(); + dR_kaon = TMath::Sqrt((dphi_kaon * dphi_kaon) + (deta_kaon * deta_kaon)); + + if (dR_kaon <= cfgJetdR) { + isKaonInJet = true; + } else { + missing_daughter += Daughter; + } + } else if (std::abs(daughter.pdgCode()) == PionPDG) { + //=============== + // K*0 and pion + double dphi_pi_kstar = TVector2::Phi_mpi_pi(lResonance.Phi() - Daughter.Phi()); + double deta_pi_kstar = lResonance.Eta() - Daughter.Eta(); + dR_pi_kstar = TMath::Sqrt((dphi_pi_kstar * dphi_pi_kstar) + (deta_pi_kstar * deta_pi_kstar)); + + // Jet and pion + double dphi_pion = TVector2::Phi_mpi_pi(bestJet.Phi() - Daughter.Phi()); + double deta_pion = bestJet.Eta() - Daughter.Eta(); + dR_pion = TMath::Sqrt((dphi_pion * dphi_pion) + (deta_pion * deta_pion)); + + if (dR_pion <= cfgJetdR) { + isPionInJet = true; + } else { + missing_daughter += Daughter; + } + } + } // daughter - double dphi_pion = TVector2::Phi_mpi_pi(bestJetPhi - daughter.phi()); - double deta_pion = bestJetEta - daughter.eta(); - dR_pion = TMath::Sqrt((dphi_pion * dphi_pion) + (deta_pion * deta_pion)); + if (cfgJetdRHistos) { + histos.fill(HIST("dR_kstar_kaon"), dR_k_kstar, lResonance.Pt()); + histos.fill(HIST("dR_kstar_pion"), dR_pi_kstar, lResonance.Pt()); + + if (bestR < cfgJetdR) { + histos.fill(HIST("dR_taggedjet_all"), dR_kaon, lResonance.Pt()); + histos.fill(HIST("dR_taggedjet_all"), dR_pion, lResonance.Pt()); + histos.fill(HIST("dR_taggedjet_kaon"), dR_kaon, lResonance.Pt()); + histos.fill(HIST("dR_taggedjet_pion"), dR_pion, lResonance.Pt()); + + if (bestJet.Pt() > 6.0 && bestJet.Pt() < 8.0) { + histos.fill(HIST("dR_taggedjet_all_6_8"), dR_kaon, lResonance.Pt()); + histos.fill(HIST("dR_taggedjet_all_6_8"), dR_pion, lResonance.Pt()); + histos.fill(HIST("Kstar_pT_INJet_6_8"), lResonance.Pt()); + } + if (bestJet.Pt() > 8.0) { + histos.fill(HIST("JetpT_8to"), bestJet.Pt()); + } + if (bestJet.Pt() > 8.0 && bestJet.Pt() < 10.0) { + histos.fill(HIST("Kstar_pT_INJet_8_10"), lResonance.Pt()); + } + if (bestJet.Pt() > 10.0 && bestJet.Pt() < 12.0) { + histos.fill(HIST("Kstar_pT_INJet_10_12"), lResonance.Pt()); + } - if (bestR < cfgJetdR) { - if (cfgJetdRHistos) { - histos.fill(HIST("dR_taggedjet_pion"), dR_pion, lResonance.Pt()); - histos.fill(HIST("dR_taggedjet_all"), dR_pion, lResonance.Pt()); + // Daughters out of jets + if (!isKaonInJet || !isPionInJet) { + ROOT::Math::PxPyPzEVector recoveredJet = bestJet + missing_daughter; + if (bestJet.Pt() > 6.0 && bestJet.Pt() < 8.0) { + histos.fill(HIST("missed_kpi_INJets_6_8"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); - if (bestJetpT > 6.0 && bestJetpT < 8.0) - histos.fill(HIST("dR_taggedjet_all_6_8"), dR_pion, lResonance.Pt()); - } - if (dR_pion > cfgJetdR) { - pion_out = true; - missing_pt += daughter.pt(); + if (recoveredJet.Pt() > 8.0) { + histos.fill(HIST("recoveredJetpT_6_8to8"), recoveredJet.Pt()); + histos.fill(HIST("Kstar_pT_6_8to8_IN_recoveredJet"), lResonance.Pt()); } - } // INSIDE Jets - } // pion daughter - } else { - if (std::abs(daughter.pdgCode()) == KaonPDG) { - double dphi_kaon = TVector2::Phi_mpi_pi(bestJetPhi - daughter.phi()); - double deta_kaon = bestJetEta - daughter.eta(); - dR_kaon = TMath::Sqrt((dphi_kaon * dphi_kaon) + (deta_kaon * deta_kaon)); - - if (bestR < cfgJetdR) { - if (cfgJetdRHistos) { - histos.fill(HIST("dR_taggedjet_kaon"), dR_kaon, lResonance.Pt()); - histos.fill(HIST("dR_taggedjet_all"), dR_kaon, lResonance.Pt()); - - if (bestJetpT > 6.0 && bestJetpT < 8.0) - histos.fill(HIST("dR_taggedjet_all_6_8"), dR_kaon, lResonance.Pt()); - } - - if (dR_kaon > cfgJetdR) { - kaon_out = true; - missing_pt = daughter.pt(); + if (recoveredJet.Pt() > 8.0 && recoveredJet.Pt() < 10.0) { + histos.fill(HIST("Kstar_pT_6_8to8_10_IN_recoveredJet"), lResonance.Pt()); } + } // 6 < bestJetpT < 8 GeV/c + if (bestJet.Pt() > 8.0 && bestJet.Pt() < 10.0) { + histos.fill(HIST("missed_kpi_INJets_8_10"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); } - } // kaon daughter - } // phi(1020) - } // daughter - - if (kaon_out || pion_out) { - double recoveredJetpT = bestJetpT + missing_pt; - if (cfgJetdRHistos) { - if (bestJetpT > 6.0 && bestJetpT < 8.0) { - histos.fill(HIST("normalJetpT_6_8_kstarSpectra"), lResonance.Pt()); - histos.fill(HIST("missed_kpi_INJets_6_8"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - if (recoveredJetpT > 8.0) { - histos.fill(HIST("recoveredJetpT_6_8to8_10"), recoveredJetpT); - histos.fill(HIST("recoveredJetpT_6_8to8_10_kstarSpectra"), lResonance.Pt()); + if (bestJet.Pt() > 10.0 && bestJet.Pt() < 12.0) { + histos.fill(HIST("missed_kpi_INJets_10_12"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); } - } - - if (bestJetpT > 8.0 && bestJetpT < 10.0) { - histos.fill(HIST("missed_kpi_INJets_8_10"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - histos.fill(HIST("normalJetpT_8_10_kstarSpectra"), lResonance.Pt()); - } - if (bestJetpT > 10.0 && bestJetpT < 12.0) { - histos.fill(HIST("missed_kpi_INJets_10_12"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - histos.fill(HIST("normalJetpT_10_12_kstarSpectra"), lResonance.Pt()); - } - if (bestJetpT > 12.0 && bestJetpT < 15.0) - histos.fill(HIST("missed_kpi_INJets_12_15"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - if (bestJetpT > 15.0 && bestJetpT < 25.0) - histos.fill(HIST("missed_kpi_INJets_15_25"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - if (bestJetpT > 25.0) - histos.fill(HIST("missed_kpi_INJets_25_infinite"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - - if (bestJetpT > 8.0) { - histos.fill(HIST("missed_kpi_INJets_8_infinite"), (bestJetpT - missing_pt) / bestJetpT, lResonance.Pt()); - histos.fill(HIST("normalJetpT_8_kstarSpectra"), lResonance.Pt()); - } - histos.fill(HIST("JetMigration"), bestJetpT, recoveredJetpT); - } // cfgJetdRHistos - } // kaon_out || pion_out + if (bestJet.Pt() > 12.0 && bestJet.Pt() < 15.0) { + histos.fill(HIST("missed_kpi_INJets_12_15"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); + } + if (bestJet.Pt() > 15.0 && bestJet.Pt() < 25.0) { + histos.fill(HIST("missed_kpi_INJets_15_25"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); + } + if (bestJet.Pt() > 25.0) { + histos.fill(HIST("missed_kpi_INJets_25_infinite"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); + } + if (bestJet.Pt() > 8.0) { + histos.fill(HIST("missed_kpi_INJets_8_infinite"), (bestJet.Pt() - missing_daughter.Pt()) / bestJet.Pt(), lResonance.Pt()); + } + histos.fill(HIST("JetMigration"), bestJet.Pt(), recoveredJet.Pt()); + } // Daughters out of jet + } // K*0 InJet + } // cfgJetdRHistos } // mcParticles }; - PROCESS_SWITCH(kstarInOO, processJetQA, "Process dR of K*0 Inclusive and Inside jet", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Resonances/kstarqa.cxx b/PWGLF/Tasks/Resonances/kstarqa.cxx index 8dd87cb002a..91cc416aca4 100644 --- a/PWGLF/Tasks/Resonances/kstarqa.cxx +++ b/PWGLF/Tasks/Resonances/kstarqa.cxx @@ -179,6 +179,8 @@ struct Kstarqa { } configGp; + Service pdgDB{}; + enum MultEstimator { kFT0M, kFT0A, @@ -361,6 +363,12 @@ struct Kstarqa { hInvMass.add("h1RecMult", "Multiplicity reconstructed", kTH1F, {multiplicityAxis}); hInvMass.add("h1RecMult2", "Multiplicity reconstructed", kTH1F, {multiplicityAxis}); hInvMass.add("h1KSRecsplit", "KS meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); + + hInvMass.add("h3KstarMassGen", "Gen pt, multiplicity, mass", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h3KstarMassGenCalib", "Gen pt, multiplicity, mass", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h3KstarMassRec", "Rec pt, multiplicity, mass", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h3KstarMassRecCalib", "Rec pt, multiplicity, mass", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + // hInvMass.add("hAllGenCollisionsImpact", "All generated collisions vs impact parameter", kTH1F, {multiplicityAxis}); hInvMass.add("hAllGenCollisions", "All generated events", kTH1F, {multiplicityAxis}); hInvMass.add("hAllGenCollisions1Rec", "All gen events with at least one rec event", kTH1F, {multiplicityAxis}); @@ -561,52 +569,73 @@ struct Kstarqa { if (configGp.isGlobalTracks) { if (!candidate.isGlobalTrack()) return false; + if (std::abs(candidate.pt()) < configGp.cfgCutPT) return false; + if (std::abs(candidate.eta()) > configGp.cfgCutEtaMax) return false; + if (!configGp.isApplyPtDepDCAxyCut) { if (std::abs(candidate.dcaXY()) > configGp.cfgCutDCAxyMax) return false; + } else { if (std::abs(candidate.dcaXY()) > (0.0105 + 0.035 / std::pow(candidate.pt(), 1.1))) return false; } if (std::abs(candidate.dcaZ()) > configGp.cfgCutDCAz) return false; + if (candidate.itsNCls() < configGp.cfgITScluster) return false; + if (candidate.tpcNClsFound() < configGp.cfgTPCcluster) return false; + if (configGp.hasITS && !candidate.hasITS()) return false; - if (configGp.isITSTPCRefit && (!(o2::aod::track::ITSrefit) || !(o2::aod::track::TPCrefit))) - return false; + + if (configGp.isITSTPCRefit) { + if (!(candidate.flags() & o2::aod::track::ITSrefit) || + !(candidate.flags() & o2::aod::track::TPCrefit)) { + return false; + } + } if (configGp.cfgPVContributor && !candidate.isPVContributor()) return false; + } else if (!configGp.isGlobalTracks) { if (std::abs(candidate.pt()) < configGp.cfgCutPT) return false; - // if (std::abs(candidate.eta()) > configGp.cfgCutEtaMax || std::abs(candidate.eta()) < configGp.cfgCutEtaMin) + if (std::abs(candidate.eta()) > configGp.cfgCutEtaMax) return false; - // if (std::abs(candidate.dcaXY()) > configGp.cfgCutDCAxyMax || std::abs(candidate.dcaXY()) < configGp.cfgCutDCAxyMin) + if (std::abs(candidate.dcaXY()) > configGp.cfgCutDCAxyMax) return false; + if (std::abs(candidate.dcaZ()) > configGp.cfgCutDCAz) return false; + // if (candidate.tpcCrossedRowsOverFindableCls() < configGp.cfgRCRFC) - return false; + // return false; + if (candidate.itsNCls() < configGp.cfgITScluster) return false; + if (candidate.tpcNClsFound() < configGp.cfgTPCcluster) return false; + // if (candidate.itsChi2NCl() >= configGp.cfgITSChi2NCl) // return false; + // if (candidate.tpcChi2NCl() >= configGp.cfgTPCChi2NClMax || candidate.tpcChi2NCl() < configGp.cfgTPCChi2NClMin) // return false; + if (configGp.cfgPVContributor && !candidate.isPVContributor()) return false; + if (!candidate.isPrimaryTrack()) return false; } @@ -619,32 +648,22 @@ struct Kstarqa { { const auto pglobal = track.p(); const auto ptpc = track.tpcInnerParam(); - if (std::abs(pglobal - ptpc) > configGp.cFakeTrackCutKa) { - return true; - } - return false; + return std::abs(pglobal - ptpc) > configGp.cFakeTrackCutKa; } // deep angle cut on pair to remove photon conversion template bool selectionPair(const T1& candidate1, const T2& candidate2) { - double pt1, pt2, pz1, pz2, p1, p2, angle; - pt1 = candidate1.pt(); - pt2 = candidate2.pt(); - pz1 = candidate1.pz(); - pz2 = candidate2.pz(); - p1 = candidate1.p(); - p2 = candidate2.p(); - angle = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); - if (configGp.isApplyDeepAngle && angle < configGp.cfgDeepAngle) { - return false; - } - // double deltaRvalue = std::sqrt(TVector2::Phi_mpi_pi(candidate1.phi() - candidate2.phi()) * TVector2::Phi_mpi_pi(candidate1.phi() - candidate2.phi()) + (candidate1.eta() - candidate2.eta()) * (candidate1.eta() - candidate2.eta())); - // if (deltaRvalue < configGp.deltaRCut) { - // return false; - // } - return true; + const double pt1 = candidate1.pt(); + const double pt2 = candidate2.pt(); + const double pz1 = candidate1.pz(); + const double pz2 = candidate2.pz(); + const double p1 = candidate1.p(); + const double p2 = candidate2.p(); + const double angle = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + + return !configGp.isApplyDeepAngle || angle >= configGp.cfgDeepAngle; } template @@ -1021,8 +1040,8 @@ struct Kstarqa { return false; } - std::array pvec0; - std::array pvec1; + std::array pvec0 = {0.0, 0.0, 0.0}; + std::array pvec1 = {0.0, 0.0, 0.0}; // Defining filters for events (event selection) // Processed events will be already fulfilling the event selection @@ -1049,53 +1068,75 @@ struct Kstarqa { using LabeledTracks = soa::Join; //*********Varibles declaration*************** - float multiplicity{-1.0}, theta2; - ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, mother, motherRot, daughterSelected, fourVecDauCM, daughterRotCM; + float multiplicity{-1.0}, theta2{0.0}; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, mother, motherRot, daughterSelected, fourVecDauCM, daughterRotCM, genDaughter1, genDaughter2, genMother; ROOT::Math::XYZVector randomVec, beamVec, normalVec; bool isMix = false; template - void fillInvMass(const T1& daughter1, const T1& daughter2, const T1& mother, float multiplicity, bool isMix, const T2& track1, const T2& track2) + void fillInvMass(const T1& dau1, const T1& dau2, const T1& motherVec, float multiplicityFill, bool isMixInput, const T2& track1, const T2& track2) { - daughterSelected = (boostDaugter1) ? daughter1 : daughter2; // polarization calculations - ROOT::Math::Boost boost{mother.BoostToCM()}; // boost mother to center of mass frame - fourVecDauCM = boost(daughterSelected); // boost the frame of daughter same as mother + daughterSelected = (boostDaugter1) ? dau1 : dau2; // polarization calculations + + // Boost mother to the center-of-mass frame + ROOT::Math::Boost boost{motherVec.BoostToCM()}; + + // Boost selected daughter to the mother rest frame + fourVecDauCM = boost(daughterSelected); - // if (std::abs(mother.Rapidity()) < configGp.rapidityMotherData) { if (activateTHnSparseCosThStarHelicity) { - auto cosThetaStarHelicity = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); + auto cosThetaStarHelicity = motherVec.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(motherVec.Vect().Mag2())); + + // Unlike-sign pairs if (track1.sign() * track2.sign() < 0) { - if (!isMix) { - if (std::abs(mother.Rapidity()) < configGp.rapidityMotherData) { - hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + + // Same-event + if (!isMixInput) { + + if (std::abs(motherVec.Rapidity()) < configGp.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicityFill, motherVec.Pt(), motherVec.M(), cosThetaStarHelicity); } + // Rotational background for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / configGp.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / configGp.rotationalCut); - daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + daughterRot = ROOT::Math::PxPyPzMVector(dau1.Px() * std::cos(theta2) - dau1.Py() * std::sin(theta2), dau1.Px() * std::sin(theta2) + dau1.Py() * std::cos(theta2), dau1.Pz(), dau1.M()); - motherRot = daughterRot + daughter2; + motherRot = daughterRot + dau2; ROOT::Math::Boost boost2{motherRot.BoostToCM()}; daughterRotCM = boost2(daughterRot); auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); - if (calcRotational && std::abs(motherRot.Rapidity()) < configGp.rapidityMotherData) - hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarHelicityRot); + if (calcRotational && std::abs(motherRot.Rapidity()) < configGp.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicityFill, motherRot.Pt(), motherRot.M(), cosThetaStarHelicityRot); + } } - } else if (isMix && std::abs(mother.Rapidity()) < configGp.rapidityMotherData) { - hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + + // Mixed-event + } else if (std::abs(motherVec.Rapidity()) < configGp.rapidityMotherData) { + + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicityFill, motherVec.Pt(), motherVec.M(), cosThetaStarHelicity); } + + // Like-sign pairs } else { - if (!isMix) { - if (calcLikeSign && std::abs(mother.Rapidity()) < configGp.rapidityMotherData) { + + if (!isMixInput) { + + if (calcLikeSign && std::abs(motherVec.Rapidity()) < configGp.rapidityMotherData) { + if (track1.sign() > 0 && track2.sign() > 0) { - hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + + hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), multiplicityFill, motherVec.Pt(), motherVec.M(), cosThetaStarHelicity); + } else if (track1.sign() < 0 && track2.sign() < 0) { - hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + + hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), multiplicityFill, motherVec.Pt(), motherVec.M(), cosThetaStarHelicity); } } } @@ -1124,8 +1165,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } // Fill the event counter @@ -1317,7 +1356,7 @@ struct Kstarqa { void processME(EventCandidatesMix const&, TrackCandidates const&) { // Map estimator to pair and multiplicity accessor - auto runMixing = [&](auto& pair, auto multiplicityGetter) { + auto runMixing = [&](const auto& pair, auto multiplicityGetter) { for (const auto& [c1, tracks1, c2, tracks2] : pair) { // if (!c1.sel8() || !c2.sel8()) // continue; @@ -1419,7 +1458,7 @@ struct Kstarqa { void processMEMC(EventCandidatesMC const&, TrackCandidatesMC const&, aod::McParticles const&, aod::McCollisions const&) { - auto runMixing = [&](auto& pair, auto multiplicityGetter) { + auto runMixing = [&](const auto& pair, auto multiplicityGetter) { for (const auto& [c1, tracks1, c2, tracks2] : pair) { if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { // don't fill event cut histogram @@ -1539,8 +1578,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } // Fill the event counter @@ -1713,8 +1750,6 @@ struct Kstarqa { } PROCESS_SWITCH(Kstarqa, processSEMC, "Process same event in MC", false); - Service pdgDB; - void processGen(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) // void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) { @@ -1760,8 +1795,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } hInvMass.fill(HIST("h1GenMult"), multiplicity); @@ -1879,8 +1912,6 @@ struct Kstarqa { multiplicity1 = RecCollision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity1 = RecCollision.centFV0A(); - } else { - multiplicity1 = RecCollision.centFT0M(); // default } isSelectedEvent = true; @@ -1896,7 +1927,7 @@ struct Kstarqa { } auto impactPar = mcCollision.impactParameter(); - auto multiplicityGen = -1; + auto multiplicityGen = -1.0f; multiplicityGen = mcCollision.centFT0M(); hInvMass.fill(HIST("MCcorrections/hImpactParameterGen"), impactPar); hInvMass.fill(HIST("MCcorrections/MultiplicityGen"), multiplicityGen); @@ -1941,7 +1972,7 @@ struct Kstarqa { } hInvMass.fill(HIST("CorrFactors/hGenEvents"), multiplicityNch, 2.5); - float multiplicity = -1.0; + float multiplicitySigLoss = -1.0; bool isSelectedEvent = false; for (auto const& collision : collisions) { @@ -1951,15 +1982,13 @@ struct Kstarqa { continue; if (cSelectMultEstimator == kFT0M) { - multiplicity = collision.centFT0M(); + multiplicitySigLoss = collision.centFT0M(); } else if (cSelectMultEstimator == kFT0A) { - multiplicity = collision.centFT0A(); + multiplicitySigLoss = collision.centFT0A(); } else if (cSelectMultEstimator == kFT0C) { - multiplicity = collision.centFT0C(); + multiplicitySigLoss = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { - multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default + multiplicitySigLoss = collision.centFV0A(); } isSelectedEvent = true; } @@ -1967,7 +1996,7 @@ struct Kstarqa { // auto multiplicityGen = -1; // multiplicityGen = mcCollision.centFT0M(); - hInvMass.fill(HIST("CorrFactors/hMultiplicityVsMultMC"), multiplicity, multiplicityNch); + hInvMass.fill(HIST("CorrFactors/hMultiplicityVsMultMC"), multiplicitySigLoss, multiplicityNch); hInvMass.fill(HIST("CorrFactors/hNrecInGen"), collisions.size()); hInvMass.fill(HIST("CorrFactors/MultiplicityGen"), multiplicityNch); if (isSelectedEvent) { @@ -1996,7 +2025,12 @@ struct Kstarqa { // continue; int pdgDau = kCurrentDaughter.pdgCode(); - int sign = (pdgDau > 0) - (pdgDau < 0); + int sign = 0; + if (pdgDau > 0) { + sign = 1; + } else if (pdgDau < 0) { + sign = -1; + } if (sign > 0) hasPos = true; @@ -2016,8 +2050,8 @@ struct Kstarqa { if ((passkaon && passpion) && (hasPos && hasNeg)) { mother = daughter1 + daughter2; // Kstar meson - hInvMass.fill(HIST("CorrFactors/h2dGenKstar"), multiplicity, mother.Pt()); - hInvMass.fill(HIST("CorrFactors/h3dGenKstarVsMultMCVsMultiplicity"), multiplicityNch, multiplicity, mother.Pt()); + hInvMass.fill(HIST("CorrFactors/h2dGenKstar"), multiplicitySigLoss, mother.Pt()); + hInvMass.fill(HIST("CorrFactors/h3dGenKstarVsMultMCVsMultiplicity"), multiplicityNch, multiplicitySigLoss, mother.Pt()); hInvMass.fill(HIST("CorrFactors/hSignalLoss1"), mother.pt(), multiplicityNch); if (isSelectedEvent) { hInvMass.fill(HIST("CorrFactors/hSignalLoss2"), mother.pt(), multiplicityNch); @@ -2033,6 +2067,8 @@ struct Kstarqa { } PROCESS_SWITCH(Kstarqa, processEvSigLossFactors, "Process Event and Signal loss", false); + double genMass = 0.0, recMass = 0.0, recPt = 0.0, genPt = 0.0; + void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, EventMCGenerated const&) { rEventSelection.fill(HIST("eventsCheckRec"), 0.5); @@ -2061,8 +2097,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } hInvMass.fill(HIST("hAllRecCollisions"), multiplicity); @@ -2144,7 +2178,8 @@ struct Kstarqa { } rEventSelection.fill(HIST("recMCparticles"), 6.5); - if (!(track1PDG == PDG_t::kPiPlus && track2PDG == PDG_t::kKPlus) && !(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kPiPlus)) { + if ((track1PDG != PDG_t::kPiPlus || track2PDG != PDG_t::kKPlus) && + (track1PDG != PDG_t::kKPlus || track2PDG != PDG_t::kPiPlus)) { continue; } rEventSelection.fill(HIST("recMCparticles"), 7.5); @@ -2300,13 +2335,35 @@ struct Kstarqa { oldindex = mothertrack1.globalIndex(); if (track1PDG == PDG_t::kPiPlus) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + + genDaughter1 = ROOT::Math::PxPyPzMVector(mctrack1.px(), mctrack1.py(), mctrack1.pz(), massPi); + genDaughter2 = ROOT::Math::PxPyPzMVector(mctrack2.px(), mctrack2.py(), mctrack2.pz(), massKa); + } else if (track1PDG == PDG_t::kKPlus) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + + genDaughter1 = ROOT::Math::PxPyPzMVector(mctrack1.px(), mctrack1.py(), mctrack1.pz(), massKa); + genDaughter2 = ROOT::Math::PxPyPzMVector(mctrack2.px(), mctrack2.py(), mctrack2.pz(), massPi); } - mother = daughter1 + daughter2; // Kstar meson + mother = daughter1 + daughter2; // Kstar meson + genMother = genDaughter1 + genDaughter2; // Gen Kstar from MC daughters + + recMass = mother.M(); + recPt = mother.Pt(); + + genMass = genMother.M(); + genPt = mothertrack1.pt(); + + hInvMass.fill(HIST("h3KstarMassGen"), genPt, multiplicity, genMass); + hInvMass.fill(HIST("h3KstarMassGenCalib"), genPt, multiplicityRec, genMass); + + hInvMass.fill(HIST("h3KstarMassRec"), recPt, multiplicity, recMass); + hInvMass.fill(HIST("h3KstarMassRecCalib"), recPt, multiplicityRec, recMass); hInvMass.fill(HIST("h2KstarRecpt2"), mothertrack1.pt(), multiplicity, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); hInvMass.fill(HIST("h2KstarRecptCalib2"), mothertrack1.pt(), multiplicityRec, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); @@ -2318,6 +2375,7 @@ struct Kstarqa { hInvMass.fill(HIST("h1KstarRecMass"), mother.M()); hInvMass.fill(HIST("h2KstarRecpt1"), mother.Pt(), multiplicity, mother.M()); hInvMass.fill(HIST("h2KstarRecptCalib1"), mother.Pt(), multiplicityRec, mother.M()); + // h3KstarMassGen } } } @@ -2349,8 +2407,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } hInvMass.fill(HIST("hAllRecCollisions"), multiplicity); @@ -2561,8 +2617,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } // Fill the event counter @@ -2658,7 +2712,7 @@ struct Kstarqa { void processMEPhi(EventCandidatesMix const&, TrackCandidates const&) { // Map estimator to pair and multiplicity accessor - auto runMixing = [&](auto& pair, auto multiplicityGetter) { + auto runMixing = [&](const auto& pair, auto multiplicityGetter) { for (const auto& [c1, tracks1, c2, tracks2] : pair) { // if (!c1.sel8() || !c2.sel8()) // continue; @@ -2758,8 +2812,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } hInvMass.fill(HIST("h1GenMult"), multiplicity); @@ -2846,7 +2898,7 @@ struct Kstarqa { } hInvMass.fill(HIST("CorrFactors/hGenEvents"), multiplicityNch, 2.5); - float multiplicity = -1.0; + float multiplicityPhi = -1.0; bool isSelectedEvent = false; for (auto const& collision : collisions) { @@ -2856,15 +2908,13 @@ struct Kstarqa { continue; if (cSelectMultEstimator == kFT0M) { - multiplicity = collision.centFT0M(); + multiplicityPhi = collision.centFT0M(); } else if (cSelectMultEstimator == kFT0A) { - multiplicity = collision.centFT0A(); + multiplicityPhi = collision.centFT0A(); } else if (cSelectMultEstimator == kFT0C) { - multiplicity = collision.centFT0C(); + multiplicityPhi = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { - multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default + multiplicityPhi = collision.centFV0A(); } isSelectedEvent = true; } @@ -2872,7 +2922,7 @@ struct Kstarqa { // auto multiplicityGen = -1; // multiplicityGen = mcCollision.centFT0M(); - hInvMass.fill(HIST("CorrFactors/hMultiplicityVsMultMC"), multiplicity, multiplicityNch); + hInvMass.fill(HIST("CorrFactors/hMultiplicityVsMultMC"), multiplicityPhi, multiplicityNch); hInvMass.fill(HIST("CorrFactors/hNrecInGen"), collisions.size()); hInvMass.fill(HIST("CorrFactors/MultiplicityGen"), multiplicityNch); if (isSelectedEvent) { @@ -2901,7 +2951,12 @@ struct Kstarqa { // continue; int pdgDau = kCurrentDaughter.pdgCode(); - int sign = (pdgDau > 0) - (pdgDau < 0); + int sign = 0; + if (pdgDau > 0) { + sign = 1; + } else if (pdgDau < 0) { + sign = -1; + } if (sign > 0) hasPos = true; @@ -2921,8 +2976,8 @@ struct Kstarqa { if ((passkaon && passpion) && (hasPos && hasNeg)) { mother = daughter1 + daughter2; // Kstar meson - hInvMass.fill(HIST("CorrFactors/h2dGenKstar"), multiplicity, mother.Pt()); - hInvMass.fill(HIST("CorrFactors/h3dGenKstarVsMultMCVsMultiplicity"), multiplicityNch, multiplicity, mother.Pt()); + hInvMass.fill(HIST("CorrFactors/h2dGenKstar"), multiplicityPhi, mother.Pt()); + hInvMass.fill(HIST("CorrFactors/h3dGenKstarVsMultMCVsMultiplicity"), multiplicityNch, multiplicityPhi, mother.Pt()); hInvMass.fill(HIST("CorrFactors/hSignalLoss1"), mother.pt(), multiplicityNch); if (isSelectedEvent) { hInvMass.fill(HIST("CorrFactors/hSignalLoss2"), mother.pt(), multiplicityNch); @@ -2963,8 +3018,6 @@ struct Kstarqa { multiplicity = collision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity = collision.centFV0A(); - } else { - multiplicity = collision.centFT0M(); // default } hInvMass.fill(HIST("hAllRecCollisions"), multiplicity); @@ -3044,7 +3097,7 @@ struct Kstarqa { } rEventSelection.fill(HIST("recMCparticles"), 5.5); - if ((track1PDG != PDG_t::kKPlus) || (track2PDG != PDG_t::kKPlus)) { + if (track1PDG != PDG_t::kKPlus || track2PDG != PDG_t::kKPlus) { continue; } rEventSelection.fill(HIST("recMCparticles"), 6.5); @@ -3076,9 +3129,10 @@ struct Kstarqa { } rEventSelection.fill(HIST("recMCparticles"), 11.5); - if (!configGp.isapplypTdepPID && !(selectionPID(track1, 1) && selectionPID(track2, 1))) { // kaon and kaon + if (!configGp.isapplypTdepPID && !(selectionPID(track1, 1) && selectionPID(track2, 1))) { continue; - } else if (configGp.isapplypTdepPID && !(selectionPIDPtDep(track1, 1) && selectionPIDPtDep(track2, 1))) { // kaon and kaon + } + if (configGp.isapplypTdepPID && !(selectionPIDPtDep(track1, 1) && selectionPIDPtDep(track2, 1))) { continue; } rEventSelection.fill(HIST("recMCparticles"), 12.5); @@ -3147,8 +3201,6 @@ struct Kstarqa { centrality = RecCollision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { centrality = RecCollision.centFV0A(); - } else { - centrality = RecCollision.centFT0M(); // default } isSelectedEvent = true; @@ -3197,7 +3249,7 @@ struct Kstarqa { auto impactPar = mcCollision.impactParameter(); // auto multiplicityRec = -1; - auto multiplicityGen = -1; + auto multiplicityGen = -1.0f; multiplicityGen = mcCollision.centFT0M(); hInvMass.fill(HIST("MCcorrections/hImpactParameterGen"), impactPar); hInvMass.fill(HIST("MCcorrections/MultiplicityGen"), multiplicityGen); @@ -3221,8 +3273,6 @@ struct Kstarqa { multiplicity1 = RecCollision.centFT0C(); } else if (cSelectMultEstimator == kFV0A) { multiplicity1 = RecCollision.centFV0A(); - } else { - multiplicity1 = RecCollision.centFT0M(); // default } isSelectedEvent = true; } diff --git a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx index e8771cbb8a6..83eb796ac94 100644 --- a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx @@ -17,32 +17,31 @@ #include "PWGLF/DataModel/LFLambda1405Table.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" #include #include #include -#include #include #include #include #include #include #include +#include #include +#include #include #include #include #include #include -#include -#include #include #include @@ -61,11 +60,14 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using TracksFull = soa::Join; -using CollisionsFull = soa::Join; -using CollisionsFullWCentQVecs = soa::Join; -using CollisionsFullMc = soa::Join; -using CollisionsFullMcWCent = soa::Join; +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullWQVecs = soa::Join; +using CollisionsFullMc = soa::Join; +// using CollisionsFullMcWCent = soa::Join; + +using BinningCentPosZ = ColumnBinningPolicy; +using BinningMultPosZ = ColumnBinningPolicy, aod::collision::PosZ>; enum L1405DecayType { kSigmaMinusPiToPiPiNeutron = 0, kSigmaPlusPiToPiPiNeutron, @@ -113,13 +115,15 @@ struct lambda1405candidate { float occupancy = -1; // Occupancy of the collision float scalarProd = -1; // Scalar product for flow analysis + + int poolBin = -1; // Pool bin for event mixing }; struct lambda1405analysis { - int lambda1405PdgCode = 102132; // PDG code for Lambda(1405) - Produces outputDataTable; // Output table for Lambda(1405) candidates - Produces outputDataFlowTable; // Output table for Lambda(1405) flow analysis - Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC + int lambda1405PdgCode = 102132; // o2-linter: disable=pdg/explicit-code + Produces outputDataTable; // Output table for Lambda(1405) candidates + Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC + Produces outputSigmaEffMC; // Output table for Lambda(1405) sigma efficiency in MC Service ccdb; @@ -130,44 +134,51 @@ struct lambda1405analysis { HistogramRegistry rSigmaPlus{"sigmaPlus", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rSelections{"selections", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; // Configurable for event selection - Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable cutEtaDaughter{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; - Configurable cutDcaToPvSigma{"cutDcaToPvSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; - Configurable cutDcaToPvPiFromSigma{"cutDcaToPvPiFromSigma", 2., "Min DCA to primary vertex for pion from Sigma candidates (cm)"}; - - Configurable cutMinPtL1405{"cutMinPtL1405", 2.0f, "Minimum pT cut for Lambda(1405) candidates (GeV/c)"}; - Configurable cutUpperMass{"cutUpperMass", 1.6f, "Upper mass cut for Lambda(1405) candidates (GeV/c^2)"}; - Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; - Configurable cutSigmaMass{"cutSigmaMass", 0.1, "Sigma mass window (MeV/c^2)"}; - Configurable cutItsNClusKinkMin{"cutItsNClusKinkMin", 1, "Minimum number of ITS clusters for kink daughter"}; - Configurable cutItsNClusKinkMax{"cutItsNClusKinkMax", 3, "Maximum number of ITS clusters for kink daughter"}; - Configurable cutNTpcClus{"cutNTpcClus", 90, "Minimum number of Tpc clusters for pion candidate"}; - Configurable cutNSigTpc{"cutNSigTpc", 3, "NSigTpcPion"}; - Configurable cutNSigTof{"cutNSigTof", 3, "NSigTofPion"}; - Configurable cutMaxDcaZBach{"cutMaxDcaZBach", 0.1, "Maximum DcaZ for bachelor pion (cm)"}; - Configurable dcaXYBachNSigmaMax{"dcaXYBachNSigmaMax", 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"}; - Configurable dcaXYPtBachFunc{"dcaXYPtBachFunc", "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"}; - Configurable cutSigmaQtAPMin{"cutSigmaQtAPMin", "0.17", "Functional form of minimum qT(alpha) selection"}; - Configurable cutSigmaQtAPMax{"cutSigmaQtAPMax", "0.2", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMinBachPiPtVsL1405Pt{"cutMinBachPiPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMaxBachPiPtVsL1405Pt{"cutMaxBachPiPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMinSigmaPtVsL1405Pt{"cutMinSigmaPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMaxSigmaPtVsL1405Pt{"cutMaxSigmaPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; + struct : o2::framework::ConfigurableGroup { + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable centMultMin{"centMultMin", 0., "Minimum collision centrality/multiplicity accepted"}; + Configurable centMultMax{"centMultMax", 100., "Maximum collision centrality/multiplicity accepted"}; + Configurable occupancyMax{"occupancyMax", 3000000., "Maximum collision occupancy accepted"}; + } eventSelection; + + struct : o2::framework::ConfigurableGroup { + Configurable cutEtaDaughter{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; + Configurable cutDcaToPvSigma{"cutDcaToPvSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; + Configurable cutDcaToPvPiFromSigma{"cutDcaToPvPiFromSigma", 2., "Min DCA to primary vertex for pion from Sigma candidates (cm)"}; + Configurable cutMinPtL1405{"cutMinPtL1405", 2.0f, "Minimum pT cut for Lambda(1405) candidates (GeV/c)"}; + Configurable cutUpperMass{"cutUpperMass", 1.6f, "Upper mass cut for Lambda(1405) candidates (GeV/c^2)"}; + Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; + Configurable cutSigmaMass{"cutSigmaMass", 0.1, "Sigma mass window (MeV/c^2)"}; + Configurable cutItsNClusKinkMin{"cutItsNClusKinkMin", 1, "Minimum number of ITS clusters for kink daughter"}; + Configurable cutItsNClusKinkMax{"cutItsNClusKinkMax", 3, "Maximum number of ITS clusters for kink daughter"}; + Configurable cutNTpcClus{"cutNTpcClus", 90, "Minimum number of Tpc clusters for pion candidate"}; + Configurable cutNSigTpc{"cutNSigTpc", 3, "NSigTpcPion"}; + Configurable cutNSigTof{"cutNSigTof", 3, "NSigTofPion"}; + Configurable cutMaxDcaZBach{"cutMaxDcaZBach", 0.1, "Maximum DcaZ for bachelor pion (cm)"}; + Configurable dcaXYBachNSigmaMax{"dcaXYBachNSigmaMax", 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"}; + Configurable dcaXYPtBachFunc{"dcaXYPtBachFunc", "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"}; + Configurable cutSigmaQtAPMin{"cutSigmaQtAPMin", "0.17", "Functional form of minimum qT(alpha) selection"}; + Configurable cutSigmaQtAPMax{"cutSigmaQtAPMax", "0.2", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMinBachPiPtVsL1405Pt{"cutMinBachPiPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMaxBachPiPtVsL1405Pt{"cutMaxBachPiPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMinSigmaPtVsL1405Pt{"cutMinSigmaPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMaxSigmaPtVsL1405Pt{"cutMaxSigmaPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; + } selections; // Configurables for flow analysis - Configurable centMultMin{"centMultMin", 0., "Minimum collision centrality/multiplicity accepted"}; - Configurable centMultMax{"centMultMax", 100., "Maximum collision centrality/multiplicity accepted"}; - Configurable occupancyMax{"occupancyMax", 3000000., "Maximum collision occupancy accepted"}; Configurable minDEta{"minDEta", -1., "Minimum delta eta between L1405-track pairs"}; Configurable assTrkMinPt{"assTrkMinPt", 0., "Minimum pT of associated track for 2PC"}; Configurable assTrkMaxPt{"assTrkMaxPt", 10., "Maximum pT of associated track for 2PC"}; Configurable saveDEtaDPhi{"saveDEtaDPhi", false, "If true, save the dEta and dPhi distributions for Lambda(1405) candidates"}; Configurable fillFlowTree{"fillFlowTree", false, "If true, fill the output tree with Lambda(1405) candidates"}; + Configurable useCentrality{"useCentrality", true, "If true, use centrality for binning"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; // Downsample for table filling Configurable downSampleFactor{"downSampleFactor", 1., "Fraction of candidates to keep in TTree"}; Configurable ptDownSampleMax{"ptDownSampleMax", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable skipBkgSigmas{"skipBkgSigmas", true, "If true, skip un-matched sigmas in efficiency process function"}; Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Lambda(1405) candidates"}; Configurable doLikeSignBkg{"doLikeSignBkg", false, "Use like-sign background"}; Configurable useTof{"useTof", false, "Use Tof for PID for pion candidates"}; @@ -182,19 +193,24 @@ struct lambda1405analysis { TF1 funcMinQtAlphaAP, funcMaxQtAlphaAP, funcMinBachPiPtVsL1405Pt, funcMaxBachPiPtVsL1405Pt, funcMinSigmaPtVsL1405Pt, funcMaxSigmaPtVsL1405Pt, funcDcaXYPtCutBachPi; - using CollisionsCentSel = soa::Filtered; - using McRecoCollisionsCentSel = soa::Filtered; + using CollisionsSel = soa::Filtered; + using CollisionsSelWQVecs = soa::Filtered; + using McRecoCollisionsSel = soa::Filtered; - Filter filterOccupancy = aod::evsel::ft0cOccupancyInTimeRange <= occupancyMax; + Filter filterOccupancy = aod::evsel::ft0cOccupancyInTimeRange <= eventSelection.occupancyMax; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + SliceCache cache; + + int poolBins{0}; + // Needed for DCA propagation of bachelor tracks - int mRunNumber; - float mBz; o2::base::MatLayerCylSet* lut = nullptr; // Configurable axes + ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}, "Z vertex position pools"}; + ConfigurableAxis centMultPoolBins{"centMultPoolBins", {VARIABLE_WIDTH, 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100}, "Event cent/mult pools"}; ConfigurableAxis axisPvContrib{"axisPvContrib", {5000, 0., 5000.}, ""}; ConfigurableAxis axisCent{"axisCent", {100, 0., 100.}, ""}; ConfigurableAxis axisOccupancy{"axisOccupancy", {100, 0., 140000.}, ""}; @@ -224,6 +240,10 @@ struct lambda1405analysis { void init(InitContext const&) { + // Define pool bins + poolBins = (centMultPoolBins->size() - 2) * (zPoolBins->size() - 2); + const AxisSpec axisPoolBin = {poolBins, -0.5, static_cast(poolBins) - 0.5, "PoolBin"}; + // Axes const AxisSpec ptAxis{axisPtL1405, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec pCompAxisL1405{axisPCompsL1405, "#it{p}_{comp} (GeV/#it{c})"}; @@ -253,6 +273,10 @@ struct lambda1405analysis { rEventSelection.add("hCentMultVsPvContrib", "hCentMultVsPvContrib", {HistType::kTH2F, {centMultAxis, pvContribAxis}}); rEventSelection.add("hOccVsPvContrib", "hOccVsPvContrib", {HistType::kTH2F, {occAxis, pvContribAxis}}); rEventSelection.add("hCentVsOcc", "hCentVsOcc", {HistType::kTH2F, {centMultAxis, occAxis}}); + rEventSelection.add("hCentPoolBin", "Centrality pool bin", {HistType::kTH2F, {{axisCent}, {axisPoolBin}}}); + rEventSelection.add("hZVtxPoolBin", "Z vtx pool bin", {HistType::kTH2F, {{vertexZAxis}, {axisPoolBin}}}); + rEventSelection.add("hMultPoolBin", "Multiplicity pool bin", {HistType::kTH2F, {{axisCent}, {axisPoolBin}}}); + rEventSelection.add("hPoolBins", "Pool bins", {HistType::kTH1F, {{102, -1.5, 100.5}}}); // Sigma- candidate properties rSigmaMinus.add("hMassXiMinusSigmaMinus", "hMassXiMinusSigmaMinus", {HistType::kTH2F, {xiMassAxis, sigmaMassAxis}}); @@ -319,18 +343,18 @@ struct lambda1405analysis { rLambda1405.add("h3BachPiDcaXYVsPt", "h3BachPiDcaXYVsPt", {HistType::kTH3F, {ptKinkDaugAxis, dcaBachPiAxis, centMultAxis}}); rLambda1405.add("h3BachPiDcaZVsPt", "h3BachPiDcaZVsPt", {HistType::kTH3F, {ptKinkDaugAxis, dcaBachPiAxis, centMultAxis}}); // Sparse histograms - std::vector axesMass = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis}; - if (doprocessMc || doprocessMcWCentSel) { + std::vector axesMass = {axisPoolBin, lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis}; + if (doprocessMc) { axesMass.push_back(pvContribAxis); } else { axesMass.push_back(centMultAxis); } rLambda1405.add("hSparseL1405", "THn for mass peak", HistType::kTHnSparseF, axesMass); - std::vector axesScalarProd = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis, centMultAxis, scalarProdAxis}; - if (doprocessDataWCentQVecs) { + std::vector axesScalarProd = {axisPoolBin, lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis, centMultAxis, scalarProdAxis}; + if (doprocessDataWQVecsSameEvent || doprocessDataWQVecsMixedEvent) { rLambda1405.add("hSparseL1405ScalProd", "THn for SP", HistType::kTHnSparseF, axesScalarProd); } - std::vector axesCorrel = {lambda1405MassAxis, ptAxis, deltaEtaAxis, deltaPhiAxis}; + std::vector axesCorrel = {axisPoolBin, lambda1405MassAxis, ptAxis, deltaEtaAxis, deltaPhiAxis}; if (saveDEtaDPhi) { rLambda1405.add("hSparseL1405Correl", "THn for 2PC", HistType::kTHnSparseF, axesCorrel); } @@ -397,14 +421,14 @@ struct lambda1405analysis { rSelections.get(HIST("hSelectionsKinkPr"))->GetXaxis()->SetBinLabel(6, "has TOF"); rSelections.get(HIST("hSelectionsKinkPr"))->GetXaxis()->SetBinLabel(7, "N#sigma TOF"); - if (doprocessDataWCentQVecs) { + if (doprocessDataWQVecsSameEvent || doprocessDataWQVecsMixedEvent) { rLambda1405.add("hScalarProd", "hScalarProd", {HistType::kTH2F, {scalarProdAxis, ptAxis}}); std::vector axesFlow = {lambda1405MassAxis, ptAxis, centMultAxis, scalarProdAxis}; rLambda1405.add("hSparseFlowL1405", "THn for SP", HistType::kTHnSparseF, axesFlow); } // Add MC histograms - if (doprocessMc || doprocessMcWCentSel) { + if (doprocessMc) { rSelections.add("hRecoNotMatchedCounter", "hRecoNotMatchedCounter", {HistType::kTH1D, {{4, -0.5, 3.5f}}}); rSelections.get(HIST("hRecoNotMatchedCounter"))->GetXaxis()->SetBinLabel(1, "#Lambda(1405)"); @@ -446,22 +470,29 @@ struct lambda1405analysis { rLambda1405.add("h2PtMassMC", "h2PtMassMC", {HistType::kTH2F, {ptAxis, lambda1405MassAxis}}); } + if (doprocessMcSigmasCentSel) { + rSigmaPlus.add("hSparseGenFromRecoSigmaPlus", "THn for generated Sigma plus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + rSigmaPlus.add("hSparseGenSigmaPlus", "THn for generated Sigma plus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + rSigmaMinus.add("hSparseGenFromRecoSigmaMinus", "THn for generated Sigma minus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + rSigmaMinus.add("hSparseGenSigmaMinus", "THn for generated Sigma minus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + } + // Functional selections - funcMinQtAlphaAP = TF1("funcMinQtAlphaAP", Form("%s", cutSigmaQtAPMin.value.data()), -1, 1); - LOGF(info, "funcMinQtAlphaAP: %s", Form("%s", cutSigmaQtAPMin.value.data())); - funcMaxQtAlphaAP = TF1("funcMaxQtAlphaAP", Form("%s", cutSigmaQtAPMax.value.data()), -1, 1); - LOGF(info, "funcMaxQtAlphaAP: %s", Form("%s", cutSigmaQtAPMax.value.data())); - funcMinBachPiPtVsL1405Pt = TF1("funcMinBachPiPtVsL1405Pt", Form("%s", cutMinBachPiPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMinBachPiPtVsL1405Pt: %s", Form("%s", cutMinBachPiPtVsL1405Pt.value.data())); - funcMaxBachPiPtVsL1405Pt = TF1("funcMaxBachPiPtVsL1405Pt", Form("%s", cutMaxBachPiPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMaxBachPiPtVsL1405Pt: %s", Form("%s", cutMaxBachPiPtVsL1405Pt.value.data())); - funcMinSigmaPtVsL1405Pt = TF1("funcMinSigmaPtVsL1405Pt", Form("%s", cutMinSigmaPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMinSigmaPtVsL1405Pt: %s", Form("%s", cutMinSigmaPtVsL1405Pt.value.data())); - funcMaxSigmaPtVsL1405Pt = TF1("funcMaxSigmaPtVsL1405Pt", Form("%s", cutMaxSigmaPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMaxSigmaPtVsL1405Pt: %s", Form("%s", cutMaxSigmaPtVsL1405Pt.value.data())); - funcDcaXYPtCutBachPi = TF1("funcDcaXYPtCutBachPi", Form("[0]*%s", dcaXYPtBachFunc.value.data()), 0.001, 100); - funcDcaXYPtCutBachPi.SetParameter(0, dcaXYBachNSigmaMax); - LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", dcaXYPtBachFunc.value.data())); + funcMinQtAlphaAP = TF1("funcMinQtAlphaAP", Form("%s", selections.cutSigmaQtAPMin.value.data()), -1, 1); + LOGF(info, "funcMinQtAlphaAP: %s", Form("%s", selections.cutSigmaQtAPMin.value.data())); + funcMaxQtAlphaAP = TF1("funcMaxQtAlphaAP", Form("%s", selections.cutSigmaQtAPMax.value.data()), -1, 1); + LOGF(info, "funcMaxQtAlphaAP: %s", Form("%s", selections.cutSigmaQtAPMax.value.data())); + funcMinBachPiPtVsL1405Pt = TF1("funcMinBachPiPtVsL1405Pt", Form("%s", selections.cutMinBachPiPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMinBachPiPtVsL1405Pt: %s", Form("%s", selections.cutMinBachPiPtVsL1405Pt.value.data())); + funcMaxBachPiPtVsL1405Pt = TF1("funcMaxBachPiPtVsL1405Pt", Form("%s", selections.cutMaxBachPiPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMaxBachPiPtVsL1405Pt: %s", Form("%s", selections.cutMaxBachPiPtVsL1405Pt.value.data())); + funcMinSigmaPtVsL1405Pt = TF1("funcMinSigmaPtVsL1405Pt", Form("%s", selections.cutMinSigmaPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMinSigmaPtVsL1405Pt: %s", Form("%s", selections.cutMinSigmaPtVsL1405Pt.value.data())); + funcMaxSigmaPtVsL1405Pt = TF1("funcMaxSigmaPtVsL1405Pt", Form("%s", selections.cutMaxSigmaPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMaxSigmaPtVsL1405Pt: %s", Form("%s", selections.cutMaxSigmaPtVsL1405Pt.value.data())); + funcDcaXYPtCutBachPi = TF1("funcDcaXYPtCutBachPi", Form("[0]*%s", selections.dcaXYPtBachFunc.value.data()), 0.001, 100); + funcDcaXYPtCutBachPi.SetParameter(0, selections.dcaXYBachNSigmaMax); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", selections.dcaXYPtBachFunc.value.data())); rSelections.print(); rSigmaMinus.print(); @@ -469,20 +500,37 @@ struct lambda1405analysis { rLambda1405.print(); // Info for DCA propagation of bachelor tracks - mRunNumber = 0; - mBz = 0; ccdb->setURL(ccdbPath); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); } + /// Get the binning pool associated to the collision + /// \param collision is the collision + /// \param binPolicy is the binning policy for the correlation + template + int getPoolBin(const TColl& collision, const TBinningType& binPolicy) + { + int poolBin{0}; + float centMult = getCentMult(collision); + poolBin = binPolicy.getBin(std::make_tuple(centMult, collision.posZ())); + if constexpr (std::is_same_v) { + rEventSelection.fill(HIST("hCentPoolBin"), centMult, poolBin); + } else if constexpr (std::is_same_v) { + rEventSelection.fill(HIST("hMultPoolBin"), centMult, poolBin); + } + rEventSelection.fill(HIST("hZVtxPoolBin"), collision.posZ(), poolBin); + rEventSelection.fill(HIST("hPoolBins"), poolBin); + return poolBin; + } + template float getCentMult(const TCollision& collision) { - if constexpr (requires { collision.centFT0C(); }) { + if (useCentrality) { return collision.centFT0C(); } else { - return collision.multFT0C(); + return collision.multFT0M(); } } @@ -517,8 +565,9 @@ struct lambda1405analysis { double massSigma = isSigmaMinus ? o2::constants::physics::MassSigmaMinus : o2::constants::physics::MassSigmaPlus; double pMother = std::sqrt(sigmaPx * sigmaPx + sigmaPy * sigmaPy + sigmaPz * sigmaPz); - if (pMother < 1e-12f) { - LOG(info) << "Recalculation of Sigma momentum failed: mother momentum is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz; + float zeroValTolerance{1e-12f}; + if (pMother < zeroValTolerance) { + LOG(debug) << "Recalculation of Sigma momentum failed: mother momentum is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz; return -999.f; } if (isSigmaMinus) { @@ -537,8 +586,8 @@ struct lambda1405analysis { double B = -4.0 * a * K; double C = 4.0 * eChDau * eChDau * massSigma * massSigma - K * K; - if (std::abs(A) < 1e-6f) { - LOG(info) << "Recalculation of Sigma momentum failed: A is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C; + if (std::abs(A) < zeroValTolerance) { + LOG(debug) << "Recalculation of Sigma momentum failed: A is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C; return -999.f; } if (isSigmaMinus) { @@ -547,22 +596,22 @@ struct lambda1405analysis { rSelections.fill(HIST("hRecalcSigmaPlusMom"), 2); // Non-zero A } - double D = B * B - 4.0 * A * C; - if (D < 0.0) { - LOG(info) << "Recalculation of Sigma momentum failed: D is negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C << ", D = " << D; + double det = B * B - 4.0 * A * C; + if (det < 0.0) { + LOG(debug) << "Recalculation of Sigma momentum failed: determinant is negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C << ", determinant = " << det; return -999.f; } if (isSigmaMinus) { - rSelections.fill(HIST("hRecalcSigmaMinusMom"), 3); // Positive D + rSelections.fill(HIST("hRecalcSigmaMinusMom"), 3); // Positive determinant } else { - rSelections.fill(HIST("hRecalcSigmaPlusMom"), 3); // Positive D + rSelections.fill(HIST("hRecalcSigmaPlusMom"), 3); // Positive determinant } - double sqrtD = std::sqrt(D); - double P1 = (-B + sqrtD) / (2.0 * A); - double P2 = (-B - sqrtD) / (2.0 * A); - if (P2 < 0.0 && P1 < 0.0) { - LOG(info) << "Recalculation of Sigma momentum failed: both solutions are negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", P1: " << P1 << ", P2: " << P2; + double sqrtDet = std::sqrt(det); + double p1 = (-B + sqrtDet) / (2.0 * A); + double p2 = (-B - sqrtDet) / (2.0 * A); + if (p2 < 0.0 && p1 < 0.0) { + LOG(debug) << "Recalculation of Sigma momentum failed: both solutions are negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", p1: " << p1 << ", p2: " << p2; return -999.f; } if (isSigmaMinus) { @@ -572,43 +621,40 @@ struct lambda1405analysis { } success = true; - if (P2 < 0.0) { - return static_cast(P1); + if (p2 < 0.0) { + return static_cast(p1); } - if (P1 < 0.0) { - return static_cast(P2); + if (p1 < 0.0) { + return static_cast(p2); } - double p1Diff = std::abs(P1 - pMother); - double p2Diff = std::abs(P2 - pMother); - return static_cast((p1Diff < p2Diff) ? P1 : P2); + double p1Diff = std::abs(p1 - pMother); + double p2Diff = std::abs(p2 - pMother); + return static_cast((p1Diff < p2Diff) ? p1 : p2); } template - bool selectPiBach(const TTrack& candidate, const o2::dataformats::VertexBase& vtx, float centMult) + bool selectPiBach(const TTrack& candidate, float centMult) { - if (std::abs(candidate.tpcNSigmaPi()) > cutNSigTpc) { + if (std::abs(candidate.tpcNSigmaPi()) > selections.cutNSigTpc) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 2); // Nsigma Tpc - if (candidate.tpcNClsFound() < cutNTpcClus) { + if (candidate.tpcNClsFound() < selections.cutNTpcClus) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 3); // Tpc clusters - if (std::abs(candidate.eta()) > cutEtaDaughter) { + if (std::abs(candidate.eta()) > selections.cutEtaDaughter) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 4); // Eta selection - o2::track::TrackParCov trackParCovTrack = getTrackParCov(candidate); - std::array dcaInfoMoth; - o2::base::Propagator::Instance()->propagateToDCABxByBz({vtx.getX(), vtx.getY(), vtx.getZ()}, - trackParCovTrack, 2.f, static_cast(cfgMaterialCorrection.value), - &dcaInfoMoth); - rLambda1405.fill(HIST("h3BachPiDcaXYVsPt"), candidate.pt(), dcaInfoMoth[0], centMult); - rLambda1405.fill(HIST("h3BachPiDcaZVsPt"), candidate.pt(), dcaInfoMoth[1], centMult); - if (std::abs(dcaInfoMoth[0]) > funcDcaXYPtCutBachPi.Eval(candidate.pt()) || std::abs(dcaInfoMoth[1]) > cutMaxDcaZBach) { + std::array dcaInfoBachPi{candidate.dcaXY(), candidate.dcaZ()}; + rLambda1405.fill(HIST("h3BachPiDcaXYVsPt"), candidate.pt(), dcaInfoBachPi[0], centMult); + rLambda1405.fill(HIST("h3BachPiDcaZVsPt"), candidate.pt(), dcaInfoBachPi[1], centMult); + if (std::abs(dcaInfoBachPi[0]) > funcDcaXYPtCutBachPi.Eval(candidate.pt()) || + std::abs(dcaInfoBachPi[1]) > selections.cutMaxDcaZBach) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 5); // DCA selection @@ -621,22 +667,22 @@ struct lambda1405analysis { { rSelections.fill(HIST("hSelectionsKinkPi"), 0); // All pion kink candidates - if (std::abs(candidate.tpcNSigmaPi()) > cutNSigTpc) { + if (std::abs(candidate.tpcNSigmaPi()) > selections.cutNSigTpc) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 1); // Nsigma Tpc - if (candidate.tpcNClsFound() < cutNTpcClus) { + if (candidate.tpcNClsFound() < selections.cutNTpcClus) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 2); // Tpc clusters - if (std::abs(candidate.eta()) > cutEtaDaughter) { + if (std::abs(candidate.eta()) > selections.cutEtaDaughter) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 3); // Eta selection - if (candidate.itsNCls() < cutItsNClusKinkMin || candidate.itsNCls() > cutItsNClusKinkMax) { + if (candidate.itsNCls() < selections.cutItsNClusKinkMin || candidate.itsNCls() > selections.cutItsNClusKinkMax) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 4); // ITS clusters @@ -646,7 +692,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsKinkPi"), 5); // has Tof - if (useTof && std::abs(candidate.tofNSigmaPi()) > cutNSigTof) { + if (useTof && std::abs(candidate.tofNSigmaPi()) > selections.cutNSigTof) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 6); // Nsigma Tof @@ -659,22 +705,22 @@ struct lambda1405analysis { { rSelections.fill(HIST("hSelectionsKinkPr"), 0); // All proton kink candidates - if (std::abs(candidate.tpcNSigmaPr()) > cutNSigTpc) { + if (std::abs(candidate.tpcNSigmaPr()) > selections.cutNSigTpc) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 1); // Nsigma Tpc - if (candidate.tpcNClsFound() < cutNTpcClus) { + if (candidate.tpcNClsFound() < selections.cutNTpcClus) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 2); // Tpc clusters - if (std::abs(candidate.eta()) > cutEtaDaughter) { + if (std::abs(candidate.eta()) > selections.cutEtaDaughter) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 3); // eta selection - if (candidate.itsNCls() < cutItsNClusKinkMin || candidate.itsNCls() > cutItsNClusKinkMax) { + if (candidate.itsNCls() < selections.cutItsNClusKinkMin || candidate.itsNCls() > selections.cutItsNClusKinkMax) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 4); // ITS clusters @@ -684,7 +730,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsKinkPr"), 5); // has Tof - if (useTof && std::abs(candidate.tofNSigmaPr()) > cutNSigTof) { + if (useTof && std::abs(candidate.tofNSigmaPr()) > selections.cutNSigTof) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 6); // Nsigma Tof @@ -744,24 +790,8 @@ struct lambda1405analysis { rLambda1405.fill(HIST("h2BachPiPtNSigTpc"), cand.bachPiPt, cand.bachPiNSigTpc); rLambda1405.fill(HIST("h2BachPiPtNSigTof"), cand.bachPiPt, cand.bachPiNSigTof); - // std::vector axesMass = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis}; - // if (doprocessMc || doprocessMcWCentSel) { - // axesMass.push_back(pvContribAxis); - // } else { - // axesMass.push_back(centMultAxis); - // } - // rLambda1405.add("hSparseL1405", "THn for mass peak", HistType::kTHnSparseF, axes); - // std::vector axesScalarProd = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis, centMultAxis, scalarProdAxis}; - // if (doprocessDataWCentQVecs) { - // rLambda1405.add("hSparseL1405ScalProd", "THn for SP", HistType::kTHnSparseF, axesScalarProd); - // } - // std::vector axesCorrel = {lambda1405MassAxis, ptAxis, deltaEtaAxis, deltaPhiAxis}; - // if (saveDEtaDPhi) { - // rLambda1405.add("hSparseL1405Correl", "THn for 2PC", HistType::kTHnSparseF, axesCorrel); - // } - auto hSparseMass = rLambda1405.get(HIST("hSparseL1405")); - std::vector sparseMassEntry = {cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; + std::vector sparseMassEntry = {static_cast(cand.poolBin), cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; if constexpr (IsMC) { sparseMassEntry.push_back(cand.pvContrib); } else { @@ -769,14 +799,14 @@ struct lambda1405analysis { } hSparseMass->Fill(sparseMassEntry.data()); if constexpr (FillQVectors) { - std::vector sparseScalProdEntry = {cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; + std::vector sparseScalProdEntry = {static_cast(cand.poolBin), cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; sparseScalProdEntry.push_back(cand.centMult); sparseScalProdEntry.push_back(cand.scalarProd); auto hSparseScalProd = rLambda1405.get(HIST("hSparseL1405ScalProd")); hSparseScalProd->Fill(sparseScalProdEntry.data()); } if constexpr (FillCorrelations) { - std::vector sparseCorrelEntry = {cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; + std::vector sparseCorrelEntry = {static_cast(cand.poolBin), cand.massL1405, cand.pt()}; auto hSparseCorrel = rLambda1405.get(HIST("hSparseL1405Correl")); sparseCorrelEntry.push_back(0.0); // Δη sparseCorrelEntry.push_back(0.0); // Δφ @@ -804,37 +834,22 @@ struct lambda1405analysis { } } - void initCCDB(aod::BCs::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - LOG(info) << "Initializing CCDB for run " << mRunNumber; - o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); - o2::base::Propagator::initFieldFromGRP(grpmag); - mBz = grpmag->getNominalL3Field(); - - if (!lut) { - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - } - o2::base::Propagator::Instance()->setMatLUT(lut); - LOG(info) << "Task initialized for run " << mRunNumber << " with magnetic field " << mBz << " kZG"; - } - - template - void constructCollCandidates(const TColl& collision, aod::KinkCands::iterator const& sigmaCand, TracksFull const& tracks, std::vector& selectedCandidates) + template + void constructCollCandidates(const TColl& collision, + aod::KinkCands::iterator const& sigmaCand, + TracksFull const& tracks, + std::vector& selectedCandidates, + TBinningType binPolicy) { - // Retrieve primary vertex, once for all candidates in the collision - auto const& bc = collision.template bc_as(); - initCCDB(bc); - o2::dataformats::VertexBase primaryVertex; - primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); - primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - lambda1405candidate lambda1405Cand{}; + if constexpr (!IsMc) { + // Set pool bin + int const poolBin = getPoolBin(collision, binPolicy); + lambda1405Cand.poolBin = poolBin; + } + rSelections.fill(HIST("hSelectionsL1405"), 0); // All candidates rSelections.fill(HIST("hSelectionsSigmaMinus"), 0); // All Sigma- candidates rSelections.fill(HIST("hSelectionsSigmaPlus"), 0); // All Sigma+ candidates @@ -907,12 +922,12 @@ struct lambda1405analysis { rSigmaPlus.fill(HIST("h2PtPrKinkNSigBeforeCuts"), kinkDauTrack.pt(), kinkDauTrack.tpcNSigmaPr()); } - if (lambda1405Cand.isSigmaMinus && (sigmaCand.mSigmaMinus() < o2::constants::physics::MassSigmaMinus - cutSigmaMass || - sigmaCand.mSigmaMinus() > o2::constants::physics::MassSigmaMinus + cutSigmaMass)) { + if (lambda1405Cand.isSigmaMinus && (sigmaCand.mSigmaMinus() < o2::constants::physics::MassSigmaMinus - selections.cutSigmaMass || + sigmaCand.mSigmaMinus() > o2::constants::physics::MassSigmaMinus + selections.cutSigmaMass)) { return; } - if (lambda1405Cand.isSigmaPlus && (sigmaCand.mSigmaPlus() < o2::constants::physics::MassSigmaPlus - cutSigmaMass || - sigmaCand.mSigmaPlus() > o2::constants::physics::MassSigmaPlus + cutSigmaMass)) { + if (lambda1405Cand.isSigmaPlus && (sigmaCand.mSigmaPlus() < o2::constants::physics::MassSigmaPlus - selections.cutSigmaMass || + sigmaCand.mSigmaPlus() > o2::constants::physics::MassSigmaPlus + selections.cutSigmaMass)) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -921,7 +936,7 @@ struct lambda1405analysis { rSelections.fill(HIST("hSelectionsSigmaPlus"), 3); // Passed mass sel } - if (std::abs(sigmaCand.dcaMothPv()) > cutDcaToPvSigma) { + if (std::abs(sigmaCand.dcaMothPv()) > selections.cutDcaToPvSigma) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -930,7 +945,7 @@ struct lambda1405analysis { rSelections.fill(HIST("hSelectionsSigmaPlus"), 4); // Passed cutDcaToPvSigma } - if (std::abs(sigmaCand.dcaDaugPv()) < cutDcaToPvPiFromSigma) { + if (std::abs(sigmaCand.dcaDaugPv()) < selections.cutDcaToPvPiFromSigma) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -940,7 +955,7 @@ struct lambda1405analysis { } float sigmaRad = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); - if (sigmaRad < cutSigmaRadius) { + if (sigmaRad < selections.cutSigmaRadius) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -1010,7 +1025,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsBachPi"), 1); - if (!selectPiBach(piTrack, primaryVertex, lambda1405Cand.centMult)) { + if (!selectPiBach(piTrack, lambda1405Cand.centMult)) { continue; } rSelections.fill(HIST("hSelectionsL1405"), 2); // Bach Pi selection @@ -1022,7 +1037,7 @@ struct lambda1405analysis { } else if (lambda1405Cand.isSigmaPlus) { invMass = RecoDecay::m(std::array{sigmaMom, piMom}, std::array{o2::constants::physics::MassSigmaPlus, o2::constants::physics::MassPiMinus}); } - if (invMass > cutUpperMass) { + if (invMass > selections.cutUpperMass) { continue; } rSelections.fill(HIST("hSelectionsL1405"), 3); // Upper mass selection @@ -1065,7 +1080,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsL1405"), 4); // Pt correlations - if (lambda1405Cand.pt() < cutMinPtL1405) { + if (lambda1405Cand.pt() < selections.cutMinPtL1405) { continue; } rSelections.fill(HIST("hSelectionsL1405"), 5); // Accepted @@ -1079,20 +1094,16 @@ struct lambda1405analysis { template bool checkSigmaKinkMC(const mcTrack& mcTrackSigma, const mcTrack& mcTrackKinkDau, float sigmaAbsPDG, float kinkAbsPDG, aod::McParticles const&) { - LOG(info) << "Checking Sigma kink decay for MC tracks: Sigma PDG = " << mcTrackSigma.pdgCode() << ", Kink daughter PDG = " << mcTrackKinkDau.pdgCode(); if (std::abs(mcTrackSigma.pdgCode()) != sigmaAbsPDG || std::abs(mcTrackKinkDau.pdgCode()) != kinkAbsPDG) { - LOG(info) << "PDG codes do not match expected values: Sigma PDG = " << sigmaAbsPDG << ", Kink daughter PDG = " << kinkAbsPDG; return false; // Not a valid Sigma kink decay } if (!mcTrackKinkDau.has_mothers()) { - LOG(info) << "Kink daughter has no mothers"; return false; // No mothers found } // Check if the kink comes from the Sigma bool isKinkFromSigma = false; for (const auto& mcMother : mcTrackKinkDau.template mothers_as()) { if (mcMother.globalIndex() == mcTrackSigma.globalIndex()) { - LOG(info) << "Kink daughter comes from the Sigma"; isKinkFromSigma = true; break; } @@ -1100,15 +1111,15 @@ struct lambda1405analysis { return isKinkFromSigma; // Return true if the kink comes from the Sigma } - template - void fillOutputData(const TCollision& collision, const TCand& sigmaCands, const TTrack& tracks) + template + void fillOutputData(const TCollision& collision, const TCand& sigmaCands, const TTrack& tracks, TBinningType binPolicy) { - if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { + if (std::abs(collision.posZ()) > eventSelection.cutZVertex || !collision.sel8()) { return; } rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); float centMult = getCentMult(collision); - if (centMult < centMultMin || centMult > centMultMax) { + if (centMult < eventSelection.centMultMin || centMult > eventSelection.centMultMax) { return; } rEventSelection.fill(HIST("hCentMultVsPvContrib"), centMult, collision.numContrib()); @@ -1117,7 +1128,7 @@ struct lambda1405analysis { for (const auto& sigmaCand : sigmaCands) { std::vector selectedCandidates; - constructCollCandidates(collision, sigmaCand, tracks, selectedCandidates); + constructCollCandidates(collision, sigmaCand, tracks, selectedCandidates, binPolicy); for (const auto& lambda1405Cand : selectedCandidates) { if (lambda1405Cand.isSigmaMinus) { rLambda1405.fill(HIST("h2SigmaMinusMassVsLambdaMass"), lambda1405Cand.massL1405, lambda1405Cand.sigmaMinusMass); @@ -1142,17 +1153,8 @@ struct lambda1405analysis { lambda1405Cand.kinkPrNSigTpc, lambda1405Cand.kinkPrNSigTof, lambda1405Cand.kinkDcaDauToPv, lambda1405Cand.bachPiNSigTpc, lambda1405Cand.bachPiNSigTof, - lambda1405Cand.centMult, lambda1405Cand.occupancy); - } else { - outputDataFlowTable(ptCand, lambda1405Cand.massL1405, - lambda1405Cand.sigmaPt, - lambda1405Cand.sigmaMinusMass, lambda1405Cand.sigmaPlusMass, - lambda1405Cand.sigmaAlphaAP, lambda1405Cand.sigmaQtAP, - lambda1405Cand.kinkPiNSigTpc, lambda1405Cand.kinkPiNSigTof, - lambda1405Cand.kinkPrNSigTpc, lambda1405Cand.kinkPrNSigTof, - lambda1405Cand.kinkDcaDauToPv, - lambda1405Cand.bachPiNSigTpc, lambda1405Cand.bachPiNSigTof, - lambda1405Cand.scalarProd, lambda1405Cand.centMult); + lambda1405Cand.scalarProd, + lambda1405Cand.centMult, lambda1405Cand.occupancy, lambda1405Cand.poolBin); // 24 } } @@ -1174,23 +1176,93 @@ struct lambda1405analysis { } } - void processData(CollisionsFull::iterator const& collision, - aod::KinkCands const& kinkCands, - TracksFull const& tracks, - const aod::BCs&) + void processDataSameEvent(CollisionsSel::iterator const& collision, + aod::KinkCands const& kinkCands, + TracksFull const& tracks, + const aod::BCs&) + { + if (useCentrality) { + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + fillOutputData(collision, kinkCands, tracks, binPolicy); + } else { + BinningMultPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + fillOutputData(collision, kinkCands, tracks, binPolicy); + } + } + PROCESS_SWITCH(lambda1405analysis, processDataSameEvent, "Data processing", true); + + void processDataWQVecsSameEvent(CollisionsSelWQVecs::iterator const& collision, + aod::KinkCands const& kinkCands, + TracksFull const& tracks, + const aod::BCs&) { - fillOutputData(collision, kinkCands, tracks); + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + fillOutputData(collision, kinkCands, tracks, binPolicy); } - PROCESS_SWITCH(lambda1405analysis, processData, "Data processing", true); + PROCESS_SWITCH(lambda1405analysis, processDataWQVecsSameEvent, "Data processing with centrality and Q vectors info", false); - void processDataWCentQVecs(CollisionsCentSel::iterator const& collision, + void processDataMixedEvent(CollisionsFull const& collisions, aod::KinkCands const& kinkCands, TracksFull const& tracks, const aod::BCs&) { - fillOutputData(collision, kinkCands, tracks); + auto pairsTuple = std::make_tuple(kinkCands, tracks); + if (useCentrality) { + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + Pair const pairs{binPolicy, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + for (const auto& [sigmasColl, sigmas, bachPisColl, bachPis] : pairs) { + if (sigmas.size() == 0 || bachPis.size() == 0) { + continue; + } + int const poolBinSigma = getPoolBin(sigmasColl, binPolicy); + int const poolBinBachPi = getPoolBin(bachPisColl, binPolicy); + if (poolBinBachPi != poolBinSigma) { + LOG(debug) << "Different poolBins for sigma and bachelor pi: " << poolBinSigma << " vs " << poolBinBachPi; + continue; + } + fillOutputData(sigmasColl, sigmas, bachPis, binPolicy); + } + } else { + BinningMultPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + Pair const pairs{binPolicy, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + for (const auto& [sigmasColl, sigmas, bachPisColl, bachPis] : pairs) { + if (sigmas.size() == 0 || bachPis.size() == 0) { + continue; + } + int const poolBinSigma = getPoolBin(sigmasColl, binPolicy); + int const poolBinBachPi = getPoolBin(bachPisColl, binPolicy); + if (poolBinBachPi != poolBinSigma) { + LOG(debug) << "Different poolBins for sigma and bachelor pi: " << poolBinSigma << " vs " << poolBinBachPi; + continue; + } + fillOutputData(sigmasColl, sigmas, bachPis, binPolicy); + } + } } - PROCESS_SWITCH(lambda1405analysis, processDataWCentQVecs, "Data processing with centrality and Q vectors info", false); + PROCESS_SWITCH(lambda1405analysis, processDataMixedEvent, "Data event mixing processing", false); + + void processDataWQVecsMixedEvent(CollisionsSelWQVecs const& collisions, + aod::KinkCands const& kinkCands, + TracksFull const& tracks, + const aod::BCs&) + { + auto pairsTuple = std::make_tuple(kinkCands, tracks); + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + Pair const pairs{binPolicy, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + for (const auto& [sigmasColl, sigmas, bachPisColl, bachPis] : pairs) { + if (sigmas.size() == 0 || bachPis.size() == 0) { + continue; + } + int const poolBinSigma = getPoolBin(sigmasColl, binPolicy); + int const poolBinBachPi = getPoolBin(bachPisColl, binPolicy); + if (poolBinBachPi != poolBinSigma) { + LOG(debug) << "Different poolBins for sigma and bachelor pi: " << poolBinSigma << " vs " << poolBinBachPi; + continue; + } + fillOutputData(sigmasColl, sigmas, bachPis, binPolicy); + } + } + PROCESS_SWITCH(lambda1405analysis, processDataWQVecsMixedEvent, "Data event mixing with centrality and Q vectors info", false); template int matchGenDecay(const TMother& motherPart, const aod::McParticles& mcParticles, std::array& daugsIdxs) @@ -1271,42 +1343,31 @@ struct lambda1405analysis { const TTrack& tracks, const aod::McParticles& particlesMC) { - LOG(info) << "Filling output MC for " << recoCollisions.size() << " collisions, " << sigmaCands.size() << " Sigma candidates, and " << tracks.size() << " tracks"; for (const auto& collision : recoCollisions) { - LOG(info) << "\n\nProcessing collision with global index: " << collision.globalIndex() << " and " << sigmaCands.size() << " Sigma candidates, and " << tracks.size() << " tracks"; - if (std::abs(collision.posZ()) > cutZVertex) { // || !collision.sel8()) { - LOG(info) << "Collision failed Z vertex cut: " << collision.posZ(); + if (std::abs(collision.posZ()) > eventSelection.cutZVertex) { // || !collision.sel8()) { continue; } - LOG(info) << "Collision passed Z vertex cut: " << collision.posZ(); rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); float centMult = getCentMult(collision); - LOG(info) << "Collision centrality: " << centMult; - if (centMult < centMultMin || centMult > centMultMax) { - LOG(info) << "Collision failed centrality cut: " << centMult; + if (centMult < eventSelection.centMultMin || centMult > eventSelection.centMultMax) { continue; } - LOG(info) << "Collision passed centrality cut: " << centMult; rEventSelection.fill(HIST("hCentMultVsPvContrib"), centMult, collision.numContrib()); rEventSelection.fill(HIST("hOccVsPvContrib"), collision.ft0cOccupancyInTimeRange(), collision.numContrib()); rEventSelection.fill(HIST("hCentVsOcc"), centMult, collision.ft0cOccupancyInTimeRange()); auto sigmaCandsPerCol = sigmaCands.sliceBy(mKinkPerCol, collision.globalIndex()); auto tracksPerCol = tracks.sliceBy(mPerColTracks, collision.globalIndex()); - LOG(info) << "Start loop on " << sigmaCandsPerCol.size() << " Sigma candidates ... "; for (const auto& sigmaCand : sigmaCandsPerCol) { - LOG(info) << "Processing Sigma candidate with global index: " << sigmaCand.globalIndex(); // Perform the sigma matching here, so sigma histograms // can be used for efficiency studies on the sigma auto labelSigma = trackLabelsMC.rawIteratorAt(sigmaCand.trackMothId()); auto labelKinkDaug = trackLabelsMC.rawIteratorAt(sigmaCand.trackDaugId()); if (!labelSigma.has_mcParticle()) { - LOG(info) << "Sigma candidate with global index: " << sigmaCand.globalIndex() << " is not matched to MC particle"; rSelections.fill(HIST("hRecoNotMatchedCounter"), 1); // Sigma not matched } if (!labelKinkDaug.has_mcParticle()) { - LOG(info) << "Kink daughter candidate with global index: " << sigmaCand.globalIndex() << " is not matched to MC particle"; rSelections.fill(HIST("hRecoNotMatchedCounter"), 2); // Kink daughter not matched } auto genSigma = labelSigma.template mcParticle_as(); @@ -1317,21 +1378,17 @@ struct lambda1405analysis { bool isSigmaPlusToPrKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaPlus, PDG_t::kProton, particlesMC); if (!isSigmaMinusKink && !isSigmaPlusToPiKink && !isSigmaPlusToPrKink) { - LOG(info) << "Candidate is not a valid Sigma kink decay, skipping ..."; continue; // Skip if not a valid Sigma kink decay } if (isSigmaMinusKink) { - LOG(info) << "Filling h2DeltaGenRecoPtSigmaMinus with: " << sigmaCand.ptMoth() - genSigma.pt() << ", " << sigmaCand.ptMoth(); rSigmaMinus.fill(HIST("h2DeltaGenRecoPtSigmaMinus"), sigmaCand.ptMoth() - genSigma.pt(), sigmaCand.ptMoth()); } if (isSigmaPlusToPiKink || isSigmaPlusToPrKink) { - LOG(info) << "Filling h2DeltaGenRecoPtSigmaPlus with: " << sigmaCand.ptMoth() - genSigma.pt() << ", " << sigmaCand.ptMoth(); rSigmaPlus.fill(HIST("h2DeltaGenRecoPtSigmaPlus"), sigmaCand.ptMoth() - genSigma.pt(), sigmaCand.ptMoth()); } - std::vector selectedCandidates; - LOG(info) << "Constructing Lambda(1405) candidates from Sigma candidate with global index: " << sigmaCand.globalIndex(); - constructCollCandidates(collision, sigmaCand, tracksPerCol, selectedCandidates); + const int dummyPoolBin{-1}; // Not used in MC, but required by the function signature + constructCollCandidates(collision, sigmaCand, tracksPerCol, selectedCandidates, dummyPoolBin); for (const auto& lambda1405Cand : selectedCandidates) { rLambda1405.fill(HIST("hRecoL1405"), 0., lambda1405Cand.pt()); // All reconstructed @@ -1476,16 +1533,197 @@ struct lambda1405analysis { } PROCESS_SWITCH(lambda1405analysis, processMc, "MC processing", false); - void processMcWCentSel(McRecoCollisionsCentSel const& recoCollisions, - aod::KinkCands const& kinkCands, - aod::McTrackLabels const& trackLabelsMC, - aod::McParticles const& particlesMC, - TracksFull const& tracks, - const aod::BCs&) + void processMcSigmasCentSel(McRecoCollisionsSel const& recoCollisions, + aod::KinkCands const& sigmaCands, + aod::McTrackLabels const& trackLabelsMC, + aod::McParticles const& particlesMC, + aod::McCollisions const&, + const aod::BCs&) { - fillOutputMc(recoCollisions, kinkCands, trackLabelsMC, tracks, particlesMC); + // Loop over kink candidates to fill Sigma efficiency histograms + for (const auto& collision : recoCollisions) { + if (std::abs(collision.posZ()) > eventSelection.cutZVertex) { // || !collision.sel8()) { + continue; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + float centMult = getCentMult(collision); + if (centMult < eventSelection.centMultMin || centMult > eventSelection.centMultMax) { + continue; + } + + rEventSelection.fill(HIST("hCentMultVsPvContrib"), centMult, collision.numContrib()); + rEventSelection.fill(HIST("hOccVsPvContrib"), collision.ft0cOccupancyInTimeRange(), collision.numContrib()); + rEventSelection.fill(HIST("hCentVsOcc"), centMult, collision.ft0cOccupancyInTimeRange()); + + // Compute occupancy and pv contrib of the generated collision + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + if (recoCollsPerMcColl.size() == 0) { + continue; // Skip if no reconstructed collisions associated with this MC collision + } + unsigned genNumContrib = 0; + float genOcc{0.f}; + float genCentMult{0.f}; + for (const auto& recCol : recoCollsPerMcColl) { + genNumContrib = recCol.numContrib() > genNumContrib ? recCol.numContrib() : genNumContrib; + genOcc = recCol.ft0cOccupancyInTimeRange() > genOcc ? recCol.ft0cOccupancyInTimeRange() : genOcc; + genCentMult = getCentMult(collision) > genCentMult ? getCentMult(collision) : genCentMult; + } + + auto sigmaCandsPerCol = sigmaCands.sliceBy(mKinkPerCol, collision.globalIndex()); + for (const auto& sigmaCand : sigmaCandsPerCol) { + + auto labelSigma = trackLabelsMC.rawIteratorAt(sigmaCand.trackMothId()); + auto labelKinkDaug = trackLabelsMC.rawIteratorAt(sigmaCand.trackDaugId()); + if (!labelSigma.has_mcParticle() || !labelKinkDaug.has_mcParticle()) { + continue; // No generated particles + } + auto genSigma = labelSigma.template mcParticle_as(); + auto genKinkDaug = labelKinkDaug.template mcParticle_as(); + + bool isSigmaMinusKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaMinus, PDG_t::kPiPlus, particlesMC); + bool isSigmaPlusToPiKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaPlus, PDG_t::kPiPlus, particlesMC); + bool isSigmaPlusToPrKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaPlus, PDG_t::kProton, particlesMC); + + if (skipBkgSigmas && (!isSigmaMinusKink && !isSigmaPlusToPiKink && !isSigmaPlusToPrKink)) { + continue; // Skip if not a valid Sigma kink decay + } + + float sigmaPt = sigmaCand.ptMoth(); + if (downSampleFactor < 1.) { + float const pseudoRndm = sigmaPt * 1000. - static_cast(sigmaPt * 1000); + if (sigmaPt < ptDownSampleMax && pseudoRndm >= downSampleFactor) { + continue; + } + } + + std::array sigmaMomReco{sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array kinkMomReco{sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + float recoSigmaAlphaAP = alphaAP(sigmaMomReco, kinkMomReco); + float recoSigmaQtAP = qtAP(sigmaMomReco, kinkMomReco); + + // Recompute the sigma momentum + bool success{false}; + float sigmaPRecalc = recalcSigmaMom(success, isSigmaMinusKink, + sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth(), + sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()); + if (!success && skipSigmasFailedRecompMom) { + return; + } + if (success) { + float sigmaPOriginal = std::sqrt(sigmaCand.pxMoth() * sigmaCand.pxMoth() + + sigmaCand.pyMoth() * sigmaCand.pyMoth() + + sigmaCand.pzMoth() * sigmaCand.pzMoth()); + if (sigmaPRecalc > 0.f && sigmaPOriginal > 0.f) { + float scale = sigmaPRecalc / sigmaPOriginal; + sigmaMomReco[0] *= scale; + sigmaMomReco[1] *= scale; + sigmaMomReco[2] *= scale; + + sigmaPt = std::sqrt(sigmaMomReco[0] * sigmaMomReco[0] + sigmaMomReco[1] * sigmaMomReco[1]); + if (isSigmaMinusKink) { + rSigmaMinus.fill(HIST("hDeltaPxRecalcSigmaMinus"), sigmaMomReco[0] - sigmaCand.pxMoth(), sigmaCand.pxMoth()); + rSigmaMinus.fill(HIST("hDeltaPyRecalcSigmaMinus"), sigmaMomReco[1] - sigmaCand.pyMoth(), sigmaCand.pyMoth()); + rSigmaMinus.fill(HIST("hDeltaPzRecalcSigmaMinus"), sigmaMomReco[2] - sigmaCand.pzMoth(), sigmaCand.pzMoth()); + rSigmaMinus.fill(HIST("hRecalcPtFactorSigmaMinus"), scale, sigmaPOriginal); + } else { + rSigmaPlus.fill(HIST("hDeltaPxRecalcSigmaPlus"), sigmaMomReco[0] - sigmaCand.pxMoth(), sigmaCand.pxMoth()); + rSigmaPlus.fill(HIST("hDeltaPyRecalcSigmaPlus"), sigmaMomReco[1] - sigmaCand.pyMoth(), sigmaCand.pyMoth()); + rSigmaPlus.fill(HIST("hDeltaPzRecalcSigmaPlus"), sigmaMomReco[2] - sigmaCand.pzMoth(), sigmaCand.pzMoth()); + rSigmaPlus.fill(HIST("hRecalcPtFactorSigmaPlus"), scale, sigmaPOriginal); + } + } + } + + float recoRecalcPtSigmaAlphaAP = alphaAP(sigmaMomReco, kinkMomReco); + float recoRecalcPtSigmaQtAP = qtAP(sigmaMomReco, kinkMomReco); + float massSigma = isSigmaMinusKink ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); + + // Generated properties + float genMassSigma{-1.f}; + if (isSigmaMinusKink || isSigmaPlusToPiKink || isSigmaPlusToPrKink) { + genMassSigma = std::sqrt(genSigma.e() * genSigma.e() - genSigma.p() * genSigma.p()); + std::array sigmaMomGen{sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array kinkMomGen{sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + float genSigmaAlphaAP = alphaAP(sigmaMomGen, kinkMomGen); + float genSigmaQtAP = qtAP(sigmaMomGen, kinkMomGen); + float sigmaRadius = std::hypot(genKinkDaug.vx(), genKinkDaug.vy()); + if (isSigmaMinusKink) { + rSigmaMinus.fill(HIST("hSparseGenFromRecoSigmaMinus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } else if (isSigmaPlusToPiKink || isSigmaPlusToPrKink) { + rSigmaPlus.fill(HIST("hSparseGenFromRecoSigmaPlus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } + } + + // Fill table with sigma properties for efficiency studies + outputSigmaEffMC( + sigmaCand.pxMoth(), sigmaCand.pxMoth() - genSigma.px(), + sigmaCand.pyMoth(), sigmaCand.pyMoth() - genSigma.py(), + sigmaCand.pzMoth(), sigmaCand.pzMoth() - genSigma.pz(), + massSigma, massSigma - genMassSigma, + sigmaCand.pxMoth() - sigmaMomReco[0], + sigmaCand.pyMoth() - sigmaMomReco[1], + sigmaCand.pzMoth() - sigmaMomReco[2], + genSigma.phi(), + genSigma.eta(), + sigmaCand.pxDaug(), sigmaCand.pxDaug() - genKinkDaug.px(), + sigmaCand.pyDaug(), sigmaCand.pyDaug() - genKinkDaug.py(), + sigmaCand.pzDaug(), sigmaCand.pzDaug() - genKinkDaug.pz(), + genKinkDaug.phi(), + genKinkDaug.eta(), + sigmaCand.xDecVtx(), sigmaCand.xDecVtx() - genKinkDaug.vx(), + sigmaCand.yDecVtx(), sigmaCand.yDecVtx() - genKinkDaug.vy(), + sigmaCand.zDecVtx(), sigmaCand.zDecVtx() - genKinkDaug.vz(), + recoSigmaAlphaAP, recoSigmaQtAP, + recoRecalcPtSigmaAlphaAP, recoRecalcPtSigmaQtAP, + sigmaCand.dcaDaugPv(), sigmaCand.dcaMothPv(), + genSigma.pdgCode(), genKinkDaug.pdgCode(), + centMult, collision.ft0cOccupancyInTimeRange(), collision.numContrib()); + } + } + + // generated sigmas + for (const auto& genSigma : particlesMC) { + if (std::abs(genSigma.pdgCode()) != PDG_t::kSigmaMinus && std::abs(genSigma.pdgCode()) != PDG_t::kSigmaPlus) { + continue; // Only consider Sigma candidates + } + + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, genSigma.mcCollision().globalIndex()); + if (recoCollsPerMcColl.size() == 0) { + continue; // Skip if no reconstructed collisions associated with this MC collision + } + + unsigned genNumContrib = 0; + float genOcc{0.f}; + float genCentMult{0.f}; + for (const auto& recCol : recoCollsPerMcColl) { + genNumContrib = recCol.numContrib() > genNumContrib ? recCol.numContrib() : genNumContrib; + genOcc = recCol.ft0cOccupancyInTimeRange() > genOcc ? recCol.ft0cOccupancyInTimeRange() : genOcc; + genCentMult = getCentMult(recCol) > genCentMult ? getCentMult(recCol) : genCentMult; + } + + // Check the sigma daughter of the kink decay + std::vector arrSigmaDaugs = {}; + RecoDecay::getDaughters(genSigma, &arrSigmaDaugs, std::array{0}, 1); + for (auto iProng = 0u; iProng < arrSigmaDaugs.size(); ++iProng) { + auto daughSigma = particlesMC.rawIteratorAt(arrSigmaDaugs[iProng]); + float genMassSigma = std::sqrt(genSigma.e() * genSigma.e() - genSigma.p() * genSigma.p()); + std::array sigmaMomGen{genSigma.px(), genSigma.py(), genSigma.pz()}; + std::array kinkMomGen{daughSigma.px(), daughSigma.py(), daughSigma.pz()}; + float genSigmaAlphaAP = alphaAP(sigmaMomGen, kinkMomGen); + float genSigmaQtAP = qtAP(sigmaMomGen, kinkMomGen); + float sigmaRadius = std::hypot(daughSigma.vx(), daughSigma.vy()); + + if (std::abs(daughSigma.pdgCode()) == PDG_t::kPiPlus && std::abs(genSigma.pdgCode()) == PDG_t::kSigmaMinus) { + rSigmaMinus.fill(HIST("hSparseGenSigmaMinus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } else if (std::abs(daughSigma.pdgCode()) == PDG_t::kPiPlus && std::abs(genSigma.pdgCode()) == PDG_t::kSigmaPlus) { + rSigmaPlus.fill(HIST("hSparseGenSigmaPlus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } else if (std::abs(daughSigma.pdgCode()) == PDG_t::kProton && std::abs(genSigma.pdgCode()) == PDG_t::kSigmaPlus) { + rSigmaPlus.fill(HIST("hSparseGenSigmaPlus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } + } + } } - PROCESS_SWITCH(lambda1405analysis, processMcWCentSel, "MC processing with centrality selection", false); + PROCESS_SWITCH(lambda1405analysis, processMcSigmasCentSel, "MC processing for sigma efficiency studies", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx index 9ecfda3ff5e..a9ffd4f6082 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx @@ -95,7 +95,7 @@ struct Lambda1520analysisinpp { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Service pdg; + Service pdg{}; RCTFlagsChecker rctChecker; struct : ConfigurableGroup { @@ -203,6 +203,13 @@ struct Lambda1520analysisinpp { Configurable cFill1DQAs{"cFill1DQAs", false, "Invariant mass 1D"}; Configurable centEstimator{"centEstimator", 0, "Select centrality estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C"}; + // calibration + Configurable> cfgGenMultCuts{"cfgGenMultCuts", std::vector{500, 300, 200, 120, 80, 50, 30, 10, 0}, "Generated multiplicity lower cuts"}; + Configurable> cfgCentBinCentres{"cfgCentBinCentres", std::vector{2.5f, 7.5f, 15.0f, 25.0f, 35.0f, 45.0f, 55.0f, 75.0f, 95.0f}, "Reco centrality bin centres"}; + Configurable cfgGenMultEtaMax{"cfgGenMultEtaMax", 0.5f, "Max Eta for generated mid-rapidity multiplicity"}; + Configurable cfgGenMultEtaMin{"cfgGenMultEtaMin", -0.5f, "Min Eta for generated mid-rapidity multiplicity"}; + Configurable useManualCalibration{"useManualCalibration", false, "Use Manual generated multiplicity for centrality estimation"}; + TRandom* rn = new TRandom(); // Pre-filters for efficient process @@ -487,12 +494,13 @@ struct Lambda1520analysisinpp { float massKa = MassKaonCharged; float massPr = MassProton; + static constexpr float kInvalidCentrality = -999.0f; // Centralicity estimator selection template - float centEst(Coll collisions) + float centEst(const Coll& collisions) { - float returnValue = -999.0f; + float returnValue = kInvalidCentrality; switch (centEstimator) { case 0: returnValue = collisions.centFT0M(); @@ -514,68 +522,89 @@ struct Lambda1520analysisinpp { bool isSelected(const Coll& collision, bool fillHist = true) { auto applyCut = [&](bool enabled, bool condition, int bin) { - if (!enabled) + if (!enabled) { return true; - if (!condition) + } + if (!condition) { return false; - if (fillHist) + } + if (fillHist) { histos.fill(HIST("CollCutCounts"), bin); + } return true; }; - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 0); + } - if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) + if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) { return false; + } if (!applyCut(configEvents.cfgEvtTriggerTVXSel, - collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) + collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) { return false; + } if (!applyCut(configEvents.cfgEvtNoTFBorderCut, - collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) + collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) { return false; + } if (!applyCut(configEvents.cfgEvtNoITSROFrameBorderCut, - collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) + collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) + if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) { return false; + } - if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) + if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) + if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) { return false; + } - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 8); + } return true; } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (configTracks.cDCAr7SigCut && std::abs(track.dcaXY()) > (0.004f + 0.013f / (track.pt()))) // 7 - Sigma cut + { return false; - if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) + } + if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) { return false; - if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) + } + if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) { return false; - if (configTracks.cfgHasTOF && !track.hasTOF()) + } + if (configTracks.cfgHasTOF && !track.hasTOF()) { return false; - if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) + } + if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) { return false; - if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + } + if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { return false; - if (configTracks.cfgPVContributor && !track.isPVContributor()) + } + if (configTracks.cfgPVContributor && !track.isPVContributor()) { return false; - if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) + } + if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) { return false; + } return true; } @@ -604,14 +633,17 @@ struct Lambda1520analysisinpp { // TPC PID (interval check) for (size_t i = 0; i < vProtonTPCPIDpTintv.size() - 1; ++i) { if (pt > vProtonTPCPIDpTintv[i] && pt < vProtonTPCPIDpTintv[i + 1]) { - if (std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts[i]) + if (std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts[i]) { tpcPIDPassed = true; + } } } // TOF bypass option (for QA or MC) if (configPID.cByPassTOF) { - return std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back(); + { + return std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back(); + } } // Case 1: No TOF and pt ≤ threshold → accept only via TPC PID @@ -631,8 +663,9 @@ struct Lambda1520analysisinpp { for (size_t i = 0; i < vProtonTOFPIDpTintv.size(); ++i) { if (pt < vProtonTOFPIDpTintv[i]) { if (std::abs(tofNsigmaPr) < vProtonTOFPIDcuts[i] && - std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back()) + std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back()) { return true; + } } } } else if (configPID.cPIDcutType == CircularType) { @@ -642,8 +675,9 @@ struct Lambda1520analysisinpp { float combinedSigma2 = tpcNsigmaPr * tpcNsigmaPr + tofNsigmaPr * tofNsigmaPr; - if (combinedSigma2 < vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i]) + if (combinedSigma2 < vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i]) { return true; + } } } } @@ -731,10 +765,7 @@ struct Lambda1520analysisinpp { template bool rejectPion(const T& candidate) { - if (candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection) { - return false; - } - return true; + return !(candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection); } auto static constexpr MaxNoLambda1520Daughters = 2; @@ -767,12 +798,14 @@ struct Lambda1520analysisinpp { for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { // Full index policy is needed to consider all possible combinations - if (trk1.index() == trk2.index()) - continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + if (trk1.index() == trk2.index()) { + continue; + } // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. // apply the track cut - if (!trackCut(trk1) || !trackCut(trk2)) + if (!trackCut(trk1) || !trackCut(trk2)) { continue; + } //// Initialize variables // Trk1: Proton @@ -798,10 +831,12 @@ struct Lambda1520analysisinpp { deltaEta = std::abs(trk1etaPr - trk2etaKa); deltaPhi = std::abs(trk1phiPr - trk2phiKa); deltaPhi = (deltaPhi > o2::constants::math::PI) ? (o2::constants::math::TwoPI - deltaPhi) : deltaPhi; - if (deltaEta >= cMaxDeltaEtaCut) + if (deltaEta >= cMaxDeltaEtaCut) { continue; - if (deltaPhi >= cMaxDeltaPhiCut) + } + if (deltaPhi >= cMaxDeltaPhiCut) { continue; + } } //// QA plots before the selection @@ -839,10 +874,13 @@ struct Lambda1520analysisinpp { //// Apply the pid selection if (crejectPion && rejectPion(trk2)) // to remove pion contamination from the kaon track + { continue; + } - if (!ptDependentPidProton(trk1) || !ptDependentPidKaon(trk2)) + if (!ptDependentPidProton(trk1) || !ptDependentPidKaon(trk2)) { continue; + } //// QA plots after the selection if constexpr (IsData) { // --- PID QA Proton @@ -896,8 +934,9 @@ struct Lambda1520analysisinpp { auto v1 = lDecayDaughter1.Vect(); auto v2 = lDecayDaughter2.Vect(); float alpha = std::acos(v1.Dot(v2) / (v1.R() * v2.R())); - if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) + if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) { continue; + } } lResonance = lDecayDaughter1 + lDecayDaughter2; @@ -908,15 +947,20 @@ struct Lambda1520analysisinpp { if constexpr (IsData || IsMix) { // Rapidity cut - if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) + if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) { continue; + } } if (cfgUseCutsOnMother) { if (resonancePt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (cFilladditionalQAeventPlots) { @@ -943,14 +987,19 @@ struct Lambda1520analysisinpp { auto resonanceRotPt = lResonanceRot.Pt(); // Rapidity cut - if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) + if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) { continue; + } if (cfgUseCutsOnMother) { if (resonanceRotPt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceRotMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (trk1.sign() < 0) { if (cFill1DQAs) { @@ -1040,22 +1089,30 @@ struct Lambda1520analysisinpp { mothersPDGtrk2.pop_back(); } - if (std::abs(mctrk1.pdgCode()) != kProton || std::abs(mctrk2.pdgCode()) != kKPlus) + if (std::abs(mctrk1.pdgCode()) != kProton || std::abs(mctrk2.pdgCode()) != kKPlus) { continue; + } if (motherstrk1[0] != motherstrk2[0]) // Same mother + { continue; + } - if (std::abs(mothersPDGtrk1[0]) != Pdg::kLambda1520_Py) + if (std::abs(mothersPDGtrk1[0]) != Pdg::kLambda1520_Py) { continue; + } // LOGF(info, "mother trk1 id: %d, mother trk1: %d, trk1 id: %d, trk1 pdgcode: %d, mother trk2 id: %d, mother trk2: %d, trk2 id: %d, trk2 pdgcode: %d", motherstrk1[0], mothersPDGtrk1[0], trk1.globalIndex(), mctrk1.pdgCode(), motherstrk2[0], mothersPDGtrk2[0], trk2.globalIndex(), mctrk2.pdgCode()); if (cUseEtacutMC && std::abs(lResonance.Eta()) > cEtacutMC) // eta cut + { continue; + } if (cUseRapcutMC && std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) // rapidity cut + { continue; + } histos.fill(HIST("QA/MC/h2RecoEtaPt_after"), lResonance.Eta(), resonancePt); histos.fill(HIST("QA/MC/h2RecoPhiRapidity_after"), lResonance.Phi(), resonanceRapidity); @@ -1116,11 +1173,47 @@ struct Lambda1520analysisinpp { } } + // Helper 1: Calculate generated mid-rapidity multiplicity + template + int getGenMidRapMultiplicity(McPartsT const& partsThisMc) + { + int nCh = 0; + for (auto const& part : partsThisMc) { + if (!part.isPhysicalPrimary()) { + continue; + } + if (part.eta() > cfgGenMultEtaMax || part.eta() < cfgGenMultEtaMin) { + continue; + } + auto pdgParticle = pdg->GetParticle(part.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0) { + continue; + } + nCh++; + } + return nCh; + } + + // Helper 2: Map multiplicity count to a specific centrality bin + float getCentClassFromGenMult(int nCh) + { + const auto& cuts = cfgGenMultCuts.value; + const auto& centres = cfgCentBinCentres.value; + for (size_t i = 0; i < cuts.size(); ++i) { + if (nCh >= cuts[i]) { + return centres[i]; + } + } + return kInvalidCentrality; // Invalid centrality + } + void processData(EventCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isSelected(collision)) // Default event selection + { return; + } auto centrality = centEst(collision); @@ -1134,10 +1227,14 @@ struct Lambda1520analysisinpp { void processRotational(EventCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isSelected(collision, false)) // Default event selection + { return; + } if (!collision.isInelGt0()) // <-- + { return; + } fillHistograms(collision, tracks, tracks); } @@ -1162,16 +1259,24 @@ struct Lambda1520analysisinpp { // } if (!isSelected(collision1, false)) // Default event selection + { continue; + } if (!isSelected(collision2, false)) // Default event selection + { continue; + } if (!collision1.isInelGt0()) // <-- + { continue; + } if (!collision2.isInelGt0()) // <-- + { continue; + } if (cFilladditionalQAeventPlots) { // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) @@ -1196,11 +1301,13 @@ struct Lambda1520analysisinpp { aod::McCollisions const&, MCTrackCandidates const& tracks, aod::McParticles const&) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } - if (!isSelected(collision)) + if (!isSelected(collision)) { return; + } auto centrality = centEst(collision); @@ -1215,11 +1322,12 @@ struct Lambda1520analysisinpp { void processMCGen(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } bool isInAfterAllCuts = isSelected(collision, false); - bool inVtx10 = (std::abs(collision.mcCollision().posZ()) > configEvents.cfgEvtZvtx) ? false : true; + bool inVtx10 = std::abs(collision.mcCollision().posZ()) <= configEvents.cfgEvtZvtx; bool isTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); bool isSel8 = collision.sel8(); @@ -1247,8 +1355,9 @@ struct Lambda1520analysisinpp { bool pass2 = std::abs(daughterPDGs[0]) == kProton || std::abs(daughterPDGs[1]) == kProton; // At least one decay to Proton // Checking if we have both decay products - if (!pass1 || !pass2) + if (!pass1 || !pass2) { continue; + } // LOGF(info, "Part PDG: %d", part.pdgCode(), "DAU_ID1: %d", pass1, "DAU_ID2: %d", pass2); @@ -1256,12 +1365,15 @@ struct Lambda1520analysisinpp { histos.fill(HIST("QA/MC/h2GenPhiRapidity_beforeanycut"), part.phi(), part.y()); if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) // rapidity cut + { continue; + } if (cfgUseDaughterEtaCutMC) { for (auto const& daughters : part.daughters_as()) { - if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) - continue; // eta cut for daughters + if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) { + continue; + } // eta cut for daughters } // loop over daughters } @@ -1269,64 +1381,74 @@ struct Lambda1520analysisinpp { histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterRapcut"), part.phi(), part.y()); if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) // eta cut + { continue; + } histos.fill(HIST("QA/MC/h2GenEtaPt_afterEtaRapCut"), part.eta(), part.pt()); histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterEtaRapCut"), part.phi(), part.y()); histos.fill(HIST("QA/Gen"), 1); if (part.pdgCode() > 0) // without any event selection + { histos.fill(HIST("Result/MC/Genlambda1520pt"), 0, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 0, part.pt(), centrality); + } if (inVtx10) // vtx10 { histos.fill(HIST("QA/Gen"), 2); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 1, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 1, part.pt(), centrality); + } } if (inVtx10 && isSel8) // vtx10, sel8 { histos.fill(HIST("QA/Gen"), 3); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 2, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 2, part.pt(), centrality); + } } if (inVtx10 && isTriggerTVX) // vtx10, TriggerTVX { histos.fill(HIST("QA/Gen"), 4); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 3, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 3, part.pt(), centrality); + } } if (inVtx10 && isTrueINELgt0) // vtx10, INEL>0 { histos.fill(HIST("QA/Gen"), 5); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 4, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 4, part.pt(), centrality); + } } if (isInAfterAllCuts) // after all event selection { histos.fill(HIST("QA/Gen"), 6); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 5, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 5, part.pt(), centrality); + } } if (isInAfterAllCuts && isTrueINELgt0) // after all event selection && INEL>0 { histos.fill(HIST("QA/Gen"), 7); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 6, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 6, part.pt(), centrality); + } } } } @@ -1345,27 +1467,44 @@ struct Lambda1520analysisinpp { bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); bool isInAfterAllCuts = isSelected(collision, false); - float centrality = mcCollision.centFT0M(); + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mcCollision.centFT0M(); - if (isTrueINELgt0 && isInAfterAllCuts) + if (centrality == kInvalidCentrality) { + continue; + } + + if (isTrueINELgt0 && isInAfterAllCuts) { histos.fill(HIST("Event/MultiplicityRecoEv"), centrality); + } } // Loop on generated collisions to fill the event factor for the INEL>0 correction for (const auto& mccolls : mcCollisions) { - float centrality = mccolls.centFT0M(); - bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); + + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mccolls.centFT0M(); + + if (centrality == kInvalidCentrality) { + continue; + } + + bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); // QA for Trigger efficiency histos.fill(HIST("Event/hMCEventIndices"), centrality, Inel); - if (inVtx10) + if (inVtx10) { histos.fill(HIST("Event/hMCEventIndices"), centrality, Inel10); - if (isTrueINELgt0) + } + if (isTrueINELgt0) { histos.fill(HIST("Event/hMCEventIndices"), centrality, Inelg0); - if (inVtx10 && isTrueINELgt0) + } + if (inVtx10 && isTrueINELgt0) { histos.fill(HIST("Event/hMCEventIndices"), centrality, Inelg010); + } } } PROCESS_SWITCH(Lambda1520analysisinpp, processEventFactor, "Process Event factor", false); @@ -1384,7 +1523,13 @@ struct Lambda1520analysisinpp { bool isInAfterAllCuts = isSelected(collision, false); bool inVtx10 = std::abs(mcCollision.posZ()) <= configEvents.cfgEvtZvtx; - float centrality = mcCollision.centFT0M(); + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mcCollision.centFT0M(); + + if (centrality == kInvalidCentrality) { + continue; + } auto computePtL = [&](float pt, float m_ref) { float ptL2 = pt * pt + m_ref * m_ref - MassLambda1520 * MassLambda1520; @@ -1392,22 +1537,27 @@ struct Lambda1520analysisinpp { }; // ===== NUM ===== - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } - if (!isInAfterAllCuts) + if (!isInAfterAllCuts) { continue; + } for (const auto& part : particlesInCollision) { - if (!part.isPhysicalPrimary()) + if (!part.isPhysicalPrimary()) { continue; + } - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } - if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) + if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) { continue; + } float pt = part.pt(); @@ -1470,15 +1620,22 @@ struct Lambda1520analysisinpp { // Loop on generated collisions to fill the event factor for the INEL>0 correction for (const auto& mccolls : mcCollisions) { - float centrality = mccolls.centFT0M(); + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); - bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mccolls.centFT0M(); - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); + if (centrality == kInvalidCentrality) { + continue; + } + + bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } auto computePtL = [&](float pt, float m_ref) { float ptL2 = pt * pt + m_ref * m_ref - MassLambda1520 * MassLambda1520; @@ -1487,11 +1644,13 @@ struct Lambda1520analysisinpp { for (const auto& part : particlesInCollision) { - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } - if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) + if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) { continue; + } // ========================= // ===== LAMBDA(1520) ====== @@ -1511,17 +1670,20 @@ struct Lambda1520analysisinpp { bool pass2 = std::abs(daughterPDGs[0]) == kProton || std::abs(daughterPDGs[1]) == kProton; // At least one decay to Proton // Checking if we have both decay products - if (!pass1 || !pass2) + if (!pass1 || !pass2) { continue; + } - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/SignalLoss/GenTruelambda1520pt_den"), part.pt(), centrality); - else + } else { histos.fill(HIST("Result/SignalLoss/GenTrueantilambda1520pt_den"), part.pt(), centrality); + } } - if (!part.isPhysicalPrimary()) + if (!part.isPhysicalPrimary()) { continue; + } float pt = part.pt(); float weight = 1.f; @@ -1535,11 +1697,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTruekaonpt_den"), pt, centrality); float ptL = computePtL(pt, massKa); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genkaonpt_den"), ptL, centrality, weight); } @@ -1553,11 +1717,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTrueprotonpt_den"), pt, centrality); float ptL = computePtL(pt, massPr); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genprotonpt_den"), ptL, centrality, weight); } @@ -1570,11 +1736,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTruelambdapt_den"), pt, centrality); float ptL = computePtL(pt, MassLambda0); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genlambdapt_den"), ptL, centrality, weight); } @@ -1587,11 +1755,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTruexipt_den"), pt, centrality); float ptL = computePtL(pt, MassXiMinus); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genxipt_den"), ptL, centrality, weight); } @@ -1604,11 +1774,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTrueomegapt_den"), pt, centrality); float ptL = computePtL(pt, MassOmegaMinus); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genomegapt_den"), ptL, centrality, weight); } diff --git a/PWGLF/Tasks/Resonances/phi1020analysis.cxx b/PWGLF/Tasks/Resonances/phi1020analysis.cxx index c50093c91c2..9aee9ebd3e1 100644 --- a/PWGLF/Tasks/Resonances/phi1020analysis.cxx +++ b/PWGLF/Tasks/Resonances/phi1020analysis.cxx @@ -88,7 +88,7 @@ struct Phi1020analysis { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Service pdg; + Service pdg{}; RCTFlagsChecker rctChecker; struct : ConfigurableGroup { @@ -202,12 +202,6 @@ struct Phi1020analysis { using MCEventCandidates = soa::Join; using MCTrackCandidates = soa::Filtered>; - Partition posKaon = aod::track::signed1Pt > static_cast(0); - Partition negKaon = aod::track::signed1Pt < static_cast(0); - - Partition PosKaon_MC = aod::track::signed1Pt > static_cast(0); - Partition NegKaon_MC = aod::track::signed1Pt < static_cast(0); - /// Figures ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.12f, 0.14f, 0.16f, 0.18f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.45f, 0.5f, 0.55f, 0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 0.95f, 1.0f, 1.1f, 1.2f, 1.25f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.75f, 1.8f, 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.6f, 3.7f, 3.8f, 3.9f, 4.0f, 4.1f, 4.2f, 4.5f, 4.6f, 4.8f, 4.9f, 5.0f, 5.5f, 5.6f, 6.0f, 6.4f, 6.5f, 7.0f, 7.2f, 8.0f, 9.0f, 9.5f, 9.6f, 10.0f, 11.0f, 11.5f, 12.0f, 13.0f, 14.0f, 14.4f, 15.0f, 16.0f, 18.0f, 19.2f, 20.0f}, "Binning of the pT axis"}; ConfigurableAxis binsEta{"binsEta", {150, -1.5f, 1.5f}, ""}; @@ -415,7 +409,7 @@ struct Phi1020analysis { // Centralicity estimator selection template - float centEst(Coll collisions) + float centEst(const Coll& collisions) { float returnValue = -999.0f; switch (centEstimator) { @@ -439,68 +433,89 @@ struct Phi1020analysis { bool isSelected(const Coll& collision, bool fillHist = true) { auto applyCut = [&](bool enabled, bool condition, int bin) { - if (!enabled) + if (!enabled) { return true; - if (!condition) + } + if (!condition) { return false; - if (fillHist) + } + if (fillHist) { histos.fill(HIST("CollCutCounts"), bin); + } return true; }; - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 0); + } - if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) + if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) { return false; + } if (!applyCut(configEvents.cfgEvtTriggerTVXSel, - collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) + collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) { return false; + } if (!applyCut(configEvents.cfgEvtNoTFBorderCut, - collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) + collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) { return false; + } if (!applyCut(configEvents.cfgEvtNoITSROFrameBorderCut, - collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) + collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) + if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) { return false; + } - if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) + if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) + if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) { return false; + } - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 8); + } return true; } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (configTracks.cDCAr7SigCut && std::abs(track.dcaXY()) > (0.004f + 0.013f / (track.pt()))) // 7 - Sigma cut + { return false; - if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) + } + if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) { return false; - if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) + } + if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) { return false; - if (configTracks.cfgHasTOF && !track.hasTOF()) + } + if (configTracks.cfgHasTOF && !track.hasTOF()) { return false; - if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) + } + if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) { return false; - if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + } + if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { return false; - if (configTracks.cfgPVContributor && !track.isPVContributor()) + } + if (configTracks.cfgPVContributor && !track.isPVContributor()) { return false; - if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) + } + if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) { return false; + } return true; } @@ -602,10 +617,7 @@ struct Phi1020analysis { template bool rejectPion(const T& candidate) { - if (candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection) { - return false; - } - return true; + return !(candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection); } auto static constexpr MaxNophi1020Daughters = 2; @@ -637,13 +649,18 @@ struct Phi1020analysis { LorentzVectorPtEtaPhiMass lDecayDaughter1, lDecayDaughter2, lResonance, ldaughterRot, lResonanceRot; for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { - // Full index policy is needed to consider all possible combinations - if (trk1.index() == trk2.index()) - continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + LOG(info) << "Before pass, Track1 index:" << trk1.index() << ",Track2 index:" << trk2.index(); + + if (trk2.index() <= trk1.index()) { + continue; + } + + LOG(info) << "After pass, Track1 index:" << trk1.index() << ",Track2 index:" << trk2.index(); // apply the track cut - if (!trackCut(trk1) || !trackCut(trk2)) + if (!trackCut(trk1) || !trackCut(trk2)) { continue; + } //// Initialize variables // Trk1: Proton @@ -669,10 +686,12 @@ struct Phi1020analysis { deltaEta = std::abs(trk1eta - trk2eta); deltaPhi = std::abs(trk1phi - trk2phi); deltaPhi = (deltaPhi > o2::constants::math::PI) ? (o2::constants::math::TwoPI - deltaPhi) : deltaPhi; - if (deltaEta >= cMaxDeltaEtaCut) + if (deltaEta >= cMaxDeltaEtaCut) { continue; - if (deltaPhi >= cMaxDeltaPhiCut) + } + if (deltaPhi >= cMaxDeltaPhiCut) { continue; + } } //// QA plots before the selection @@ -702,13 +721,17 @@ struct Phi1020analysis { //// Apply the pid selection if (crejectPion && rejectPion(trk2)) // to remove pion contamination from the kaon track + { continue; + } - if (configPID.ispTdepPID && (!ptDependentPidKaon(trk1) || !ptDependentPidKaon(trk2))) + if (configPID.ispTdepPID && (!ptDependentPidKaon(trk1) || !ptDependentPidKaon(trk2))) { continue; + } - if (!configPID.ispTdepPID && (!selectionPID(trk1) || !selectionPID(trk2))) + if (!configPID.ispTdepPID && (!selectionPID(trk1) || !selectionPID(trk2))) { continue; + } //// QA plots after the selection if constexpr (IsData) { // --- PID QA Proton @@ -762,8 +785,9 @@ struct Phi1020analysis { auto v1 = lDecayDaughter1.Vect(); auto v2 = lDecayDaughter2.Vect(); float alpha = std::acos(v1.Dot(v2) / (v1.R() * v2.R())); - if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) + if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) { continue; + } } lResonance = lDecayDaughter1 + lDecayDaughter2; @@ -773,14 +797,19 @@ struct Phi1020analysis { auto resonanceRapidity = lResonance.Rapidity(); // Rapidity cut - if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) + if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) { continue; + } if (cfgUseCutsOnMother) { if (resonancePt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (cFilladditionalQAeventPlots) { @@ -807,14 +836,19 @@ struct Phi1020analysis { auto resonanceRotPt = lResonanceRot.Pt(); // Rapidity cut - if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) + if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) { continue; + } if (cfgUseCutsOnMother) { if (resonanceRotPt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceRotMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (cFill1DQAs) { histos.fill(HIST("Result/Data/phi1020InvMassRotation"), resonanceRotMass); @@ -883,14 +917,18 @@ struct Phi1020analysis { mothersPDGtrk2.pop_back(); } - if (std::abs(mctrk1.pdgCode()) != kKPlus || std::abs(mctrk2.pdgCode()) != kKPlus) + if (std::abs(mctrk1.pdgCode()) != kKPlus || std::abs(mctrk2.pdgCode()) != kKPlus) { continue; + } if (motherstrk1[0] != motherstrk2[0]) // Same mother + { continue; + } - if (std::abs(mothersPDGtrk1[0]) != Pdg::kPhi) + if (std::abs(mothersPDGtrk1[0]) != Pdg::kPhi) { continue; + } // LOGF(info, "mother trk1 id: %d, mother trk1: %d, trk1 id: %d, trk1 pdgcode: %d, mother trk2 id: %d, mother trk2: %d, trk2 id: %d, trk2 pdgcode: %d", motherstrk1[0], mothersPDGtrk1[0], trk1.globalIndex(), mctrk1.pdgCode(), motherstrk2[0], mothersPDGtrk2[0], trk2.globalIndex(), mctrk2.pdgCode()); @@ -953,7 +991,9 @@ struct Phi1020analysis { TrackCandidates const& tracks) { if (!isSelected(collision)) // Default event selection + { return; + } auto centrality = centEst(collision); @@ -967,10 +1007,14 @@ struct Phi1020analysis { void processRotational(EventCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isSelected(collision, false)) // Default event selection + { return; + } if (!collision.isInelGt0()) // <-- + { return; + } fillHistograms(collision, tracks, tracks); } @@ -995,16 +1039,24 @@ struct Phi1020analysis { // } if (!isSelected(collision1, false)) // Default event selection + { continue; + } if (!isSelected(collision2, false)) // Default event selection + { continue; + } if (!collision1.isInelGt0()) // <-- + { continue; + } if (!collision2.isInelGt0()) // <-- + { continue; + } if (cFilladditionalQAeventPlots) { // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) @@ -1029,11 +1081,13 @@ struct Phi1020analysis { aod::McCollisions const&, MCTrackCandidates const& tracks, aod::McParticles const&) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } - if (!isSelected(collision)) + if (!isSelected(collision)) { return; + } auto centrality = centEst(collision); @@ -1048,8 +1102,9 @@ struct Phi1020analysis { void processMCGen(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } bool isInAfterAllCuts = isSelected(collision, false); @@ -1083,20 +1138,24 @@ struct Phi1020analysis { histos.fill(HIST("QA/MC/h2GenPhiRapidity_beforeanycut"), part.phi(), part.y()); if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) // rapidity cut + { continue; + } if (cfgUseDaughterEtaCutMC) { for (auto const& daughters : part.daughters_as()) { - if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) - continue; // eta cut for daughters + if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) { + continue; + } // eta cut for daughters } // loop over daughters } histos.fill(HIST("QA/MC/h2GenEtaPt_afterRapcut"), part.eta(), part.pt()); histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterRapcut"), part.phi(), part.y()); - if (isInAfterAllCuts && isTrueINELgt0) // after all event selection && INEL>0 + if (isInAfterAllCuts && isTrueINELgt0) { // after all event selection && INEL>0 histos.fill(HIST("Result/MC/Genphi1020pt"), part.pt(), centrality); + } } } PROCESS_SWITCH(Phi1020analysis, processMCGen, "Process Event for MC only", false); @@ -1116,8 +1175,9 @@ struct Phi1020analysis { float centrality = mcCollision.centFT0M(); - if (isTrueINELgt0 && isInAfterAllCuts) + if (isTrueINELgt0 && isInAfterAllCuts) { histos.fill(HIST("Event/MultiplicityRecoEv"), centrality); + } } // Loop on generated collisions to fill the event factor for the INEL>0 correction @@ -1128,8 +1188,9 @@ struct Phi1020analysis { const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); // QA for Trigger efficiency - if (inVtx10 && isTrueINELgt0) + if (inVtx10 && isTrueINELgt0) { histos.fill(HIST("Event/MultiplicityGenEv"), centrality); + } } } PROCESS_SWITCH(Phi1020analysis, processEventFactor, "Process Event factor", false); @@ -1151,22 +1212,26 @@ struct Phi1020analysis { float centrality = mcCollision.centFT0M(); // ===== NUM ===== - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } - if (!isInAfterAllCuts) + if (!isInAfterAllCuts) { continue; + } for (const auto& part : particlesInCollision) { - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } float pt = part.pt(); // phi - if (std::abs(part.pdgCode()) == Pdg::kPhi) + if (std::abs(part.pdgCode()) == Pdg::kPhi) { histos.fill(HIST("Result/SignalLoss/GenTruephi1020pt_num"), pt, centrality); + } } } @@ -1179,13 +1244,15 @@ struct Phi1020analysis { const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } for (const auto& part : particlesInCollision) { - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } // ========================= // ===== PHI(1020) ====== diff --git a/PWGLF/Tasks/Resonances/phiflowder.cxx b/PWGLF/Tasks/Resonances/phiflowder.cxx index 1293ceb8b3b..7ebe626ca24 100644 --- a/PWGLF/Tasks/Resonances/phiflowder.cxx +++ b/PWGLF/Tasks/Resonances/phiflowder.cxx @@ -17,9 +17,10 @@ #include "PWGLF/DataModel/LFPhiFlowTables.h" #include -#include +#include #include #include +#include #include #include #include @@ -31,11 +32,13 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include +#include #include #include #include #include +#include using namespace o2; using namespace o2::framework; @@ -59,9 +62,18 @@ struct phiflowder { ConfigurableAxis axisInvMass{"axisInvMass", {120, 0.9f, 1.2f}, "#it{M}_{K^{+}K^{-}} (GeV/#it{c}^{2})"}; ConfigurableAxis axisPhiPt{"axisPhiPt", {100, 0.f, 10.f}, "#it{p}_{T}^{K^{+}K^{-}} (GeV/#it{c})"}; ConfigurableAxis axisCent{"axisCent", {80, 0.f, 80.f}, "Centrality (%)"}; - ConfigurableAxis axisNKaons{"axisNKaons", {300, 0.f, 300.f}, "Number of stored kaons per event"}; + ConfigurableAxis axisV1{"axisV1", {1000, -1.0f, 1.0f}, "v1"}; + ConfigurableAxis axisEta{"axisEta", {8, -0.8f, 0.8f}, "Eta"}; ConfigurableAxis axisNPairs{"axisNPairs", {500, 0.f, 5000.f}, "Number of K^{+}K^{-} pairs per event"}; + Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgCentBins{"cfgCentBins", {8, 0.0, 80}, "Mixing bins - centrality"}; + /*Configurable ptMix{"ptMix", 0.2f, "ME: pT bin width"}; + Configurable etaMix{"etaMix", 0.2f, "ME: eta bin width"}; + Configurable phiMix{"phiMix", 0.3f, "ME: phi bin width"};*/ + ConfigurableAxis cfgSPAngleBins{"cfgSPAngleBins", {12, 0.0, 2.0 * TMath::Pi()}, "Mixing bins - odd spectator-plane angle"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; static constexpr uint8_t kPID1 = 1u << 0; @@ -74,12 +86,18 @@ struct phiflowder { void init(InitContext const&) { histos.add("hCentrality", "Centrality distribution", kTH1F, {axisCent}); - histos.add("hPhiMassSame", "Same-event K^{+}K^{-} invariant mass", kTH1F, {axisInvMass}); - histos.add("hPhiPtSame", "Same-event K^{+}K^{-} pT", kTH1F, {axisPhiPt}); - histos.add("hNplusPerEvent", "Number of stored K^{+} per event", kTH1F, {axisNKaons}); - histos.add("hNminusPerEvent", "Number of stored K^{-} per event", kTH1F, {axisNKaons}); - histos.add("hNphiSamePerEvent", "Number of same-event K^{+}K^{-} pairs per event", kTH1F, {axisNPairs}); - histos.add("hSparseSame", "Same-event K^{+}K^{-};M;pT;centrality", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent}); + histos.add("hSparseSame", "Same-event K^{+}K^{-};M;pT;centrality", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}); + histos.add("hSparseMix", "Mixed-event K^{+}K^{-};M;pT;centrality", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); + histos.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); + histos.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); + histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); + histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); + histos.add("hMixpairs", "hMixpairs", HistType::kTHnSparseF, {axisNPairs}, true); + histos.add("hSparseSameUx", "Same-event #Sigma u_{x};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); + histos.add("hSparseSameUy", "Same-event #Sigma u_{y};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); + histos.add("hSparseSameUQA", "Same-event #Sigma u#upoint Q_{A};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); + histos.add("hSparseSameUQC", "Same-event #Sigma u#upoint Q_{C};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); } uint8_t getRequiredPidBit() const @@ -135,6 +153,74 @@ struct phiflowder { return angle >= deepAngleCut.value; } + template + int fillMixedPairs(const TPosKaons& posGroup, + const TNegKaons& negGroup, + float centrality, float qxZDCA, float qxZDCC, float qyZDCA, float qyZDCC) + { + int nMixedPairs = 0; + + for (const auto& kPlus : posGroup) { + if (!passStoredPID(kPlus)) { + continue; + } + + ROOT::Math::PxPyPzMVector plusVec( + kPlus.px(), + kPlus.py(), + kPlus.pz(), + o2::constants::physics::MassKPlus); + + for (const auto& kMinus : negGroup) { + if (!passStoredPID(kMinus)) { + continue; + } + + if (!passDeepAngle(kPlus.px(), + kPlus.py(), + kPlus.pz(), + kMinus.px(), + kMinus.py(), + kMinus.pz())) { + continue; + } + + ROOT::Math::PxPyPzMVector minusVec( + kMinus.px(), + kMinus.py(), + kMinus.pz(), + o2::constants::physics::MassKPlus); + + const auto phiCandidate = plusVec + minusVec; + + const float phiMass = phiCandidate.M(); + const float phiPt = phiCandidate.Pt(); + float etaCand = phiCandidate.Eta(); + double phiCand = phiCandidate.Phi(); + if (phiCand < 0.0) { + phiCand += 2.0 * TMath::Pi(); + } + double const cosNPhi = std::cos(phiCand); + double const sinNPhi = std::sin(phiCand); + + auto ux = cosNPhi; // real part of candidate q vector + auto uy = sinNPhi; // imaginary part of candidate q vector + auto oddv1 = ux * (qxZDCA - qxZDCC) + uy * (qyZDCA - qyZDCC); + // auto evenv1 = ux * (qxZDCA + qxZDCC) + uy * (qyZDCA + qyZDCC); + + if (phiMass < massMin.value || phiMass > massMax.value) { + continue; + } + + histos.fill(HIST("hSparseMix"), phiMass, phiPt, centrality, etaCand, oddv1); + + nMixedPairs++; + } + } + + return nMixedPairs; + } + Filter centralityFilter = (aod::kaonevent::cent >= centMin) && (aod::kaonevent::cent < centMax); using EventCandidates = soa::Filtered; @@ -145,12 +231,27 @@ struct phiflowder { void processSameData(EventCandidates::iterator const& collision, aod::KaonTracks const& /*kaontracks*/) { const float centrality = collision.cent(); + auto qxZDCA = collision.qxA(); + auto qyZDCA = collision.qyA(); + auto qxZDCC = collision.qxC(); + auto qyZDCC = collision.qyC(); + + auto qxtQxp = qxZDCC * qxZDCA; + auto qytQyp = qyZDCC * qyZDCA; + auto qxytp = qxtQxp + qytQyp; + // auto qxpQyt = qxZDCA * qyZDCC; + // auto qxtQyp = qxZDCC * qyZDCA; histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hpQxytpvscent"), centrality, qxytp); + histos.fill(HIST("hpQxpvscent"), centrality, qxZDCA); + histos.fill(HIST("hpQxtvscent"), centrality, qxZDCC); + histos.fill(HIST("hpQypvscent"), centrality, qyZDCA); + histos.fill(HIST("hpQytvscent"), centrality, qyZDCC); auto posThisColl = posKaons->sliceByCached(aod::kaonpair::kaoneventId, collision.globalIndex(), cache); auto negThisColl = negKaons->sliceByCached(aod::kaonpair::kaoneventId, collision.globalIndex(), cache); - + /* int nPlus = 0; int nMinus = 0; int nPhiSame = 0; @@ -169,7 +270,7 @@ struct phiflowder { histos.fill(HIST("hNplusPerEvent"), nPlus); histos.fill(HIST("hNminusPerEvent"), nMinus); - + */ for (const auto& kPlus : posThisColl) { if (!passStoredPID(kPlus)) { continue; @@ -192,23 +293,320 @@ struct phiflowder { const float phiMass = phiCandidate.M(); const float phiPt = phiCandidate.Pt(); + const float etaCand = phiCandidate.Eta(); + double phiCand = phiCandidate.Phi(); + if (phiCand < 0.0) { + phiCand += 2.0 * TMath::Pi(); + } + double const cosNPhi = std::cos(phiCand); + double const sinNPhi = std::sin(phiCand); + + auto ux = cosNPhi; // real part of candidate q vector + auto uy = sinNPhi; // imaginary part of candidate q vector + auto oddv1 = ux * (qxZDCA - qxZDCC) + uy * (qyZDCA - qyZDCC); + // auto evenv1 = ux * (qxZDCA + qxZDCC) + uy * (qyZDCA + qyZDCC); + auto uQA = ux * qxZDCA + uy * qyZDCA; + auto uQC = ux * qxZDCC + uy * qyZDCC; if (phiMass < massMin || phiMass > massMax) { continue; } - histos.fill(HIST("hPhiMassSame"), phiMass); - histos.fill(HIST("hPhiPtSame"), phiPt); - histos.fill(HIST("hSparseSame"), phiMass, phiPt, centrality); + histos.fill(HIST("hSparseSame"), phiMass, phiPt, centrality, etaCand, oddv1); + histos.fill(HIST("hSparseSameUx"), phiMass, phiPt, centrality, etaCand, ux); + histos.fill(HIST("hSparseSameUy"), phiMass, phiPt, centrality, etaCand, uy); + histos.fill(HIST("hSparseSameUQA"), phiMass, phiPt, centrality, etaCand, uQA); + histos.fill(HIST("hSparseSameUQC"), phiMass, phiPt, centrality, etaCand, uQC); + // nPhiSame++; + } + } + } + + PROCESS_SWITCH(phiflowder, processSameData, "Process same-event K+K- pairs", true); + + void processLikeSign(EventCandidates::iterator const& collision, aod::KaonTracks const& /*kaontracks*/) + { + const float centrality = collision.cent(); + + auto posThisColl = posKaons->sliceByCached(aod::kaonpair::kaoneventId, collision.globalIndex(), cache); + auto negThisColl = negKaons->sliceByCached(aod::kaonpair::kaoneventId, collision.globalIndex(), cache); + /* + int nPlus = 0; + int nMinus = 0; + int nPhiLike = 0; + + for (const auto& kPlus : posThisColl) { + if (passStoredPID(kPlus)) { + nPlus++; + } + } + + for (const auto& kMinus : negThisColl) { + if (passStoredPID(kMinus)) { + nMinus++; + } + } + + histos.fill(HIST("hNplusLikePerEvent"), nPlus); + histos.fill(HIST("hNminusLikePerEvent"), nMinus); + */ + + // K+K+ pairs + for (const auto& kPlus1 : posThisColl) { + if (!passStoredPID(kPlus1)) { + continue; + } + + ROOT::Math::PxPyPzMVector plusVec1(kPlus1.px(), kPlus1.py(), kPlus1.pz(), o2::constants::physics::MassKPlus); + + for (const auto& kPlus2 : posThisColl) { + if (!passStoredPID(kPlus2)) { + continue; + } + + // Reject self-pairs and count every unique K+K+ pair only once. + if (kPlus2.kaonIndex() <= kPlus1.kaonIndex()) { + continue; + } - nPhiSame++; + if (!passDeepAngle(kPlus1.px(), kPlus1.py(), kPlus1.pz(), kPlus2.px(), kPlus2.py(), kPlus2.pz())) { + continue; + } + + ROOT::Math::PxPyPzMVector plusVec2(kPlus2.px(), kPlus2.py(), kPlus2.pz(), o2::constants::physics::MassKPlus); + + const auto likeCandidate = plusVec1 + plusVec2; + const float likeMass = likeCandidate.M(); + const float likePt = likeCandidate.Pt(); + + if (likeMass < massMin.value || likeMass > massMax.value) { + continue; + } + histos.fill(HIST("hSparseLike"), likeMass, likePt, centrality); + // nPhiLike++; } } - histos.fill(HIST("hNphiSamePerEvent"), nPhiSame); + // K-K- pairs + for (const auto& kMinus1 : negThisColl) { + if (!passStoredPID(kMinus1)) { + continue; + } + + ROOT::Math::PxPyPzMVector minusVec1(kMinus1.px(), kMinus1.py(), kMinus1.pz(), o2::constants::physics::MassKPlus); + + for (const auto& kMinus2 : negThisColl) { + if (!passStoredPID(kMinus2)) { + continue; + } + + // Reject self-pairs and count every unique K-K- pair only once. + if (kMinus2.kaonIndex() <= kMinus1.kaonIndex()) { + continue; + } + + if (!passDeepAngle(kMinus1.px(), kMinus1.py(), kMinus1.pz(), kMinus2.px(), kMinus2.py(), kMinus2.pz())) { + continue; + } + + ROOT::Math::PxPyPzMVector minusVec2(kMinus2.px(), kMinus2.py(), kMinus2.pz(), o2::constants::physics::MassKPlus); + + const auto likeCandidate = minusVec1 + minusVec2; + const float likeMass = likeCandidate.M(); + const float likePt = likeCandidate.Pt(); + + if (likeMass < massMin.value || likeMass > massMax.value) { + continue; + } + + histos.fill(HIST("hSparseLike"), likeMass, likePt, centrality); + // nPhiLike++; + } + } } - PROCESS_SWITCH(phiflowder, processSameData, "Process same-event K+K- pairs", true); + PROCESS_SWITCH(phiflowder, processLikeSign, "Process like-sign K+K+ and K-K- pairs", true); + + // Processing Event Mixing + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{cfgVtxBins, cfgCentBins}, true}; + + void processMixedData(EventCandidates const& collisions, + aod::KaonTracks const& /*kaontracks*/) + { + BinningType colBinning{{cfgVtxBins, cfgCentBins}, true}; + for (const auto& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing.value, -1, collisions, collisions)) { + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + const float centrality1 = collision1.cent(); + const float centrality2 = collision2.cent(); + + auto qxZDCA = collision1.qxA(); + auto qyZDCA = collision1.qyA(); + auto qxZDCC = collision1.qxC(); + auto qyZDCC = collision1.qyC(); + + // K+ from event 1 and K- from event 2 + auto posGroup1 = posKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision1.globalIndex(), + cache); + + auto negGroup2 = negKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision2.globalIndex(), + cache); + + // K+ from event 2 and K- from event 1 + auto posGroup2 = posKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision2.globalIndex(), + cache); + + auto negGroup1 = negKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision1.globalIndex(), + cache); + + int nMixedPairs = 0; + + nMixedPairs += fillMixedPairs(posGroup1, + negGroup2, + centrality1, qxZDCA, qxZDCC, qyZDCA, qyZDCC); + + nMixedPairs += fillMixedPairs(posGroup2, + negGroup1, + centrality2, qxZDCA, qxZDCC, qyZDCA, qyZDCC); + + histos.fill(HIST("hMixpairs"), nMixedPairs); + } + } + + PROCESS_SWITCH(phiflowder, processMixedData, "Process mixed-event K+K- pairs", true); + + // Processing Event Mixing + void processMixedData2(EventCandidates const& collisions, + aod::KaonTracks const& /*kaontracks*/) + { + // Calculate the odd spectator-plane angle directly + // from the Q vectors already stored in KaonEvents. + auto getSPAngle = + [](EventCandidates::iterator const& collision) -> float { + const float qxOdd = + collision.qxA() - collision.qxC(); + + const float qyOdd = + collision.qyA() - collision.qyC(); + + float psiSP = + std::atan2(qyOdd, qxOdd); + + // Put first-harmonic angle in [0, 2pi). + if (psiSP < 0.f) { + psiSP += 2.f * TMath::Pi(); + } + + return psiSP; + }; + + using BinningTypeSP = + FlexibleBinningPolicy< + std::tuple, + aod::kaonevent::Posz, + aod::kaonevent::Cent, + decltype(getSPAngle)>; + + BinningTypeSP binningOnSPAngle{ + {getSPAngle}, + {cfgVtxBins, + cfgCentBins, + cfgSPAngleBins}, + true}; + + for (const auto& [collision1, collision2] : + selfCombinations(binningOnSPAngle, + nEvtMixing.value, + -1, + collisions, + collisions)) { + + if (collision1.globalIndex() == + collision2.globalIndex()) { + continue; + } + + const float centrality = + collision1.cent(); + + const float qxZDCA = + collision1.qxA(); + + const float qyZDCA = + collision1.qyA(); + + const float qxZDCC = + collision1.qxC(); + + const float qyZDCC = + collision1.qyC(); + + // K+ from event 1 and K- from event 2. + auto posGroup1 = + posKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision1.globalIndex(), + cache); + + auto negGroup2 = + negKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision2.globalIndex(), + cache); + + // K+ from event 2 and K- from event 1. + auto posGroup2 = + posKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision2.globalIndex(), + cache); + + auto negGroup1 = + negKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision1.globalIndex(), + cache); + + int nMixedPairs = 0; + + // Both combinations use centrality and Q vectors + // from collision1. + nMixedPairs += + fillMixedPairs(posGroup1, + negGroup2, + centrality, + qxZDCA, + qxZDCC, + qyZDCA, + qyZDCC); + + nMixedPairs += + fillMixedPairs(posGroup2, + negGroup1, + centrality, + qxZDCA, + qxZDCC, + qyZDCA, + qyZDCC); + + histos.fill(HIST("hMixpairs"), + nMixedPairs); + } + } + + PROCESS_SWITCH(phiflowder, processMixedData2, "Process mixed-event K+K- pairs in SP-angle bins", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/CMakeLists.txt b/PWGLF/Tasks/Strangeness/CMakeLists.txt index 67a056aab45..9b08a271008 100644 --- a/PWGLF/Tasks/Strangeness/CMakeLists.txt +++ b/PWGLF/Tasks/Strangeness/CMakeLists.txt @@ -200,3 +200,8 @@ o2physics_add_dpl_workflow(zdccalderived SOURCES zdccalderived.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(forwardlambdakzeroanalysis + SOURCES forwardlambdakzeroanalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::GlobalTracking O2::DCAFitter + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx index 7b068daee88..16411bb5780 100644 --- a/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx @@ -17,6 +17,7 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" #include "Common/CCDB/TriggerAliases.h" #include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" @@ -85,6 +86,15 @@ struct Derivedcascadeanalysis { Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::aod::rctsel::RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; + + struct : ConfigurableGroup { + std::string prefix = "rctConfigurations"; // JSON group name + Configurable cfgRCTLabel{"cfgRCTLabel", "", "Which detector condition requirements? (CBT, CBT_hadronPID, CBT_electronPID, CBT_calo, CBT_muon, CBT_muon_glo)"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "Include ZDC flags in the bit selection (for Pb-Pb only)"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } rctConfigurations; + struct : ConfigurableGroup { std::string prefix = "qa"; Configurable doFillNsigmaTPCHistPionBach{"doFillNsigmaTPCHistPionBach", false, ""}; @@ -114,6 +124,7 @@ struct Derivedcascadeanalysis { Configurable doNoCollInRofStandardCut{"doNoCollInRofStandardCut", true, "Enable an evevnt selection which rejects a collision if there are other events within the same ITS ROF with mult above threshold"}; Configurable doMultiplicityCorrCut{"doMultiplicityCorrCut", false, "Enable multiplicity vs centrality correlation cut"}; Configurable doITSallLayersCut{"doITSallLayersCut", false, "Enable event selection which rejects collisions when ITS was rebooting."}; + Configurable doCBTselection{"doCBTselection", true, "Require only events with good PID (CBT_hadronPID)"}; Configurable minOccupancy{"minOccupancy", -1, "Minimal occupancy"}; Configurable maxOccupancy{"maxOccupancy", -1, "Maximal occupancy"}; Configurable minOccupancyFT0{"minOccupancyFT0", -1, "Minimal occupancy"}; @@ -311,13 +322,15 @@ struct Derivedcascadeanalysis { SETBIT(selectionCheckMask, 11); } + rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); + histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {vertexZ}); histos.add("hEventMultFt0C", "", kTH1F, {{500, 0, 5000}}); histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{101, 0, 101}}); histos.add("hEventSelection", "hEventSelection", kTH1F, {{22, 0, 22}}); // TODO adjust labels - std::array eventSelLabelRun3 = {"all", "sel8", "TVX", "PV_{z}", "cent", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "kIsVertexITSTPC", "kIsVertexTOFmatched", "kIsVertexTRDmatched", "kNoITSROFrameBorder", "kNoTimeFrameBorder", "MultCorrCut", "kNoCollInTimeRangeStrict", "kNoCollInTimeRangeStandard", "min Occup", "mxOccup", "kNoCollInRofStrict", "kNoCollInRofStandard", "kIsGoodITSLayersAll", "occupFt0", "-"}; + std::array eventSelLabelRun3 = {"all", "sel8", "TVX", "PV_{z}", "cent", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "kIsVertexITSTPC", "kIsVertexTOFmatched", "kIsVertexTRDmatched", "kNoITSROFrameBorder", "kNoTimeFrameBorder", "MultCorrCut", "kNoCollInTimeRangeStrict", "kNoCollInTimeRangeStandard", "min Occup", "mxOccup", "kNoCollInRofStrict", "kNoCollInRofStandard", "kIsGoodITSLayersAll", "occupFt0", "CBT sel"}; std::array eventSelLabelRun2 = {"all", "sel8", "TVX", "PV_{z}", "cent", "sel7", "kINT7", "kNoIncompleteDAQ", "kNoInconsistentVtx", "kNoPileupFromSPD", "kNoV0PFPileup", "kNoPileupInMultBins", "kNoPileupMV", "kNoPileupTPC", "kNoV0MOnVsOfPileup", "kNoSPDOnVsOfPileup", "kNoSPDClsVsTklBG", "INEL0", "-", "-", "-", "-"}; for (int i = 1; i <= histos.get(HIST("hEventSelection"))->GetNbinsX(); i++) { if (doprocessCascades || doprocessCascadesMCrec || doprocessCascadesMCforEff) { @@ -798,6 +811,13 @@ struct Derivedcascadeanalysis { } interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource) * 1.e-3; + + if (eventSelectionRun3Flags.doCBTselection && !rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(coll)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 21.5 /* Pass CBT condition */); + } } else { centrality = eventSelectionRun2Flags.useSPDTrackletsCent ? coll.centRun2SPDTracklets() : coll.centRun2V0M(); diff --git a/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx b/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx new file mode 100644 index 00000000000..d5a8c4e85d4 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx @@ -0,0 +1,2521 @@ +// 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 forwardlambdakzeroanalysis.cxx +/// \brief V0s (K0s, Lambda and antiLambda) analysis task using derived data +/// +/// \author David Dobrigkeit Chinellato , Austrian Academy of Sciences & MBI +/// \author Romain Schotter , Austrian Academy of Sciences & MBI +// +// V0 analysis task +// ================ +// +// This code loops over a V0Cores table and produces some +// standard analysis output. It is meant to be run over +// derived data. +// +// Comments, questions, complaints, suggestions? +// Please write to: +// romain.schotter@cern.ch +// david.dobrigkeit.chinellato@cern.ch +// + +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using namespace o2::aod::rctsel; + +using Vec3D = ROOT::Math::SVector; +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +// simple checkers, but ensure 64 bit integers +#define BITSET(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) +#define BITCHECK(var, nbit) ((var) & (static_cast(1) << static_cast(nbit))) + +enum CentEstimator { + kCentFT0C = 0, + kCentFT0M, + kCentFT0CVariant1, + kCentMFT, + kCentNGlobal, + kCentFV0A +}; + +struct forwardlambdakzeroanalysis { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master analysis switches + Configurable analyseK0Short{"analyseK0Short", true, "process K0Short-like candidates"}; + Configurable analyseLambda{"analyseLambda", true, "process Lambda-like candidates"}; + Configurable analyseAntiLambda{"analyseAntiLambda", true, "process AntiLambda-like candidates"}; + Configurable analyseD0{"analyseD0", true, "process D0-like candidates"}; + Configurable analyseAntiD0{"analyseAntiD0", true, "process AntiD0-like candidates"}; + Configurable calculateFeeddownMatrix{"calculateFeeddownMatrix", true, "fill feeddown matrix if MC"}; + + Configurable doPPAnalysis{"doPPAnalysis", false, "if in pp, set to true"}; + Configurable irSource{"irSource", "", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + Configurable centralityEstimator{"centralityEstimator", kCentFT0C, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFT0CVariant1, 3:CentMFT, 4:CentNGlobal, 5:CentFV0A)"}; + Configurable doUPCanalysis{"doUPCanalysis", true, "Study V0s in hadronic and UPC collisions"}; + + Configurable doEventQA{"doEventQA", false, "do event QA histograms"}; + Configurable doCompleteTopoQA{"doCompleteTopoQA", false, "do topological variable QA histograms"}; + Configurable doPlainTopoQA{"doPlainTopoQA", true, "do simple 1D QA of candidates"}; + + // for MC + Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; + Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + + struct : ConfigurableGroup { + std::string prefix = "eventSelections"; // JSON group name + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border (Run 3 only)"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border (Run 3 only)"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track (Run 3 only)"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference (Run 3 only)"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF (Run 3 only)"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD (Run 3 only)"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds (Run 3 only)"}; + 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 requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + + Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + // fast check on interaction rate + Configurable minIR{"minIR", -1, "minimum IR collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + } eventSelections; + + static constexpr float DefaultLifetimeCuts[1][3] = {{20., 30., 20.}}; + + struct : ConfigurableGroup { + std::string prefix = "v0Selections"; // JSON group name + + // Selection criteria: acceptance + Configurable rapidityMin{"rapidityMin", 0.5, "min rapidity"}; + Configurable rapidityMax{"rapidityMax", 0.5, "max rapidity"}; + Configurable daughterEtaCutMin{"daughterEtaCutMin", 0.8, "min eta for daughters"}; + Configurable daughterEtaCutMax{"daughterEtaCutMax", 0.8, "max eta for daughters"}; + Configurable minTrackPt{"minTrackPt", 0.8, "min track pT (GeV/c)"}; + + // Standard 5 topological criteria + Configurable v0CosPA{"v0CosPA", 0.97, "min V0 CosPA"}; + Configurable v0OpAngle{"v0OpAngle", 0., "min V0 opening angle"}; + Configurable dcaV0Dau{"dcaV0Dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcaNegToPVxy{"dcaNegToPVxy", .05, "min DCAxy Neg To PV (cm)"}; + Configurable dcaPosToPVxy{"dcaPosToPVxy", .05, "min DCAxy Pos To PV (cm)"}; + Configurable dcaNegToPVz{"dcaNegToPVz", .05, "min DCAz Neg To PV (cm)"}; + Configurable dcaPosToPVz{"dcaPosToPVz", .05, "min DCAz Pos To PV (cm)"}; + Configurable v0RadiusMin{"v0RadiusMin", 1.2, "minimum V0 radius (cm)"}; + Configurable v0RadiusMax{"v0RadiusMax", 1e+09, "maximum V0 radius (cm)"}; + Configurable v0Zmin{"v0Zmin", 1.2, "minimum V0 z (cm)"}; + Configurable v0Zmax{"v0Zmax", 1e+09, "maximum V0 z (cm)"}; + 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"}; + + // invariant mass selection + Configurable compMassRejectionK0Short{"compMassRejectionK0Short", -1, "Competing K^{0}_{S} mass rejection (GeV/#it{c}^{2})"}; + Configurable compMassRejectionLambda{"compMassRejectionLambda", -1, "Competing Lambda mass rejection (GeV/#it{c}^{2})"}; + + // 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"}; + + // Track quality + Configurable minMFTclusters{"minMFTclusters", -1, "minimum MFT clusters"}; + Configurable maxMFTchi2PerNcls{"maxMFTchi2PerNcls", 1e+09, "maximum MFT chi2 per clusters"}; + Configurable maxMFTchi2{"maxMFTchi2", 1e+09, "max. MFT chi2"}; + } v0Selections; + + struct : ConfigurableGroup { + std::string prefix = "rctConfigurations"; // JSON group name + Configurable cfgRCTLabel{"cfgRCTLabel", "", "Which detector condition requirements? (CBT, CBT_hadronPID, CBT_electronPID, CBT_calo, CBT_muon, CBT_muon_glo)"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "Include ZDC flags in the bit selection (for Pb-Pb only)"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } rctConfigurations; + + RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdbConfigurations"; // JSON group name + 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"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + + // manual + Configurable useCustomMagField{"useCustomMagField", false, "Use custom magnetic field value"}; + Configurable customMagField{"customMagField", 5.0f, "Manually set magnetic field"}; + } ccdbConfigurations; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + ctpRateFetcher rateFetcher; + int mRunNumber; + float magField; + std::map metadata; + o2::parameters::GRPMagField* grpmag = nullptr; + + // CCDB options + struct : ConfigurableGroup { + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisPtXi{"axisPtXi", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for feeddown from Xi"}; + ConfigurableAxis axisPtCoarse{"axisPtCoarse", {VARIABLE_WIDTH, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 10.0f, 15.0f}, "pt axis for QA"}; + ConfigurableAxis axisPtResol{"axisPtResol", {100, -1.0f, 1.0f}, "Axis for momentum resolution (GeV/c)"}; + ConfigurableAxis axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, "Axis for K0S invariant mass (GeV/c2)"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "Axis for Lambda invariant mass (GeV/c2)"}; + ConfigurableAxis axisD0Mass{"axisD0Mass", {200, 1.75f, 1.95f}, "Axis for D0 invariant mass (GeV/c2)"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f}, "Centrality"}; + ConfigurableAxis axisCentralityFine{"axisCentralityFine", {101, 0.0f, 101.0f}, "Centrality"}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {500, 0, 50}, "Binning for the interaction rate (kHz)"}; + ConfigurableAxis axisMultFT0M{"axisMultFT0M", {500, 0.0f, +100000.0f}, "Multiplicity FT0M"}; + ConfigurableAxis axisMultFT0C{"axisMultFT0C", {500, 0.0f, +10000.0f}, "Multiplicity FT0C"}; + ConfigurableAxis axisMultFV0A{"axisMultFV0A", {500, 0.0f, +100000.0f}, "Multiplicity FV0A"}; + + ConfigurableAxis axisRawCentrality{"axisRawCentrality", {VARIABLE_WIDTH, 0.000f, 52.320f, 75.400f, 95.719f, 115.364f, 135.211f, 155.791f, 177.504f, 200.686f, 225.641f, 252.645f, 281.906f, 313.850f, 348.302f, 385.732f, 426.307f, 470.146f, 517.555f, 568.899f, 624.177f, 684.021f, 748.734f, 818.078f, 892.577f, 973.087f, 1058.789f, 1150.915f, 1249.319f, 1354.279f, 1465.979f, 1584.790f, 1710.778f, 1844.863f, 1985.746f, 2134.643f, 2291.610f, 2456.943f, 2630.653f, 2813.959f, 3006.631f, 3207.229f, 3417.641f, 3637.318f, 3865.785f, 4104.997f, 4354.938f, 4615.786f, 4885.335f, 5166.555f, 5458.021f, 5762.584f, 6077.881f, 6406.834f, 6746.435f, 7097.958f, 7462.579f, 7839.165f, 8231.629f, 8635.640f, 9052.000f, 9484.268f, 9929.111f, 10389.350f, 10862.059f, 11352.185f, 11856.823f, 12380.371f, 12920.401f, 13476.971f, 14053.087f, 14646.190f, 15258.426f, 15890.617f, 16544.433f, 17218.024f, 17913.465f, 18631.374f, 19374.983f, 20136.700f, 20927.783f, 21746.796f, 22590.880f, 23465.734f, 24372.274f, 25314.351f, 26290.488f, 27300.899f, 28347.512f, 29436.133f, 30567.840f, 31746.818f, 32982.664f, 34276.329f, 35624.859f, 37042.588f, 38546.609f, 40139.742f, 41837.980f, 43679.429f, 45892.130f, 400000.000f}, "raw centrality signal"}; // for QA + + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + + // topological variable QA axes + ConfigurableAxis axisDCAtoPVxy{"axisDCAtoPVxy", {100, 0.0f, 5.0f}, "DCAxy (cm)"}; + ConfigurableAxis axisDCAtoPVz{"axisDCAtoPVz", {100, -5.0f, 5.0f}, "DCAz (cm)"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {20, 0.0f, 2.0f}, "DCA (cm)"}; + ConfigurableAxis axisCosPA{"axisCosPA", {1000, 0.0f, 1.0f}, "cos(PA)"}; + ConfigurableAxis axisOpeningAngle{"axisOpeningAngle", {1000, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}, "Opening angle (rad)"}; + ConfigurableAxis axisV0Radius{"axisV0Radius", {20, 0.0f, 60.0f}, "V0 2D radius (cm)"}; + ConfigurableAxis axisV0Z{"axisV0Z", {100, -50.0f, 0.0f}, "V0 Z (cm)"}; + ConfigurableAxis axisV0Rapidity{"axisV0Rapidity", {100, -4.0f, -1.0f}, "Rapidity"}; + ConfigurableAxis axisV0ProperLifeTime{"axisV0ProperLifeTime", {100, 0.0f, 50.0f}, "Proper lifetime (cm)"}; + ConfigurableAxis axisV0PseudoProperLifeTime{"axisV0PseudoProperLifeTime", {100, -50.0f, 50.0f}, "Pseudo-proper lifetime (cm)"}; + + ConfigurableAxis axisMFTchi2{"axisMFTchi2", {1000, 0.0f, 1000.0f}, "#chi^{2}"}; + ConfigurableAxis axisMFTchi2NDF{"axisMFTchi2NDF", {100, 0.0f, 100.0f}, "#chi^{2} per MFT clusters"}; + ConfigurableAxis axisMFTclus{"axisMFTclus", {10, 0.0f, 10.0f}, "N MFT Clusters"}; + + // UPC axes + ConfigurableAxis axisSelGap{"axisSelGap", {4, -1.5, 2.5}, "Gap side"}; + + // AP plot axes + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // MC coll assoc QA axis + ConfigurableAxis axisMonteCarloNch{"axisMonteCarloNch", {300, 0.0f, 3000.0f}, "N_{ch} MC"}; + } axisConfigurations; + + // UPC selections + SGSelector sgSelector; + struct : ConfigurableGroup { + std::string prefix = "upcCuts"; // JSON group name + Configurable fv0Cut{"fv0Cut", 100., "FV0A threshold"}; + Configurable ft0Acut{"ft0Acut", 200., "FT0A threshold"}; + Configurable ft0Ccut{"ft0Ccut", 100., "FT0C threshold"}; + Configurable zdcCut{"zdcCut", 10., "ZDC threshold"}; + // Configurable gapSel{"gapSel", 2, "Gap selection"}; + } upcCuts; + + // DCA fitter configurations + struct : ConfigurableGroup { + std::string prefix = "fitterConfigurations"; // JSON group name + Configurable propagateToPCA{"propagateToPCA", true, "Propagate to PCA?"}; + Configurable minParamChange{"minParamChange", 4., "Stop minimization iterations if largest change of any X is smaller than this."}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "Stop iterations is chi2/chi2old > this"}; + Configurable useAbsDCA{"useAbsDCA", true, "Use abs. distance minimization rather than chi2"}; + Configurable useLUTMatCorr{"useLUTMatCorr", true, "Use material LUT correction, instead of TGeo material correction or no material correction."}; + Configurable useTGeoMatCorr{"useTGeoMatCorr", false, "Use material TGeo correction, instead of LUT material correction or no material correction."}; + } fitterConfigurations; + + o2::base::MatLayerCylSet* lut; // material LUT for DCA fitter + o2::vertexing::FwdDCAFitterN<2> fitter; + + // Taken from https://github.com/AliceO2Group/O2Physics/blob/master/PWGLF/TableProducer/Strangeness/sigma0builder.cxx#L319 + // Thanks Gianni! + // ______________________________________________________ + // Struct to store V0Pair properties + struct PairTopoInfo { + float X = -999.f; + float Y = -999.f; + float Z = -999.f; + float Radius = -999.f; + std::array positiveMomentum = {0.0f, 0.0f, 0.0f}; + std::array negativeMomentum = {0.0f, 0.0f, 0.0f}; + float dcaPosToPVxy = -999.f; + float dcaNegToPVxy = -999.f; + float dcaPosToPVz = -999.f; + float dcaNegToPVz = -999.f; + float pTot = -999.f; + float pT = -999.f; + float pZ = -999.f; + float DistOverTotMom = -1.f; + float ZdistOverPz = -1.f; + float DCADau = -999.f; + float CosPA = -1.f; + float OpAngle = -999.f; + float mK0s = -999.f; + float mLambda = -999.f; + float mAntiLambda = -999.f; + float mD0 = -999.f; + float mAntiD0 = -999.f; + float QtArm = -999.f; + float AlphaArm = -999.f; + float rapidityK0s = -999.f; + float rapidityLambda = -999.f; + float rapidityD0 = -999.f; + int posNclusters = -1; + int negNclusters = -1; + float posChi2 = 999.f; + float negChi2 = 999.f; + float posChi2PerNclus = 999.f; + float negChi2PerNclus = 999.f; + + // MC specific information + int label = -1; + int motherLabel = -1; + float xMc = -999.f; + float yMc = -999.f; + float zMc = -999.f; + std::array momentumMc = {0.0f, 0.0f, 0.0f}; + std::array positiveMomentumMc = {0.0f, 0.0f, 0.0f}; + std::array negativeMomentumMc = {0.0f, 0.0f, 0.0f}; + std::array momentumMotherMc = {0.0f, 0.0f, 0.0f}; + int processPositive = -1; + int processNegative = -1; + float pTotMc = -999.f; + float pTMc = -999.f; + float pZMc = -999.f; + float rapMc = -999.f; + int pdgCodePositive = 0; + int pdgCodeNegative = 0; + int pdgCode = 0; + int pdgCodeMother = 0; + int mcCollision = -1; + bool isPhysicalPrimary = false; + bool motherIsPhysicalPrimary = false; + }; + + // For manual sliceBy + // Preslice> perMcCollision = aod::v0data::straMCCollisionId; + PresliceUnsorted> perMcCollision = o2::aod::mccollisionlabel::mcCollisionId; + + enum Selection : uint64_t { selCosPA = 0, + selOpAngle, + selRadius, + selRadiusMax, + selZmin, + selZmax, + selDCANegToPVxy, + selDCAPosToPVxy, + selDCANegToPVz, + selDCAPosToPVz, + selDCAV0Dau, + selK0ShortRapidityMin, + selK0ShortRapidityMax, + selLambdaRapidityMin, + selLambdaRapidityMax, + selD0RapidityMin, + selD0RapidityMax, + selK0ShortMassRejection, + selLambdaMassRejection, + selK0ShortCTau, + selLambdaCTau, + selD0CTau, + selK0ShortPseudoLifetimeMin, + selK0ShortPseudoLifetimeMax, + selLambdaPseudoLifetimeMin, + selLambdaPseudoLifetimeMax, + selD0PseudoLifetimeMin, + selD0PseudoLifetimeMax, + selK0ShortArmenteros, + selPosGoodMFTTrack, + selNegGoodMFTTrack, + selConsiderK0Short, // for mc tagging + selConsiderLambda, // for mc tagging + selConsiderAntiLambda, // for mc tagging + selConsiderD0, // for mc tagging + selConsiderAntiD0, // for mc tagging + selPhysPrimK0Short, // for mc tagging + selPhysPrimLambda, // for mc tagging + selPhysPrimAntiLambda, // for mc tagging + selPhysPrimD0, // for mc tagging + selPhysPrimAntiD0, // for mc tagging + }; + + uint64_t maskTopological; + uint64_t maskTrackProperties; + + uint64_t maskK0ShortSpecific; + uint64_t maskLambdaSpecific; + uint64_t maskAntiLambdaSpecific; + uint64_t maskD0Specific; + uint64_t maskAntiD0Specific; + + uint64_t maskSelectionK0Short; + uint64_t maskSelectionLambda; + uint64_t maskSelectionAntiLambda; + uint64_t maskSelectionD0; + uint64_t maskSelectionAntiD0; + + uint64_t secondaryMaskSelectionLambda; + uint64_t secondaryMaskSelectionAntiLambda; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL(ccdbConfigurations.ccdbUrl); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + // initialise bit masks + // Mask with all topologic selections + maskTopological = 0; + BITSET(maskTopological, selCosPA); + BITSET(maskTopological, selRadius); + BITSET(maskTopological, selRadiusMax); + BITSET(maskTopological, selDCANegToPVxy); + BITSET(maskTopological, selDCAPosToPVxy); + BITSET(maskTopological, selDCANegToPVz); + BITSET(maskTopological, selDCAPosToPVz); + BITSET(maskTopological, selDCAV0Dau); + BITSET(maskTopological, selZmin); + BITSET(maskTopological, selZmax); + BITSET(maskTopological, selOpAngle); + + // Mask for specifically selecting K0Short + maskK0ShortSpecific = 0; + BITSET(maskK0ShortSpecific, selK0ShortRapidityMin); + BITSET(maskK0ShortSpecific, selK0ShortRapidityMax); + BITSET(maskK0ShortSpecific, selK0ShortCTau); + BITSET(maskK0ShortSpecific, selK0ShortPseudoLifetimeMin); + BITSET(maskK0ShortSpecific, selK0ShortPseudoLifetimeMax); + BITSET(maskK0ShortSpecific, selK0ShortArmenteros); + BITSET(maskK0ShortSpecific, selConsiderK0Short); + BITSET(maskK0ShortSpecific, selLambdaMassRejection); + // Mask for specifically selecting Lambda + maskLambdaSpecific = 0; + BITSET(maskLambdaSpecific, selLambdaRapidityMin); + BITSET(maskLambdaSpecific, selLambdaRapidityMax); + BITSET(maskLambdaSpecific, selLambdaCTau); + BITSET(maskLambdaSpecific, selLambdaPseudoLifetimeMin); + BITSET(maskLambdaSpecific, selLambdaPseudoLifetimeMax); + BITSET(maskLambdaSpecific, selConsiderLambda); + BITSET(maskLambdaSpecific, selK0ShortMassRejection); + // Mask for specifically selecting AntiLambda + maskAntiLambdaSpecific = 0; + BITSET(maskAntiLambdaSpecific, selLambdaRapidityMin); + BITSET(maskAntiLambdaSpecific, selLambdaRapidityMax); + BITSET(maskAntiLambdaSpecific, selLambdaCTau); + BITSET(maskAntiLambdaSpecific, selLambdaPseudoLifetimeMin); + BITSET(maskAntiLambdaSpecific, selLambdaPseudoLifetimeMax); + BITSET(maskAntiLambdaSpecific, selConsiderAntiLambda); + BITSET(maskAntiLambdaSpecific, selK0ShortMassRejection); + // Mask for specifically selecting D0 + maskD0Specific = 0; + BITSET(maskD0Specific, selD0RapidityMin); + BITSET(maskD0Specific, selD0RapidityMax); + BITSET(maskD0Specific, selD0CTau); + BITSET(maskD0Specific, selD0PseudoLifetimeMin); + BITSET(maskD0Specific, selD0PseudoLifetimeMax); + BITSET(maskD0Specific, selConsiderD0); + BITSET(maskD0Specific, selK0ShortMassRejection); + BITSET(maskD0Specific, selLambdaMassRejection); + // Mask for specifically selecting D0 + maskAntiD0Specific = 0; + BITSET(maskAntiD0Specific, selD0RapidityMin); + BITSET(maskAntiD0Specific, selD0RapidityMax); + BITSET(maskAntiD0Specific, selD0CTau); + BITSET(maskAntiD0Specific, selD0PseudoLifetimeMin); + BITSET(maskAntiD0Specific, selD0PseudoLifetimeMax); + BITSET(maskAntiD0Specific, selConsiderAntiD0); + BITSET(maskAntiD0Specific, selK0ShortMassRejection); + BITSET(maskAntiD0Specific, selLambdaMassRejection); + + // ask for specific TPC/TOF PID selections + maskTrackProperties = 0; + BITSET(maskTrackProperties, selPosGoodMFTTrack); + BITSET(maskTrackProperties, selNegGoodMFTTrack); + + // Primary particle selection, central to analysis + maskSelectionK0Short = maskTopological | maskTrackProperties | maskK0ShortSpecific; + maskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; + maskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + maskSelectionD0 = maskTopological | maskTrackProperties | maskD0Specific; + maskSelectionAntiD0 = maskTopological | maskTrackProperties | maskAntiD0Specific; + + BITSET(maskSelectionK0Short, selPhysPrimK0Short); + BITSET(maskSelectionLambda, selPhysPrimLambda); + BITSET(maskSelectionAntiLambda, selPhysPrimAntiLambda); + BITSET(maskSelectionD0, selPhysPrimD0); + BITSET(maskSelectionAntiD0, selPhysPrimAntiD0); + + // No primary requirement for feeddown matrix + secondaryMaskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; + secondaryMaskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + + // Initialise the RCTFlagsChecker + rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); + + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1D, {{23, -0.5f, +22.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"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + 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.add("hEventCentrality", "hEventCentrality", kTH1D, {axisConfigurations.axisCentralityFine}); + histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisNch}); + + histos.add("hEventPVz", "hEventPVz", kTH1D, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVz", "hCentralityVsPVz", kTH2D, {axisConfigurations.axisCentralityFine, {100, -20.0f, +20.0f}}); + if (doprocessGenerated) { + histos.add("hEventPVzMC", "hEventPVzMC", kTH1D, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVzMC", "hCentralityVsPVzMC", kTH2D, {axisConfigurations.axisCentralityFine, {100, -20.0f, +20.0f}}); + } + + histos.add("hEventOccupancy", "hEventOccupancy", kTH1D, {axisConfigurations.axisOccupancy}); + histos.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisOccupancy}); + + if (doUPCanalysis) { + histos.add("hGapSide", "Gap side; Entries", kTH1D, {{5, -0.5, 4.5}}); + histos.add("hSelGapSide", "Selected gap side; Entries", kTH1D, {axisConfigurations.axisSelGap}); + histos.add("hEventCentralityVsSelGapSide", ";Centrality (%); Selected gap side", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisSelGap}); + } + + histos.add("hInteractionRate", "hInteractionRate", kTH1D, {axisConfigurations.axisIRBinning}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisIRBinning}); + + histos.add("hInteractionRateVsOccupancy", "hInteractionRateVsOccupancy", kTH2D, {axisConfigurations.axisIRBinning, axisConfigurations.axisOccupancy}); + + auto hSelectionV0s = histos.add("GeneralQA/hSelectionV0s", "hSelectionV0s", kTH1D, {{static_cast(selPhysPrimAntiD0) + 3, -0.5f, static_cast(selPhysPrimAntiD0) + 2.5f}}); + hSelectionV0s->GetXaxis()->SetBinLabel(1, "All"); + hSelectionV0s->GetXaxis()->SetBinLabel(selCosPA + 2, "cosPA"); + hSelectionV0s->GetXaxis()->SetBinLabel(selOpAngle + 2, "Op. angle"); + hSelectionV0s->GetXaxis()->SetBinLabel(selRadius + 2, "Radius min."); + hSelectionV0s->GetXaxis()->SetBinLabel(selRadiusMax + 2, "Radius max."); + hSelectionV0s->GetXaxis()->SetBinLabel(selZmin + 2, "Z min."); + hSelectionV0s->GetXaxis()->SetBinLabel(selZmax + 2, "Z max."); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCANegToPVxy + 2, "DCAxy neg. to PV"); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCAPosToPVxy + 2, "DCAxy pos. to PV"); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCANegToPVz + 2, "DCAz neg. to PV"); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCAPosToPVz + 2, "DCAz pos. to PV"); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCAV0Dau + 2, "DCA V0 dau."); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortRapidityMin + 2, "K^{0}_{S} rap. min"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortRapidityMax + 2, "K^{0}_{S} rap. max"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaRapidityMin + 2, "#Lambda rap. min"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaRapidityMax + 2, "#Lambda rap. max"); + hSelectionV0s->GetXaxis()->SetBinLabel(selD0RapidityMin + 2, "D^{0} rap. min"); + hSelectionV0s->GetXaxis()->SetBinLabel(selD0RapidityMax + 2, "D^{0} rap. max"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortMassRejection + 2, "K^{0}_{S} mass rej."); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaMassRejection + 2, "#Lambda mass rej."); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortCTau + 2, "K^{0}_{S} lifetime"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaCTau + 2, "#Lambda lifetime"); + hSelectionV0s->GetXaxis()->SetBinLabel(selD0CTau + 2, "D^{0} lifetime"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortPseudoLifetimeMin + 2, "K^{0}_{S} pseudo-time min"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortPseudoLifetimeMax + 2, "K^{0}_{S} pseudo-time max"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaPseudoLifetimeMin + 2, "#Lambda pseudo-time min"); + 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(selPosGoodMFTTrack + 2, "Pos. good MFT track"); + hSelectionV0s->GetXaxis()->SetBinLabel(selNegGoodMFTTrack + 2, "Neg. good MFT track"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderK0Short + 2, "True K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderLambda + 2, "True #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderAntiLambda + 2, "True #bar{#Lambda}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderD0 + 2, "True D^{0}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderAntiD0 + 2, "True #bar{D}^{0}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimK0Short + 2, "Phys. prim. K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimLambda + 2, "Phys. prim. #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimAntiLambda + 2, "Phys. prim. #bar{#Lambda}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimD0 + 2, "Phys. prim. D^{0}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimAntiD0 + 2, "Phys. prim. #bar{D}^{0}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimAntiD0 + 3, "Cand. selected"); + + // histograms versus mass + if (analyseK0Short) { + histos.add("h2dNbrOfK0ShortVsCentrality", "h2dNbrOfK0ShortVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + if (doUPCanalysis) { + // Non-UPC info + histos.add("h3dMassK0ShortHadronic", "h3dMassK0ShortHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + // UPC info + histos.add("h3dMassK0ShortSGA", "h3dMassK0ShortSGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + histos.add("h3dMassK0ShortSGC", "h3dMassK0ShortSGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + histos.add("h3dMassK0ShortDG", "h3dMassK0ShortDG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + } + } + if (analyseLambda) { + histos.add("h2dNbrOfLambdaVsCentrality", "h2dNbrOfLambdaVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassLambda", "h3dMassLambda", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + if (doUPCanalysis) { + // Non-UPC info + histos.add("h3dMassLambdaHadronic", "h3dMassLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // UPC info + histos.add("h3dMassLambdaSGA", "h3dMassLambdaSGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassLambdaSGC", "h3dMassLambdaSGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassLambdaDG", "h3dMassLambdaDG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + } + } + if (analyseAntiLambda) { + histos.add("h2dNbrOfAntiLambdaVsCentrality", "h2dNbrOfAntiLambdaVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + if (doUPCanalysis) { + // Non-UPC info + histos.add("h3dMassAntiLambdaHadronic", "h3dMassAntiLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // UPC info + histos.add("h3dMassAntiLambdaSGA", "h3dMassAntiLambdaSGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassAntiLambdaSGC", "h3dMassAntiLambdaSGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassAntiLambdaDG", "h3dMassAntiLambdaDG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + } + } + if (analyseD0) { + histos.add("h2dNbrOfD0VsCentrality", "h2dNbrOfD0VsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassD0", "h3dMassD0", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + if (doUPCanalysis) { + // Non-UPC info + histos.add("h3dMassD0Hadronic", "h3dMassD0Hadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + // UPC info + histos.add("h3dMassD0SGA", "h3dMassD0SGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + histos.add("h3dMassD0SGC", "h3dMassD0SGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + histos.add("h3dMassD0DG", "h3dMassD0DG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + } + } + if (analyseAntiD0) { + histos.add("h2dNbrOfAntiD0VsCentrality", "h2dNbrOfAntiD0VsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassAntiD0", "h3dMassAntiD0", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + if (doUPCanalysis) { + // Non-UPC info + histos.add("h3dMassAntiD0Hadronic", "h3dMassAntiLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + // UPC info + histos.add("h3dMassAntiD0SGA", "h3dMassAntiD0SGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + histos.add("h3dMassAntiD0SGC", "h3dMassAntiD0SGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + histos.add("h3dMassAntiD0DG", "h3dMassAntiD0DG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisD0Mass}); + } + } + + if (analyseLambda && calculateFeeddownMatrix && doprocessMonteCarlo) { + histos.add("h3dLambdaFeeddown", "h3dLambdaFeeddown", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisPtXi}); + histos.add("h3dLambdaFeeddownFromXi0", "h3dLambdaFeeddownFromXi0", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisPtXi}); + } + if (analyseAntiLambda && calculateFeeddownMatrix && doprocessMonteCarlo) { + histos.add("h3dAntiLambdaFeeddown", "h3dAntiLambdaFeeddown", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisPtXi}); + histos.add("h3dAntiLambdaFeeddownFromXi0", "h3dAntiLambdaFeeddownFromXi0", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisPtXi}); + } + + if (analyseK0Short) + histos.add("hMassK0Short", "hMassK0Short", kTH1D, {axisConfigurations.axisK0Mass}); + if (analyseLambda) + histos.add("hMassLambda", "hMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + if (analyseAntiLambda) + histos.add("hMassAntiLambda", "hMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + if (analyseD0) + histos.add("hMassD0", "hMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + if (analyseAntiD0) + histos.add("hMassAntiD0", "hMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + if (doPlainTopoQA) { + // All candidates received + histos.add("hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("hPosDCAToPVz", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); + histos.add("hOpeningAngle", "hOpeningAngle", kTH1D, {axisConfigurations.axisOpeningAngle}); + histos.add("hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("hV0Z", "hV0Z", kTH1D, {axisConfigurations.axisV0Z}); + histos.add("hV0Rapidity", "hV0Rapidity", kTH1D, {axisConfigurations.axisV0Rapidity}); + histos.add("hV0LifetimeK0s", "hV0LifetimeK0s", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("hV0LifetimeLambda", "hV0LifetimeLambda", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("hV0LifetimeD0", "hV0LifetimeD0", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("hV0PseudoLifetimeK0s", "hV0PseudoLifetimeK0s", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("hV0PseudoLifetimeLambda", "hV0PseudoLifetimeLambda", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("hV0PseudoLifetimeD0", "hV0PseudoLifetimeD0", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("hV0InvMassK0s", "hV0InvMassK0s", kTH1D, {axisConfigurations.axisK0Mass}); + histos.add("hV0InvMassLambda", "hV0InvMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("hV0InvMassAntiLambda", "hV0InvMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("hV0InvMassD0", "hV0InvMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + histos.add("hV0InvMassAntiD0", "hV0InvMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + histos.add("hPositiveMFTcls", "hPositiveMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("hNegativeMFTcls", "hNegativeMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("hPositiveMFTchi2PerNcls", "hPositiveMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("hNegativeMFTchi2PerNcls", "hNegativeMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + histos.add("hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + if (doprocessMonteCarlo) { + histos.add("hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + } + if (analyseK0Short) { + histos.add("K0Short/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("K0Short/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("K0Short/hPosDCAToPVz", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("K0Short/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("K0Short/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("K0Short/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); + histos.add("K0Short/hOpeningAngle", "hOpeningAngle", kTH1D, {axisConfigurations.axisOpeningAngle}); + histos.add("K0Short/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("K0Short/hV0Z", "hV0Z", kTH1D, {axisConfigurations.axisV0Z}); + histos.add("K0Short/hV0Rapidity", "hV0Rapidity", kTH1D, {axisConfigurations.axisV0Rapidity}); + histos.add("K0Short/hV0LifetimeK0s", "hV0LifetimeK0s", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("K0Short/hV0LifetimeLambda", "hV0LifetimeLambda", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("K0Short/hV0LifetimeD0", "hV0LifetimeD0", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("K0Short/hV0PseudoLifetimeK0s", "hV0PseudoLifetimeK0s", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("K0Short/hV0PseudoLifetimeLambda", "hV0PseudoLifetimeLambda", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("K0Short/hV0PseudoLifetimeD0", "hV0PseudoLifetimeD0", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("K0Short/hV0InvMassK0s", "hV0InvMassK0s", kTH1D, {axisConfigurations.axisK0Mass}); + histos.add("K0Short/hV0InvMassLambda", "hV0InvMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("K0Short/hV0InvMassAntiLambda", "hV0InvMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("K0Short/hV0InvMassD0", "hV0InvMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + histos.add("K0Short/hV0InvMassAntiD0", "hV0InvMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + histos.add("K0Short/hPositiveMFTcls", "hPositiveMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("K0Short/hNegativeMFTcls", "hNegativeMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("K0Short/hPositiveMFTchi2PerNcls", "hPositiveMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("K0Short/hNegativeMFTchi2PerNcls", "hNegativeMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("K0Short/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + histos.add("K0Short/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + if (doprocessMonteCarlo) { + histos.add("K0Short/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("K0Short/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + } + } + if (analyseLambda) { + histos.add("Lambda/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("Lambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("Lambda/hPosDCAToPVz", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("Lambda/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("Lambda/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); + histos.add("Lambda/hOpeningAngle", "hOpeningAngle", kTH1D, {axisConfigurations.axisOpeningAngle}); + histos.add("Lambda/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("Lambda/hV0Z", "hV0Z", kTH1D, {axisConfigurations.axisV0Z}); + histos.add("Lambda/hV0Rapidity", "hV0Rapidity", kTH1D, {axisConfigurations.axisV0Rapidity}); + histos.add("Lambda/hV0LifetimeK0s", "hV0LifetimeK0s", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("Lambda/hV0LifetimeLambda", "hV0LifetimeLambda", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("Lambda/hV0LifetimeD0", "hV0LifetimeD0", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("Lambda/hV0PseudoLifetimeK0s", "hV0PseudoLifetimeK0s", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("Lambda/hV0PseudoLifetimeLambda", "hV0PseudoLifetimeLambda", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("Lambda/hV0PseudoLifetimeD0", "hV0PseudoLifetimeD0", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("Lambda/hV0InvMassK0s", "hV0InvMassK0s", kTH1D, {axisConfigurations.axisK0Mass}); + histos.add("Lambda/hV0InvMassLambda", "hV0InvMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("Lambda/hV0InvMassAntiLambda", "hV0InvMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("Lambda/hV0InvMassD0", "hV0InvMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + histos.add("Lambda/hV0InvMassAntiD0", "hV0InvMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + histos.add("Lambda/hPositiveMFTcls", "hPositiveMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("Lambda/hNegativeMFTcls", "hNegativeMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("Lambda/hPositiveMFTchi2PerNcls", "hPositiveMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("Lambda/hNegativeMFTchi2PerNcls", "hNegativeMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("Lambda/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + histos.add("Lambda/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + if (doprocessMonteCarlo) { + histos.add("Lambda/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("Lambda/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + } + } + if (analyseAntiLambda) { + histos.add("AntiLambda/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiLambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("AntiLambda/hPosDCAToPVz", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiLambda/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("AntiLambda/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); + histos.add("AntiLambda/hOpeningAngle", "hOpeningAngle", kTH1D, {axisConfigurations.axisOpeningAngle}); + histos.add("AntiLambda/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("AntiLambda/hV0Z", "hV0Z", kTH1D, {axisConfigurations.axisV0Z}); + histos.add("AntiLambda/hV0Rapidity", "hV0Rapidity", kTH1D, {axisConfigurations.axisV0Rapidity}); + histos.add("AntiLambda/hV0LifetimeK0s", "hV0LifetimeK0s", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("AntiLambda/hV0LifetimeLambda", "hV0LifetimeLambda", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("AntiLambda/hV0LifetimeD0", "hV0LifetimeD0", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("AntiLambda/hV0PseudoLifetimeK0s", "hV0PseudoLifetimeK0s", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("AntiLambda/hV0PseudoLifetimeLambda", "hV0PseudoLifetimeLambda", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("AntiLambda/hV0PseudoLifetimeD0", "hV0PseudoLifetimeD0", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("AntiLambda/hV0InvMassK0s", "hV0InvMassK0s", kTH1D, {axisConfigurations.axisK0Mass}); + histos.add("AntiLambda/hV0InvMassLambda", "hV0InvMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("AntiLambda/hV0InvMassAntiLambda", "hV0InvMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("AntiLambda/hV0InvMassD0", "hV0InvMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + histos.add("AntiLambda/hV0InvMassAntiD0", "hV0InvMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + histos.add("AntiLambda/hPositiveMFTcls", "hPositiveMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("AntiLambda/hNegativeMFTcls", "hNegativeMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("AntiLambda/hPositiveMFTchi2PerNcls", "hPositiveMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("AntiLambda/hNegativeMFTchi2PerNcls", "hNegativeMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("AntiLambda/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + histos.add("AntiLambda/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + if (doprocessMonteCarlo) { + histos.add("AntiLambda/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiLambda/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + } + } + if (analyseD0) { + histos.add("D0/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("D0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("D0/hPosDCAToPVz", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("D0/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("D0/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("D0/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); + histos.add("D0/hOpeningAngle", "hOpeningAngle", kTH1D, {axisConfigurations.axisOpeningAngle}); + histos.add("D0/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("D0/hV0Z", "hV0Z", kTH1D, {axisConfigurations.axisV0Z}); + histos.add("D0/hV0Rapidity", "hV0Rapidity", kTH1D, {axisConfigurations.axisV0Rapidity}); + histos.add("D0/hV0LifetimeK0s", "hV0LifetimeK0s", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("D0/hV0LifetimeLambda", "hV0LifetimeLambda", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("D0/hV0LifetimeD0", "hV0LifetimeD0", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("D0/hV0PseudoLifetimeK0s", "hV0PseudoLifetimeK0s", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("D0/hV0PseudoLifetimeLambda", "hV0PseudoLifetimeLambda", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("D0/hV0PseudoLifetimeD0", "hV0PseudoLifetimeD0", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("D0/hV0InvMassK0s", "hV0InvMassK0s", kTH1D, {axisConfigurations.axisK0Mass}); + histos.add("D0/hV0InvMassLambda", "hV0InvMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("D0/hV0InvMassAntiLambda", "hV0InvMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("D0/hV0InvMassD0", "hV0InvMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + histos.add("D0/hV0InvMassAntiD0", "hV0InvMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + histos.add("D0/hPositiveMFTcls", "hPositiveMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("D0/hNegativeMFTcls", "hNegativeMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("D0/hPositiveMFTchi2PerNcls", "hPositiveMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("D0/hNegativeMFTchi2PerNcls", "hNegativeMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("D0/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + histos.add("D0/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + if (doprocessMonteCarlo) { + histos.add("D0/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("D0/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + } + } + if (analyseAntiD0) { + histos.add("AntiD0/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiD0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("AntiD0/hPosDCAToPVz", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiD0/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); + histos.add("AntiD0/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("AntiD0/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); + histos.add("AntiD0/hOpeningAngle", "hOpeningAngle", kTH1D, {axisConfigurations.axisOpeningAngle}); + histos.add("AntiD0/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("AntiD0/hV0Z", "hV0Z", kTH1D, {axisConfigurations.axisV0Z}); + histos.add("AntiD0/hV0Rapidity", "hV0Rapidity", kTH1D, {axisConfigurations.axisV0Rapidity}); + histos.add("AntiD0/hV0LifetimeK0s", "hV0LifetimeK0s", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("AntiD0/hV0LifetimeLambda", "hV0LifetimeLambda", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("AntiD0/hV0LifetimeD0", "hV0LifetimeD0", kTH1D, {axisConfigurations.axisV0ProperLifeTime}); + histos.add("AntiD0/hV0PseudoLifetimeK0s", "hV0PseudoLifetimeK0s", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("AntiD0/hV0PseudoLifetimeLambda", "hV0PseudoLifetimeLambda", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("AntiD0/hV0PseudoLifetimeD0", "hV0PseudoLifetimeD0", kTH1D, {axisConfigurations.axisV0PseudoProperLifeTime}); + histos.add("AntiD0/hV0InvMassK0s", "hV0InvMassK0s", kTH1D, {axisConfigurations.axisK0Mass}); + histos.add("AntiD0/hV0InvMassLambda", "hV0InvMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("AntiD0/hV0InvMassAntiLambda", "hV0InvMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + histos.add("AntiD0/hV0InvMassD0", "hV0InvMassD0", kTH1D, {axisConfigurations.axisD0Mass}); + histos.add("AntiD0/hV0InvMassAntiD0", "hV0InvMassAntiD0", kTH1D, {axisConfigurations.axisD0Mass}); + + histos.add("AntiD0/hPositiveMFTcls", "hPositiveMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("AntiD0/hNegativeMFTcls", "hNegativeMFTcls", kTH1D, {axisConfigurations.axisMFTclus}); + histos.add("AntiD0/hPositiveMFTchi2PerNcls", "hPositiveMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("AntiD0/hNegativeMFTchi2PerNcls", "hNegativeMFTchi2PerNcls", kTH1D, {axisConfigurations.axisMFTchi2NDF}); + histos.add("AntiD0/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + histos.add("AntiD0/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); + if (doprocessMonteCarlo) { + histos.add("AntiD0/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiD0/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + } + } + } + + // Check if doing the right thing in AP space please + histos.add("GeneralQA/h2dArmenterosAll", "h2dArmenterosAll", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosK0sSelected", "h2dArmenterosK0sSelected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosLambdaSelected", "h2dArmenterosLambdaSelected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosD0Selected", "h2dArmenterosD0Selected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + + // Creation of histograms: MC generated + if (doprocessGenerated) { + histos.add("hGenEvents", "hGenEvents", kTH2D, {{axisConfigurations.axisNch}, {2, -0.5f, +1.5f}}); + histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + histos.add("hGenEventCentrality", "hGenEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); + + histos.add("hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", kTH2D, {axisConfigurations.axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2D, {axisConfigurations.axisCentrality, {50, -0.5f, 49.5f}}); + + histos.add("hCentralityVsMultMC", "hCentralityVsMultMC", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisNch}); + + histos.add("h2dGenK0Short", "h2dGenK0Short;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenLambda", "h2dGenLambda;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambda", "h2dGenAntiLambda;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinus", "h2dGenXiMinus;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlus", "h2dGenXiPlus;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinus", "h2dGenOmegaMinus;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlus", "h2dGenOmegaPlus;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + + histos.add("h2dGenD0", "h2dGenD0;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenAntiD0", "h2dGenAntiD0;Centrality (%); #it{p}_{T} (GeV/#it{c})", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + + histos.add("h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + + histos.add("h2dGenD0VsMultMC_RecoedEvt", "h2dGenD0VsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiD0VsMultMC_RecoedEvt", "h2dGenAntiD0VsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + + histos.add("h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + + histos.add("h2dGenD0VsMultMC", "h2dGenD0VsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiD0VsMultMC", "h2dGenAntiD0VsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + } + + if (fitterConfigurations.useLUTMatCorr && fitterConfigurations.useTGeoMatCorr) { + LOG(fatal) << "Cannot run with both useLUTMatCorr = on and useTGeoMatCorr = on. Please check your configuration!"; + } + + // standards hardcoded in builder ... + // ...but can be changed easily since fitter is public + fitter.setPropagateToPCA(fitterConfigurations.propagateToPCA); + fitter.setMaxR(200.); + fitter.setMinParamChange(fitterConfigurations.minParamChange); // 1e-3 for DCAfitter ; 4.0 for FwdDCAfitter + fitter.setMinRelChi2Change(fitterConfigurations.minRelChi2Change); // 0.9 for DCAfitter ; 1e-3 for FwdDCAfitter + // fitter.setMaxDZIni(1e9); + // fitter.setMaxDXYIni(4.0f); + // fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(fitterConfigurations.useAbsDCA); + // fitter.setWeightedFinalPCA(false); + fitter.setTGeoMat(fitterConfigurations.useTGeoMatCorr); + // LUT has to be loaded later + lut = nullptr; + // fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrLUT); + + // mag field has to be set later + fitter.setBz(-999.9f); // will NOT make sense if not changed + + // inspect histogram sizes, please + histos.print(); + } + + // ______________________________________________________ + // Return centrality estimate for a given collision. + // If takeMcCentrality is enabled, the centrality is taken from the MC collision; otherwise it is taken + // from the reconstructed collision. Returns -1 if no corresponding centrality estimator is found or if no MC collision is associated to the recoed collision. + template + auto getCentralityRun3(TCollision const& collision) + { + // Helper lambda to extract centrality from any object exposing the cent* columns + auto extractCentrality = [this](auto const& coll) -> float { + switch (centralityEstimator) { + case kCentFT0C: + return coll.centFT0C(); + case kCentFT0M: + return coll.centFT0M(); + case kCentFT0CVariant1: + return coll.centFT0CVariant1(); + // case kCentMFT: return coll.centMFT(); + case kCentNGlobal: + return coll.centNGlobal(); + case kCentFV0A: + return coll.centFV0A(); + default: + return -1.f; + } + }; + return extractCentrality(collision); + } + + // ______________________________________________________ + // Return slicing output + template + auto getGroupedCollisions(TCollisions const& collisions, int globalIndex) + { + return collisions.sliceBy(perMcCollision, globalIndex); + } + + template + void initCCDB(TBCs const& bcs, TCollision collision) + { + auto bc = collision.template bc_as(); + if (!bcs.size()) { + LOGF(warn, "No BC found, skipping this DF."); + return; // signal to skip this DF + } + + if (mRunNumber == bc.runNumber()) { + return; + } + + mRunNumber = bc.runNumber(); + // Fetching magnetic field if requested + // In case override, don't proceed, please - no CCDB access required + if (ccdbConfigurations.useCustomMagField) { + magField = ccdbConfigurations.customMagField; + } else { + grpmag = ccdb->getForRun(ccdbConfigurations.grpmagPath, mRunNumber); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run " << mRunNumber; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + magField = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for run " << mRunNumber << " with magnetic field of " << magField << " kZG"; + } + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << mRunNumber; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->template getForRun(ccdbConfigurations.lutPath.value, mRunNumber)); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + LOG(info) << "Setting global propagator material propagation LUT"; + o2::base::Propagator::Instance()->setMatLUT(lut); + + if (fitterConfigurations.useLUTMatCorr) { + fitter.setMatLUT(lut); + } + fitter.setBz(magField); + } + + template + uint64_t computeReconstructionBitmap(TV0 v0, float rapK0s, float rapLambda, float rapD0) + // precalculate this information so that a check is one mask operation, not many + { + uint64_t bitMap = 0; + // + // Base topological variables + // + // v0 radius min/max selections + if (v0.Radius > v0Selections.v0RadiusMin) { + BITSET(bitMap, selRadius); + } + if (v0.Radius < v0Selections.v0RadiusMax) { + BITSET(bitMap, selRadiusMax); + } + // v0 radius min/max selections + if (v0.Z > v0Selections.v0Zmin) { + BITSET(bitMap, selZmin); + } + if (v0.Z < v0Selections.v0Zmax) { + BITSET(bitMap, selZmax); + } + // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses + if (std::fabs(v0.dcaPosToPVxy) > v0Selections.dcaPosToPVxy) { + BITSET(bitMap, selDCAPosToPVxy); + } + if (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) { + BITSET(bitMap, selDCAPosToPVz); + } + if (std::fabs(v0.dcaNegToPVz) > v0Selections.dcaNegToPVz) { + BITSET(bitMap, selDCANegToPVz); + } + // V0 cosine of pointing angle + if (v0.CosPA > v0Selections.v0CosPA) { + BITSET(bitMap, selCosPA); + } + // V0 opening angle + if (v0.OpAngle > v0Selections.v0OpAngle) { + BITSET(bitMap, selOpAngle); + } + // DCA between v0 daughters + if (v0.DCADau < v0Selections.dcaV0Dau) { + BITSET(bitMap, selDCAV0Dau); + } + + // + // rapidity + // + if (rapK0s > v0Selections.rapidityMin) { + BITSET(bitMap, selK0ShortRapidityMin); + } + if (rapK0s < v0Selections.rapidityMax) { + BITSET(bitMap, selK0ShortRapidityMax); + } + if (rapLambda > v0Selections.rapidityMin) { + BITSET(bitMap, selLambdaRapidityMin); + } + if (rapLambda < v0Selections.rapidityMax) { + BITSET(bitMap, selLambdaRapidityMax); + } + if (rapD0 > v0Selections.rapidityMin) { + BITSET(bitMap, selD0RapidityMin); + } + if (rapD0 < v0Selections.rapidityMax) { + BITSET(bitMap, selD0RapidityMax); + } + + // + // competing mass rejection + // + if ((analyseD0 || analyseAntiD0) && + (std::fabs(v0.mK0s - o2::constants::physics::MassK0Short) > v0Selections.compMassRejectionK0Short)) { + BITSET(bitMap, selK0ShortMassRejection); + } + if ((analyseD0 || analyseAntiD0) && + (std::fabs(v0.mLambda - o2::constants::physics::MassLambda0) > v0Selections.compMassRejectionLambda)) { + BITSET(bitMap, selLambdaMassRejection); + } + if ((analyseLambda || analyseAntiLambda) && std::fabs(v0.mK0s - o2::constants::physics::MassK0Short) > v0Selections.compMassRejectionK0Short) { + BITSET(bitMap, selK0ShortMassRejection); + } + if (analyseK0Short && std::fabs(v0.mLambda - o2::constants::physics::MassLambda0) > v0Selections.compMassRejectionLambda) { + BITSET(bitMap, selLambdaMassRejection); + } + + // + // MFT quality flags + // + if (v0.posNclusters > v0Selections.minMFTclusters && + v0.posChi2 < v0Selections.maxMFTchi2 && + v0.posChi2PerNclus < v0Selections.maxMFTchi2PerNcls) { + BITSET(bitMap, selPosGoodMFTTrack); + } + if (v0.negNclusters > v0Selections.minMFTclusters && + v0.negChi2 < v0Selections.maxMFTchi2 && + v0.negChi2PerNclus < v0Selections.maxMFTchi2PerNcls) { + BITSET(bitMap, selNegGoodMFTTrack); + } + + // + // proper lifetime + if ((analyseD0 || analyseAntiD0) && v0.DistOverTotMom * o2::constants::physics::MassD0 < v0Selections.lifetimeCut->get("lifetimecutD0")) { + BITSET(bitMap, selD0CTau); + } + if ((analyseLambda || analyseAntiLambda) && v0.DistOverTotMom * o2::constants::physics::MassLambda0 < v0Selections.lifetimeCut->get("lifetimecutLambda")) { + BITSET(bitMap, selLambdaCTau); + } + if (analyseK0Short && v0.DistOverTotMom * o2::constants::physics::MassK0Short < v0Selections.lifetimeCut->get("lifetimecutK0S")) { + BITSET(bitMap, selK0ShortCTau); + } + + // + // Pseudo-proper lifetime + if ((analyseD0 || analyseAntiD0) && v0.ZdistOverPz * o2::constants::physics::MassD0 > v0Selections.minPseudolifetime) { + BITSET(bitMap, selD0PseudoLifetimeMin); + } + if ((analyseD0 || analyseAntiD0) && v0.ZdistOverPz * o2::constants::physics::MassD0 < v0Selections.maxPseudolifetime) { + BITSET(bitMap, selD0PseudoLifetimeMax); + } + if ((analyseLambda || analyseAntiLambda) && v0.ZdistOverPz * o2::constants::physics::MassLambda0 > v0Selections.minPseudolifetime) { + BITSET(bitMap, selLambdaPseudoLifetimeMin); + } + if ((analyseLambda || analyseAntiLambda) && v0.ZdistOverPz * o2::constants::physics::MassLambda0 < v0Selections.maxPseudolifetime) { + BITSET(bitMap, selLambdaPseudoLifetimeMax); + } + if (analyseK0Short && v0.ZdistOverPz * o2::constants::physics::MassK0Short > v0Selections.minPseudolifetime) { + BITSET(bitMap, selK0ShortPseudoLifetimeMin); + } + if (analyseK0Short && v0.ZdistOverPz * o2::constants::physics::MassK0Short < v0Selections.maxPseudolifetime) { + BITSET(bitMap, selK0ShortPseudoLifetimeMax); + } + + // + // armenteros + if (v0Selections.armPodCut < 1e-4 || v0.QtArm * v0Selections.armPodCut > std::abs(v0.AlphaArm)) { + BITSET(bitMap, selK0ShortArmenteros); + } + + return bitMap; + } + + template + uint64_t computeMCAssociation(TV0 v0) + // precalculate this information so that a check is one mask operation, not many + { + uint64_t bitMap = 0; + bool isPositiveProton = v0.pdgCodePositive == PDG_t::kProton; + bool isPositiveKaon = v0.pdgCodePositive == PDG_t::kKPlus; + bool isPositivePion = v0.pdgCodePositive == PDG_t::kPiPlus || (doTreatPiToMuon && v0.pdgCodePositive == PDG_t::kMuonPlus); + bool isNegativeProton = v0.pdgCodeNegative == PDG_t::kProtonBar; + bool isNegativeKaon = v0.pdgCodeNegative == PDG_t::kKMinus; + bool isNegativePion = v0.pdgCodeNegative == PDG_t::kPiMinus || (doTreatPiToMuon && v0.pdgCodeNegative == PDG_t::kMuonMinus); + + if (v0.pdgCode == PDG_t::kK0Short && isPositivePion && isNegativePion) { + BITSET(bitMap, selConsiderK0Short); + if (v0.isPhysicalPrimary) + BITSET(bitMap, selPhysPrimK0Short); + } + if (v0.pdgCode == PDG_t::kLambda0 && isPositiveProton && isNegativePion) { + BITSET(bitMap, selConsiderLambda); + if (v0.isPhysicalPrimary) + BITSET(bitMap, selPhysPrimLambda); + } + if (v0.pdgCode == PDG_t::kLambda0Bar && isPositivePion && isNegativeProton) { + BITSET(bitMap, selConsiderAntiLambda); + if (v0.isPhysicalPrimary) + BITSET(bitMap, selPhysPrimAntiLambda); + } + if (v0.pdgCode == o2::constants::physics::kD0 && isPositivePion && isNegativeKaon) { + BITSET(bitMap, selConsiderD0); + if (v0.isPhysicalPrimary) + BITSET(bitMap, selPhysPrimD0); + } + if (v0.pdgCode == o2::constants::physics::kD0Bar && isPositiveKaon && isNegativePion) { + BITSET(bitMap, selConsiderAntiD0); + if (v0.isPhysicalPrimary) + BITSET(bitMap, selPhysPrimAntiD0); + } + return bitMap; + } + + bool verifyMask(uint64_t bitmap, uint64_t mask) + { + return (bitmap & mask) == mask; + } + + template + void analyseCandidate(TV0 v0, float pt, float centrality, uint64_t selMap, uint8_t gapSide, int& nK0Shorts, int& nLambdas, int& nAntiLambdas, int& nD0s, int& nAntiD0s) + // precalculate this information so that a check is one mask operation, not many + { + bool passK0ShortSelections = false; + bool passLambdaSelections = false; + bool passAntiLambdaSelections = false; + bool passD0Selections = false; + bool passAntiD0Selections = false; + + // machine learning is on, go for calculation of thresholds + // FIXME THIS NEEDS ADJUSTING + passK0ShortSelections = verifyMask(selMap, maskSelectionK0Short); + passLambdaSelections = verifyMask(selMap, maskSelectionLambda); + passAntiLambdaSelections = verifyMask(selMap, maskSelectionAntiLambda); + passD0Selections = verifyMask(selMap, maskSelectionD0); + passAntiD0Selections = verifyMask(selMap, maskSelectionAntiD0); + + double invMassK0Short = v0.mK0s; + double invMassLambda = v0.mLambda; + double invMassAntiLambda = v0.mAntiLambda; + double invMassD0 = v0.mD0; + double invMassAntiD0 = v0.mAntiD0; + + // __________________________________________ + // fill with no selection if plain QA requested + if (doPlainTopoQA) { + histos.fill(HIST("hPosDCAToPVxy"), v0.dcaPosToPVxy); + histos.fill(HIST("hNegDCAToPVxy"), v0.dcaNegToPVxy); + histos.fill(HIST("hPosDCAToPVz"), v0.dcaPosToPVz); + histos.fill(HIST("hNegDCAToPVz"), v0.dcaNegToPVz); + histos.fill(HIST("hDCADaughters"), v0.DCADau); + histos.fill(HIST("hCosPA"), v0.CosPA); + histos.fill(HIST("hOpeningAngle"), v0.OpAngle); + histos.fill(HIST("hV0Radius"), v0.Radius); + histos.fill(HIST("hV0Z"), v0.Z); + if (analyseK0Short) { + histos.fill(HIST("hV0Rapidity"), v0.rapidityK0s); + } else if (analyseLambda || analyseAntiLambda) { + histos.fill(HIST("hV0Rapidity"), v0.rapidityLambda); + } else if (analyseD0 || analyseAntiD0) { + histos.fill(HIST("hV0Rapidity"), v0.rapidityD0); + } + histos.fill(HIST("hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); + histos.fill(HIST("hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); + histos.fill(HIST("hV0LifetimeD0"), v0.DistOverTotMom * o2::constants::physics::MassD0); + histos.fill(HIST("hV0PseudoLifetimeK0s"), v0.ZdistOverPz * o2::constants::physics::MassK0Short); + histos.fill(HIST("hV0PseudoLifetimeLambda"), v0.ZdistOverPz * o2::constants::physics::MassLambda); + histos.fill(HIST("hV0PseudoLifetimeD0"), v0.ZdistOverPz * o2::constants::physics::MassD0); + histos.fill(HIST("hV0InvMassK0s"), invMassK0Short); + histos.fill(HIST("hV0InvMassLambda"), invMassLambda); + histos.fill(HIST("hV0InvMassAntiLambda"), invMassAntiLambda); + histos.fill(HIST("hV0InvMassD0"), invMassD0); + histos.fill(HIST("hV0InvMassAntiD0"), invMassAntiD0); + + histos.fill(HIST("hPositiveMFTcls"), v0.posNclusters); + histos.fill(HIST("hNegativeMFTcls"), v0.negNclusters); + histos.fill(HIST("hPositiveMFTchi2PerNcls"), v0.posChi2PerNclus); + histos.fill(HIST("hNegativeMFTchi2PerNcls"), v0.negChi2PerNclus); + histos.fill(HIST("hPositiveMFTchi2"), v0.posChi2); + histos.fill(HIST("hNegativeMFTchi2"), v0.negChi2); + if (doprocessMonteCarlo) { + histos.fill(HIST("hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + } + } + + // Fill first bin: all candidates + histos.fill(HIST("GeneralQA/hSelectionV0s"), 0); + // Loop over all bits in the enum and fill if passed + for (uint64_t i = 0; i <= selPhysPrimAntiD0; i++) { + if (BITCHECK(selMap, i)) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), i + 1); // +1 because bin 0 = "All" + } + } + + // __________________________________________ + // main analysis + if (passK0ShortSelections && analyseK0Short) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiD0 + 2); // + histos.fill(HIST("GeneralQA/h2dArmenterosK0sSelected"), v0.AlphaArm, v0.QtArm); // cross-check + histos.fill(HIST("h3dMassK0Short"), centrality, pt, invMassK0Short); + if (doUPCanalysis) { + if (gapSide == 0) + histos.fill(HIST("h3dMassK0ShortSGA"), centrality, pt, invMassK0Short); + else if (gapSide == 1) + histos.fill(HIST("h3dMassK0ShortSGC"), centrality, pt, invMassK0Short); + else if (gapSide == 2) + histos.fill(HIST("h3dMassK0ShortDG"), centrality, pt, invMassK0Short); + else + histos.fill(HIST("h3dMassK0ShortHadronic"), centrality, pt, invMassK0Short); + } + histos.fill(HIST("hMassK0Short"), invMassK0Short); + if (doPlainTopoQA) { + histos.fill(HIST("K0Short/hPosDCAToPVxy"), v0.dcaPosToPVxy); + histos.fill(HIST("K0Short/hNegDCAToPVxy"), v0.dcaNegToPVxy); + histos.fill(HIST("K0Short/hPosDCAToPVz"), v0.dcaPosToPVz); + histos.fill(HIST("K0Short/hNegDCAToPVz"), v0.dcaNegToPVz); + histos.fill(HIST("K0Short/hDCADaughters"), v0.DCADau); + histos.fill(HIST("K0Short/hCosPA"), v0.CosPA); + histos.fill(HIST("K0Short/hOpeningAngle"), v0.OpAngle); + histos.fill(HIST("K0Short/hV0Radius"), v0.Radius); + histos.fill(HIST("K0Short/hV0Z"), v0.Z); + histos.fill(HIST("K0Short/hV0Rapidity"), v0.rapidityK0s); + histos.fill(HIST("K0Short/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); + histos.fill(HIST("K0Short/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); + histos.fill(HIST("K0Short/hV0LifetimeD0"), v0.DistOverTotMom * o2::constants::physics::MassD0); + histos.fill(HIST("K0Short/hV0PseudoLifetimeK0s"), v0.ZdistOverPz * o2::constants::physics::MassK0Short); + histos.fill(HIST("K0Short/hV0PseudoLifetimeLambda"), v0.ZdistOverPz * o2::constants::physics::MassLambda); + histos.fill(HIST("K0Short/hV0PseudoLifetimeD0"), v0.ZdistOverPz * o2::constants::physics::MassD0); + histos.fill(HIST("K0Short/hV0InvMassK0s"), invMassK0Short); + histos.fill(HIST("K0Short/hV0InvMassLambda"), invMassLambda); + histos.fill(HIST("K0Short/hV0InvMassAntiLambda"), invMassAntiLambda); + histos.fill(HIST("K0Short/hV0InvMassD0"), invMassD0); + histos.fill(HIST("K0Short/hV0InvMassAntiD0"), invMassAntiD0); + + histos.fill(HIST("K0Short/hPositiveMFTcls"), v0.posNclusters); + histos.fill(HIST("K0Short/hNegativeMFTcls"), v0.negNclusters); + histos.fill(HIST("K0Short/hPositiveMFTchi2PerNcls"), v0.posChi2PerNclus); + histos.fill(HIST("K0Short/hNegativeMFTchi2PerNcls"), v0.negChi2PerNclus); + histos.fill(HIST("K0Short/hPositiveMFTchi2"), v0.posChi2); + histos.fill(HIST("K0Short/hNegativeMFTchi2"), v0.negChi2); + if (doprocessMonteCarlo) { + histos.fill(HIST("K0Short/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("K0Short/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + } + } + nK0Shorts++; + } + if (passLambdaSelections && analyseLambda) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiD0 + 2); // + histos.fill(HIST("GeneralQA/h2dArmenterosLambdaSelected"), v0.AlphaArm, v0.QtArm); // cross-check + histos.fill(HIST("h3dMassLambda"), centrality, pt, invMassLambda); + if (doUPCanalysis) { + if (gapSide == 0) + histos.fill(HIST("h3dMassLambdaSGA"), centrality, pt, invMassLambda); + else if (gapSide == 1) + histos.fill(HIST("h3dMassLambdaSGC"), centrality, pt, invMassLambda); + else if (gapSide == 2) + histos.fill(HIST("h3dMassLambdaDG"), centrality, pt, invMassLambda); + else + histos.fill(HIST("h3dMassLambdaHadronic"), centrality, pt, invMassLambda); + } + histos.fill(HIST("hMassLambda"), invMassLambda); + if (doPlainTopoQA) { + histos.fill(HIST("Lambda/hPosDCAToPVxy"), v0.dcaPosToPVxy); + histos.fill(HIST("Lambda/hNegDCAToPVxy"), v0.dcaNegToPVxy); + histos.fill(HIST("Lambda/hPosDCAToPVz"), v0.dcaPosToPVz); + histos.fill(HIST("Lambda/hNegDCAToPVz"), v0.dcaNegToPVz); + histos.fill(HIST("Lambda/hDCADaughters"), v0.DCADau); + histos.fill(HIST("Lambda/hCosPA"), v0.CosPA); + histos.fill(HIST("Lambda/hOpeningAngle"), v0.OpAngle); + histos.fill(HIST("Lambda/hV0Radius"), v0.Radius); + histos.fill(HIST("Lambda/hV0Z"), v0.Z); + histos.fill(HIST("Lambda/hV0Rapidity"), v0.rapidityLambda); + histos.fill(HIST("Lambda/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); + histos.fill(HIST("Lambda/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); + histos.fill(HIST("Lambda/hV0LifetimeD0"), v0.DistOverTotMom * o2::constants::physics::MassD0); + histos.fill(HIST("Lambda/hV0PseudoLifetimeK0s"), v0.ZdistOverPz * o2::constants::physics::MassK0Short); + histos.fill(HIST("Lambda/hV0PseudoLifetimeLambda"), v0.ZdistOverPz * o2::constants::physics::MassLambda); + histos.fill(HIST("Lambda/hV0PseudoLifetimeD0"), v0.ZdistOverPz * o2::constants::physics::MassD0); + histos.fill(HIST("Lambda/hV0InvMassK0s"), invMassK0Short); + histos.fill(HIST("Lambda/hV0InvMassLambda"), invMassLambda); + histos.fill(HIST("Lambda/hV0InvMassAntiLambda"), invMassAntiLambda); + histos.fill(HIST("Lambda/hV0InvMassD0"), invMassD0); + histos.fill(HIST("Lambda/hV0InvMassAntiD0"), invMassAntiD0); + + histos.fill(HIST("Lambda/hPositiveMFTcls"), v0.posNclusters); + histos.fill(HIST("Lambda/hNegativeMFTcls"), v0.negNclusters); + histos.fill(HIST("Lambda/hPositiveMFTchi2PerNcls"), v0.posChi2PerNclus); + histos.fill(HIST("Lambda/hNegativeMFTchi2PerNcls"), v0.negChi2PerNclus); + histos.fill(HIST("Lambda/hPositiveMFTchi2"), v0.posChi2); + histos.fill(HIST("Lambda/hNegativeMFTchi2"), v0.negChi2); + if (doprocessMonteCarlo) { + histos.fill(HIST("Lambda/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("Lambda/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + } + } + nLambdas++; + } + if (passAntiLambdaSelections && analyseAntiLambda) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiD0 + 2); // + histos.fill(HIST("GeneralQA/h2dArmenterosLambdaSelected"), v0.AlphaArm, v0.QtArm); // cross-check + histos.fill(HIST("h3dMassAntiLambda"), centrality, pt, invMassAntiLambda); + if (doUPCanalysis) { + if (gapSide == 0) + histos.fill(HIST("h3dMassAntiLambdaSGA"), centrality, pt, invMassAntiLambda); + else if (gapSide == 1) + histos.fill(HIST("h3dMassAntiLambdaSGC"), centrality, pt, invMassAntiLambda); + else if (gapSide == 2) + histos.fill(HIST("h3dMassAntiLambdaDG"), centrality, pt, invMassAntiLambda); + else + histos.fill(HIST("h3dMassAntiLambdaHadronic"), centrality, pt, invMassAntiLambda); + } + histos.fill(HIST("hMassAntiLambda"), invMassAntiLambda); + if (doPlainTopoQA) { + histos.fill(HIST("AntiLambda/hPosDCAToPVxy"), v0.dcaPosToPVxy); + histos.fill(HIST("AntiLambda/hNegDCAToPVxy"), v0.dcaNegToPVxy); + histos.fill(HIST("AntiLambda/hPosDCAToPVz"), v0.dcaPosToPVz); + histos.fill(HIST("AntiLambda/hNegDCAToPVz"), v0.dcaNegToPVz); + histos.fill(HIST("AntiLambda/hDCADaughters"), v0.DCADau); + histos.fill(HIST("AntiLambda/hCosPA"), v0.CosPA); + histos.fill(HIST("AntiLambda/hOpeningAngle"), v0.OpAngle); + histos.fill(HIST("AntiLambda/hV0Radius"), v0.Radius); + histos.fill(HIST("AntiLambda/hV0Z"), v0.Z); + histos.fill(HIST("AntiLambda/hV0Rapidity"), v0.rapidityLambda); + histos.fill(HIST("AntiLambda/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); + histos.fill(HIST("AntiLambda/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); + histos.fill(HIST("AntiLambda/hV0LifetimeD0"), v0.DistOverTotMom * o2::constants::physics::MassD0); + histos.fill(HIST("AntiLambda/hV0PseudoLifetimeK0s"), v0.ZdistOverPz * o2::constants::physics::MassK0Short); + histos.fill(HIST("AntiLambda/hV0PseudoLifetimeLambda"), v0.ZdistOverPz * o2::constants::physics::MassLambda); + histos.fill(HIST("AntiLambda/hV0PseudoLifetimeD0"), v0.ZdistOverPz * o2::constants::physics::MassD0); + histos.fill(HIST("AntiLambda/hV0InvMassK0s"), invMassK0Short); + histos.fill(HIST("AntiLambda/hV0InvMassLambda"), invMassLambda); + histos.fill(HIST("AntiLambda/hV0InvMassAntiLambda"), invMassAntiLambda); + histos.fill(HIST("AntiLambda/hV0InvMassD0"), invMassD0); + histos.fill(HIST("AntiLambda/hV0InvMassAntiD0"), invMassAntiD0); + + histos.fill(HIST("AntiLambda/hPositiveMFTcls"), v0.posNclusters); + histos.fill(HIST("AntiLambda/hNegativeMFTcls"), v0.negNclusters); + histos.fill(HIST("AntiLambda/hPositiveMFTchi2PerNcls"), v0.posChi2PerNclus); + histos.fill(HIST("AntiLambda/hNegativeMFTchi2PerNcls"), v0.negChi2PerNclus); + histos.fill(HIST("AntiLambda/hPositiveMFTchi2"), v0.posChi2); + histos.fill(HIST("AntiLambda/hNegativeMFTchi2"), v0.negChi2); + if (doprocessMonteCarlo) { + histos.fill(HIST("AntiLambda/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("AntiLambda/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + } + } + nAntiLambdas++; + } + if (passD0Selections && analyseD0) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiD0 + 2); // + histos.fill(HIST("GeneralQA/h2dArmenterosD0Selected"), v0.AlphaArm, v0.QtArm); // cross-check + histos.fill(HIST("h3dMassD0"), centrality, pt, invMassD0); + if (doUPCanalysis) { + if (gapSide == 0) + histos.fill(HIST("h3dMassD0SGA"), centrality, pt, invMassD0); + else if (gapSide == 1) + histos.fill(HIST("h3dMassD0SGC"), centrality, pt, invMassD0); + else if (gapSide == 2) + histos.fill(HIST("h3dMassD0DG"), centrality, pt, invMassD0); + else + histos.fill(HIST("h3dMassD0Hadronic"), centrality, pt, invMassD0); + } + histos.fill(HIST("hMassD0"), invMassD0); + if (doPlainTopoQA) { + histos.fill(HIST("D0/hPosDCAToPVxy"), v0.dcaPosToPVxy); + histos.fill(HIST("D0/hNegDCAToPVxy"), v0.dcaNegToPVxy); + histos.fill(HIST("D0/hPosDCAToPVz"), v0.dcaPosToPVz); + histos.fill(HIST("D0/hNegDCAToPVz"), v0.dcaNegToPVz); + histos.fill(HIST("D0/hDCADaughters"), v0.DCADau); + histos.fill(HIST("D0/hCosPA"), v0.CosPA); + histos.fill(HIST("D0/hOpeningAngle"), v0.OpAngle); + histos.fill(HIST("D0/hV0Radius"), v0.Radius); + histos.fill(HIST("D0/hV0Z"), v0.Z); + histos.fill(HIST("D0/hV0Rapidity"), v0.rapidityD0); + histos.fill(HIST("D0/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); + histos.fill(HIST("D0/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); + histos.fill(HIST("D0/hV0LifetimeD0"), v0.DistOverTotMom * o2::constants::physics::MassD0); + histos.fill(HIST("D0/hV0PseudoLifetimeK0s"), v0.ZdistOverPz * o2::constants::physics::MassK0Short); + histos.fill(HIST("D0/hV0PseudoLifetimeLambda"), v0.ZdistOverPz * o2::constants::physics::MassLambda); + histos.fill(HIST("D0/hV0PseudoLifetimeD0"), v0.ZdistOverPz * o2::constants::physics::MassD0); + histos.fill(HIST("D0/hV0InvMassK0s"), invMassK0Short); + histos.fill(HIST("D0/hV0InvMassLambda"), invMassLambda); + histos.fill(HIST("D0/hV0InvMassAntiLambda"), invMassAntiLambda); + histos.fill(HIST("D0/hV0InvMassD0"), invMassD0); + histos.fill(HIST("D0/hV0InvMassAntiD0"), invMassAntiD0); + + histos.fill(HIST("D0/hPositiveMFTcls"), v0.posNclusters); + histos.fill(HIST("D0/hNegativeMFTcls"), v0.negNclusters); + histos.fill(HIST("D0/hPositiveMFTchi2PerNcls"), v0.posChi2PerNclus); + histos.fill(HIST("D0/hNegativeMFTchi2PerNcls"), v0.negChi2PerNclus); + histos.fill(HIST("D0/hPositiveMFTchi2"), v0.posChi2); + histos.fill(HIST("D0/hNegativeMFTchi2"), v0.negChi2); + if (doprocessMonteCarlo) { + histos.fill(HIST("D0/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("D0/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + } + } + nD0s++; + } + if (passAntiD0Selections && analyseAntiD0) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiD0 + 2); // + histos.fill(HIST("GeneralQA/h2dArmenterosD0Selected"), v0.AlphaArm, v0.QtArm); // cross-check + histos.fill(HIST("h3dMassAntiD0"), centrality, pt, invMassAntiD0); + if (doUPCanalysis) { + if (gapSide == 0) + histos.fill(HIST("h3dMassAntiD0SGA"), centrality, pt, invMassAntiD0); + else if (gapSide == 1) + histos.fill(HIST("h3dMassAntiD0SGC"), centrality, pt, invMassAntiD0); + else if (gapSide == 2) + histos.fill(HIST("h3dMassAntiD0DG"), centrality, pt, invMassAntiD0); + else + histos.fill(HIST("h3dMassAntiD0Hadronic"), centrality, pt, invMassAntiD0); + } + histos.fill(HIST("hMassAntiD0"), invMassAntiD0); + if (doPlainTopoQA) { + histos.fill(HIST("AntiD0/hPosDCAToPVxy"), v0.dcaPosToPVxy); + histos.fill(HIST("AntiD0/hNegDCAToPVxy"), v0.dcaNegToPVxy); + histos.fill(HIST("AntiD0/hPosDCAToPVz"), v0.dcaPosToPVz); + histos.fill(HIST("AntiD0/hNegDCAToPVz"), v0.dcaNegToPVz); + histos.fill(HIST("AntiD0/hDCADaughters"), v0.DCADau); + histos.fill(HIST("AntiD0/hCosPA"), v0.CosPA); + histos.fill(HIST("AntiD0/hOpeningAngle"), v0.OpAngle); + histos.fill(HIST("AntiD0/hV0Radius"), v0.Radius); + histos.fill(HIST("AntiD0/hV0Z"), v0.Z); + histos.fill(HIST("AntiD0/hV0Rapidity"), v0.rapidityD0); + histos.fill(HIST("AntiD0/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); + histos.fill(HIST("AntiD0/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); + histos.fill(HIST("AntiD0/hV0LifetimeD0"), v0.DistOverTotMom * o2::constants::physics::MassD0); + histos.fill(HIST("AntiD0/hV0PseudoLifetimeK0s"), v0.ZdistOverPz * o2::constants::physics::MassK0Short); + histos.fill(HIST("AntiD0/hV0PseudoLifetimeLambda"), v0.ZdistOverPz * o2::constants::physics::MassLambda); + histos.fill(HIST("AntiD0/hV0PseudoLifetimeD0"), v0.ZdistOverPz * o2::constants::physics::MassD0); + histos.fill(HIST("AntiD0/hV0InvMassK0s"), invMassK0Short); + histos.fill(HIST("AntiD0/hV0InvMassLambda"), invMassLambda); + histos.fill(HIST("AntiD0/hV0InvMassAntiLambda"), invMassAntiLambda); + histos.fill(HIST("AntiD0/hV0InvMassD0"), invMassD0); + histos.fill(HIST("AntiD0/hV0InvMassAntiD0"), invMassAntiD0); + + histos.fill(HIST("AntiD0/hPositiveMFTcls"), v0.posNclusters); + histos.fill(HIST("AntiD0/hNegativeMFTcls"), v0.negNclusters); + histos.fill(HIST("AntiD0/hPositiveMFTchi2PerNcls"), v0.posChi2PerNclus); + histos.fill(HIST("AntiD0/hNegativeMFTchi2PerNcls"), v0.negChi2PerNclus); + histos.fill(HIST("AntiD0/hPositiveMFTchi2"), v0.posChi2); + histos.fill(HIST("AntiD0/hNegativeMFTchi2"), v0.negChi2); + if (doprocessMonteCarlo) { + histos.fill(HIST("AntiD0/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("AntiD0/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + } + } + nAntiD0s++; + } + } + + template + void fillFeeddownMatrix(TV0 v0, float pt, float centrality, uint64_t selMap) + // fill feeddown matrix for Lambdas or AntiLambdas + // fixme: a potential improvement would be to consider mass windows for the l/al + { + if (v0.motherLabel < 0) + return; // does not have mother particle in record, skip + + float rapidityXi = 999.f; + if (std::abs(v0.pdgCodeMother) == PDG_t::kXiMinus) + rapidityXi = RecoDecay::y(std::array{v0.momentumMotherMc[0], v0.momentumMotherMc[1], v0.momentumMotherMc[2]}, o2::constants::physics::MassXiMinus); + if (std::abs(v0.pdgCodeMother) == o2::constants::physics::Pdg::kXi0) + rapidityXi = RecoDecay::y(std::array{v0.momentumMotherMc[0], v0.momentumMotherMc[1], v0.momentumMotherMc[2]}, o2::constants::physics::MassXi0); + + if (std::fabs(rapidityXi) > 0.5f) + return; // not a valid mother rapidity (PDG selection is later) + + // __________________________________________ + if (verifyMask(selMap, secondaryMaskSelectionLambda) && analyseLambda) { + if (v0.motherIsPhysicalPrimary) { + if (v0.pdgCodeMother == PDG_t::kXiMinus) { + histos.fill(HIST("h3dLambdaFeeddown"), centrality, pt, std::hypot(v0.momentumMotherMc[0], v0.momentumMotherMc[1])); + } + if (v0.pdgCodeMother == PDG_t::kXiMinus || v0.pdgCodeMother == o2::constants::physics::Pdg::kXi0) { + histos.fill(HIST("h3dLambdaFeeddownFromXi0"), centrality, pt, std::hypot(v0.momentumMotherMc[0], v0.momentumMotherMc[1])); + } + } + } + if (verifyMask(selMap, secondaryMaskSelectionAntiLambda) && analyseAntiLambda) { + if (v0.motherIsPhysicalPrimary) { + if (v0.pdgCodeMother == PDG_t::kXiPlusBar) { + histos.fill(HIST("h3dAntiLambdaFeeddown"), centrality, pt, std::hypot(v0.momentumMotherMc[0], v0.momentumMotherMc[1])); + } + if (v0.pdgCodeMother == PDG_t::kXiPlusBar || v0.pdgCodeMother == -o2::constants::physics::Pdg::kXi0) { + histos.fill(HIST("h3dAntiLambdaFeeddownFromXi0"), centrality, pt, std::hypot(v0.momentumMotherMc[0], v0.momentumMotherMc[1])); + } + } + } + } + + template + bool isEventAccepted(TCollision const& collision, TBCs const& /*bcs*/, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) { + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + } + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + } + + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + } + + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + } + + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + } + + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + } + + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + } + + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + } + + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + } + + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + } + + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + } + + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); + } + + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + } + + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + } + + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); + } + + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + } + + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + } + + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + } + + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 18 /* Below min occupancy */); + } + + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 19 /* Above max occupancy */); + } + + // Fetch interaction rate only if required (in order to limit ccdb calls) + auto bc = collision.template bc_as(); + double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3 : -1; + if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 20 /* Below min IR */); + } + + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 21 /* Above max IR */); + } + + if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 22 /* Pass CBT condition */); + } + return true; + } + + // ______________________________________________________ + // Simulated processing + // Return the list of indices to the recoed collision associated to a given MC collision. + template + std::vector getListOfRecoCollIndices(TMCollisions const& mcCollisions, TCollisions const& collisions, TBCs const& bcs) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + auto groupedCollisions = getGroupedCollisions(collisions, mcCollision.globalIndex()); + int biggestNContribs = -1; + int bestCollisionIndex = -1; + for (auto const& collision : groupedCollisions) { + // consider event selections in the recoed <-> gen collision association, for the denominator (or numerator) of the efficiency (or signal loss)? + if (eventSelections.useEvtSelInDenomEff) { + if (!isEventAccepted(collision, bcs, false)) { + continue; + } + } + + // Find the collision with the biggest nbr of PV contributors + // Follows what was done here: https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/mcCollsExtra.cxx#L93 + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + bestCollisionIndex = collision.globalIndex(); + } + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; + } + return listBestCollisionIdx; + } + + // ______________________________________________________ + // Reconstructed data processing + // Fill reconstructed event information + // Return centrality, occupancy, interaction rate, gap side and selGapside via reference-passing in arguments + template + void fillReconstructedEventProperties(TCollision const& collision, TBCs const& /*bcs*/, float& centrality, float& collisionOccupancy, double& interactionRate, int& gapSide, int& selGapSide) + { + centrality = getCentralityRun3(collision); + collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + // Fetch interaction rate only if required (in order to limit ccdb calls) + auto bc = collision.template bc_as(); + interactionRate = !irSource.value.empty() ? rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3 : -1; + + if (doUPCanalysis) { + // gap side + // gapSide = collision.gapSide(); + gapSide = -1; + // -1 --> Hadronic + // 0 --> Single Gap - A side + // 1 --> Single Gap - C side + // 2 --> Double Gap - both A & C sides + // selGapSide = sgSelector.trueGap(collision, upcCuts.fv0Cut, upcCuts.ft0Acut, upcCuts.ft0Ccut, upcCuts.zdcCut); + + histos.fill(HIST("hGapSide"), gapSide); + histos.fill(HIST("hSelGapSide"), selGapSide); + histos.fill(HIST("hEventCentralityVsSelGapSide"), centrality, selGapSide <= 2 ? selGapSide : -1); + } + + histos.fill(HIST("hEventCentrality"), centrality); + + histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + if (doEventQA) { + histos.fill(HIST("hCentralityVsNGlobal"), centrality, collision.multNTracksGlobal()); + histos.fill(HIST("hEventCentVsMultFT0M"), collision.centFT0M(), collision.multFT0A() + collision.multFT0C()); + histos.fill(HIST("hEventCentVsMultFT0C"), collision.centFT0C(), collision.multFT0C()); + histos.fill(HIST("hEventCentVsMultNGlobal"), collision.centNGlobal(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventCentVsMultFV0A"), collision.centFV0A(), collision.multFV0A()); + histos.fill(HIST("hEventMultFT0MvsMultNGlobal"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultFT0CvsMultNGlobal"), collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultFV0AvsMultNGlobal"), collision.multFV0A(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultPVvsMultNGlobal"), collision.multNTracksPVeta1(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultFT0CvsMultFV0A"), collision.multFT0C(), collision.multFV0A()); + } + + histos.fill(HIST("hCentralityVsPVz"), centrality, collision.posZ()); + histos.fill(HIST("hEventPVz"), collision.posZ()); + + histos.fill(HIST("hEventOccupancy"), collisionOccupancy); + histos.fill(HIST("hCentralityVsOccupancy"), centrality, collisionOccupancy); + + histos.fill(HIST("hInteractionRate"), interactionRate); + histos.fill(HIST("hCentralityVsInteractionRate"), centrality, interactionRate); + + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + return; + } + + // ______________________________________________________ + // Simulated processing + // Fill generated event information (for event loss/splitting estimation) + template + void fillGeneratedEventProperties(TMCCollisions const& mcCollisions, TCollisions const& collisions, TBCs const& bcs) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + // Apply selections on MC collisions + if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { + continue; + } + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 0 /* all gen. events*/); + + auto groupedCollisions = getGroupedCollisions(collisions, mcCollision.globalIndex()); + // Check if there is at least one of the reconstructed collisions associated to this MC collision + // If so, we consider it + bool atLeastOne = false; + int biggestNContribs = -1; + float centrality = 100.5f; + int nCollisions = 0; + for (auto const& collision : groupedCollisions) { + + if (!isEventAccepted(collision, bcs, false)) { + continue; + } + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + centrality = getCentralityRun3(collision); + } + nCollisions++; + + atLeastOne = true; + } + + histos.fill(HIST("hCentralityVsNcoll_beforeEvSel"), centrality, groupedCollisions.size()); + histos.fill(HIST("hCentralityVsNcoll_afterEvSel"), centrality, nCollisions); + + histos.fill(HIST("hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hCentralityVsPVzMC"), centrality, mcCollision.posZ()); + histos.fill(HIST("hEventPVzMC"), mcCollision.posZ()); + + if (atLeastOne) { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + + histos.fill(HIST("hGenEventCentrality"), centrality); + } + } + return; + } + + // BUILDER PART: largely inspired of the strangenessBuilderModule + // FIXME: to be put in a dedicated table producer if it works + //__________________________________________________ + // MC kink handling + template + int getOriginatingParticle(mcpart const& part, int& indexForPositionOfDecay, bool treatPiToMuDecays) + { + int returnValue = -1; + if (part.has_mothers()) { + auto const& motherList = part.template mothers_as(); + if (motherList.size() == 1) { + for (const auto& mother : motherList) { + if (std::abs(part.pdgCode()) == PDG_t::kMuonMinus && treatPiToMuDecays) { + // muon decay, de-ref mother twice + if (mother.has_mothers()) { + auto grandMotherList = mother.template mothers_as(); + if (grandMotherList.size() == 1) { + for (const auto& grandMother : grandMotherList) { + returnValue = grandMother.globalIndex(); + indexForPositionOfDecay = mother.globalIndex(); // for V0 decay position: grab muon + } + } + } + } else { + returnValue = mother.globalIndex(); + indexForPositionOfDecay = part.globalIndex(); + } + } + } + } + return returnValue; + } + + //___________________________________________________________________ + // 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 + { + // 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]); + x2x0 = static_cast(mb.meanX2X0); + return t.propagateToVtxhelixWithMCS(PV[2], {PV[0], PV[1]}, PVcov, magField, x2x0); + } + + template + std::vector buildV0s(TCollision const& collision, TMFTTracks const& /*mftTracks*/, TTracks const& besttracks, TMCParticles const& mcParticles) + { + std::vector v0; + for (const auto& [amft1, amft2] : combinations(besttracks, besttracks)) { + auto mftPositive = amft1.template mfttrack_as(); + auto mftNegative = amft2.template mfttrack_as(); + + if (mftPositive.eta() < v0Selections.daughterEtaCutMin) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + if (mftPositive.eta() > v0Selections.daughterEtaCutMax) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + if (mftNegative.eta() < v0Selections.daughterEtaCutMin) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + if (mftNegative.eta() > v0Selections.daughterEtaCutMax) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + if (mftPositive.pt() < v0Selections.minTrackPt) + continue; + if (mftNegative.pt() < v0Selections.minTrackPt) + continue; + + // Consider only tracks of opposite charges + if (mftPositive.sign() < 0) + continue; + if (mftNegative.sign() > 0) + continue; + + SMatrix5 tpars1(mftPositive.x(), mftPositive.y(), mftPositive.phi(), mftPositive.tgl(), mftPositive.signed1Pt()); + std::vector v1; + SMatrix55 tcovs1(v1.begin(), v1.end()); + o2::track::TrackParCovFwd pars1{mftPositive.z(), tpars1, tcovs1, mftPositive.chi2()}; + o2::track::TrackParCovFwd pars1Copy{mftPositive.z(), tpars1, tcovs1, mftPositive.chi2()}; + + SMatrix5 tpars2(mftNegative.x(), mftNegative.y(), mftNegative.phi(), mftNegative.tgl(), mftNegative.signed1Pt()); + std::vector v2; + SMatrix55 tcovs2(v2.begin(), v2.end()); + 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(); + + // Move close to minima + int nCand = 0; + try { + nCand = fitter.process(pars1, pars2); + } catch (...) { + continue; + } + if (nCand == 0) { + continue; + } + + fitter.FwdpropagateTracksToVertex(); // propagate e and K to D vertex + if (!fitter.isPropagateTracksToVertexDone()) { + continue; + } + + auto lTrack1 = fitter.getTrack(0); + auto lTrack2 = fitter.getTrack(1); + + PairTopoInfo pairInfo; + // DCA between cascade daughters + pairInfo.DCADau = std::sqrt(fitter.getChi2AtPCACandidate()); + + // get decay vertex coordinates + Vec3D vtx = fitter.getPCACandidate(); + pairInfo.X = vtx[0]; + pairInfo.Y = vtx[1]; + 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; + + // get daughter momenta + pairInfo.positiveMomentum[0] = lTrack1.getPx(); + pairInfo.positiveMomentum[1] = lTrack1.getPy(); + pairInfo.positiveMomentum[2] = lTrack1.getPz(); + pairInfo.negativeMomentum[0] = lTrack2.getPx(); + pairInfo.negativeMomentum[1] = lTrack2.getPy(); + pairInfo.negativeMomentum[2] = lTrack2.getPz(); + + pairInfo.CosPA = RecoDecay::cpa( + std::array{collision.posX(), collision.posY(), collision.posZ()}, + std::array{vtx[0], vtx[1], vtx[2]}, + std::array{pairInfo.positiveMomentum[0] + pairInfo.negativeMomentum[0], + pairInfo.positiveMomentum[1] + pairInfo.negativeMomentum[1], + pairInfo.positiveMomentum[2] + pairInfo.negativeMomentum[2]}); + + // Momenta + TVector3 track1Momentum(pairInfo.positiveMomentum[0], pairInfo.positiveMomentum[1], pairInfo.positiveMomentum[2]); + TVector3 track2Momentum(pairInfo.negativeMomentum[0], pairInfo.negativeMomentum[1], pairInfo.negativeMomentum[2]); + + pairInfo.OpAngle = track1Momentum.Angle(track2Momentum); + + // Radius + pairInfo.Radius = std::sqrt(vtx[0] * vtx[0] + vtx[1] * vtx[1]); + + // Dist over tot mom. + float px = pairInfo.positiveMomentum[0] + pairInfo.negativeMomentum[0]; + float py = pairInfo.positiveMomentum[1] + pairInfo.negativeMomentum[1]; + float pz = pairInfo.positiveMomentum[2] + pairInfo.negativeMomentum[2]; + pairInfo.DistOverTotMom = std::sqrt(vtx[0] * vtx[0] + vtx[1] * vtx[1] + vtx[2] * vtx[2]) / std::sqrt(px * px + py * py + pz * pz); + + // Z dist over pz + pairInfo.ZdistOverPz = vtx[2] / pz; + + // V0 Momenta + pairInfo.pT = std::sqrt(px * px + py * py); + pairInfo.pTot = std::sqrt(px * px + py * py + pz * pz); + pairInfo.pZ = pz; + + // Armenteros-Podolanski variables + float momTot2 = RecoDecay::p2(px, py, pz); + float dp = RecoDecay::dotProd(std::array{pairInfo.negativeMomentum[0], pairInfo.negativeMomentum[1], pairInfo.negativeMomentum[2]}, std::array{px, py, pz}); + pairInfo.QtArm = std::sqrt(RecoDecay::p2(pairInfo.negativeMomentum[0], pairInfo.negativeMomentum[1], pairInfo.negativeMomentum[2]) - dp * dp / momTot2); // qtarm + + float momTot = RecoDecay::p(px, py, pz); + float lQlNeg = RecoDecay::dotProd(std::array{pairInfo.negativeMomentum[0], pairInfo.negativeMomentum[1], pairInfo.negativeMomentum[2]}, std::array{px, py, pz}) / momTot; + float lQlPos = RecoDecay::dotProd(std::array{pairInfo.positiveMomentum[0], pairInfo.positiveMomentum[1], pairInfo.positiveMomentum[2]}, std::array{px, py, pz}) / momTot; + pairInfo.AlphaArm = (lQlPos - lQlNeg) / (lQlPos + lQlNeg); // alphav0 + + // Inv. mass + pairInfo.mK0s = RecoDecay::m(std::array{pairInfo.positiveMomentum, pairInfo.negativeMomentum}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiMinus}); + pairInfo.mLambda = RecoDecay::m(std::array{pairInfo.positiveMomentum, pairInfo.negativeMomentum}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiMinus}); + pairInfo.mAntiLambda = RecoDecay::m(std::array{pairInfo.positiveMomentum, pairInfo.negativeMomentum}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassProtonBar}); + pairInfo.mD0 = RecoDecay::m(std::array{pairInfo.positiveMomentum, pairInfo.negativeMomentum}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiMinus}); + pairInfo.mAntiD0 = RecoDecay::m(std::array{pairInfo.positiveMomentum, pairInfo.negativeMomentum}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKMinus}); + + // Rapidity + pairInfo.rapidityK0s = RecoDecay::y(std::array{pairInfo.positiveMomentum[0] + pairInfo.negativeMomentum[0], pairInfo.positiveMomentum[1] + pairInfo.negativeMomentum[1], pairInfo.positiveMomentum[2] + pairInfo.negativeMomentum[2]}, o2::constants::physics::MassKaonNeutral); + pairInfo.rapidityLambda = RecoDecay::y(std::array{pairInfo.positiveMomentum[0] + pairInfo.negativeMomentum[0], pairInfo.positiveMomentum[1] + pairInfo.negativeMomentum[1], pairInfo.positiveMomentum[2] + pairInfo.negativeMomentum[2]}, o2::constants::physics::MassLambda); + pairInfo.rapidityD0 = RecoDecay::y(std::array{pairInfo.positiveMomentum[0] + pairInfo.negativeMomentum[0], pairInfo.positiveMomentum[1] + pairInfo.negativeMomentum[1], pairInfo.positiveMomentum[2] + pairInfo.negativeMomentum[2]}, o2::constants::physics::MassD0); + + // + pairInfo.posNclusters = mftPositive.nClusters(); + pairInfo.posChi2 = mftPositive.chi2(); + pairInfo.posChi2PerNclus = mftPositive.chi2() / mftPositive.nClusters(); + + pairInfo.negNclusters = mftNegative.nClusters(); + pairInfo.negChi2 = mftNegative.chi2(); + pairInfo.negChi2PerNclus = mftNegative.chi2() / mftNegative.nClusters(); + + //_________________________________________________________ + // MC handling part + if constexpr (requires { mftNegative.mcParticleId(); mftPositive.mcParticleId(); }) { + // Association check + // There might be smarter ways of doing this in the future + if (mftNegative.has_mcParticle() && mftPositive.has_mcParticle()) { + auto lMCNegTrack = mftNegative.template mcParticle_as(); + auto lMCPosTrack = mftPositive.template mcParticle_as(); + + pairInfo.pdgCodePositive = lMCPosTrack.pdgCode(); + pairInfo.pdgCodeNegative = lMCNegTrack.pdgCode(); + pairInfo.processPositive = lMCPosTrack.getProcess(); + pairInfo.processNegative = lMCNegTrack.getProcess(); + pairInfo.positiveMomentumMc[0] = lMCPosTrack.px(); + pairInfo.positiveMomentumMc[1] = lMCPosTrack.py(); + pairInfo.positiveMomentumMc[2] = lMCPosTrack.pz(); + pairInfo.negativeMomentumMc[0] = lMCNegTrack.px(); + pairInfo.negativeMomentumMc[1] = lMCNegTrack.py(); + pairInfo.negativeMomentumMc[2] = lMCNegTrack.pz(); + + // check for pi -> mu + antineutrino decay + // if present, de-reference original V0 correctly and provide label to original object + // NOTA BENE: the prong info will still correspond to a muon, treat carefully! + int negOriginating = -1, posOriginating = -1, particleForDecayPositionIdx = -1; + negOriginating = getOriginatingParticle(lMCNegTrack, particleForDecayPositionIdx, doTreatPiToMuon); + posOriginating = getOriginatingParticle(lMCPosTrack, particleForDecayPositionIdx, doTreatPiToMuon); + + if (negOriginating > -1 && negOriginating == posOriginating) { + auto originatingV0 = mcParticles.rawIteratorAt(negOriginating); + auto particleForDecayPosition = mcParticles.rawIteratorAt(particleForDecayPositionIdx); + + pairInfo.label = originatingV0.globalIndex(); + pairInfo.xMc = particleForDecayPosition.vx(); + pairInfo.yMc = particleForDecayPosition.vy(); + pairInfo.zMc = particleForDecayPosition.vz(); + + if (originatingV0.has_mcCollision()) { + pairInfo.mcCollision = originatingV0.mcCollisionId(); // save this reference, please + } + + // acquire information + pairInfo.pdgCode = originatingV0.pdgCode(); + pairInfo.isPhysicalPrimary = originatingV0.isPhysicalPrimary(); + pairInfo.momentumMc[0] = originatingV0.px(); + pairInfo.momentumMc[1] = originatingV0.py(); + pairInfo.momentumMc[2] = originatingV0.pz(); + pairInfo.pTotMc = std::sqrt(pairInfo.momentumMc[0] * pairInfo.momentumMc[0] + pairInfo.momentumMc[1] * pairInfo.momentumMc[1] + pairInfo.momentumMc[2] * pairInfo.momentumMc[2]); + pairInfo.pTMc = std::sqrt(pairInfo.momentumMc[0] * pairInfo.momentumMc[0] + pairInfo.momentumMc[1] * pairInfo.momentumMc[1]); + pairInfo.pZMc = pairInfo.momentumMc[2]; + + if (pairInfo.pdgCode == PDG_t::kK0Short) + pairInfo.rapMc = RecoDecay::y(std::array{pairInfo.momentumMc[0], pairInfo.momentumMc[1], pairInfo.momentumMc[2]}, o2::constants::physics::MassKaonNeutral); + else if (std::abs(pairInfo.pdgCode) == PDG_t::kLambda0) + pairInfo.rapMc = RecoDecay::y(std::array{pairInfo.momentumMc[0], pairInfo.momentumMc[1], pairInfo.momentumMc[2]}, o2::constants::physics::MassLambda); + else if (std::abs(pairInfo.pdgCode) == o2::constants::physics::kD0) + pairInfo.rapMc = RecoDecay::y(std::array{pairInfo.momentumMc[0], pairInfo.momentumMc[1], pairInfo.momentumMc[2]}, o2::constants::physics::MassD0); + + if (originatingV0.has_mothers()) { + for (const auto& lV0Mother : originatingV0.template mothers_as()) { + pairInfo.pdgCodeMother = lV0Mother.pdgCode(); + pairInfo.motherLabel = lV0Mother.globalIndex(); + pairInfo.momentumMotherMc[0] = lV0Mother.px(); + pairInfo.momentumMotherMc[1] = lV0Mother.py(); + pairInfo.momentumMotherMc[2] = lV0Mother.pz(); + pairInfo.motherIsPhysicalPrimary = lV0Mother.isPhysicalPrimary(); + } + } + } + } // end association check + } // end MC handling + + v0.push_back(pairInfo); + } // end v0 loop + return v0; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void analyzeRecoedV0sInRealData(TCollision const& collision, TMFTTracks const& mftTracks, TTracks const& besttracks, TBCs const& bcs) + { + // Fire up CCDB + initCCDB(bcs, collision); + + if (!isEventAccepted(collision, bcs, true)) { + return; + } + + float centrality = -1; + float collisionOccupancy = -2; // -1 already taken for the case where occupancy cannot be evaluated + double interactionRate = -1; + // gap side + int gapSide = -1; + int selGapSide = -1; // -1 --> Hadronic ; 0 --> Single Gap - A side ; 1 --> Single Gap - C side ; 2 --> Double Gap - both A & C sides + // Fill recoed event properties + fillReconstructedEventProperties(collision, bcs, centrality, collisionOccupancy, interactionRate, gapSide, selGapSide); + + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + + // __________________________________________ + // perform main analysis + int nK0Shorts = 0; + int nLambdas = 0; + int nAntiLambdas = 0; + int nD0s = 0; + int nAntiD0s = 0; + std::vector V0s = buildV0s(collision, mftTracks, besttracks, static_cast(nullptr)); + for (const auto& v0 : V0s) { + // fill AP plot for all V0s + histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.AlphaArm, v0.QtArm); + + uint64_t selMap = computeReconstructionBitmap(v0, v0.rapidityK0s, v0.rapidityLambda, v0.rapidityD0); + + // consider for histograms for all species + BITSET(selMap, selConsiderK0Short); + BITSET(selMap, selConsiderLambda); + BITSET(selMap, selConsiderAntiLambda); + BITSET(selMap, selConsiderD0); + BITSET(selMap, selConsiderAntiD0); + + BITSET(selMap, selPhysPrimK0Short); + BITSET(selMap, selPhysPrimLambda); + BITSET(selMap, selPhysPrimAntiLambda); + BITSET(selMap, selPhysPrimD0); + BITSET(selMap, selPhysPrimAntiD0); + + analyseCandidate(v0, v0.pT, centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas, nD0s, nAntiD0s); + } // end v0 loop + + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + if (analyseK0Short) { + histos.fill(HIST("h2dNbrOfK0ShortVsCentrality"), centrality, nK0Shorts); + } + if (analyseLambda) { + histos.fill(HIST("h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + } + if (analyseAntiLambda) { + histos.fill(HIST("h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); + } + if (analyseD0) { + histos.fill(HIST("h2dNbrOfD0VsCentrality"), centrality, nD0s); + } + if (analyseAntiD0) { + histos.fill(HIST("h2dNbrOfAntiD0VsCentrality"), centrality, nAntiD0s); + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + template + void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TMFTTracks const& mftTracks, TTracks const& besttracks, TBCs const& bcs, TMCParticles const& mcParticles) + { + // Fire up CCDB + initCCDB(bcs, collision); + + if (!isEventAccepted(collision, bcs, true)) { + return; + } + + float centrality = -1; + float collisionOccupancy = -2; // -1 already taken for the case where occupancy cannot be evaluated + double interactionRate = -1; + // gap side + int gapSide = -1; + int selGapSide = -1; // -1 --> Hadronic ; 0 --> Single Gap - A side ; 1 --> Single Gap - C side ; 2 --> Double Gap - both A & C sides + // Fill recoed event properties + fillReconstructedEventProperties(collision, bcs, centrality, collisionOccupancy, interactionRate, gapSide, selGapSide); + + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + + // __________________________________________ + // perform main analysis + int nK0Shorts = 0; + int nLambdas = 0; + int nAntiLambdas = 0; + int nD0s = 0; + int nAntiD0s = 0; + std::vector V0s = buildV0s(collision, mftTracks, besttracks, mcParticles); + for (const auto& v0 : V0s) { + if (v0.label < 0) { + continue; + } + + // fill AP plot for all V0s + histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.AlphaArm, v0.QtArm); + + uint64_t selMap = computeReconstructionBitmap(v0, v0.rapMc, v0.rapMc, v0.rapMc); + selMap = selMap | computeMCAssociation(v0); + + // feeddown matrix always with association + if (calculateFeeddownMatrix) + fillFeeddownMatrix(v0, v0.pTMc, centrality, selMap); + + // consider only associated candidates if asked to do so, disregard association + if (!doMCAssociation) { + BITSET(selMap, selConsiderK0Short); + BITSET(selMap, selConsiderLambda); + BITSET(selMap, selConsiderAntiLambda); + BITSET(selMap, selConsiderD0); + BITSET(selMap, selConsiderAntiD0); + + BITSET(selMap, selPhysPrimK0Short); + BITSET(selMap, selPhysPrimLambda); + BITSET(selMap, selPhysPrimAntiLambda); + BITSET(selMap, selPhysPrimD0); + BITSET(selMap, selPhysPrimAntiD0); + } + + analyseCandidate(v0, v0.pTMc, centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas, nD0s, nAntiD0s); + } // end v0 loop + + // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision + if (analyseK0Short) { + histos.fill(HIST("h2dNbrOfK0ShortVsCentrality"), centrality, nK0Shorts); + } + if (analyseLambda) { + histos.fill(HIST("h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + } + if (analyseAntiLambda) { + histos.fill(HIST("h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); + } + if (analyseD0) { + histos.fill(HIST("h2dNbrOfD0VsCentrality"), centrality, nD0s); + } + if (analyseAntiD0) { + histos.fill(HIST("h2dNbrOfAntiD0VsCentrality"), centrality, nAntiD0s); + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + template + void analyzeGeneratedV0s(TMCCollisions const& mcCollisions, TMcParticles const& mcParticles, TCollisions const& collisions, TBCs const& bcs) + { + fillGeneratedEventProperties(mcCollisions, collisions, bcs); + std::vector listBestCollisionIdx = getListOfRecoCollIndices(mcCollisions, collisions, bcs); + for (auto const& mcParticle : mcParticles) { + if (!mcParticle.has_mcCollision()) + continue; + + auto mcCollision = mcParticle.template mcCollision_as>(); + if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { + continue; + } + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + + if (!mcParticle.isPhysicalPrimary()) + continue; + + float ptmc = mcParticle.pt(); + float ymc = 1e3; + if (mcParticle.pdgCode() == PDG_t::kK0Short) + ymc = RecoDecay::y(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()}, o2::constants::physics::MassKaonNeutral); + else if (std::abs(mcParticle.pdgCode()) == PDG_t::kLambda0) + ymc = RecoDecay::y(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()}, o2::constants::physics::MassLambda); + else if (std::abs(mcParticle.pdgCode()) == o2::constants::physics::kD0) + ymc = RecoDecay::y(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()}, o2::constants::physics::MassD0); + else if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) + ymc = RecoDecay::y(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()}, o2::constants::physics::MassXiMinus); + else if (std::abs(mcParticle.pdgCode()) == PDG_t::kOmegaMinus) + ymc = RecoDecay::y(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()}, o2::constants::physics::MassOmegaMinus); + + if (ymc > v0Selections.rapidityMax) + continue; + if (ymc < v0Selections.rapidityMin) + continue; + + float centrality = 100.5f; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + centrality = getCentralityRun3(collision); + + if (mcParticle.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kXiMinus) { + histos.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kXiPlusBar) { + histos.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kOmegaMinus) { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kOmegaPlusBar) { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (mcParticle.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("h2dGenK0Short"), centrality, ptmc); + histos.fill(HIST("h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("h2dGenLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + histos.fill(HIST("h2dGenAntiLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kXiMinus) { + histos.fill(HIST("h2dGenXiMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kXiPlusBar) { + histos.fill(HIST("h2dGenXiPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kOmegaMinus) { + histos.fill(HIST("h2dGenOmegaMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (mcParticle.pdgCode() == PDG_t::kOmegaPlusBar) { + histos.fill(HIST("h2dGenOmegaPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + } + + // ______________________________________________________ + // Real data processing in Run 3 - no MC subscription + void processRealData(soa::Join::iterator const& collision, + aod::MFTTracks const& tracks, + soa::SmallGroups const& besttracks, + aod::BCsWithTimestamps const& bcs) + { + analyzeRecoedV0sInRealData(collision, tracks, besttracks, bcs); + } + + // ______________________________________________________ + // Simulated processing in Run 3 (subscribes to MC information too) + void processMonteCarlo(soa::Join::iterator const& collision, + soa::Join const& tracks, + soa::SmallGroups> const& besttracks, + aod::BCsWithTimestamps const& bcs, + soa::Join const& /*mccollisions*/, + aod::McParticles const& mcParticles) + { + analyzeRecoedV0sInMonteCarlo(collision, tracks, besttracks, bcs, mcParticles); + } + + // ______________________________________________________ + // Simulated processing in Run 3 (subscribes to MC information too) + void processGenerated(soa::Join const& mcCollisions, aod::McParticles const& mcParticles, soa::Join const& collisions, aod::BCsWithTimestamps const& bcs) + { + analyzeGeneratedV0s(mcCollisions, mcParticles, collisions, bcs); + } + + PROCESS_SWITCH(forwardlambdakzeroanalysis, processRealData, "process as if real data", true); + PROCESS_SWITCH(forwardlambdakzeroanalysis, processMonteCarlo, "process as if MC", false); + PROCESS_SWITCH(forwardlambdakzeroanalysis, processGenerated, "process MC generated", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index 4b6c530b523..2b136e6ccb3 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -66,12 +66,18 @@ #include +#include +#include #include #include #include +#include #include #include #include +#include +#include +#include #include #include @@ -81,8 +87,10 @@ using namespace o2::framework; using namespace o2::framework::expressions; using TracksComplete = soa::Join; +using TracksCompleteMC = soa::Join; using V0DatasWithoutTrackX = soa::Join; using V0DatasWithoutTrackXMC = soa::Join; +using V0DatasWithoutTrackXWithMCCores = soa::Join; struct HStrangeCorrelation { // for efficiency corrections if requested @@ -123,12 +131,13 @@ struct HStrangeCorrelation { Configurable mixingParameter{"mixingParameter", 10, "how many events are mixed"}; Configurable doMCassociation{"doMCassociation", false, "fill everything only for MC associated"}; Configurable doTriggPhysicalPrimary{"doTriggPhysicalPrimary", false, "require physical primary for trigger particles"}; + Configurable doClosureTestTriggerWithRecoTrackMatch{"doClosureTestTriggerWithRecoTrackMatch", false, "add closure-test correlations requiring the truth trigger to have at least one reconstructed track with a matching MC label"}; Configurable applyNewMCSelection{"applyNewMCSelection", false, "apply new MC Generated selection"}; Configurable doSeparateFT0Prediction{"doSeparateFT0Prediction", false, "separate FT0M to FT0A and FT0C in prediction process"}; Configurable useCentralityinPrediction{"useCentralityinPrediction", false, "if true, use centrality instead of multiplisity"}; Configurable doMirroringInDelataEta{"doMirroringInDelataEta", false, "if true, fill only positive delta eta and mirror the negative side in post processing, Adjust the delta axis!"}; - Configurable fillCorrelationHistWithMass{"fillCorrelationHistWithMass", false, "if true, fill correlation histograms with particle mass"}; Configurable doMassSpectrumCheck{"doMassSpectrumCheck", false, "if true, add and fill invariant-mass spectrum"}; + Configurable doCorrelationsHadronV0daughter{"doCorrelationsHadronV0daughter", false, "if true, do correlations of hadrons with V0 daughters"}; } masterConfigurations; // master analysis switches @@ -210,7 +219,8 @@ struct HStrangeCorrelation { Configurable requireClusterInITS{"requireClusterInITS", false, "require cluster in ITS for V0 and cascade daughter tracks"}; Configurable minITSClustersForDaughterTracks{"minITSClustersForDaughterTracks", 1, "Minimum number of ITS clusters for V0 daughter tracks"}; Configurable requireDCAzCut{"requireDCAzCut", false, "require DCAz cut for trigger and associated primary tracks"}; - + Configurable doITSChi2Selection{"doITSChi2Selection", false, "require ITS chi2 cut for trigger and associated primary tracks"}; + Configurable checkForITSTPCMissmatchMC{"checkForITSTPCMissmatchMC", false, "if true, reject tracks with MC mask bit 13 (ITS-TPC mismatch) for trigger and associated primary tracks"}; // --- Trigger: DCA variation from basic formula: |DCAxy| < 0.004f + (0.013f / pt) Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; @@ -223,6 +233,8 @@ struct HStrangeCorrelation { Configurable dcaZconstantAssoc{"dcaZconstantAssoc", 0.004, "[0] in |DCAz| < [0]+[1]/pT"}; Configurable dcaZpTdepAssoc{"dcaZpTdepAssoc", 0.013, "[1] in |DCAz| < [0]+[1]/pT"}; Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in HStrangeCorrelationFilter"}; + Configurable chi2ITSfit{"chi2ITSfit", 36, "chi2 ITS fit for trigger and associated primary tracks"}; + } trackSelection; struct : ConfigurableGroup { std::string prefix = "v0Selection"; @@ -279,7 +291,7 @@ struct HStrangeCorrelation { // Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; // // on the fly correction instead of mixingParameter - Configurable doOnTheFlyFlattening{"doOnTheFlyFlattening", 0, "enable an on-the-fly correction instead of using mixing"}; + Configurable doOnTheFlyFlattening{"doOnTheFlyFlattening", false, "enable an on-the-fly correction instead of using mixing"}; // delta eta ranges for toward and transverse checks Configurable transwerseDeltaEtaRangeMin{"transwerseDeltaEtaRangeMin", 1.0, "minimum delta eta for transverse region"}; @@ -288,6 +300,34 @@ struct HStrangeCorrelation { // (N.B.: sources that can be investigated in post are not listed!) } checks; + struct : ConfigurableGroup { + std::string prefix = "pairLossK0Configurations"; + Configurable applyRecoEventSelection{"applyRecoEventSelection", true, "apply the standard reconstructed-event selection in the K0 pair-loss diagnostic"}; + Configurable daughterPtMin{"daughterPtMin", 0.05f, "minimum generated daughter pT for the findable K0 category"}; + Configurable daughterEtaMax{"daughterEtaMax", 0.9f, "maximum absolute generated daughter eta for the findable K0 category"}; + Configurable minRadius{"minRadius", 0.8f, "minimum radius in metres used for the minimum delta-phi-star search"}; + Configurable maxRadius{"maxRadius", 2.5f, "maximum radius in metres used for the minimum delta-phi-star search"}; + Configurable radiusStep{"radiusStep", 0.05f, "radius step in metres used for the minimum delta-phi-star search"}; + ConfigurableAxis axisMinDeltaPhiStar{"axisMinDeltaPhiStar", {120, 0.0f, 0.3f}, "minimum absolute delta phi star"}; + ConfigurableAxis axisSignedDeltaPhiStar{"axisSignedDeltaPhiStar", {120, -0.3f, 0.3f}, "signed delta phi star at the minimum"}; + ConfigurableAxis axisDaughterDeltaEta{"axisDaughterDeltaEta", {100, -0.2f, 0.2f}, "trigger-daughter delta eta"}; + ConfigurableAxis axisDaughterDeltaPhi{"axisDaughterDeltaPhi", {120, -0.3f, 0.3f}, "trigger-daughter delta phi"}; + ConfigurableAxis axisDecayRadius{"axisDecayRadius", {100, 0.0f, 200.0f}, "generated K0 decay radius (cm)"}; + // The following mirror the isValidTrigger() cuts applied by hStrangeCorrelationFilter.cxx + // when building the TriggerTracks table. They must be kept in sync by hand with whatever + // values are configured for that (separate) filter task, since this diagnostic cannot read + // them directly: it only sees the already-filtered TriggerTracks table, not why a given + // best-collision track failed to enter it. + Configurable triggerTracksEtaMin{"triggerTracksEtaMin", -0.8f, "must match triggerEtaMin in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksEtaMax{"triggerTracksEtaMax", 0.8f, "must match triggerEtaMax in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksPtMin{"triggerTracksPtMin", 3.0f, "must match triggerPtCutMin in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksPtMax{"triggerTracksPtMax", 20.0f, "must match triggerPtCutMax in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksMinCrossedRows{"triggerTracksMinCrossedRows", 70, "must match minTPCNCrossedRows in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksRequireITS{"triggerTracksRequireITS", true, "must match triggerRequireITS in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksMaxSharedClusters{"triggerTracksMaxSharedClusters", 200, "must match triggerMaxTPCSharedClusters in hStrangeCorrelationFilter.cxx"}; + Configurable triggerTracksRequireLayer0{"triggerTracksRequireLayer0", false, "must match triggerRequireL0 in hStrangeCorrelationFilter.cxx"}; + } pairLossK0Configurations; + struct ValidCollision { struct ValidParticle { float eta; @@ -298,13 +338,13 @@ struct HStrangeCorrelation { float efficiencyError; int type; }; - float pvz; - float mult; + float pvz = 0.0f; + float mult = 0.0f; std::vector trigParticles; std::vector assocParticles; void addValidParticle(float eta, float phi, float pt, int region, float efficiency, float efficiencyError, int type) { - ValidParticle particle{eta, phi, pt, region, efficiency, efficiencyError, type}; + ValidParticle particle{.eta = eta, .phi = phi, .pt = pt, .region = region, .efficiency = efficiency, .efficiencyError = efficiencyError, .type = type}; if (type == -1) { trigParticles.push_back(particle); @@ -318,43 +358,43 @@ struct HStrangeCorrelation { ValidCollisions validCollisions; // objects to use for efficiency corrections - TH2F* hEfficiencyTrigger; - TH3F* hEfficiencyTriggerMult; - THnF* hEfficiencyTriggerMultVsPhi; - TH2F* hEfficiencyPion; - TH2F* hEfficiencyK0Short; - THnF* hEfficiencyK0ShortMultVsPhi; - TH2F* hEfficiencyLambda; - THnF* hEfficiencyLambdaMultVsPhi; - TH2F* hEfficiencyAntiLambda; - THnF* hEfficiencyAntiLambdaMultVsPhi; - TH2F* hEfficiencyXiMinus; - THnF* hEfficiencyXiMinusMultVsPhi; - TH2F* hEfficiencyXiPlus; - THnF* hEfficiencyXiPlusMultVsPhi; - TH2F* hEfficiencyOmegaMinus; - THnF* hEfficiencyOmegaMinusMultVsPhi; - TH2F* hEfficiencyOmegaPlus; - THnF* hEfficiencyOmegaPlusMultVsPhi; - TH2F* hEfficiencyHadron; - TH3F* hEfficiencyHadronMult; - TH1F* hPurityHadron; - TH2F* hPurityHadronMult; + TH2F* hEfficiencyTrigger = nullptr; + TH3F* hEfficiencyTriggerMult = nullptr; + THnF* hEfficiencyTriggerMultVsPhi = nullptr; + TH2F* hEfficiencyPion = nullptr; + TH2F* hEfficiencyK0Short = nullptr; + THnF* hEfficiencyK0ShortMultVsPhi = nullptr; + TH2F* hEfficiencyLambda = nullptr; + THnF* hEfficiencyLambdaMultVsPhi = nullptr; + TH2F* hEfficiencyAntiLambda = nullptr; + THnF* hEfficiencyAntiLambdaMultVsPhi = nullptr; + TH2F* hEfficiencyXiMinus = nullptr; + THnF* hEfficiencyXiMinusMultVsPhi = nullptr; + TH2F* hEfficiencyXiPlus = nullptr; + THnF* hEfficiencyXiPlusMultVsPhi = nullptr; + TH2F* hEfficiencyOmegaMinus = nullptr; + THnF* hEfficiencyOmegaMinusMultVsPhi = nullptr; + TH2F* hEfficiencyOmegaPlus = nullptr; + THnF* hEfficiencyOmegaPlusMultVsPhi = nullptr; + TH2F* hEfficiencyHadron = nullptr; + TH3F* hEfficiencyHadronMult = nullptr; + TH1F* hPurityHadron = nullptr; + TH2F* hPurityHadronMult = nullptr; // objects to propagate the efficiency uncertainty - TH2F* hEfficiencyUncertaintyTrigger; - TH3F* hEfficiencyUncertaintyTriggerMult; - TH2F* hEfficiencyUncertaintyPion; - TH2F* hEfficiencyUncertaintyK0Short; - TH2F* hEfficiencyUncertaintyLambda; - TH2F* hEfficiencyUncertaintyAntiLambda; - TH2F* hEfficiencyUncertaintyXiMinus; - TH2F* hEfficiencyUncertaintyXiPlus; - TH2F* hEfficiencyUncertaintyOmegaMinus; - TH2F* hEfficiencyUncertaintyOmegaPlus; - TH2F* hEfficiencyUncertaintyHadron; - TH3F* hEfficiencyUncertaintyHadronMult; - TH1F* hPurityUncertaintyHadron; - TH2F* hPurityUncertaintyHadronMult; + TH2F* hEfficiencyUncertaintyTrigger = nullptr; + TH3F* hEfficiencyUncertaintyTriggerMult = nullptr; + TH2F* hEfficiencyUncertaintyPion = nullptr; + TH2F* hEfficiencyUncertaintyK0Short = nullptr; + TH2F* hEfficiencyUncertaintyLambda = nullptr; + TH2F* hEfficiencyUncertaintyAntiLambda = nullptr; + TH2F* hEfficiencyUncertaintyXiMinus = nullptr; + TH2F* hEfficiencyUncertaintyXiPlus = nullptr; + TH2F* hEfficiencyUncertaintyOmegaMinus = nullptr; + TH2F* hEfficiencyUncertaintyOmegaPlus = nullptr; + TH2F* hEfficiencyUncertaintyHadron = nullptr; + TH3F* hEfficiencyUncertaintyHadronMult = nullptr; + TH1F* hPurityUncertaintyHadron = nullptr; + TH2F* hPurityUncertaintyHadronMult = nullptr; using BinningTypePP = ColumnBinningPolicy; using BinningTypePbPb = ColumnBinningPolicy; @@ -366,11 +406,13 @@ struct HStrangeCorrelation { // Preslice collisionSlicePions = aod::assocHadrons::collisionId; Preslice collisionSliceHadrons = aod::assocHadrons::collisionId; Preslice perCollision = aod::mcparticle::mcCollisionId; + Preslice pairLossTracksPerCollision = aod::track::collisionId; + Preslice pairLossV0sPerCollision = aod::v0data::collisionId; - static constexpr std::string_view V0names[] = {"K0Short", "Lambda", "AntiLambda"}; - static constexpr std::string_view Cascadenames[] = {"XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus"}; - static constexpr std::string_view Particlenames[] = {"K0Short", "Lambda", "AntiLambda", "XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus", "Pion", "Hadron"}; - static constexpr int PdgCodes[] = {310, 3122, -3122, 3312, -3312, 3334, -3334, 211}; + static constexpr std::array V0names = {"K0Short", "Lambda", "AntiLambda"}; + static constexpr std::array Cascadenames = {"XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus"}; + static constexpr std::array Particlenames = {"K0Short", "Lambda", "AntiLambda", "XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus", "Pion", "Hadron"}; + static constexpr std::array PdgCodes = {310, 3122, -3122, 3312, -3312, 3334, -3334, 211}; static constexpr int IndexPion = 7; static constexpr int IndexXiMinus = 0; @@ -394,14 +436,14 @@ struct HStrangeCorrelation { } } - uint16_t doCorrelation; - int mRunNumber; - int mRunNumberZorro; + uint16_t doCorrelation = 0; + int mRunNumber = -1; + int mRunNumberZorro = -1; std::vector> axisRanges; - const float ctauxi = 4.91; // from PDG - const float ctauomega = 2.461; // from PDG + static constexpr float ctauxi = 4.91; // from PDG + static constexpr float ctauomega = 2.461; // from PDG static constexpr float MinRadiusTPC = 0.8; static constexpr float MaxRadiusTPC = 2.5; @@ -410,6 +452,124 @@ struct HStrangeCorrelation { static constexpr int AssocParticleTypes = 9; // K0S, Lambda, AntiLambda, Xi-, Xi+, Omega-, Omega+, Pion, Hadron static constexpr int AssocParticleTypesNoHadron = 8; // K0S, Lambda, AntiLambda, Xi-, Xi+, Omega-, Omega+, Pion + static constexpr int AssocV0Types = 3; // K0S, Lambda, AntiLambda, + static constexpr int AssocCascadeTypes = 4; // Xi-, Xi+, Omega-, Omega+ + + enum PairLossK0Stage : int { + PairLossGenPair = 0, + PairLossFindablePair, + PairLossTriggerAnyCollision, + PairLossTriggerBestCollision, + PairLossTriggerInTable, + PairLossTriggerFinal, + PairLossPositiveDaughterBestCollision, + PairLossNegativeDaughterBestCollision, + PairLossBothDaughtersBestCollision, + PairLossV0AnyCollision, + PairLossV0BestCollision, + PairLossV0InTable, + PairLossV0Final, + PairLossBothFinalBeforeAutocorrelation, + PairLossFinalPair, + PairLossK0NStages + }; + + static constexpr std::array PairLossK0StageNames = { + "Gen pair", + "Findable K0->pi+pi-", + "Trigger track, any rec collision", + "Trigger track, best collision", + "Trigger in TriggerTracks", + "Trigger final selection", + "Positive daughter track", + "Negative daughter track", + "Both daughter tracks", + "V0 candidate, any rec collision", + "V0 candidate, best collision", + "V0 in AssocV0s", + "V0 final selection", + "Both final, before autocorrelation", + "Final reconstructed pair"}; + + struct PairLossTrackInfo { + int64_t globalIndex = -1; + float pt = 0.0f; + float eta = 0.0f; + float phi = 0.0f; + int sign = 0; + int tpcCrossedRows = 0; + int tpcSharedClusters = 0; + int itsClusters = 0; + bool hasLayer0 = false; + }; + + // First-failing-condition breakdown for the stage3->4 gate ("Trigger track, best collision" + // -> "Trigger in TriggerTracks"). Order mirrors the early-return order of isValidTrigger() + // in hStrangeCorrelationFilter.cxx exactly, so "first reason to fail" means the same thing here. + enum PairLossTriggerTracksFailureReason : int { + PairLossTriggerTracksPassed = 0, + PairLossTriggerTracksFailEta, + PairLossTriggerTracksFailPt, + PairLossTriggerTracksFailCrossedRows, + PairLossTriggerTracksFailITS, + PairLossTriggerTracksFailSharedClusters, + PairLossTriggerTracksFailLayer0, + PairLossTriggerTracksNReasons + }; + + static constexpr std::array PairLossTriggerTracksFailureNames = { + "Passed all cuts (in TriggerTracks)", + "Failed eta window", + "Failed pT window", + "Failed min TPC crossed rows", + "Failed hasITS requirement", + "Failed max TPC shared clusters", + "Failed ITS layer-0 requirement"}; + + struct PairLossV0Info { + int64_t globalIndex = -1; + int64_t positiveTrackId = -1; + int64_t negativeTrackId = -1; + float pt = 0.0f; + float eta = 0.0f; + float phi = 0.0f; + float radius = 0.0f; + float cosPA = 0.0f; + float dcaDaughters = 0.0f; + float massNSigma = 0.0f; + }; + + struct PairLossTruthTrackInfo { + int64_t globalIndex = -1; + float pt = 0.0f; + float eta = 0.0f; + float phi = 0.0f; + int sign = 0; + }; + + struct PairLossTruthK0Info { + int64_t globalIndex = -1; + float pt = 0.0f; + float eta = 0.0f; + float phi = 0.0f; + float decayRadius = -1.0f; + bool findable = false; + PairLossTruthTrackInfo positiveDaughter; + PairLossTruthTrackInfo negativeDaughter; + }; + + struct PairLossDeltaPhiStarInfo { + bool valid = false; + float minAbs = std::numeric_limits::max(); + float signedAtMin = 0.0f; + float radiusAtMin = -1.0f; + }; + + using PairLossTrackMap = std::unordered_map>; + using PairLossV0Map = std::unordered_map>; + + int mPairLossRunNumber = -1; + double mPairLossMagneticField = 0.0; /// Function to aid in calculating delta-phi /// \param phi1 first phi value @@ -421,6 +581,86 @@ struct HStrangeCorrelation { return shiftedDeltaPhi; } + static bool isPairLossTriggerPdg(int pdgCode) + { + const int absPdg = std::abs(pdgCode); + return absPdg == PDG_t::kPiPlus || absPdg == PDG_t::kKPlus || absPdg == PDG_t::kProton || absPdg == PDG_t::kElectron || absPdg == PDG_t::kMuonMinus; + } + + template + PairLossTrackInfo makePairLossTrackInfo(TTrack const& track) const + { + return PairLossTrackInfo{ + .globalIndex = static_cast(track.globalIndex()), + .pt = track.pt(), + .eta = track.eta(), + .phi = track.phi(), + .sign = track.sign(), + .tpcCrossedRows = track.tpcNClsCrossedRows(), + .tpcSharedClusters = track.tpcNClsShared(), + .itsClusters = track.itsNCls(), + .hasLayer0 = static_cast(TESTBIT(track.itsClusterMap(), 0))}; + } + + // Replicates isValidTrigger() from hStrangeCorrelationFilter.cxx condition-by-condition + // (same early-return order) so that, for a trigger already known to exist in the best + // collision (stage 3), we can tell which single cut is responsible for it not making it + // into the TriggerTracks table (stage 4), instead of only knowing that it failed overall. + int classifyTriggerTracksFailure(PairLossTrackInfo const& info) + { + if (info.eta > pairLossK0Configurations.triggerTracksEtaMax || info.eta < pairLossK0Configurations.triggerTracksEtaMin) { + return PairLossTriggerTracksFailEta; + } + if (info.pt > pairLossK0Configurations.triggerTracksPtMax || info.pt < pairLossK0Configurations.triggerTracksPtMin) { + return PairLossTriggerTracksFailPt; + } + if (info.tpcCrossedRows < pairLossK0Configurations.triggerTracksMinCrossedRows) { + return PairLossTriggerTracksFailCrossedRows; + } + if (info.itsClusters <= 0 && pairLossK0Configurations.triggerTracksRequireITS) { + return PairLossTriggerTracksFailITS; + } + if (info.tpcSharedClusters > pairLossK0Configurations.triggerTracksMaxSharedClusters) { + return PairLossTriggerTracksFailSharedClusters; + } + if (!info.hasLayer0 && pairLossK0Configurations.triggerTracksRequireLayer0) { + return PairLossTriggerTracksFailLayer0; + } + return PairLossTriggerTracksPassed; + } + + PairLossDeltaPhiStarInfo calculateMinimumDeltaPhiStar(PairLossTruthTrackInfo const& trigger, PairLossTruthTrackInfo const& daughter, double magneticField, float decayRadiusCm) + { + PairLossDeltaPhiStarInfo result; + if (trigger.pt <= 0.0f || daughter.pt <= 0.0f || pairLossK0Configurations.radiusStep <= 0.0f) { + return result; + } + + const double triggerPhase = (-0.3 * magneticField * trigger.sign) / (2.0 * trigger.pt); + const double daughterPhase = (-0.3 * magneticField * daughter.sign) / (2.0 * daughter.pt); + const double deltaPhi = daughter.phi - trigger.phi; + const double startRadius = std::max(static_cast(pairLossK0Configurations.minRadius), static_cast(std::max(decayRadiusCm, 0.0f)) / 100.0); + const double maxRadius = pairLossK0Configurations.maxRadius; + const double radiusStep = pairLossK0Configurations.radiusStep; + + for (double radius = startRadius; radius <= maxRadius + 0.5 * radiusStep; radius += radiusStep) { + const double daughterArgument = daughterPhase * radius; + const double triggerArgument = triggerPhase * radius; + if (std::abs(daughterArgument) > 1.0 || std::abs(triggerArgument) > 1.0) { + continue; + } + const double signedDeltaPhiStar = RecoDecay::constrainAngle(deltaPhi + std::asin(daughterArgument) - std::asin(triggerArgument), -PI); + const float absDeltaPhiStar = std::abs(signedDeltaPhiStar); + if (absDeltaPhiStar < result.minAbs) { + result.valid = true; + result.minAbs = absDeltaPhiStar; + result.signedAtMin = signedDeltaPhiStar; + result.radiusAtMin = radius; + } + } + return result; + } + /// Function to load zorro /// \param bc provided such that the run number + timestamp can be used void initZorro(aod::BCsWithTimestamps::iterator const& bc) @@ -446,91 +686,99 @@ struct HStrangeCorrelation { LOG(info) << "Loading efficiencies from CCDB for run " << mRunNumber << " now..."; auto timeStamp = bc.timestamp(); - TList* listEfficiencies = ccdb->getForTimeStamp(efficiencyCCDBPath, timeStamp); + auto* listEfficiencies = ccdb->getForTimeStamp(efficiencyCCDBPath, timeStamp); if (!listEfficiencies) { LOG(fatal) << "Problem getting TList object with efficiencies!"; } - hEfficiencyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); - hEfficiencyTriggerMult = static_cast(listEfficiencies->FindObject("hEfficiencyTriggerMult")); - hEfficiencyTriggerMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyTriggerMultVsPhi")); - hEfficiencyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); - hEfficiencyK0ShortMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyK0ShortMultVsPhi")); - hEfficiencyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyLambda")); - hEfficiencyLambdaMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyLambdaMultVsPhi")); - hEfficiencyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); - hEfficiencyAntiLambdaMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyAntiLambdaMultVsPhi")); - hEfficiencyXiMinus = static_cast(listEfficiencies->FindObject("hEfficiencyXiMinus")); - hEfficiencyXiMinusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyXiMinusMultVsPhi")); - hEfficiencyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); - hEfficiencyXiPlusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyXiPlusMultVsPhi")); - hEfficiencyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); - hEfficiencyOmegaMinusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinusMultVsPhi")); - hEfficiencyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); - hEfficiencyOmegaPlusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlusMultVsPhi")); - hEfficiencyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyHadron")); - hEfficiencyHadronMult = static_cast(listEfficiencies->FindObject("hEfficiencyHadronMult")); - hEfficiencyPion = static_cast(listEfficiencies->FindObject("hEfficiencyPion")); - hPurityHadron = static_cast(listEfficiencies->FindObject("hPurityHadron")); - hPurityHadronMult = static_cast(listEfficiencies->FindObject("hPurityHadronMult")); - hEfficiencyUncertaintyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTrigger")); - hEfficiencyUncertaintyTriggerMult = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTriggerMult")); - hEfficiencyUncertaintyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyK0Short")); - hEfficiencyUncertaintyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyLambda")); - hEfficiencyUncertaintyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyAntiLambda")); - hEfficiencyUncertaintyXiMinus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiMinus")); - hEfficiencyUncertaintyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiPlus")); - hEfficiencyUncertaintyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaMinus")); - hEfficiencyUncertaintyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaPlus")); - hEfficiencyUncertaintyPion = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyPion")); - hEfficiencyUncertaintyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadron")); - hEfficiencyUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadronMult")); - hPurityUncertaintyHadron = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadron")); - hPurityUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadronMult")); - if (efficiencyFlags.applyEfficiencyPropagation && !efficiencyFlags.applyEffAsFunctionOfMultAndPhi && !hEfficiencyUncertaintyTrigger) + hEfficiencyTrigger = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); + hEfficiencyTriggerMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTriggerMult")); + hEfficiencyTriggerMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTriggerMultVsPhi")); + hEfficiencyK0Short = dynamic_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); + hEfficiencyK0ShortMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyK0ShortMultVsPhi")); + hEfficiencyLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyLambda")); + hEfficiencyLambdaMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyLambdaMultVsPhi")); + hEfficiencyAntiLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); + hEfficiencyAntiLambdaMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyAntiLambdaMultVsPhi")); + hEfficiencyXiMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiMinus")); + hEfficiencyXiMinusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiMinusMultVsPhi")); + hEfficiencyXiPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); + hEfficiencyXiPlusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiPlusMultVsPhi")); + hEfficiencyOmegaMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); + hEfficiencyOmegaMinusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinusMultVsPhi")); + hEfficiencyOmegaPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); + hEfficiencyOmegaPlusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlusMultVsPhi")); + hEfficiencyHadron = dynamic_cast(listEfficiencies->FindObject("hEfficiencyHadron")); + hEfficiencyHadronMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyHadronMult")); + hEfficiencyPion = dynamic_cast(listEfficiencies->FindObject("hEfficiencyPion")); + hPurityHadron = dynamic_cast(listEfficiencies->FindObject("hPurityHadron")); + hPurityHadronMult = dynamic_cast(listEfficiencies->FindObject("hPurityHadronMult")); + hEfficiencyUncertaintyTrigger = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTrigger")); + hEfficiencyUncertaintyTriggerMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTriggerMult")); + hEfficiencyUncertaintyK0Short = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyK0Short")); + hEfficiencyUncertaintyLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyLambda")); + hEfficiencyUncertaintyAntiLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyAntiLambda")); + hEfficiencyUncertaintyXiMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiMinus")); + hEfficiencyUncertaintyXiPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiPlus")); + hEfficiencyUncertaintyOmegaMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaMinus")); + hEfficiencyUncertaintyOmegaPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaPlus")); + hEfficiencyUncertaintyPion = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyPion")); + hEfficiencyUncertaintyHadron = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadron")); + hEfficiencyUncertaintyHadronMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadronMult")); + hPurityUncertaintyHadron = dynamic_cast(listEfficiencies->FindObject("hPurityUncertaintyHadron")); + hPurityUncertaintyHadronMult = dynamic_cast(listEfficiencies->FindObject("hPurityUncertaintyHadronMult")); + if (efficiencyFlags.applyEfficiencyPropagation && !efficiencyFlags.applyEffAsFunctionOfMultAndPhi && !hEfficiencyUncertaintyTrigger) { LOG(fatal) << "Problem getting hEfficiencyUncertaintyTrigger!"; - if (efficiencyFlags.applyEffAsFunctionOfMult && !hEfficiencyTriggerMult) + } + if (efficiencyFlags.applyEffAsFunctionOfMult && !hEfficiencyTriggerMult) { LOG(fatal) << "Problem getting hEfficiencyTriggerMult!"; + } LOG(info) << "Efficiencies now loaded for " << mRunNumber; } template - uint64_t v0selectionBitmap(TV0 v0, float pvx, float pvy, float pvz) + uint64_t v0selectionBitmap(TV0 const& v0, float pvx, float pvy, float pvz) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; // proper lifetime , DCA daughter to prim.vtx if (masterConfigurations.doCorrelationK0Short) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S) { SETBIT(bitMap, 0); + } // DCA daughter to prim.vtx and armenteros float dcaCut = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; - if (std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha())) + if (std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha())) { SETBIT(bitMap, 3); + } } if (masterConfigurations.doCorrelationLambda) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) { SETBIT(bitMap, 1); + } // DCA daughter to prim.vtx - if (std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV) { SETBIT(bitMap, 4); + } } if (masterConfigurations.doCorrelationAntiLambda) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) { SETBIT(bitMap, 2); + } // DCA daughter to prim.vtx - if (std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV) { SETBIT(bitMap, 5); + } } return bitMap; } template - uint64_t cascadeselectionBitmap(TCascade casc, float pvx, float pvy, float pvz) + uint64_t cascadeselectionBitmap(TCascade const& casc, float pvx, float pvy, float pvz) { uint64_t bitMap = 0; float cascpos = std::hypot(casc.x() - pvx, casc.y() - pvy, casc.z() - pvz); @@ -545,64 +793,80 @@ struct HStrangeCorrelation { // TPC PID and DCA daughter to prim.vtx and comopeting casc.rej and life time if (masterConfigurations.doCorrelationXiMinus) { // DCA daughter to prim.vtx - if (isGoodDCANegCasc) + if (isGoodDCANegCasc) { SETBIT(bitMap, 0); + } // comopeting casc.rej - if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 4); - if (ctauXi < cascadeSelections.proplifetime) + } + if (ctauXi < cascadeSelections.proplifetime) { SETBIT(bitMap, 8); + } // y cut - if (std::abs(casc.yXi()) < cascadeSelections.rapCut) + if (std::abs(casc.yXi()) < cascadeSelections.rapCut) { SETBIT(bitMap, 12); + } } if (masterConfigurations.doCorrelationXiPlus) { // DCA daughter to prim.vtx - if (isGoodDCAPosCasc) + if (isGoodDCAPosCasc) { SETBIT(bitMap, 1); + } // comopeting casc.rej - if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 5); + } // life time - if (ctauXi < cascadeSelections.proplifetime) + if (ctauXi < cascadeSelections.proplifetime) { SETBIT(bitMap, 9); + } // y cut - if (std::abs(casc.yXi()) > cascadeSelections.rapCut) + if (std::abs(casc.yXi()) > cascadeSelections.rapCut) { SETBIT(bitMap, 13); + } } if (masterConfigurations.doCorrelationOmegaMinus) { // DCA daughter to prim.vtx - if (isGoodDCANegCasc) + if (isGoodDCANegCasc) { SETBIT(bitMap, 2); + } // comopeting casc.rej - if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 6); + } // life time - if (ctauOmega < cascadeSelections.proplifetime) + if (ctauOmega < cascadeSelections.proplifetime) { SETBIT(bitMap, 10); + } // y cut - if (std::abs(casc.yOmega()) < cascadeSelections.rapCut) + if (std::abs(casc.yOmega()) < cascadeSelections.rapCut) { SETBIT(bitMap, 14); + } } if (masterConfigurations.doCorrelationOmegaPlus) { // DCA daughter to prim.vtx - if (isGoodDCAPosCasc) + if (isGoodDCAPosCasc) { SETBIT(bitMap, 3); + } // comopeting casc.rej - if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 7); + } // life time - if (ctauOmega < cascadeSelections.proplifetime) + if (ctauOmega < cascadeSelections.proplifetime) { SETBIT(bitMap, 11); + } // y cut - if (std::abs(casc.yOmega()) > cascadeSelections.rapCut) + if (std::abs(casc.yOmega()) > cascadeSelections.rapCut) { SETBIT(bitMap, 15); + } } return bitMap; } template - bool isValidTrigger(TTrack track, bool isLeading) + bool isValidTrigger(TTrack const& track, bool isLeading) { if (track.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsTrigger) { return false; // crossed rows @@ -636,10 +900,13 @@ struct HStrangeCorrelation { if (useTheLeadingParticleAsTrigger && !isLeading) { return false; } + if (trackSelection.doITSChi2Selection && track.itsChi2NCl() > trackSelection.chi2ITSfit) { + return false; + } return true; } template - bool isValidAssocHadron(TTrack track) + bool isValidAssocHadron(TTrack const& track) { if (track.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { return false; // crossed rows @@ -664,68 +931,86 @@ struct HStrangeCorrelation { if (track.pt() > axisRanges[2][1] || track.pt() < axisRanges[2][0]) { return false; } + if (trackSelection.doITSChi2Selection && track.itsChi2NCl() > trackSelection.chi2ITSfit) { + return false; + } return true; } // V0selection in PbPb template - bool v0SelectedPbPb(TV0 v0) + bool v0SelectedPbPb(TV0 const& v0) { // v0radius - if (v0.v0radius() < v0Selection.v0RadiusMin) + if (v0.v0radius() < v0Selection.v0RadiusMin) { return false; - if (v0.v0radius() > v0Selection.v0RadiusMax) + } + if (v0.v0radius() > v0Selection.v0RadiusMax) { return false; + } // v0cosPA - if (v0.v0cosPA() < v0Selection.v0cospa) + if (v0.v0cosPA() < v0Selection.v0cospa) { return false; + } // dcaV0daughters - if (v0.dcaV0daughters() > v0Selection.dcaV0dau) + if (v0.dcaV0daughters() > v0Selection.dcaV0dau) { return false; + } return true; } // cascadeselection in PbPb template - bool cascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) + bool cascadeSelectedPbPb(TCascade const& casc, float pvx, float pvy, float pvz) { // bachBaryonCosPA - if (casc.bachBaryonCosPA() < cascadeSelections.bachBaryonCosPA) + if (casc.bachBaryonCosPA() < cascadeSelections.bachBaryonCosPA) { return false; + } // bachBaryonDCAxyToPV - if (std::abs(casc.bachBaryonDCAxyToPV()) > cascadeSelections.bachBaryonDCAxyToPV) + if (std::abs(casc.bachBaryonDCAxyToPV()) > cascadeSelections.bachBaryonDCAxyToPV) { return false; + } // casccosPA - if (casc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa) + if (casc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa) { return false; + } // dcacascdaughters float ptDepCut = cascadeSelections.dcaCacsDauPar0; - if (casc.pt() > cascadeSelections.lowPtForCascDaugPtDep && casc.pt() < cascadeSelections.highPtForCascDaugPtDep) + if (casc.pt() > cascadeSelections.lowPtForCascDaugPtDep && casc.pt() < cascadeSelections.highPtForCascDaugPtDep) { ptDepCut = cascadeSelections.dcaCacsDauPar1; - else if (casc.pt() > cascadeSelections.highPtForCascDaugPtDep) + } else if (casc.pt() > cascadeSelections.highPtForCascDaugPtDep) { ptDepCut = cascadeSelections.dcaCacsDauPar2; - if (casc.dcacascdaughters() > ptDepCut) + } + if (casc.dcacascdaughters() > ptDepCut) { return false; + } // dcaV0daughters - if (casc.dcaV0daughters() > cascadeSelections.cascdcaV0dau) + if (casc.dcaV0daughters() > cascadeSelections.cascdcaV0dau) { return false; + } // dcav0topv - if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV) + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV) { return false; + } // cascradius - if (casc.cascradius() < cascadeSelections.cascRadius) + if (casc.cascradius() < cascadeSelections.cascRadius) { return false; + } // v0radius - if (casc.v0radius() < cascadeSelections.cascv0RadiusMin) + if (casc.v0radius() < cascadeSelections.cascv0RadiusMin) { return false; + } // v0cosPA - if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascadeSelections.cascv0cospa) + if (casc.v0cosPA(pvx, pvy, pvz) < cascadeSelections.cascv0cospa) { return false; + } // lambdaMassWin - if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow) { return false; + } return true; } - double calculateAverageDeltaPhiStar(double* trigg, double* assoc, double B) + double calculateAverageDeltaPhiStar(std::array const& trigg, std::array const& assoc, double B) { double dPhiStar = 0; double dPhiStarMean = 0; @@ -741,7 +1026,7 @@ struct HStrangeCorrelation { return dPhiStarMean; } - void fillTriggerHistogram(std::shared_ptr hist, double pt, double mult, float eff, float effUncert, float purity, float purityErr) + void fillTriggerHistogram(std::shared_ptr const& hist, double pt, double mult, float eff, float effUncert, float purity, float purityErr) { int binx = hist->GetXaxis()->FindBin(pt); int biny = hist->GetYaxis()->FindBin(mult); @@ -752,10 +1037,10 @@ struct HStrangeCorrelation { hist->SetBinContent(binx, biny, newContent); hist->SetBinError(binx, biny, newUncert); } - void fillCorrelationHistogram(std::shared_ptr hist, double binFillThn[], float etaWeight, float efficiency, float totalEffUncert, float purity, float totalPurityUncert) + void fillCorrelationHistogram(std::shared_ptr const& hist, std::array const& binFillThn, float etaWeight, float efficiency, float totalEffUncert, float purity, float totalPurityUncert) { - float previousContent, previousError2, currentContent, currentError2; - int bin = hist->GetBin(binFillThn); + float previousContent = 0.0f, previousError2 = 0.0f, currentContent = 0.0f, currentError2 = 0.0f; + int bin = hist->GetBin(binFillThn.data()); previousContent = hist->GetBinContent(bin); previousError2 = hist->GetBinError2(bin); currentContent = previousContent + etaWeight * purity / (efficiency); @@ -780,30 +1065,37 @@ struct HStrangeCorrelation { } bool firstLoop = false; for (auto const& triggerTrack : triggers) { - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } auto trigg = triggerTrack.track_as(); - if (!isValidTrigger(trigg, triggerTrack.isLeading())) + if (!isValidTrigger(trigg, triggerTrack.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { continue; + } float efficiencyTrigg = 1.0f; float efficiencyTriggError = 0.0f; float purityTrigg = 1.0f; float purityTriggErr = 0.0; - double bintrig[4] = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; + std::array bintrig = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; if (efficiencyFlags.applyEfficiencyForTrigger) { if (!efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { efficiencyTrigg = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); - if (efficiencyFlags.applyPurityTrigger) + if (efficiencyFlags.applyPurityTrigger) { purityTrigg = hPurityHadron->Interpolate(trigg.pt()); + } if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyTriggError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); - if (efficiencyFlags.applyPurityTrigger) + if (efficiencyFlags.applyPurityTrigger) { purityTriggErr = hPurityHadron->Interpolate(trigg.pt()); + } } } else { - efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); + efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); if (efficiencyFlags.applyEfficiencyPropagation) { - efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); + efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); } } if (efficiencyTrigg == 0) { // check for zero efficiency, do not apply if the case @@ -817,12 +1109,13 @@ struct HStrangeCorrelation { } double triggSign = trigg.sign(); - double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + std::array triggForDeltaPhiStar = {trigg.phi(), trigg.pt(), triggSign}; if (mixingInBf) { currentCollision.addValidParticle(trigg.eta(), trigg.phi(), trigg.pt(), -1, efficiencyTrigg, efficiencyTriggError, -1); - if (firstLoop) + if (firstLoop) { continue; + } } for (auto const& assocCandidate : assocs) { firstLoop = true; @@ -831,11 +1124,13 @@ struct HStrangeCorrelation { //---] syst cuts [--- if ((masterConfigurations.doPPAnalysis && (assoc.v0radius() < v0Selection.v0RadiusMin || assoc.v0radius() > v0Selection.v0RadiusMax || std::abs(assoc.dcapostopv()) < v0Selection.dcapostopv || std::abs(assoc.dcanegtopv()) < v0Selection.dcanegtopv || - assoc.v0cosPA() < v0Selection.v0cospa || assoc.dcaV0daughters() > v0Selection.dcaV0dau))) + assoc.v0cosPA() < v0Selection.v0cospa || assoc.dcaV0daughters() > v0Selection.dcaV0dau))) { continue; + } - if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(assoc)) + if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(assoc)) { continue; + } uint64_t selMap = v0selectionBitmap(assoc, pvx, pvy, pvz); @@ -854,12 +1149,15 @@ struct HStrangeCorrelation { } //---] track quality check [--- - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); @@ -870,16 +1168,19 @@ struct HStrangeCorrelation { float pttrigger = trigg.pt(); // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } - TH2F* hEfficiencyV0[3]; - TH2F* hEfficiencyUncertaintyV0[3]; - THnF* hEfficiencyV0MultVsPhi[3]; + std::array hEfficiencyV0{nullptr, nullptr, nullptr}; + std::array hEfficiencyUncertaintyV0{nullptr, nullptr, nullptr}; + std::array hEfficiencyV0MultVsPhi{nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyV0MultVsPhi[0] = hEfficiencyK0ShortMultVsPhi; hEfficiencyV0MultVsPhi[1] = hEfficiencyLambdaMultVsPhi; @@ -907,14 +1208,19 @@ struct HStrangeCorrelation { double ptProton = postrack.pt(); double ptPion = negtrack.pt(); double signProton = postrack.sign(); + double signPion = negtrack.sign(); if (assocCandidate.compatible(2, trackSelection.dEdxCompatibility)) { phiProton = negtrack.phi(); etaProton = negtrack.eta(); ptProton = negtrack.pt(); signProton = negtrack.sign(); + phiPion = postrack.phi(); + etaPion = postrack.eta(); + ptPion = postrack.pt(); + signPion = postrack.sign(); } - double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; - double assocForDeltaPhiStarPion[] = {phiPion, ptPion, -1}; + std::array assocForDeltaPhiStar = {phiProton, ptProton, signProton}; + std::array assocForDeltaPhiStarPion = {phiPion, ptPion, signPion}; static_for<0, 2>([&](auto i) { constexpr int Index = i.value; @@ -923,14 +1229,16 @@ struct HStrangeCorrelation { float efficiencyError = 0.0f; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - double bin[4] = {ptassoc, assoc.eta(), assoc.phi(), mult}; - efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin)); - if (efficiencyFlags.applyEfficiencyPropagation) - efficiencyError = hEfficiencyV0MultVsPhi[Index]->GetBinError(hEfficiencyV0MultVsPhi[Index]->GetBin(bin)); + std::array bin = {ptassoc, assoc.eta(), assoc.phi(), mult}; + efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin.data())); + if (efficiencyFlags.applyEfficiencyPropagation) { + efficiencyError = hEfficiencyV0MultVsPhi[Index]->GetBinError(hEfficiencyV0MultVsPhi[Index]->GetBin(bin.data())); + } } else { efficiency = hEfficiencyV0[Index]->Interpolate(ptassoc, assoc.eta()); - if (efficiencyFlags.applyEfficiencyPropagation) + if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyError = hEfficiencyUncertaintyV0[Index]->Interpolate(ptassoc, assoc.eta()); + } } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case @@ -941,9 +1249,30 @@ struct HStrangeCorrelation { totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyError, 2) + std::pow(efficiencyTriggError * efficiency, 2)); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThnOppositeSignDaugher = {computeDeltaPhi(trigg.phi(), phiPion), trigg.eta() - etaPion, ptPion, pttrigger, pvz, mult}; + std::array binFillThnSameSignDaugher = {computeDeltaPhi(trigg.phi(), phiProton), trigg.eta() - etaProton, ptProton, pttrigger, pvz, mult}; + if ((triggSign < Neutral && !assocCandidate.compatible(2, trackSelection.dEdxCompatibility)) || (triggSign > Neutral && assocCandidate.compatible(2, trackSelection.dEdxCompatibility))) { + std::swap(binFillThnOppositeSignDaugher[1], binFillThnSameSignDaugher[1]); + std::swap(binFillThnOppositeSignDaugher[0], binFillThnSameSignDaugher[0]); + std::swap(binFillThnOppositeSignDaugher[2], binFillThnSameSignDaugher[2]); + } + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { - if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma && !masterConfigurations.fillCorrelationHistWithMass) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && + ((-massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) || + (-massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) || + (+massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma))) { + if (std::abs(deltaphi) < 0.5) { + histos.fill(HIST("sameEvent/InvariantMass/") + HIST(V0names[Index]) + HIST("/hNearSide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + } + if (std::abs(PI - deltaphi) < 0.5) { + histos.fill(HIST("sameEvent/InvariantMass/") + HIST(V0names[Index]) + HIST("/hAwaySide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + } + if (deltaphi > 1.0 && deltaphi < 1.5) { + histos.fill(HIST("sameEvent/InvariantMass/") + HIST(V0names[Index]) + HIST("/hUnderlyingEvent"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + } + } + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -961,9 +1290,10 @@ struct HStrangeCorrelation { } } } - if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && (masterConfigurations.fillCorrelationHistWithMass || (-massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma))) { - if (masterConfigurations.fillCorrelationHistWithMass) { - binFillThn[1] = getV0InvariantMass(assoc); + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && ((-massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma))) { + if (masterConfigurations.doCorrelationsHadronV0daughter) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("_hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("_hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); } fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (std::abs(deltaphi) < checks.towardDeltaEtaRange && doITSClustersQA) { @@ -990,7 +1320,7 @@ struct HStrangeCorrelation { } } } - if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma && !masterConfigurations.fillCorrelationHistWithMass) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -1021,6 +1351,10 @@ struct HStrangeCorrelation { } else { fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); } + if (masterConfigurations.doCorrelationsHadronV0daughter) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("_hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("_hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); + } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { if (mixingInBf) { @@ -1033,15 +1367,17 @@ struct HStrangeCorrelation { }); } } - if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) + if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) { return; + } int binnumb = binMult * nBinsVtxZ + binVtxZ; int hastirgorassoc = masterConfigurations.collisionHasTriggOrAssoc; if ((hastirgorassoc == 1 && currentCollision.trigParticles.empty()) || (hastirgorassoc == 2 && currentCollision.assocParticles.empty()) || (hastirgorassoc == 3 && currentCollision.trigParticles.empty() && currentCollision.assocParticles.empty()) || - (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) + (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) { return; + } for (const auto& collision : validCollisions[binnumb]) { BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; // When 'collisionHasTriggOrAssoc' = 0: @@ -1067,7 +1403,7 @@ struct HStrangeCorrelation { if (masterConfigurations.doMirroringInDelataEta) { deltaeta = std::abs(deltaeta); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; static_for<0, 2>([&](auto i) { constexpr int Index = i.value; if (Index == assoc.type && assoc.region == 0) { @@ -1086,8 +1422,9 @@ struct HStrangeCorrelation { if (validCollisions[binnumb].size() >= static_cast(masterConfigurations.mixingParameter)) { validCollisions[binnumb].erase(validCollisions[binnumb].begin()); } - if (!currentCollision.trigParticles.empty()) + if (!currentCollision.trigParticles.empty()) { validCollisions[binnumb].push_back(currentCollision); + } } void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, bool mixingInBf, float pvx, float pvy, float pvz, float mult, double bField) @@ -1107,43 +1444,51 @@ struct HStrangeCorrelation { } bool firstLoop = false; for (auto const& triggerTrack : triggers) { - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } auto trigg = triggerTrack.track_as(); - if (!isValidTrigger(trigg, triggerTrack.isLeading())) + if (!isValidTrigger(trigg, triggerTrack.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { continue; + } float efficiencyTrigg = 1.0f; float efficiencyTriggError = 0.0f; float purityTrigg = 1.0f; float purityTriggErr = 0.0f; if (efficiencyFlags.applyEfficiencyForTrigger) { - double bintrig[4] = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; + std::array bintrig = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTrigg = hEfficiencyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); } else if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); + efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); } else { efficiencyTrigg = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTrigg = hPurityHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTrigg = hPurityHadron->Interpolate(trigg.pt()); + } } if (efficiencyFlags.applyEfficiencyPropagation) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTriggError = hEfficiencyUncertaintyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); - else if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) - efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); - else + } else if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { + efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); + } else { efficiencyTriggError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTriggErr = hPurityUncertaintyHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTriggErr = hPurityUncertaintyHadron->Interpolate(trigg.pt()); + } } } if (efficiencyTrigg == 0) { // check for zero efficiency, do not apply if the case @@ -1155,12 +1500,13 @@ struct HStrangeCorrelation { fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesCascade")), trigg.pt(), mult, efficiencyTrigg, efficiencyTriggError, purityTrigg, purityTriggErr); } double triggSign = trigg.sign(); - double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + std::array triggForDeltaPhiStar = {trigg.phi(), trigg.pt(), triggSign}; if (mixingInBf) { currentCollision.addValidParticle(trigg.eta(), trigg.phi(), trigg.pt(), -1, efficiencyTrigg, efficiencyTriggError, -1); - if (firstLoop) + if (firstLoop) { continue; + } } for (auto const& assocCandidate : assocs) { firstLoop = true; @@ -1176,10 +1522,12 @@ struct HStrangeCorrelation { assoc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa || assoc.cascradius() < cascadeSelections.cascRadius || std::abs(assoc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV || - std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) + std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) { continue; - if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(assoc, pvx, pvy, pvz)) + } + if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(assoc, pvx, pvy, pvz)) { continue; + } uint64_t cascselMap = cascadeselectionBitmap(assoc, pvx, pvy, pvz); //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); @@ -1210,14 +1558,17 @@ struct HStrangeCorrelation { ptProton = negtrack.pt(); signProton = negtrack.sign(); } - double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; + std::array assocForDeltaPhiStar = {phiProton, ptProton, signProton}; //---] track quality check [--- - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || bachtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || bachtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); @@ -1228,15 +1579,18 @@ struct HStrangeCorrelation { float pttrigger = trigg.pt(); // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } - TH2F* hEfficiencyCascade[4]; - THnF* hEfficiencyCascadeMultVsPhi[4]; + std::array hEfficiencyCascade{nullptr, nullptr, nullptr, nullptr}; + std::array hEfficiencyCascadeMultVsPhi{nullptr, nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyCascadeMultVsPhi[0] = hEfficiencyXiMinusMultVsPhi; hEfficiencyCascadeMultVsPhi[1] = hEfficiencyXiPlusMultVsPhi; @@ -1249,7 +1603,7 @@ struct HStrangeCorrelation { hEfficiencyCascade[3] = hEfficiencyOmegaPlus; } - TH2F* hEfficiencyUncertaintyCascade[4]; + std::array hEfficiencyUncertaintyCascade{nullptr, nullptr, nullptr, nullptr}; hEfficiencyUncertaintyCascade[0] = hEfficiencyUncertaintyXiMinus; hEfficiencyUncertaintyCascade[1] = hEfficiencyUncertaintyXiPlus; hEfficiencyUncertaintyCascade[2] = hEfficiencyUncertaintyOmegaMinus; @@ -1271,14 +1625,16 @@ struct HStrangeCorrelation { float efficiencyError = 0.0f; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - double bin[4] = {ptassoc, assoc.eta(), assoc.phi(), mult}; - efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin)); - if (efficiencyFlags.applyEfficiencyPropagation) - efficiencyError = hEfficiencyCascadeMultVsPhi[Index]->GetBinError(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin)); + std::array bin = {ptassoc, assoc.eta(), assoc.phi(), mult}; + efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin.data())); + if (efficiencyFlags.applyEfficiencyPropagation) { + efficiencyError = hEfficiencyCascadeMultVsPhi[Index]->GetBinError(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin.data())); + } } else { efficiency = hEfficiencyCascade[Index]->Interpolate(ptassoc, assoc.eta()); - if (efficiencyFlags.applyEfficiencyPropagation) + if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyError = hEfficiencyUncertaintyCascade[Index]->Interpolate(ptassoc, assoc.eta()); + } } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case @@ -1289,36 +1645,39 @@ struct HStrangeCorrelation { totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyError, 2) + std::pow(efficiencyTriggError * efficiency, 2)); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index + 3) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(cascselMap, Index) && TESTBIT(cascselMap, Index + 4) && TESTBIT(cascselMap, Index + 8) && TESTBIT(cascselMap, Index + 12)))) { if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); - if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) + if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) { histos.fill(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); - else + } else { histos.fill(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); - if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) + if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) { histos.fill(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); - else + } else { histos.fill(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); - if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) + if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) { histos.fill(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); - else + } else { histos.fill(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { @@ -1346,15 +1705,17 @@ struct HStrangeCorrelation { }); } } - if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) + if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) { return; + } int binnumb = binMult * nBinsVtxZ + binVtxZ; int hastirgorassoc = masterConfigurations.collisionHasTriggOrAssoc; if ((hastirgorassoc == 1 && currentCollision.trigParticles.empty()) || (hastirgorassoc == 2 && currentCollision.assocParticles.empty()) || (hastirgorassoc == 3 && currentCollision.trigParticles.empty() && currentCollision.assocParticles.empty()) || - (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) + (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) { return; + } for (const auto& collision : validCollisions[binnumb]) { BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; histos.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision.pvz, collision.mult})); @@ -1375,7 +1736,7 @@ struct HStrangeCorrelation { if (masterConfigurations.doMirroringInDelataEta) { deltaeta = std::abs(deltaeta); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; static_for<0, 3>([&](auto i) { constexpr int Index = i.value; if (Index == assoc.type && assoc.region == 0) { @@ -1394,45 +1755,55 @@ struct HStrangeCorrelation { if (validCollisions[binnumb].size() >= static_cast(masterConfigurations.mixingParameter)) { validCollisions[binnumb].erase(validCollisions[binnumb].begin()); } - if (!currentCollision.trigParticles.empty()) + if (!currentCollision.trigParticles.empty()) { validCollisions[binnumb].push_back(currentCollision); + } } template void fillCorrelationsHadron(TTriggers const& triggers, THadrons const& assocs, bool mixing, float pvz, float mult, double bField) { for (auto const& triggerTrack : triggers) { - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } auto trigg = triggerTrack.template track_as(); - if (!isValidTrigger(trigg, triggerTrack.isLeading())) + if (!isValidTrigger(trigg, triggerTrack.isLeading())) { continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } float efficiencyTrigger = 1.0f; float efficiencyTriggerError = 0.0f; float purityTrigger = 1.0f; float purityTriggerError = 0.0f; if (efficiencyFlags.applyEfficiencyForTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTrigger = hEfficiencyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); - else + } else { efficiencyTrigger = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTrigger = hPurityHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTrigger = hPurityHadron->Interpolate(trigg.pt()); + } } if (efficiencyFlags.applyEfficiencyPropagation) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTriggerError = hEfficiencyUncertaintyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); - else + } else { efficiencyTriggerError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTriggerError = hPurityUncertaintyHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTriggerError = hPurityUncertaintyHadron->Interpolate(trigg.pt()); + } } } if (efficiencyTrigger == 0) { // check for zero efficiency, do not apply if the case @@ -1441,29 +1812,35 @@ struct HStrangeCorrelation { } } if (!mixing) { - if constexpr (requires { triggerTrack.extra(); }) + if constexpr (requires { triggerTrack.extra(); }) { fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesPion")), trigg.pt(), mult, efficiencyTrigger, efficiencyTriggerError, purityTrigger, purityTriggerError); - else + } else { fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesHadron")), trigg.pt(), mult, efficiencyTrigger, efficiencyTriggerError, purityTrigger, purityTriggerError); + } } double triggSign = trigg.sign(); - double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + std::array triggForDeltaPhiStar = {trigg.phi(), trigg.pt(), triggSign}; for (auto const& assocTrack : assocs) { auto assoc = assocTrack.template track_as(); //---] removing autocorrelations [--- if (doAutocorrelationRejection) { if (trigg.globalIndex() == assoc.globalIndex()) { - if constexpr (requires { assocTrack.nSigmaTPCPi(); }) + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { histos.fill(HIST("hNumberOfRejectedPairsPion"), 0.5); - else + } else { histos.fill(HIST("hNumberOfRejectedPairsHadron"), 0.5); + } continue; } } //---] track quality check [--- - if (!isValidAssocHadron(assoc)) + if (!isValidAssocHadron(assoc)) { continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(assocTrack.mcMask(), 13)) { + continue; + } if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) { continue; } @@ -1476,7 +1853,7 @@ struct HStrangeCorrelation { float pttrigger = trigg.pt(); double assocSign = assoc.sign(); - double assocForDeltaPhiStar[] = {assoc.phi(), assoc.pt(), assocSign}; + std::array assocForDeltaPhiStar = {assoc.phi(), assoc.pt(), assocSign}; float etaWeight = 1.; if (checks.doOnTheFlyFlattening) { @@ -1485,12 +1862,15 @@ struct HStrangeCorrelation { } // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } float efficiency = 1; float purity = 1.0f; @@ -1501,29 +1881,34 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { efficiency = hEfficiencyPion->Interpolate(ptassoc, assoc.eta()); - if (efficiencyFlags.applyEfficiencyPropagation) + if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyUncertainty = hEfficiencyUncertaintyPion->Interpolate(ptassoc, assoc.eta()); + } } else { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiency = hEfficiencyHadronMult->Interpolate(ptassoc, assoc.eta(), mult); - else + } else { efficiency = hEfficiencyHadron->Interpolate(ptassoc, assoc.eta()); + } if (efficiencyFlags.applyPurityHadron) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purity = hPurityHadronMult->Interpolate(ptassoc, mult); - else + } else { purity = hPurityHadron->Interpolate(ptassoc); + } } if (efficiencyFlags.applyEfficiencyPropagation) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyUncertainty = hEfficiencyUncertaintyHadronMult->Interpolate(ptassoc, assoc.eta(), mult); - else + } else { efficiencyUncertainty = hEfficiencyUncertaintyHadron->Interpolate(ptassoc, assoc.eta()); + } if (efficiencyFlags.applyPurityHadron) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityUncertainty = hPurityUncertaintyHadronMult->Interpolate(ptassoc, mult); - else + } else { purityUncertainty = hPurityUncertaintyHadron->Interpolate(ptassoc); + } } } } @@ -1537,7 +1922,7 @@ struct HStrangeCorrelation { totalPurityUncert = std::sqrt(std::pow(purityTrigger * purityUncertainty, 2) + std::pow(purity * purityTriggerError, 2)); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); if (!mixing) { if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { @@ -1569,51 +1954,58 @@ struct HStrangeCorrelation { void init(InitContext const&) { zorroSummary.setObject(zorro.getZorroSummary()); - mRunNumber = 0; - mRunNumberZorro = 0; - hEfficiencyPion = 0x0; - hEfficiencyK0Short = 0x0; - hEfficiencyLambda = 0x0; - hEfficiencyAntiLambda = 0x0; - hEfficiencyXiMinus = 0x0; - hEfficiencyXiPlus = 0x0; - hEfficiencyOmegaMinus = 0x0; - hEfficiencyOmegaPlus = 0x0; - hEfficiencyUncertaintyTrigger = 0x0; - hEfficiencyUncertaintyXiMinus = 0x0; - hEfficiencyUncertaintyXiPlus = 0x0; - hEfficiencyUncertaintyOmegaMinus = 0x0; - hEfficiencyUncertaintyOmegaPlus = 0x0; - hEfficiencyUncertaintyPion = 0x0; - hEfficiencyUncertaintyK0Short = 0x0; - hEfficiencyUncertaintyLambda = 0x0; - hEfficiencyUncertaintyAntiLambda = 0x0; - - hEfficiencyHadron = 0x0; - hPurityHadron = 0x0; - hPurityUncertaintyHadron = 0x0; - hEfficiencyUncertaintyHadron = 0x0; + hEfficiencyPion = nullptr; + hEfficiencyK0Short = nullptr; + hEfficiencyLambda = nullptr; + hEfficiencyAntiLambda = nullptr; + hEfficiencyXiMinus = nullptr; + hEfficiencyXiPlus = nullptr; + hEfficiencyOmegaMinus = nullptr; + hEfficiencyOmegaPlus = nullptr; + hEfficiencyUncertaintyTrigger = nullptr; + hEfficiencyUncertaintyXiMinus = nullptr; + hEfficiencyUncertaintyXiPlus = nullptr; + hEfficiencyUncertaintyOmegaMinus = nullptr; + hEfficiencyUncertaintyOmegaPlus = nullptr; + hEfficiencyUncertaintyPion = nullptr; + hEfficiencyUncertaintyK0Short = nullptr; + hEfficiencyUncertaintyLambda = nullptr; + hEfficiencyUncertaintyAntiLambda = nullptr; + + hEfficiencyHadron = nullptr; + hPurityHadron = nullptr; + hPurityUncertaintyHadron = nullptr; + hEfficiencyUncertaintyHadron = nullptr; // set bitmap for convenience doCorrelation = 0; - if (masterConfigurations.doCorrelationK0Short) + if (masterConfigurations.doCorrelationK0Short) { SETBIT(doCorrelation, 0); - if (masterConfigurations.doCorrelationLambda) + } + if (masterConfigurations.doCorrelationLambda) { SETBIT(doCorrelation, 1); - if (masterConfigurations.doCorrelationAntiLambda) + } + if (masterConfigurations.doCorrelationAntiLambda) { SETBIT(doCorrelation, 2); - if (masterConfigurations.doCorrelationXiMinus) + } + if (masterConfigurations.doCorrelationXiMinus) { SETBIT(doCorrelation, 3); - if (masterConfigurations.doCorrelationXiPlus) + } + if (masterConfigurations.doCorrelationXiPlus) { SETBIT(doCorrelation, 4); - if (masterConfigurations.doCorrelationOmegaMinus) + } + if (masterConfigurations.doCorrelationOmegaMinus) { SETBIT(doCorrelation, 5); - if (masterConfigurations.doCorrelationOmegaPlus) + } + if (masterConfigurations.doCorrelationOmegaPlus) { SETBIT(doCorrelation, 6); - if (masterConfigurations.doCorrelationPion) + } + if (masterConfigurations.doCorrelationPion) { SETBIT(doCorrelation, 7); - if (masterConfigurations.doCorrelationHadron) + } + if (masterConfigurations.doCorrelationHadron) { SETBIT(doCorrelation, 8); + } // Store axis ranges to prevent spurious filling // axis status: @@ -1689,86 +2081,100 @@ struct HStrangeCorrelation { // ===] delta-phi [=== if (!preAxisDeltaPhi.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesDeltaPhiOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesDeltaPhiOrig.size()) - offset; i++) { edgesDeltaPhi.emplace_back(edgesDeltaPhiOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesDeltaPhiOrig[0]; double delta = (edgesDeltaPhiOrig[1] - edgesDeltaPhiOrig[0]) / preAxisDeltaPhi.nBins.value(); - for (int i = offset; i < preAxisDeltaPhi.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisDeltaPhi.nBins.value() + 1 - offset; i++) { edgesDeltaPhi.emplace_back(min + static_cast(i) * delta); + } } // ===] delta-eta [=== if (!preAxisDeltaEta.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesDeltaEtaOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesDeltaEtaOrig.size()) - offset; i++) { edgesDeltaEta.emplace_back(edgesDeltaEtaOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesDeltaEtaOrig[0]; double delta = (edgesDeltaEtaOrig[1] - edgesDeltaEtaOrig[0]) / preAxisDeltaEta.nBins.value(); - for (int i = offset; i < preAxisDeltaEta.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisDeltaEta.nBins.value() + 1 - offset; i++) { edgesDeltaEta.emplace_back(min + static_cast(i) * delta); + } } // ===] pt assoc [=== if (!preAxisPtAssoc.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesPtAssocOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesPtAssocOrig.size()) - offset; i++) { edgesPtAssoc.emplace_back(edgesPtAssocOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesPtAssocOrig[0]; double delta = (edgesPtAssocOrig[1] - edgesPtAssocOrig[0]) / preAxisPtAssoc.nBins.value(); - for (int i = offset; i < preAxisPtAssoc.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisPtAssoc.nBins.value() + 1 - offset; i++) { edgesPtAssoc.emplace_back(min + static_cast(i) * delta); + } } // ===] pt trigger [=== if (!preAxisPtTrigger.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesPtTriggerOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesPtTriggerOrig.size()) - offset; i++) { edgesPtTrigger.emplace_back(edgesPtTriggerOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesPtTriggerOrig[0]; double delta = (edgesPtTriggerOrig[1] - edgesPtTriggerOrig[0]) / preAxisPtTrigger.nBins.value(); - for (int i = offset; i < preAxisPtTrigger.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisPtTrigger.nBins.value() + 1 - offset; i++) { edgesPtTrigger.emplace_back(min + static_cast(i) * delta); + } } // ===] vtx Z [=== if (!preAxisVtxZ.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesVtxZOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesVtxZOrig.size()) - offset; i++) { edgesVtxZ.emplace_back(edgesVtxZOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesVtxZOrig[0]; double delta = (edgesVtxZOrig[1] - edgesVtxZOrig[0]) / preAxisVtxZ.nBins.value(); - for (int i = offset; i < preAxisVtxZ.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisVtxZ.nBins.value() + 1 - offset; i++) { edgesVtxZ.emplace_back(min + static_cast(i) * delta); + } } // ===] mult percentile [=== if (!preAxisMult.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesMultOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesMultOrig.size()) - offset; i++) { edgesMult.emplace_back(edgesMultOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesMultOrig[0]; double delta = (edgesMultOrig[1] - edgesMultOrig[0]) / preAxisMult.nBins.value(); - for (int i = offset; i < preAxisMult.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisMult.nBins.value() + 1 - offset; i++) { edgesMult.emplace_back(min + static_cast(i) * delta); + } } // ===] multiplicity count [=== if (!preAxisMultiplicity.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesMultiplicityOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesMultiplicityOrig.size()) - offset; i++) { edgesMultiplicity.emplace_back(edgesMultiplicityOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesMultiplicityOrig[0]; double delta = (edgesMultiplicityOrig[1] - edgesMultiplicityOrig[0]) / preAxisMultiplicity.nBins.value(); - for (int i = offset; i < preAxisMultiplicity.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisMultiplicity.nBins.value() + 1 - offset; i++) { edgesMultiplicity.emplace_back(min + static_cast(i) * delta); + } } LOGF(info, "Initialized THnF axis delta-phi with %i bins.", edgesDeltaPhi.size() - 1); @@ -1787,6 +2193,158 @@ struct HStrangeCorrelation { const AxisSpec axisMultNDim{edgesMult, "mult percentile"}; const AxisSpec axisMultiplicityNDim{edgesMultiplicity, "Multiplicity"}; + if (doprocessPairLossK0MC) { + const AxisSpec axisPairLossEventStage{6, -0.5, 5.5, "Event-selection stage"}; + const AxisSpec axisPairLossNRecoCollisions{11, -0.5, 10.5, "#it{N}_{reco collisions} per MC collision"}; + const AxisSpec axisPairLossStage{PairLossK0NStages, -0.5, static_cast(PairLossK0NStages) - 0.5, "Reconstruction stage"}; + const AxisSpec axisPairLossFinalObjectState{4, -0.5, 3.5, "Final h-K^{0}_{S} object state"}; + const AxisSpec axisPairLossTrackLevelState{4, -0.5, 3.5, "Trigger and K^{0}_{S}-daughter track state"}; + const AxisSpec axisPairLossDaughterState{4, -0.5, 3.5, "K^{0}_{S}-daughter track state"}; + const AxisSpec axisPairLossFieldSign{3, -1.5, 1.5, "sgn(#it{B}_{z})"}; + const AxisSpec axisPairLossChargeProduct{3, -1.5, 1.5, "sgn(#it{q}_{h}#it{q}_{#pi})"}; + const AxisSpec axisPairLossMatchType{7, -0.5, 6.5, "Matched-object category"}; + const AxisSpec axisPairLossMatchCount{11, -0.5, 10.5, "#it{N}_{matched objects} per truth pair"}; + const AxisSpec axisPairLossTPCCrossedRows{161, -0.5, 160.5, "#it{N}_{TPC crossed rows}"}; + const AxisSpec axisPairLossTPCSharedClusters{161, -0.5, 160.5, "#it{N}_{TPC shared clusters}"}; + const AxisSpec axisPairLossITSClusters{8, -0.5, 7.5, "#it{N}_{ITS clusters}"}; + const AxisSpec axisPairLossLayer0{2, -0.5, 1.5, "Hit in ITS layer 0"}; + const AxisSpec axisPairLossMassNSigma{120, -12.0, 12.0, "#it{n}_{#sigma}(m_{#pi^{+}#pi^{-}}; K^{0}_{S})"}; + const AxisSpec axisPairLossCosPA{100, 0.9, 1.0, "cos(#theta_{PA})"}; + const AxisSpec axisPairLossDcaDaughters{100, 0.0, 2.0, "DCA(#pi^{+}, #pi^{-}) (cm)"}; + const AxisSpec axisPairLossDeltaPhiStarValidity{2, -0.5, 1.5, "Validity of min |#Delta#varphi^{*}_{h-#pi}|"}; + const AxisSpec axisPairLossTruthDeltaPhi{edgesDeltaPhi, "#Delta#varphi_{h-K^{0}_{S}}^{gen} (rad)"}; + const AxisSpec axisPairLossRecoDeltaPhi{edgesDeltaPhi, "#Delta#varphi_{h-K^{0}_{S}}^{reco} (rad)"}; + const AxisSpec axisPairLossTruthDeltaEta{edgesDeltaEta, "#Delta#eta_{h-K^{0}_{S}}^{gen}"}; + const AxisSpec axisPairLossRecoDeltaEta{edgesDeltaEta, "#Delta#eta_{h-K^{0}_{S}}^{reco}"}; + const AxisSpec axisPairLossTruthK0Pt{edgesPtAssoc, "#it{p}_{T,K^{0}_{S}}^{gen} (GeV/#it{c})"}; + const AxisSpec axisPairLossRecoK0Pt{edgesPtAssoc, "#it{p}_{T,K^{0}_{S}}^{reco} (GeV/#it{c})"}; + const AxisSpec axisPairLossTruthTriggerPt{edgesPtTrigger, "#it{p}_{T,h}^{gen} (GeV/#it{c})"}; + const AxisSpec axisPairLossRecoTriggerPt{edgesPtTrigger, "#it{p}_{T,h}^{reco} (GeV/#it{c})"}; + const AxisSpec axisPairLossMinDeltaPhiStar{pairLossK0Configurations.axisMinDeltaPhiStar, "min_{#it{r}} |#Delta#varphi^{*}_{h-#pi}(#it{r})| (rad)"}; + const AxisSpec axisPairLossSignedDeltaPhiStar{pairLossK0Configurations.axisSignedDeltaPhiStar, "#Delta#varphi^{*}_{h-#pi}(#it{r}_{min}) (rad)"}; + const AxisSpec axisPairLossDaughterDeltaEta{pairLossK0Configurations.axisDaughterDeltaEta, "#Delta#eta_{h-#pi}^{gen}"}; + const AxisSpec axisPairLossDaughterDeltaPhi{pairLossK0Configurations.axisDaughterDeltaPhi, "#Delta#varphi_{h-#pi}^{gen} (rad)"}; + const AxisSpec axisPairLossTruthDecayRadius{pairLossK0Configurations.axisDecayRadius, "#it{R}_{decay}^{gen}(K^{0}_{S}) (cm)"}; + const AxisSpec axisPairLossRecoV0Radius{pairLossK0Configurations.axisDecayRadius, "#it{R}_{V0}^{reco} (cm)"}; + const double pairLossRadiusMinimum = pairLossK0Configurations.minRadius; + const double pairLossRadiusMaximum = std::max(static_cast(pairLossK0Configurations.maxRadius), pairLossRadiusMinimum + 0.01); + const double pairLossRadiusStep = std::max(static_cast(pairLossK0Configurations.radiusStep), 0.001); + const int pairLossRadiusBins = std::max(1, static_cast(std::ceil((pairLossRadiusMaximum - pairLossRadiusMinimum) / pairLossRadiusStep))); + const AxisSpec axisPairLossRadiusAtMinimum{pairLossRadiusBins, pairLossRadiusMinimum, pairLossRadiusMaximum, "#it{r}_{min} (m)"}; + const AxisSpec axisPairLossTriggerTracksFailureReason{PairLossTriggerTracksNReasons, -0.5, static_cast(PairLossTriggerTracksNReasons) - 0.5, "TriggerTracks first-failing condition"}; + + histos.add("PairLossK0/Event/hCounter", "K0 pair-loss event counter", kTH1F, {axisPairLossEventStage}); + histos.add("PairLossK0/Event/hNRecoCollisions", "reconstructed collisions per MC collision", kTH1F, {axisPairLossNRecoCollisions}); + histos.add("PairLossK0/Stage/hCounts", "pair-loss diagnostic stage counts", kTH1F, {axisPairLossStage}); + histos.add("PairLossK0/Stage/hCountsFindable", "pair-loss diagnostic stage counts for findable K0", kTH1F, {axisPairLossStage}); + histos.add("PairLossK0/Stage/hPhysics", "stages in h-K0 physics variables", kTHnF, {axisPairLossStage, axisPairLossTruthDeltaPhi, axisPairLossTruthDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign}); + histos.add("PairLossK0/Stage/hPhysicsFindable", "stages in h-K0 physics variables for findable K0", kTHnF, {axisPairLossStage, axisPairLossTruthDeltaPhi, axisPairLossTruthDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign}); + histos.add("PairLossK0/Stage/hClose", "stages in trigger-daughter close-pair variables", kTHnF, {axisPairLossStage, axisPairLossMinDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign, axisPairLossChargeProduct}); + histos.add("PairLossK0/Stage/hTriggerTracksFailureReason", "first-failing TriggerTracks condition for best-collision triggers, in h-K0 physics variables", kTHnF, {axisPairLossTriggerTracksFailureReason, axisPairLossTruthDeltaPhi, axisPairLossTruthDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt}); + + histos.add("PairLossK0/State/hFinalObjectStatePhysics", "00/01/10/11 final trigger-K0 object state", kTHnF, {axisPairLossFinalObjectState, axisPairLossTruthDeltaPhi, axisPairLossTruthDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign}); + histos.add("PairLossK0/State/hFinalObjectStateClose", "00/01/10/11 final trigger-K0 object state in close-pair variables", kTHnF, {axisPairLossFinalObjectState, axisPairLossMinDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign, axisPairLossChargeProduct}); + histos.add("PairLossK0/State/hTrackLevelStateClose", "00/01/10/11 trigger-track and both-daughters state", kTHnF, {axisPairLossTrackLevelState, axisPairLossMinDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign, axisPairLossChargeProduct}); + histos.add("PairLossK0/State/hDaughterTrackStateClose", "daughter state: none/negative/positive/both", kTHnF, {axisPairLossDaughterState, axisPairLossMinDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign, axisPairLossChargeProduct}); + + histos.add("PairLossK0/Geometry/hGeneratedDaughters", "generated trigger-daughter geometry", kTHnF, {axisPairLossSignedDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign, axisPairLossChargeProduct}); + histos.add("PairLossK0/Geometry/hFinalDaughters", "geometry for final reconstructed h-K0 pairs", kTHnF, {axisPairLossSignedDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign, axisPairLossChargeProduct}); + histos.add("PairLossK0/Geometry/hRawDeltaPhiVsSignedDeltaPhiStar", "closest daughter raw delta phi versus signed delta phi star", kTH3F, {axisPairLossDaughterDeltaPhi, axisPairLossSignedDeltaPhiStar, axisPairLossFieldSign}); + histos.add("PairLossK0/Geometry/hGeneratedMinDeltaPhiStarVsDecayRadius", "generated minimum delta phi star versus K0 decay radius", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossTruthDecayRadius, axisPairLossTruthK0Pt}); + histos.add("PairLossK0/Geometry/hFinalMinDeltaPhiStarVsDecayRadius", "final-pair minimum delta phi star versus K0 decay radius", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossTruthDecayRadius, axisPairLossTruthK0Pt}); + histos.add("PairLossK0/Geometry/hGeneratedRadiusAtMinimum", "radius of the closest trigger-daughter approach", kTH3F, {axisPairLossRadiusAtMinimum, axisPairLossMinDeltaPhiStar, axisPairLossTruthK0Pt}); + histos.add("PairLossK0/Geometry/hFinalRadiusAtMinimum", "radius of the closest approach for final pairs", kTH3F, {axisPairLossRadiusAtMinimum, axisPairLossMinDeltaPhiStar, axisPairLossTruthK0Pt}); + histos.add("PairLossK0/Geometry/hDeltaPhiStarValidity", "minimum delta-phi-star validity", kTH2F, {axisPairLossDeltaPhiStarValidity, axisPairLossTruthK0Pt}); + histos.add("PairLossK0/Geometry/hAutocorrelationRejected", "pairs rejected only by reconstructed track-ID autocorrelation", kTHnF, {axisPairLossMinDeltaPhiStar, axisPairLossDaughterDeltaEta, axisPairLossTruthK0Pt, axisPairLossTruthTriggerPt, axisPairLossFieldSign}); + + histos.add("PairLossK0/Matching/hNMatches", "number of matches for each truth pair", kTH2F, {axisPairLossMatchType, axisPairLossMatchCount}); + histos.add("PairLossK0/Response/hTriggerPt", "trigger pT response", kTH2F, {axisPairLossTruthTriggerPt, axisPairLossRecoTriggerPt}); + histos.add("PairLossK0/Response/hK0Pt", "K0 pT response", kTH2F, {axisPairLossTruthK0Pt, axisPairLossRecoK0Pt}); + histos.add("PairLossK0/Response/hDeltaPhi", "h-K0 delta-phi response", kTH2F, {axisPairLossTruthDeltaPhi, axisPairLossRecoDeltaPhi}); + histos.add("PairLossK0/Response/hDeltaEta", "h-K0 delta-eta response", kTH2F, {axisPairLossTruthDeltaEta, axisPairLossRecoDeltaEta}); + + histos.add("PairLossK0/TrackQA/hTriggerTPCPairWeighted", "pair-weighted trigger TPC quality", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossTPCCrossedRows, axisPairLossTPCSharedClusters}); + histos.add("PairLossK0/TrackQA/hTriggerITSPairWeighted", "pair-weighted trigger ITS quality", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossITSClusters, axisPairLossLayer0}); + histos.add("PairLossK0/TrackQA/hPositiveDaughterTPCPairWeighted", "pair-weighted positive-daughter TPC quality", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossTPCCrossedRows, axisPairLossTPCSharedClusters}); + histos.add("PairLossK0/TrackQA/hPositiveDaughterITSPairWeighted", "pair-weighted positive-daughter ITS quality", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossITSClusters, axisPairLossLayer0}); + histos.add("PairLossK0/TrackQA/hNegativeDaughterTPCPairWeighted", "pair-weighted negative-daughter TPC quality", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossTPCCrossedRows, axisPairLossTPCSharedClusters}); + histos.add("PairLossK0/TrackQA/hNegativeDaughterITSPairWeighted", "pair-weighted negative-daughter ITS quality", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossITSClusters, axisPairLossLayer0}); + + histos.add("PairLossK0/V0QA/hCosPAVsMinDeltaPhiStar", "matched V0 cos(PA) versus minimum delta phi star", kTH2F, {axisPairLossMinDeltaPhiStar, axisPairLossCosPA}); + histos.add("PairLossK0/V0QA/hDcaDaughtersVsMinDeltaPhiStar", "matched V0 daughter DCA versus minimum delta phi star", kTH2F, {axisPairLossMinDeltaPhiStar, axisPairLossDcaDaughters}); + histos.add("PairLossK0/V0QA/hRadiusVsMinDeltaPhiStar", "matched V0 radius versus minimum delta phi star", kTH2F, {axisPairLossMinDeltaPhiStar, axisPairLossRecoV0Radius}); + histos.add("PairLossK0/V0QA/hMassNSigmaVsMinDeltaPhiStar", "AssocV0 K0 mass n-sigma versus minimum delta phi star", kTH3F, {axisPairLossMinDeltaPhiStar, axisPairLossMassNSigma, axisPairLossTruthK0Pt}); + + auto eventCounter = histos.get(HIST("PairLossK0/Event/hCounter")); + const std::array eventLabels = {"MC collision", "has rec collision", "best collision selected", "has truth trigger", "has truth K0", "has truth pair"}; + for (size_t i = 0; i < eventLabels.size(); ++i) { + eventCounter->GetXaxis()->SetBinLabel(i + 1, eventLabels[i].data()); + } + eventCounter->GetYaxis()->SetTitle("Entries"); + histos.get(HIST("PairLossK0/Event/hNRecoCollisions"))->GetYaxis()->SetTitle("MC collisions"); + auto setStageLabels = [&](auto const& stageHistogram) { + for (int i = 0; i < PairLossK0NStages; ++i) { + stageHistogram->GetXaxis()->SetBinLabel(i + 1, PairLossK0StageNames[i].data()); + } + }; + auto stageCounts = histos.get(HIST("PairLossK0/Stage/hCounts")); + auto stageCountsFindable = histos.get(HIST("PairLossK0/Stage/hCountsFindable")); + setStageLabels(stageCounts); + setStageLabels(stageCountsFindable); + stageCounts->GetYaxis()->SetTitle("Truth-pair entries"); + stageCountsFindable->GetYaxis()->SetTitle("Findable truth-pair entries"); + + auto triggerTracksFailureHistogram = histos.get(HIST("PairLossK0/Stage/hTriggerTracksFailureReason")); + for (int i = 0; i < PairLossTriggerTracksNReasons; ++i) { + triggerTracksFailureHistogram->GetAxis(0)->SetBinLabel(i + 1, PairLossTriggerTracksFailureNames[i].data()); + } + + const std::array objectStateLabels = {"00 neither", "01 K0 only", "10 trigger only", "11 both"}; + for (auto const& histogram : {histos.get(HIST("PairLossK0/State/hFinalObjectStatePhysics")), histos.get(HIST("PairLossK0/State/hFinalObjectStateClose"))}) { + for (size_t i = 0; i < objectStateLabels.size(); ++i) { + histogram->GetAxis(0)->SetBinLabel(i + 1, objectStateLabels[i].data()); + } + } + const std::array trackLevelStateLabels = {"00 neither", "01 both daughters only", "10 trigger only", "11 trigger + both daughters"}; + auto trackLevelStateHistogram = histos.get(HIST("PairLossK0/State/hTrackLevelStateClose")); + for (size_t i = 0; i < trackLevelStateLabels.size(); ++i) { + trackLevelStateHistogram->GetAxis(0)->SetBinLabel(i + 1, trackLevelStateLabels[i].data()); + } + const std::array daughterStateLabels = {"none", "negative only", "positive only", "both"}; + auto daughterStateHistogram = histos.get(HIST("PairLossK0/State/hDaughterTrackStateClose")); + for (size_t i = 0; i < daughterStateLabels.size(); ++i) { + daughterStateHistogram->GetAxis(0)->SetBinLabel(i + 1, daughterStateLabels[i].data()); + } + + auto deltaPhiStarValidityHistogram = histos.get(HIST("PairLossK0/Geometry/hDeltaPhiStarValidity")); + deltaPhiStarValidityHistogram->GetXaxis()->SetBinLabel(1, "invalid"); + deltaPhiStarValidityHistogram->GetXaxis()->SetBinLabel(2, "valid"); + const std::array matchLabels = {"trigger all collisions", "trigger best collision", "trigger final", "V0 all collisions", "V0 best collision", "V0 AssocV0s", "V0 final"}; + auto matchHistogram = histos.get(HIST("PairLossK0/Matching/hNMatches")); + for (size_t i = 0; i < matchLabels.size(); ++i) { + matchHistogram->GetXaxis()->SetBinLabel(i + 1, matchLabels[i].data()); + } + + for (auto const& histogram : {histos.get(HIST("PairLossK0/TrackQA/hTriggerITSPairWeighted")), + histos.get(HIST("PairLossK0/TrackQA/hPositiveDaughterITSPairWeighted")), + histos.get(HIST("PairLossK0/TrackQA/hNegativeDaughterITSPairWeighted"))}) { + histogram->GetZaxis()->SetBinLabel(1, "no"); + histogram->GetZaxis()->SetBinLabel(2, "yes"); + } + + for (auto const& histogram : {deltaPhiStarValidityHistogram, + matchHistogram, + histos.get(HIST("PairLossK0/Response/hTriggerPt")), + histos.get(HIST("PairLossK0/Response/hK0Pt")), + histos.get(HIST("PairLossK0/Response/hDeltaPhi")), + histos.get(HIST("PairLossK0/Response/hDeltaEta")), + histos.get(HIST("PairLossK0/V0QA/hCosPAVsMinDeltaPhiStar")), + histos.get(HIST("PairLossK0/V0QA/hDcaDaughtersVsMinDeltaPhiStar")), + histos.get(HIST("PairLossK0/V0QA/hRadiusVsMinDeltaPhiStar"))}) { + histogram->GetZaxis()->SetTitle("Entries"); + } + } + if (doprocessMixedEventHV0sInBuffer || doprocessMixedEventHCascadesInBuffer) { validCollisions.resize(histos.get(HIST("axes/hMultAxis"))->GetNbinsX() * histos.get(HIST("axes/hVertexZAxis"))->GetNbinsX()); for (size_t i = 0; i < validCollisions.size(); ++i) { @@ -1796,9 +2354,9 @@ struct HStrangeCorrelation { if (!masterConfigurations.doPPAnalysis) { // event selections in Pb-Pb histos.add("hEventSelection", "hEventSelection", kTH1F, {{10, 0, 10}}); - TString eventSelLabel[] = {"all", "sel8", "kIsTriggerTVX", "PV_{z}", "kIsGoodITSLayersAll", "kIsGoodZvtxFT0vsPV", "OccupCut", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kNoSameBunchPileup "}; + std::array eventSelLabel = {"all", "sel8", "kIsTriggerTVX", "PV_{z}", "kIsGoodITSLayersAll", "kIsGoodZvtxFT0vsPV", "OccupCut", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kNoSameBunchPileup "}; for (int i = 1; i <= histos.get(HIST("hEventSelection"))->GetNbinsX(); i++) { - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1]); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1].Data()); } } // Some QA plots @@ -1858,17 +2416,12 @@ struct HStrangeCorrelation { histos.add("EventQA/hPvz", ";pvz;Entries", kTH1F, {{30, -15, 15}}); histos.add("EventQA/hMultFT0vsTPC", ";centFT0M;multNTracksPVeta1", kTH2F, {{100, 0, 100}, {300, 0, 300}}); } - if (masterConfigurations.doFullCorrelationStudy && masterConfigurations.fillCorrelationHistWithMass) { - histos.add("sameEvent/Signal/K0Short", "", kTHnF, {axisDeltaPhiNDim, axesConfigurations.axisK0ShortMass, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - histos.add("sameEvent/Signal/Lambda", "", kTHnF, {axisDeltaPhiNDim, axesConfigurations.axisLambdaMass, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - histos.add("sameEvent/Signal/AntiLambda", "", kTHnF, {axisDeltaPhiNDim, axesConfigurations.axisLambdaMass, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } - bool hStrange = false; for (int i = 0; i < AssocParticleTypes; i++) { if (TESTBIT(doCorrelation, i)) { - if (masterConfigurations.doFullCorrelationStudy && !masterConfigurations.fillCorrelationHistWithMass) + if (masterConfigurations.doFullCorrelationStudy) { histos.add(fmt::format("sameEvent/Signal/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } if (doDeltaPhiStarCheck && masterConfigurations.doFullCorrelationStudy) { histos.add(fmt::format("sameEvent/Signal/{}DeltaPhiStar", Particlenames[i]).c_str(), "", kTH3F, {{100, -0.3, 0.3}, {50, -0.05, 0.05}, {2, -1, 1}}); // -1 oposite charge, 1 same charge } @@ -1905,10 +2458,25 @@ struct HStrangeCorrelation { histos.add("hAssocPtResolution", ";p_{T}^{reconstructed} (GeV/c); p_{T}^{generated} (GeV/c)", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisPtQA}); } - if (hStrange && masterConfigurations.doFullCorrelationStudy && !masterConfigurations.fillCorrelationHistWithMass) { + if (hStrange && masterConfigurations.doFullCorrelationStudy) { histos.addClone("sameEvent/Signal/", "sameEvent/LeftBg/"); histos.addClone("sameEvent/Signal/", "sameEvent/RightBg/"); } + + if (masterConfigurations.doFullCorrelationStudy && doprocessSameEventHV0s && masterConfigurations.doCorrelationsHadronV0daughter) { + if (TESTBIT(doCorrelation, 0)) { + histos.add("sameEvent/Signal/K0Short_hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/K0Short_hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + if (TESTBIT(doCorrelation, 1)) { + histos.add("sameEvent/Signal/Lambda_hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/Lambda_hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + if (TESTBIT(doCorrelation, 2)) { + histos.add("sameEvent/Signal/AntiLambda_hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/AntiLambda_hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + } if (TESTBIT(doCorrelation, 0) && doprocessSameEventHV0s && masterConfigurations.doMassSpectrumCheck) { histos.add("hK0ShortPtVsMass", "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisK0ShortMass}); } @@ -1923,14 +2491,35 @@ struct HStrangeCorrelation { if ((doprocessMixedEventHV0sInBuffer || doprocessMixedEventHCascadesInBuffer || doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) && masterConfigurations.doFullCorrelationStudy) { histos.addClone("sameEvent/", "mixedEvent/"); } - if (doprocessSameEventHHadrons && masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy && doprocessSameEventHV0s) { + if (TESTBIT(doCorrelation, 0)) { + histos.add("sameEvent/InvariantMass/K0Short/hNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + histos.add("sameEvent/InvariantMass/K0Short/hAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + histos.add("sameEvent/InvariantMass/K0Short/hUnderlyingEvent", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + } + if (TESTBIT(doCorrelation, 1)) { + histos.add("sameEvent/InvariantMass/Lambda/hNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/Lambda/hAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/Lambda/hUnderlyingEvent", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + } + if (TESTBIT(doCorrelation, 2)) { + histos.add("sameEvent/InvariantMass/AntiLambda/hNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/AntiLambda/hAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/AntiLambda/hUnderlyingEvent", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + } + } + if (doprocessSameEventHHadrons && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesHadron", "TriggersHadron", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); - if (doprocessSameEventHV0s && masterConfigurations.doFullCorrelationStudy) + } + if (doprocessSameEventHV0s && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesV0", "TriggersV0", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); - if (doprocessSameEventHCascades && masterConfigurations.doFullCorrelationStudy) + } + if (doprocessSameEventHCascades && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesCascade", "TriggersCascade", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); - if (doprocessSameEventHPions && masterConfigurations.doFullCorrelationStudy) + } + if (doprocessSameEventHPions && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesPion", "TriggersPion", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + } // MC generated plots if (doprocessMCGenerated) { @@ -1962,12 +2551,28 @@ struct HStrangeCorrelation { } if (doprocessClosureTest) { for (int i = 0; i < AssocParticleTypes; i++) { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("ClosureTest/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - if (TESTBIT(doCorrelation, i)) + if (masterConfigurations.doClosureTestTriggerWithRecoTrackMatch) { + histos.add(fmt::format("ClosureTest/TriggerWithRecoTrackMatch/sameEvent/{}", Particlenames[i]).c_str(), "truth pairs whose trigger has at least one reconstructed track with a matching MC label", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + if (masterConfigurations.doCorrelationsHadronV0daughter) { + histos.add(fmt::format("ClosureTest/sameEvent/{}_SameSignDaughter", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add(fmt::format("ClosureTest/sameEvent/{}_OppSignDaughter", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (masterConfigurations.doClosureTestTriggerWithRecoTrackMatch) { + histos.add(fmt::format("ClosureTest/TriggerWithRecoTrackMatch/sameEvent/{}_SameSignDaughter", Particlenames[i]).c_str(), "truth trigger-daughter pairs whose trigger has a reconstructed-track match; same-sign daughter", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add(fmt::format("ClosureTest/TriggerWithRecoTrackMatch/sameEvent/{}_OppSignDaughter", Particlenames[i]).c_str(), "truth trigger-daughter pairs whose trigger has a reconstructed-track match; opposite-sign daughter", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + } + } + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("ClosureTest/h{}", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + } } histos.add("ClosureTest/hTrigger", "Trigger Tracks", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + if (masterConfigurations.doClosureTestTriggerWithRecoTrackMatch) { + histos.add("ClosureTest/TriggerWithRecoTrackMatch/hTrigger", "Truth triggers with at least one reconstructed track with a matching MC label;#it{p}_{T}^{truth} (GeV/c);#eta^{truth};centrality (%)", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + } } if (doprocessFeedDown) { histos.add("hLambdaXiMinusFeeddownMatrix", "hLambdaXiMinusFeeddownMatrix", kTH2F, {axisPtLambda, axisPtCascade}); @@ -1989,7 +2594,7 @@ struct HStrangeCorrelation { mCounter.mPdgDatabase = pdgDB.service; mCounter.mSelectPrimaries = doAssocPhysicalPrimary.value; histos.add("Prediction/hEventSelection", "hEventSelection", kTH1F, {{3, 0, 3}}); - TString eventSelLabel[] = {"Read", "INELgt0", "|Z|<10"}; + std::array eventSelLabel = {"Read", "INELgt0", "|Z|<10"}; for (int i = 1; i <= histos.get(HIST("Prediction/hEventSelection"))->GetNbinsX(); i++) { histos.get(HIST("Prediction/hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1]); } @@ -2013,14 +2618,17 @@ struct HStrangeCorrelation { histos.add("Prediction/hFT0MvsNchEta05", "Nch in 0.5 vs FT0M multiplicity", kTH2F, {axesConfigurations.axisMultiplicity, axesConfigurations.axisMidrapidityMultiplicity}); } for (int i = 0; i < AssocParticleTypes; i++) { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("Prediction/h{}", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + } if (masterConfigurations.useCentralityinPrediction) { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("Prediction/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } } else { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("Prediction/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultiplicityNDim}); + } } } if (masterConfigurations.doSeparateFT0Prediction) { @@ -2033,7 +2641,7 @@ struct HStrangeCorrelation { // initialize CCDB *only* if efficiency correction requested // skip if not requested, saves a bit of time - if (efficiencyFlags.applyEfficiencyCorrection) { + if (efficiencyFlags.applyEfficiencyCorrection || doprocessPairLossK0MC) { ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -2075,50 +2683,58 @@ struct HStrangeCorrelation { // event selections in Pb-Pb template - bool isCollisionSelectedPbPb(TCollision collision, bool fillHists) + bool isCollisionSelectedPbPb(TCollision const& collision, bool fillHists) { - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 0.5 /* all collisions */); + } // Perform basic event selection if (!collision.sel8()) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 1.5 /* collisions after sel8*/); + } if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && masterConfigurations.requireGoodTriggerTVX) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 2.5 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + } if (std::abs(collision.posZ()) > masterConfigurations.zVertexCut) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 3.5 /* collisions after sel pvz sel*/); + } if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && masterConfigurations.requireAllGoodITSLayers) { // cut time intervals with dead ITS staves return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 4.5 /* collisions after cut time intervals with dead ITS staves*/); + } 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 (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 5.5 /* removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference*/); + } auto occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) { return false; - if (fillHists) + } + if (fillHists) { histos.fill(HIST("hEventSelection"), 6.5 /* Below min occupancy and Above max occupancy*/); + } /* if (collision.alias_bit(kTVXinTRD)) { @@ -2132,24 +2748,27 @@ struct HStrangeCorrelation { // O2-4623 return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 7.5 /* reject collisions close to Time Frame borders*/); + } if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { // reject events affected by the ITS ROF border // O2-4309 return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 8.5 /* reject events affected by the ITS ROF border*/); + } if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { // rejects collisions which are associated with the same "found-by-T0" bunch crossing // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 9.5 /* rejects collisions which are associated with the same "found-by-T0" bunch crossing*/); + } return true; } @@ -2167,6 +2786,22 @@ struct HStrangeCorrelation { return 0.1 * (grpo->getNominalL3Field()); // 1 T = 10 kG } + + double getPairLossMagneticField(int runNumber, uint64_t timestamp) + { + if (mPairLossRunNumber == runNumber) { + return mPairLossMagneticField; + } + auto* grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found for K0 pair-loss diagnostic at timestamp %llu", timestamp); + return 0.0; + } + mPairLossRunNumber = runNumber; + mPairLossMagneticField = 0.1 * grpo->getNominalL3Field(); // 1 T = 10 kG + LOGF(info, "K0 pair-loss diagnostic loaded %.1f T for run %d", mPairLossMagneticField, runNumber); + return mPairLossMagneticField; + } // if this process function is enabled, it will be such that only events with trigger particles within a given // trigger pt bin are taken for the entire processing. This allows for the calculation of e.g. efficiencies // within an event class that has a trigger (which may differ with respect to other cases, to be checked) @@ -2196,6 +2831,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } auto binNumber = histos.get(HIST("axes/hPtTriggerAxis"))->FindFixBin(track.pt()) - 1; SETBIT(triggerPresenceMap[collision.globalIndex()], binNumber); } @@ -2237,8 +2875,12 @@ struct HStrangeCorrelation { if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && !doprocessSameEventHPions) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } histos.fill(HIST("hDCAzTriggerHadron"), track.dcaZ(), track.pt()); histos.fill(HIST("hDCAxyTriggerHadron"), track.dcaXY(), track.pt()); float efficiency = 1.0f; @@ -2251,24 +2893,30 @@ struct HStrangeCorrelation { float weight = efficiencyFlags.applyEfficiencyCorrection ? 1. / efficiency : 1.0f; histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi(), weight); } } for (auto const& assocTrack : assocHadrons) { auto assoc = assocTrack.track_as(); - if (!isValidAssocHadron(assoc)) + if (!isValidAssocHadron(assoc)) { continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(assocTrack.mcMask(), 13)) { + continue; + } float efficiency = 1.0f; float purity = 1.0f; histos.fill(HIST("hDCAzAssociatedHadron"), assoc.dcaZ(), assoc.pt()); histos.fill(HIST("hDCAxyAssociatedHadron"), assoc.dcaXY(), assoc.pt()); if (efficiencyFlags.applyEfficiencyCorrection) { efficiency = hEfficiencyHadron->Interpolate(assoc.pt(), assoc.eta()); - if (efficiencyFlags.applyPurityHadron) + if (efficiencyFlags.applyPurityHadron) { purity = hPurityHadron->Interpolate(assoc.pt()); + } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case efficiency = 1; @@ -2276,16 +2924,18 @@ struct HStrangeCorrelation { float weight = efficiencyFlags.applyEfficiencyCorrection ? purity / efficiency : 1.0f; histos.fill(HIST("hAssocHadronsAllSelectedEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M(), weight); histos.fill(HIST("hAssocPtResolution"), assoc.pt(), assocTrack.mcOriginalPt()); - if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) + if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) { continue; + } histos.fill(HIST("hAssocPrimaryEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M()); histos.fill(HIST("hAsssocTrackEtaVsPtVsPhi"), assoc.pt(), assoc.eta(), assoc.phi(), weight); } // ________________________________________________ // Do hadron - hadron correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(triggerTracks, assocHadrons, false, collision.posZ(), collision.centFT0M(), bField); + } } void processSameEventHV0s(soa::Join::iterator const& collision, @@ -2326,8 +2976,8 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } - TH2F* hEfficiencyV0[3]; - THnF* hEfficiencyV0MultVsPhi[3]; + std::array hEfficiencyV0{nullptr, nullptr, nullptr}; + std::array hEfficiencyV0MultVsPhi{nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyV0MultVsPhi[0] = hEfficiencyK0ShortMultVsPhi; hEfficiencyV0MultVsPhi[1] = hEfficiencyLambdaMultVsPhi; @@ -2344,19 +2994,24 @@ struct HStrangeCorrelation { //---] track quality check [--- auto postrack = v0Data.posTrack_as(); auto negtrack = v0Data.negTrack_as(); - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } //---] syst cuts [--- if (masterConfigurations.doPPAnalysis && (v0Data.v0radius() < v0Selection.v0RadiusMin || v0Data.v0radius() > v0Selection.v0RadiusMax || std::abs(v0Data.dcapostopv()) < v0Selection.dcapostopv || std::abs(v0Data.dcanegtopv()) < v0Selection.dcanegtopv || - v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau)) + v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau)) { continue; - if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(v0Data)) + } + if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(v0Data)) { continue; + } uint64_t selMap = v0selectionBitmap(v0Data, collision.posX(), collision.posY(), collision.posZ()); static_for<0, 2>([&](auto i) { @@ -2364,8 +3019,8 @@ struct HStrangeCorrelation { float efficiency = 1.0f; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { if (efficiencyFlags.applyEfficiencyCorrection) { - double bin[4] = {v0Data.pt(), v0Data.eta(), v0Data.phi(), cent}; - efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin)); + std::array bin = {v0Data.pt(), v0Data.eta(), v0Data.phi(), cent}; + efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin.data())); } } else { if (efficiencyFlags.applyEfficiencyCorrection) { @@ -2407,12 +3062,17 @@ struct HStrangeCorrelation { if (!doprocessSameEventHCascades) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } if (!efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); } else { @@ -2424,8 +3084,9 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - V0 correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsV0(triggerTracks, associatedV0s, false, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processSameEventHCascades(soa::Join::iterator const& collision, @@ -2465,8 +3126,8 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } - TH2F* hEfficiencyCascade[4]; - THnF* hEfficiencyCascadeMultVsPhi[4]; + std::array hEfficiencyCascade{nullptr, nullptr, nullptr, nullptr}; + std::array hEfficiencyCascadeMultVsPhi{nullptr, nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyCascadeMultVsPhi[0] = hEfficiencyXiMinusMultVsPhi; @@ -2493,21 +3154,26 @@ struct HStrangeCorrelation { cascData.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadeSelections.cascCospa || cascData.cascradius() < cascadeSelections.cascRadius || std::abs(cascData.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascadeSelections.cascdcaV0ToPV || - std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) + std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) { continue; - if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(cascData, collision.posX(), collision.posY(), collision.posZ())) + } + if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(cascData, collision.posX(), collision.posY(), collision.posZ())) { continue; + } uint64_t cascselMap = cascadeselectionBitmap(cascData, collision.posX(), collision.posY(), collision.posZ()); //---] track quality check [--- auto postrack = cascData.posTrack_as(); auto negtrack = cascData.negTrack_as(); auto bachtrack = cascData.bachelor_as(); - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } static_for<0, 3>([&](auto i) { constexpr int Index = i.value; @@ -2517,8 +3183,8 @@ struct HStrangeCorrelation { float efficiency = 1.0f; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - double bin[4] = {cascData.pt(), cascData.eta(), cascData.phi(), cent}; - efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin)); + std::array bin = {cascData.pt(), cascData.eta(), cascData.phi(), cent}; + efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin.data())); } else { efficiency = hEfficiencyCascade[Index]->Interpolate(cascData.pt(), cascData.eta()); } @@ -2554,28 +3220,35 @@ struct HStrangeCorrelation { } for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } if (!efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); } else { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), track.phi(), cent); } - if (track.sign() > 0) + if (track.sign() > 0) { histos.fill(HIST("hPositiveTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); - else + } else { histos.fill(HIST("hNegativeTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); + } histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsCascade(triggerTracks, associatedCascades, false, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processSameEventHPions(soa::Join::iterator const& collision, soa::Join const& associatedPions, soa::Join const& triggerTracks, @@ -2608,29 +3281,41 @@ struct HStrangeCorrelation { // Do basic QA for (auto const& pion : associatedPions) { auto pionTrack = pion.track_as(); - if (!isValidAssocHadron(pionTrack)) + if (!isValidAssocHadron(pionTrack)) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(pion.mcMask(), 13)) { continue; + } histos.fill(HIST("hPionEtaVsPtAllSelected"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); - if (doAssocPhysicalPrimary && !pion.mcPhysicalPrimary()) + if (doAssocPhysicalPrimary && !pion.mcPhysicalPrimary()) { continue; - if (masterConfigurations.doMCassociation && std::abs(pion.pdgCode()) != PdgCodes[IndexPion]) + } + if (masterConfigurations.doMCassociation && std::abs(pion.pdgCode()) != PdgCodes[IndexPion]) { continue; + } histos.fill(HIST("hPionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); - if (pionTrack.sign() > 0) + if (pionTrack.sign() > 0) { histos.fill(HIST("hPositivePionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); - else + } else { histos.fill(HIST("hNegativePionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); + } } if (!doprocessSameEventHCascades && !doprocessSameEventHV0s) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } @@ -2638,8 +3323,9 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - Pion correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(triggerTracks, associatedPions, false, collision.posZ(), collision.centFT0M(), bField); + } } void processMixedEventHHadrons(soa::Join const& collisions, @@ -2665,10 +3351,12 @@ struct HStrangeCorrelation { if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; } - if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) + if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) { continue; - if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) + } + if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) { continue; + } if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting @@ -2683,8 +3371,9 @@ struct HStrangeCorrelation { auto slicedAssocHadrons = assocHadrons.sliceBy(collisionSliceHadrons, collision2.globalIndex()); // ________________________________________________ // Do hadron - hadron correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(slicedTriggerTracks, slicedAssocHadrons, true, collision1.posZ(), collision1.centFT0M(), bField); + } } } @@ -2718,10 +3407,12 @@ struct HStrangeCorrelation { if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, false) || (!isCollisionSelectedPbPb(collision2, false))))) { continue; } - if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) + if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) { continue; - if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) + } + if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) { continue; + } if (!doprocessMixedEventHCascades && doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { @@ -2737,8 +3428,9 @@ struct HStrangeCorrelation { auto slicedAssocV0s = associatedV0s.sliceBy(collisionSliceV0s, collision2.globalIndex()); // ________________________________________________ // Do hadron - V0 correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, false, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + } } }, colBinning); @@ -2774,10 +3466,12 @@ struct HStrangeCorrelation { if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, false) || (!isCollisionSelectedPbPb(collision2, false))))) { continue; } - if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) + if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) { continue; - if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) + } + if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) { continue; + } if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting @@ -2792,8 +3486,9 @@ struct HStrangeCorrelation { auto slicedAssocCascades = associatedCascades.sliceBy(collisionSliceCascades, collision2.globalIndex()); // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, false, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + } } }, colBinning); @@ -2822,10 +3517,12 @@ struct HStrangeCorrelation { if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; } - if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) + if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) { continue; - if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) + } + if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) { continue; + } if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting @@ -2840,8 +3537,9 @@ struct HStrangeCorrelation { auto slicedAssocPions = assocPions.sliceBy(collisionSliceHadrons, collision2.globalIndex()); // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(slicedTriggerTracks, slicedAssocPions, true, collision1.posZ(), collision1.centFT0M(), bField); + } } } @@ -2869,8 +3567,9 @@ struct HStrangeCorrelation { } for (auto const& mcParticle : mcParticles) { - if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) + if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { continue; + } static_for<0, 7>([&](auto i) { constexpr int Index = i.value; if (i == IndexPion && mcParticle.pdgCode() > Neutral) { @@ -2886,13 +3585,14 @@ struct HStrangeCorrelation { } }); } - if (collisions.size() < 1) + if (collisions.size() < 1) { return; + } // determine best collision properties int biggestNContribs = -1; - int bestCollisionFT0Mpercentile = -1; - int bestCollisionFT0Cpercentile = -1; + float bestCollisionFT0Mpercentile = -1; + float bestCollisionFT0Cpercentile = -1; float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; @@ -2911,22 +3611,26 @@ struct HStrangeCorrelation { bestCollisionVtxZ = collision.posZ(); bestCollisionINELgtZERO = collision.isInelGt0(); } - if (triggerPresenceMap.size() > 0) + if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex()]; + } } } if (collisions.size() > 1) { for (auto const& mcParticle : mcParticles) { - if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) + if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { continue; - if (std::abs(mcParticle.y()) > ySel) + } + if (std::abs(mcParticle.y()) > ySel) { continue; + } static_for<0, 7>([&](auto i) { constexpr int Index = i.value; - if (mcParticle.pdgCode() == PdgCodes[i]) + if (mcParticle.pdgCode() == PdgCodes[i]) { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]) + HIST("_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); + } }); } } @@ -2941,15 +3645,19 @@ struct HStrangeCorrelation { return; } if (masterConfigurations.applyNewMCSelection) { - if (!isCollisionSelect) + if (!isCollisionSelect) { return; + } } else { - if (!bestCollisionSel8) + if (!bestCollisionSel8) { return; - if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) + } + if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) { return; - if (!bestCollisionINELgtZERO) + } + if (!bestCollisionINELgtZERO) { return; + } } histos.fill(HIST("hClosureTestEventCounter"), 3.5f); @@ -2985,10 +3693,11 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("GeneratedWithPV/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); } - if (mcParticle.pdgCode() > 0) + if (mcParticle.pdgCode() > 0) { histos.fill(HIST("GeneratedWithPV/hPositiveTrigger"), gpt, geta, bestCollisionFT0Mpercentile); - else + } else { histos.fill(HIST("GeneratedWithPV/hNegativeTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + } } if (mcParticle.pdgCode() == PDG_t::kLambda0 && !doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { @@ -3046,13 +3755,503 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]), gpt, geta, bestCollisionFT0Mpercentile); } - if (std::abs(mcParticle.y()) < ySel) + if (std::abs(mcParticle.y()) < ySel) { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + } } }); } } - void processClosureTest(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& recCollisions, aod::McParticles const& mcParticles) + void processPairLossK0MC(aod::McCollision const& mcCollision, + soa::SmallGroups> const& recCollisions, + aod::McParticles const& mcParticles, + TracksCompleteMC const& tracks, + V0DatasWithoutTrackXWithMCCores const& v0Candidates, + aod::TriggerTracks const& triggerTracks, + aod::AssocV0s const& associatedV0s, + aod::BCsWithTimestamps const&) + { + histos.fill(HIST("PairLossK0/Event/hCounter"), 0.0f); + histos.fill(HIST("PairLossK0/Event/hNRecoCollisions"), recCollisions.size()); + if (recCollisions.size() == 0) { + return; + } + histos.fill(HIST("PairLossK0/Event/hCounter"), 1.0f); + + int64_t bestCollisionId = -1; + int largestNContributors = -1; + for (auto const& collision : recCollisions) { + if (collision.numContrib() > largestNContributors) { + largestNContributors = collision.numContrib(); + bestCollisionId = collision.globalIndex(); + } + } + if (bestCollisionId < 0) { + return; + } + + PairLossTrackMap tracksAnyCollision; + PairLossV0Map v0sAnyCollision; + for (auto const& collision : recCollisions) { + const auto trackSlice = tracks.sliceBy(pairLossTracksPerCollision, collision.globalIndex()); + for (auto const& track : trackSlice) { + if (!track.has_mcParticle()) { + continue; + } + tracksAnyCollision[track.mcParticleId()].push_back(makePairLossTrackInfo(track)); + } + const auto v0Slice = v0Candidates.sliceBy(pairLossV0sPerCollision, collision.globalIndex()); + for (auto const& v0 : v0Slice) { + if (v0.particleIdMC() < 0 || v0.pdgCode() != PDG_t::kK0Short) { + continue; + } + v0sAnyCollision[v0.particleIdMC()].push_back(PairLossV0Info{ + .globalIndex = static_cast(v0.globalIndex()), + .positiveTrackId = static_cast(v0.posTrackId()), + .negativeTrackId = static_cast(v0.negTrackId()), + .pt = v0.pt(), + .eta = v0.eta(), + .phi = v0.phi(), + .radius = v0.v0radius(), + .cosPA = v0.v0cosPA(), + .dcaDaughters = v0.dcaV0daughters(), + .massNSigma = 0.0f}); + } + } + + for (auto const& collision : recCollisions) { + if (static_cast(collision.globalIndex()) != bestCollisionId) { + continue; + } + + const bool collisionSelected = !pairLossK0Configurations.applyRecoEventSelection || + (masterConfigurations.doPPAnalysis ? isCollisionSelected(collision) : isCollisionSelectedPbPb(collision, false)); + if (!collisionSelected) { + return; + } + histos.fill(HIST("PairLossK0/Event/hCounter"), 2.0f); + + const auto bc = collision.bc_as(); + const double magneticField = getPairLossMagneticField(bc.runNumber(), bc.timestamp()); + const int magneticFieldSign = magneticField > 0.0 ? 1 : (magneticField < 0.0 ? -1 : 0); + const float multiplicity = masterConfigurations.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + static_cast(multiplicity); // retained for straightforward extension of the diagnostic axes + + PairLossTrackMap tracksBestCollision; + const auto bestTrackSlice = tracks.sliceBy(pairLossTracksPerCollision, bestCollisionId); + for (auto const& track : bestTrackSlice) { + if (!track.has_mcParticle()) { + continue; + } + tracksBestCollision[track.mcParticleId()].push_back(makePairLossTrackInfo(track)); + } + + PairLossV0Map v0sBestCollision; + const auto bestV0Slice = v0Candidates.sliceBy(pairLossV0sPerCollision, bestCollisionId); + for (auto const& v0 : bestV0Slice) { + if (v0.particleIdMC() < 0 || v0.pdgCode() != PDG_t::kK0Short) { + continue; + } + v0sBestCollision[v0.particleIdMC()].push_back(PairLossV0Info{ + .globalIndex = static_cast(v0.globalIndex()), + .positiveTrackId = static_cast(v0.posTrackId()), + .negativeTrackId = static_cast(v0.negTrackId()), + .pt = v0.pt(), + .eta = v0.eta(), + .phi = v0.phi(), + .radius = v0.v0radius(), + .cosPA = v0.v0cosPA(), + .dcaDaughters = v0.dcaV0daughters(), + .massNSigma = 0.0f}); + } + + PairLossTrackMap triggersInTable; + PairLossTrackMap triggersFinal; + const auto triggerSlice = triggerTracks.sliceBy(collisionSliceTracks, bestCollisionId); + for (auto const& triggerEntry : triggerSlice) { + auto track = triggerEntry.track_as(); + if (!track.has_mcParticle()) { + continue; + } + const int64_t mcParticleId = track.mcParticleId(); + const auto trackInfo = makePairLossTrackInfo(track); + triggersInTable[mcParticleId].push_back(trackInfo); + if (!isValidTrigger(track, triggerEntry.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerEntry.mcMask(), 13)) { + continue; + } + if (masterConfigurations.doTriggPhysicalPrimary && !triggerEntry.mcPhysicalPrimary()) { + continue; + } + triggersFinal[mcParticleId].push_back(trackInfo); + } + + PairLossV0Map v0sInTable; + PairLossV0Map v0sFinal; + const auto assocV0Slice = associatedV0s.sliceBy(collisionSliceV0s, bestCollisionId); + for (auto const& assocEntry : assocV0Slice) { + auto v0 = assocEntry.v0Core_as(); + if (v0.particleIdMC() < 0 || v0.pdgCode() != PDG_t::kK0Short || !assocEntry.mcTrue(IndexK0)) { + continue; + } + auto positiveTrack = v0.posTrack_as(); + auto negativeTrack = v0.negTrack_as(); + const PairLossV0Info v0Info{ + .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)}; + v0sInTable[v0.particleIdMC()].push_back(v0Info); + + bool passesFinalSelection = true; + if (masterConfigurations.doPPAnalysis) { + passesFinalSelection = v0.v0radius() >= v0Selection.v0RadiusMin && v0.v0radius() <= v0Selection.v0RadiusMax && + std::abs(v0.dcapostopv()) >= v0Selection.dcapostopv && std::abs(v0.dcanegtopv()) >= v0Selection.dcanegtopv && + v0.v0cosPA() >= v0Selection.v0cospa && v0.dcaV0daughters() <= v0Selection.dcaV0dau; + } else { + const float dcaCut = v0Selection.dcaDaugToPVForK0s == 0.0f ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; + const bool passesLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S; + const bool passesDaughterDcaAndArmenteros = std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha()); + passesFinalSelection = v0SelectedPbPb(v0) && passesLifetime && passesDaughterDcaAndArmenteros; + } + passesFinalSelection = passesFinalSelection && positiveTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated && + negativeTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated; + if (trackSelection.checksRequireTPCChi2) { + passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated && + negativeTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated; + } + if (trackSelection.requireClusterInITS) { + passesFinalSelection = passesFinalSelection && positiveTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks && + negativeTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks; + } + passesFinalSelection = passesFinalSelection && assocEntry.compatible(IndexK0, trackSelection.dEdxCompatibility) && + (!doAssocPhysicalPrimary || assocEntry.mcPhysicalPrimary()) && + assocEntry.invMassNSigma(IndexK0) > -massWindowConfigurations.maxPeakNSigma && + assocEntry.invMassNSigma(IndexK0) < massWindowConfigurations.maxPeakNSigma && + v0.pt() >= axisRanges[2][0] && v0.pt() <= axisRanges[2][1]; + if (passesFinalSelection) { + v0sFinal[v0.particleIdMC()].push_back(v0Info); + } + } + + std::vector truthTriggers; + std::vector truthK0s; + for (auto const& mcParticle : mcParticles) { + if (isPairLossTriggerPdg(mcParticle.pdgCode()) && std::abs(mcParticle.eta()) <= etaSel && + mcParticle.pt() >= axisRanges[3][0] && mcParticle.pt() <= axisRanges[3][1] && + (!masterConfigurations.doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary())) { + auto const* pdgParticle = pdgDB->GetParticle(mcParticle.pdgCode()); + const double charge = pdgParticle != nullptr ? pdgParticle->Charge() : 0.0; + const int sign = charge > 0.0 ? 1 : (charge < 0.0 ? -1 : 0); + if ((triggerParticleCharge > 0 && sign < 0) || (triggerParticleCharge < 0 && sign > 0) || sign == 0) { + continue; + } + truthTriggers.push_back(PairLossTruthTrackInfo{ + .globalIndex = static_cast(mcParticle.globalIndex()), + .pt = mcParticle.pt(), + .eta = mcParticle.eta(), + .phi = mcParticle.phi(), + .sign = sign}); + } + + if (mcParticle.pdgCode() != PDG_t::kK0Short || std::abs(mcParticle.eta()) > etaSel || + mcParticle.pt() < axisRanges[2][0] || mcParticle.pt() > axisRanges[2][1] || + (doAssocPhysicalPrimary && !mcParticle.isPhysicalPrimary())) { + continue; + } + PairLossTruthK0Info truthK0{ + .globalIndex = static_cast(mcParticle.globalIndex()), + .pt = mcParticle.pt(), + .eta = mcParticle.eta(), + .phi = mcParticle.phi(), + .decayRadius = -1.0f, + .findable = false, + .positiveDaughter = {}, + .negativeDaughter = {}}; + const auto daughters = mcParticle.daughters_as(); + for (auto const& daughter : daughters) { + PairLossTruthTrackInfo daughterInfo{ + .globalIndex = static_cast(daughter.globalIndex()), + .pt = daughter.pt(), + .eta = daughter.eta(), + .phi = daughter.phi(), + .sign = daughter.pdgCode() > 0 ? 1 : -1}; + if (daughter.pdgCode() == PDG_t::kPiPlus) { + truthK0.positiveDaughter = daughterInfo; + } else if (daughter.pdgCode() == -PDG_t::kPiPlus) { + truthK0.negativeDaughter = daughterInfo; + } else { + continue; + } + const float daughterDecayRadius = std::hypot(daughter.vx() - mcCollision.posX(), daughter.vy() - mcCollision.posY()); + if (truthK0.decayRadius < 0.0f) { + truthK0.decayRadius = daughterDecayRadius; + } + } + const bool hasPionDaughters = truthK0.positiveDaughter.globalIndex >= 0 && truthK0.negativeDaughter.globalIndex >= 0; + truthK0.findable = hasPionDaughters && truthK0.positiveDaughter.pt >= pairLossK0Configurations.daughterPtMin && + truthK0.negativeDaughter.pt >= pairLossK0Configurations.daughterPtMin && + std::abs(truthK0.positiveDaughter.eta) <= pairLossK0Configurations.daughterEtaMax && + std::abs(truthK0.negativeDaughter.eta) <= pairLossK0Configurations.daughterEtaMax; + truthK0s.push_back(truthK0); + } + + if (useTheLeadingParticleAsTrigger && truthTriggers.size() > 1) { + const auto leadingTrigger = std::max_element(truthTriggers.begin(), truthTriggers.end(), [](auto const& lhs, auto const& rhs) { return lhs.pt < rhs.pt; }); + const auto leadingTriggerCopy = *leadingTrigger; + truthTriggers.clear(); + truthTriggers.push_back(leadingTriggerCopy); + } + if (!truthTriggers.empty()) { + histos.fill(HIST("PairLossK0/Event/hCounter"), 3.0f); + } + if (!truthK0s.empty()) { + histos.fill(HIST("PairLossK0/Event/hCounter"), 4.0f); + } + + auto contains = [](auto const& map, int64_t key) { + auto const iterator = map.find(key); + return iterator != map.end() && !iterator->second.empty(); + }; + auto numberOfMatches = [](auto const& map, int64_t key) -> size_t { + auto const iterator = map.find(key); + return iterator == map.end() ? 0 : iterator->second.size(); + }; + auto bestTrack = [](PairLossTrackMap const& map, int64_t key) -> PairLossTrackInfo const* { + auto const iterator = map.find(key); + if (iterator == map.end() || iterator->second.empty()) { + return nullptr; + } + return &*std::max_element(iterator->second.begin(), iterator->second.end(), [](auto const& lhs, auto const& rhs) { + if (lhs.tpcCrossedRows != rhs.tpcCrossedRows) { + return lhs.tpcCrossedRows < rhs.tpcCrossedRows; + } + return lhs.itsClusters < rhs.itsClusters; + }); + }; + auto bestV0 = [](PairLossV0Map const& map, int64_t key) -> PairLossV0Info const* { + auto const iterator = map.find(key); + if (iterator == map.end() || iterator->second.empty()) { + return nullptr; + } + return &*std::max_element(iterator->second.begin(), iterator->second.end(), [](auto const& lhs, auto const& rhs) { return lhs.cosPA < rhs.cosPA; }); + }; + + bool hasTruthPair = false; + for (auto const& truthTrigger : truthTriggers) { + for (auto const& truthK0 : truthK0s) { + if (truthTrigger.globalIndex == truthK0.positiveDaughter.globalIndex || truthTrigger.globalIndex == truthK0.negativeDaughter.globalIndex) { + continue; + } + const float truthDeltaPhi = computeDeltaPhi(truthTrigger.phi, truthK0.phi); + float truthDeltaEta = truthTrigger.eta - truthK0.eta; + if (masterConfigurations.doMirroringInDelataEta) { + truthDeltaEta = std::abs(truthDeltaEta); + } + if (truthDeltaPhi < axisRanges[0][0] || truthDeltaPhi > axisRanges[0][1] || truthDeltaEta < axisRanges[1][0] || truthDeltaEta > axisRanges[1][1]) { + continue; + } + hasTruthPair = true; + + const auto positiveDeltaPhiStar = calculateMinimumDeltaPhiStar(truthTrigger, truthK0.positiveDaughter, magneticField, truthK0.decayRadius); + const auto negativeDeltaPhiStar = calculateMinimumDeltaPhiStar(truthTrigger, truthK0.negativeDaughter, magneticField, truthK0.decayRadius); + PairLossDeltaPhiStarInfo closestDeltaPhiStar; + PairLossTruthTrackInfo const* closestDaughter = nullptr; + if (positiveDeltaPhiStar.valid && (!negativeDeltaPhiStar.valid || positiveDeltaPhiStar.minAbs <= negativeDeltaPhiStar.minAbs)) { + closestDeltaPhiStar = positiveDeltaPhiStar; + closestDaughter = &truthK0.positiveDaughter; + } else if (negativeDeltaPhiStar.valid) { + closestDeltaPhiStar = negativeDeltaPhiStar; + closestDaughter = &truthK0.negativeDaughter; + } + const float closestDeltaEta = closestDaughter != nullptr ? truthTrigger.eta - closestDaughter->eta : 999.0f; + const int closestChargeProduct = closestDaughter != nullptr ? truthTrigger.sign * closestDaughter->sign : 0; + + if (truthK0.findable) { + histos.fill(HIST("PairLossK0/Geometry/hDeltaPhiStarValidity"), closestDeltaPhiStar.valid, truthK0.pt); + if (positiveDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Geometry/hGeneratedDaughters"), positiveDeltaPhiStar.signedAtMin, truthTrigger.eta - truthK0.positiveDaughter.eta, truthK0.pt, truthTrigger.pt, magneticFieldSign, truthTrigger.sign * truthK0.positiveDaughter.sign); + } + if (negativeDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Geometry/hGeneratedDaughters"), negativeDeltaPhiStar.signedAtMin, truthTrigger.eta - truthK0.negativeDaughter.eta, truthK0.pt, truthTrigger.pt, magneticFieldSign, truthTrigger.sign * truthK0.negativeDaughter.sign); + } + if (closestDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Geometry/hRawDeltaPhiVsSignedDeltaPhiStar"), computeDeltaPhi(truthTrigger.phi, closestDaughter->phi), closestDeltaPhiStar.signedAtMin, magneticFieldSign); + histos.fill(HIST("PairLossK0/Geometry/hGeneratedMinDeltaPhiStarVsDecayRadius"), closestDeltaPhiStar.minAbs, truthK0.decayRadius, truthK0.pt); + histos.fill(HIST("PairLossK0/Geometry/hGeneratedRadiusAtMinimum"), closestDeltaPhiStar.radiusAtMin, closestDeltaPhiStar.minAbs, truthK0.pt); + } + } + + const bool triggerAnyCollision = contains(tracksAnyCollision, truthTrigger.globalIndex); + const bool triggerBestCollision = contains(tracksBestCollision, truthTrigger.globalIndex); + const bool triggerInTable = contains(triggersInTable, truthTrigger.globalIndex); + const bool triggerFinal = contains(triggersFinal, truthTrigger.globalIndex); + const bool positiveDaughterBestCollision = contains(tracksBestCollision, truthK0.positiveDaughter.globalIndex); + const bool negativeDaughterBestCollision = contains(tracksBestCollision, truthK0.negativeDaughter.globalIndex); + const bool bothDaughtersBestCollision = positiveDaughterBestCollision && negativeDaughterBestCollision; + const bool v0AnyCollision = contains(v0sAnyCollision, truthK0.globalIndex); + const bool v0BestCollision = contains(v0sBestCollision, truthK0.globalIndex); + const bool v0InTable = contains(v0sInTable, truthK0.globalIndex); + const bool v0Final = contains(v0sFinal, truthK0.globalIndex); + + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 0.0f, numberOfMatches(tracksAnyCollision, truthTrigger.globalIndex)); + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 1.0f, numberOfMatches(tracksBestCollision, truthTrigger.globalIndex)); + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 2.0f, numberOfMatches(triggersFinal, truthTrigger.globalIndex)); + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 3.0f, numberOfMatches(v0sAnyCollision, truthK0.globalIndex)); + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 4.0f, numberOfMatches(v0sBestCollision, truthK0.globalIndex)); + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 5.0f, numberOfMatches(v0sInTable, truthK0.globalIndex)); + histos.fill(HIST("PairLossK0/Matching/hNMatches"), 6.0f, numberOfMatches(v0sFinal, truthK0.globalIndex)); + + bool pairBeforeAutocorrelation = false; + bool finalPair = false; + bool rejectedByAutocorrelation = false; + PairLossTrackInfo selectedTrigger; + PairLossV0Info selectedV0; + if (triggerFinal && v0Final) { + for (auto const& reconstructedTrigger : triggersFinal.at(truthTrigger.globalIndex)) { + for (auto const& reconstructedV0 : v0sFinal.at(truthK0.globalIndex)) { + const float reconstructedDeltaPhi = computeDeltaPhi(reconstructedTrigger.phi, reconstructedV0.phi); + float reconstructedDeltaEta = reconstructedTrigger.eta - reconstructedV0.eta; + if (masterConfigurations.doMirroringInDelataEta) { + reconstructedDeltaEta = std::abs(reconstructedDeltaEta); + } + if (reconstructedDeltaPhi < axisRanges[0][0] || reconstructedDeltaPhi > axisRanges[0][1] || reconstructedDeltaEta < axisRanges[1][0] || reconstructedDeltaEta > axisRanges[1][1]) { + continue; + } + pairBeforeAutocorrelation = true; + if (doAutocorrelationRejection && (reconstructedTrigger.globalIndex == reconstructedV0.positiveTrackId || reconstructedTrigger.globalIndex == reconstructedV0.negativeTrackId)) { + rejectedByAutocorrelation = true; + continue; + } + finalPair = true; + selectedTrigger = reconstructedTrigger; + selectedV0 = reconstructedV0; + break; + } + if (finalPair) { + break; + } + } + } + + const std::array stagePassed = { + true, + truthK0.findable, + triggerAnyCollision, + triggerBestCollision, + triggerInTable, + triggerFinal, + positiveDaughterBestCollision, + negativeDaughterBestCollision, + bothDaughtersBestCollision, + v0AnyCollision, + v0BestCollision, + v0InTable, + v0Final, + pairBeforeAutocorrelation, + finalPair}; + for (int stage = 0; stage < PairLossK0NStages; ++stage) { + if (!stagePassed[stage]) { + continue; + } + histos.fill(HIST("PairLossK0/Stage/hCounts"), stage); + histos.fill(HIST("PairLossK0/Stage/hPhysics"), stage, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign); + if (truthK0.findable) { + histos.fill(HIST("PairLossK0/Stage/hCountsFindable"), stage); + histos.fill(HIST("PairLossK0/Stage/hPhysicsFindable"), stage, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign); + if (closestDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Stage/hClose"), stage, closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign, closestChargeProduct); + } + } + } + + // Only meaningful conditional on the trigger already existing in the best collision + // (stage 3): this asks *why* that already-found, already-correctly-labelled track + // does or does not make it into the TriggerTracks table (stage 4). + if (triggerBestCollision) { + if (auto const* bestCollisionTrigger = bestTrack(tracksBestCollision, truthTrigger.globalIndex)) { + const int failureReason = classifyTriggerTracksFailure(*bestCollisionTrigger); + histos.fill(HIST("PairLossK0/Stage/hTriggerTracksFailureReason"), failureReason, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt); + } + } + + const int finalObjectState = (triggerFinal ? 2 : 0) + (v0Final ? 1 : 0); + const int trackLevelState = (triggerBestCollision ? 2 : 0) + (bothDaughtersBestCollision ? 1 : 0); + const int daughterTrackState = (positiveDaughterBestCollision ? 2 : 0) + (negativeDaughterBestCollision ? 1 : 0); + histos.fill(HIST("PairLossK0/State/hFinalObjectStatePhysics"), finalObjectState, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign); + if (truthK0.findable && closestDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/State/hFinalObjectStateClose"), finalObjectState, closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign, closestChargeProduct); + histos.fill(HIST("PairLossK0/State/hTrackLevelStateClose"), trackLevelState, closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign, closestChargeProduct); + histos.fill(HIST("PairLossK0/State/hDaughterTrackStateClose"), daughterTrackState, closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign, closestChargeProduct); + + if (auto const* matchedTrigger = bestTrack(tracksBestCollision, truthTrigger.globalIndex)) { + histos.fill(HIST("PairLossK0/TrackQA/hTriggerTPCPairWeighted"), closestDeltaPhiStar.minAbs, matchedTrigger->tpcCrossedRows, matchedTrigger->tpcSharedClusters); + histos.fill(HIST("PairLossK0/TrackQA/hTriggerITSPairWeighted"), closestDeltaPhiStar.minAbs, matchedTrigger->itsClusters, matchedTrigger->hasLayer0); + } + if (auto const* matchedPositiveDaughter = bestTrack(tracksBestCollision, truthK0.positiveDaughter.globalIndex)) { + histos.fill(HIST("PairLossK0/TrackQA/hPositiveDaughterTPCPairWeighted"), closestDeltaPhiStar.minAbs, matchedPositiveDaughter->tpcCrossedRows, matchedPositiveDaughter->tpcSharedClusters); + histos.fill(HIST("PairLossK0/TrackQA/hPositiveDaughterITSPairWeighted"), closestDeltaPhiStar.minAbs, matchedPositiveDaughter->itsClusters, matchedPositiveDaughter->hasLayer0); + } + if (auto const* matchedNegativeDaughter = bestTrack(tracksBestCollision, truthK0.negativeDaughter.globalIndex)) { + histos.fill(HIST("PairLossK0/TrackQA/hNegativeDaughterTPCPairWeighted"), closestDeltaPhiStar.minAbs, matchedNegativeDaughter->tpcCrossedRows, matchedNegativeDaughter->tpcSharedClusters); + histos.fill(HIST("PairLossK0/TrackQA/hNegativeDaughterITSPairWeighted"), closestDeltaPhiStar.minAbs, matchedNegativeDaughter->itsClusters, matchedNegativeDaughter->hasLayer0); + } + if (auto const* matchedV0 = bestV0(v0sBestCollision, truthK0.globalIndex)) { + histos.fill(HIST("PairLossK0/V0QA/hCosPAVsMinDeltaPhiStar"), closestDeltaPhiStar.minAbs, matchedV0->cosPA); + histos.fill(HIST("PairLossK0/V0QA/hDcaDaughtersVsMinDeltaPhiStar"), closestDeltaPhiStar.minAbs, matchedV0->dcaDaughters); + histos.fill(HIST("PairLossK0/V0QA/hRadiusVsMinDeltaPhiStar"), closestDeltaPhiStar.minAbs, matchedV0->radius); + } + if (auto const* matchedAssocV0 = bestV0(v0sInTable, truthK0.globalIndex)) { + histos.fill(HIST("PairLossK0/V0QA/hMassNSigmaVsMinDeltaPhiStar"), closestDeltaPhiStar.minAbs, matchedAssocV0->massNSigma, truthK0.pt); + } + if (pairBeforeAutocorrelation && !finalPair && rejectedByAutocorrelation) { + histos.fill(HIST("PairLossK0/Geometry/hAutocorrelationRejected"), closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign); + } + } + + if (finalPair) { + histos.fill(HIST("PairLossK0/Response/hTriggerPt"), truthTrigger.pt, selectedTrigger.pt); + histos.fill(HIST("PairLossK0/Response/hK0Pt"), truthK0.pt, selectedV0.pt); + histos.fill(HIST("PairLossK0/Response/hDeltaPhi"), truthDeltaPhi, computeDeltaPhi(selectedTrigger.phi, selectedV0.phi)); + float reconstructedDeltaEta = selectedTrigger.eta - selectedV0.eta; + if (masterConfigurations.doMirroringInDelataEta) { + reconstructedDeltaEta = std::abs(reconstructedDeltaEta); + } + histos.fill(HIST("PairLossK0/Response/hDeltaEta"), truthDeltaEta, reconstructedDeltaEta); + if (truthK0.findable) { + if (positiveDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Geometry/hFinalDaughters"), positiveDeltaPhiStar.signedAtMin, truthTrigger.eta - truthK0.positiveDaughter.eta, truthK0.pt, truthTrigger.pt, magneticFieldSign, truthTrigger.sign * truthK0.positiveDaughter.sign); + } + if (negativeDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Geometry/hFinalDaughters"), negativeDeltaPhiStar.signedAtMin, truthTrigger.eta - truthK0.negativeDaughter.eta, truthK0.pt, truthTrigger.pt, magneticFieldSign, truthTrigger.sign * truthK0.negativeDaughter.sign); + } + if (closestDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Geometry/hFinalMinDeltaPhiStarVsDecayRadius"), closestDeltaPhiStar.minAbs, truthK0.decayRadius, truthK0.pt); + histos.fill(HIST("PairLossK0/Geometry/hFinalRadiusAtMinimum"), closestDeltaPhiStar.radiusAtMin, closestDeltaPhiStar.minAbs, truthK0.pt); + } + } + } + } + } + if (hasTruthPair) { + histos.fill(HIST("PairLossK0/Event/hCounter"), 5.0f); + } + return; + } + } + + void processClosureTest(aod::McCollision const& /*mcCollision*/, + soa::SmallGroups> const& recCollisions, + aod::McParticles const& mcParticles, + TracksCompleteMC const& tracks) { std::vector triggerIndices; @@ -3067,6 +4266,22 @@ struct HStrangeCorrelation { std::vector omegaMinusIndices; std::vector omegaPlusIndices; + // A truth trigger belongs to this set when at least one reconstructed track + // in any reconstructed collision associated with the current MC collision + // points back to it through its MC label. No best-collision, track-quality, + // or final-trigger selection is imposed here: this is the "any track" stage. + std::unordered_set mcParticleIdsWithRecoTrackMatch; + if (masterConfigurations.doClosureTestTriggerWithRecoTrackMatch) { + for (auto const& recCollision : recCollisions) { + const auto trackSlice = tracks.sliceBy(pairLossTracksPerCollision, recCollision.globalIndex()); + for (auto const& track : trackSlice) { + if (track.has_mcParticle()) { + mcParticleIdsWithRecoTrackMatch.insert(track.mcParticleId()); + } + } + } + } + for (auto const& mcParticle : mcParticles) { double geta = mcParticle.eta(); if (std::abs(geta) > etaSel) { @@ -3088,22 +4303,28 @@ struct HStrangeCorrelation { histos.fill(HIST("hClosureTestEventCounter"), 0.5f); - int bestCollisionFT0Mpercentile = -1; + float bestCollisionCentpercentile = -1; float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; + bool isCollisionSelect = false; int biggestNContribs = -1; uint32_t bestCollisionTriggerPresenceMap = 0; for (auto const& recCollision : recCollisions) { if (biggestNContribs < recCollision.numContrib()) { biggestNContribs = recCollision.numContrib(); - bestCollisionFT0Mpercentile = recCollision.centFT0M(); - bestCollisionSel8 = recCollision.sel8(); - bestCollisionVtxZ = recCollision.posZ(); - bestCollisionINELgtZERO = recCollision.isInelGt0(); - if (triggerPresenceMap.size() > 0) + bestCollisionCentpercentile = masterConfigurations.doPPAnalysis ? recCollision.centFT0M() : recCollision.centFT0C(); + if (masterConfigurations.applyNewMCSelection) { + isCollisionSelect = ((masterConfigurations.doPPAnalysis && isCollisionSelected(recCollision)) || (!masterConfigurations.doPPAnalysis && isCollisionSelectedPbPb(recCollision, false))); + } else { + bestCollisionSel8 = recCollision.sel8(); + bestCollisionVtxZ = recCollision.posZ(); + bestCollisionINELgtZERO = recCollision.isInelGt0(); + } + if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; + } } } // ________________________________________________ @@ -3112,18 +4333,26 @@ struct HStrangeCorrelation { return; } - if (masterConfigurations.doGenEventSelection) { - if (!bestCollisionSel8) - return; - if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) - return; - if (!bestCollisionINELgtZERO) - return; - if (bestCollisionFT0Mpercentile > axisRanges[5][1] || bestCollisionFT0Mpercentile < axisRanges[5][0]) { + if (masterConfigurations.applyNewMCSelection) { + if (!isCollisionSelect) { return; } + } else { + if (masterConfigurations.doGenEventSelection) { + if (!bestCollisionSel8) { + return; + } + if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) { + return; + } + if (!bestCollisionINELgtZERO) { + return; + } + if (bestCollisionCentpercentile > axisRanges[5][1] || bestCollisionCentpercentile < axisRanges[5][0]) { + return; + } + } } - histos.fill(HIST("hClosureTestEventCounter"), 1.5f); for (auto const& mcParticle : mcParticles) { @@ -3157,7 +4386,10 @@ struct HStrangeCorrelation { if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { if (!masterConfigurations.doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { triggerIndices.emplace_back(iteratorNum); - histos.fill(HIST("ClosureTest/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + histos.fill(HIST("ClosureTest/hTrigger"), gpt, geta, bestCollisionCentpercentile); + if (masterConfigurations.doClosureTestTriggerWithRecoTrackMatch && mcParticleIdsWithRecoTrackMatch.find(mcParticle.globalIndex()) != mcParticleIdsWithRecoTrackMatch.end()) { + histos.fill(HIST("ClosureTest/TriggerWithRecoTrackMatch/hTrigger"), gpt, geta, bestCollisionCentpercentile); + } } if (masterConfigurations.doCorrelationHadron) { if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { @@ -3221,6 +4453,9 @@ struct HStrangeCorrelation { double getatrigger = triggerParticle.eta(); double gphitrigger = triggerParticle.phi(); double pttrigger = triggerParticle.pt(); + const bool triggerHasRecoTrackMatch = masterConfigurations.doClosureTestTriggerWithRecoTrackMatch && mcParticleIdsWithRecoTrackMatch.find(triggerParticle.globalIndex()) != mcParticleIdsWithRecoTrackMatch.end(); + auto const* triggerPdg = pdgDB->GetParticle(triggerParticle.pdgCode()); + const double triggerCharge = triggerPdg ? triggerPdg->Charge() : 0.; auto const& mother = triggerParticle.mothers_first_as(); auto globalIndex = mother.globalIndex(); static_for<0, 8>([&](auto i) { // associated loop @@ -3235,14 +4470,43 @@ struct HStrangeCorrelation { double deltaeta = getatrigger - getaassoc; // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; - if (TESTBIT(doCorrelation, i)) - histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, bestCollisionVtxZ, bestCollisionFT0Mpercentile); + } + if (TESTBIT(doCorrelation, i)) { + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + if (triggerHasRecoTrackMatch) { + histos.fill(HIST("ClosureTest/TriggerWithRecoTrackMatch/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + } + } + if (i < 3 && TESTBIT(doCorrelation, i) && masterConfigurations.doCorrelationsHadronV0daughter) { + auto const assocParticleDaughters = assocParticle.daughters_as(); + for (const auto& assocParticleDaughter : assocParticleDaughters) { + auto const* daughterPdg = pdgDB->GetParticle(assocParticleDaughter.pdgCode()); + const double daughterCharge = daughterPdg ? daughterPdg->Charge() : 0.; + // Neutral daughters, including pi0, do not correspond to reconstructed V0 daughter tracks. + if (triggerCharge == 0. || daughterCharge == 0.) { + continue; + } + if (triggerCharge * daughterCharge > 0.) { + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_SameSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaughter.phi()), getatrigger - assocParticleDaughter.eta(), assocParticleDaughter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + if (triggerHasRecoTrackMatch) { + histos.fill(HIST("ClosureTest/TriggerWithRecoTrackMatch/sameEvent/") + HIST(Particlenames[Index]) + HIST("_SameSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaughter.phi()), getatrigger - assocParticleDaughter.eta(), assocParticleDaughter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + } + } else { + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_OppSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaughter.phi()), getatrigger - assocParticleDaughter.eta(), assocParticleDaughter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + if (triggerHasRecoTrackMatch) { + histos.fill(HIST("ClosureTest/TriggerWithRecoTrackMatch/sameEvent/") + HIST(Particlenames[Index]) + HIST("_OppSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaughter.phi()), getatrigger - assocParticleDaughter.eta(), assocParticleDaughter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + } + } + } + } } } }); @@ -3264,14 +4528,16 @@ struct HStrangeCorrelation { //---] track quality check [--- auto postrack = v0Data.posTrack_as(); auto negtrack = v0Data.negTrack_as(); - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; + } //---] syst cuts [--- if (v0Data.v0radius() < v0Selection.v0RadiusMin || v0Data.v0radius() > v0Selection.v0RadiusMax || std::abs(v0Data.dcapostopv()) < v0Selection.dcapostopv || std::abs(v0Data.dcanegtopv()) < v0Selection.dcanegtopv || - v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau) + v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau) { continue; + } if (v0Data.has_mcParticle()) { auto v0mcParticle = v0Data.mcParticle_as(); @@ -3351,12 +4617,14 @@ struct HStrangeCorrelation { if (((masterConfigurations.doPPAnalysis && !isCollisionSelected(collision))) || (!masterConfigurations.doPPAnalysis && !isCollisionSelectedPbPb(collision, false))) { return; } - if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) + if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) { return; + } // ________________________________________________ - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsV0(triggerTracks, associatedV0s, true, true, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processMixedEventHCascadesInBuffer(soa::Join::iterator const& collision, aod::AssocV0s const&, aod::AssocCascades const& associatedCascades, aod::TriggerTracks const& triggerTracks, @@ -3378,12 +4646,14 @@ struct HStrangeCorrelation { if ((masterConfigurations.doPPAnalysis && !isCollisionSelected(collision)) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision, false)))) { return; } - if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) + if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) { return; + } // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsCascade(triggerTracks, associatedCascades, true, true, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processPrediction(soa::Join::iterator const& mcCollision, aod::McParticles const& mcParticles) { @@ -3537,12 +4807,15 @@ struct HStrangeCorrelation { double deltaeta = getatrigger - getaassoc; // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } if (TESTBIT(doCorrelation, i)) { if (masterConfigurations.useCentralityinPrediction) { histos.fill(HIST("Prediction/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, mcCollision.posZ(), centMultFT0M); @@ -3578,12 +4851,13 @@ struct HStrangeCorrelation { PROCESS_SWITCH(HStrangeCorrelation, processMCGenerated, "Process MC generated", false); PROCESS_SWITCH(HStrangeCorrelation, processClosureTest, "Process Closure Test", false); + PROCESS_SWITCH(HStrangeCorrelation, processPairLossK0MC, "Diagnose truth-matched h-K0 pair loss", false); PROCESS_SWITCH(HStrangeCorrelation, processFeedDown, "process Feed Down", false); PROCESS_SWITCH(HStrangeCorrelation, processPrediction, "process model prediction", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(context)}; } diff --git a/PWGLF/Tasks/Strangeness/lambdalambda.cxx b/PWGLF/Tasks/Strangeness/lambdalambda.cxx index 2a861ea7ac9..47ba728a94a 100644 --- a/PWGLF/Tasks/Strangeness/lambdalambda.cxx +++ b/PWGLF/Tasks/Strangeness/lambdalambda.cxx @@ -527,6 +527,9 @@ struct lambdalambda { RanPhi += RecoV02.Phi(); RecoV02Rot = ROOT::Math::PxPyPzMVector(RecoV02.Pt() * std::cos(RanPhi), RecoV02.Pt() * std::sin(RanPhi), RecoV02.Pz(), RecoV02.M()); RecoV0V0Rot = RecoV01 + RecoV02Rot; + if (std::abs(RecoV0V0Rot.Rapidity()) > cfgV0V0RapMax) + continue; + histos.fill(HIST("h_InvMass_rot"), RecoV0V0Rot.M(), RecoV0V0Rot.Pt(), centrality, V01Tag + V02Tag); } } diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx index 76b9d788c63..668dd8f7541 100644 --- a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -47,8 +48,6 @@ #include #include #include -#include -#include #include #include #include @@ -170,6 +169,13 @@ static inline int piIdx(const T& t) { return t.pionIndexmc(); } + +template +static inline float dcaV0ToPVMC(const T& t) +{ + return t.dcaV0ToPVmc(); +} + } // namespace mcacc // Optional fixed-leg correction pointers kept outside the task struct. @@ -221,19 +227,24 @@ struct lambdaspincorrderived { Configurable useNUA{"useNUA", false, "Apply single-candidate NUA weight in (phi,eta)"}; Configurable ConfNUAPathLambda{"ConfNUAPathLambda", "", "CCDB path for Lambda NUA TH2D(phi,eta)"}; Configurable ConfNUAPathAntiLambda{"ConfNUAPathAntiLambda", "", "CCDB path for AntiLambda NUA TH2D(phi,eta)"}; + + // Mixing selection and binning Configurable> massMixEdges{"massMixEdges", {1.09f, 1.108f, 1.122f, 1.14f}, "Mass-mixing region edges: [SB low | signal | SB high]"}; Configurable cfgMixLegMode{"cfgMixLegMode", 0, "0=replace leg-1 only, 1=replace leg-2 only, 2=do both one-leg replacements"}; Configurable cfgV5MassBins{"cfgV5MassBins", 5, "Number of fixed mass bins for V5 mixing"}; Configurable cfgV5NeighborPt{"cfgV5NeighborPt", 0, "v5: neighbor bins in pT (use symmetric ±N, edge-safe)"}; Configurable cfgV5NeighborEta{"cfgV5NeighborEta", 0, "v5: neighbor bins in eta (use symmetric ±N, edge-safe)"}; Configurable cfgV5NeighborPhi{"cfgV5NeighborPhi", 0, "v5: neighbor bins in phi (use symmetric ±N, periodic wrap)"}; - Configurable usePairKineMatch{"usePairKineMatch", true, "Require pair-level matching between (A,B) and (C,B)"}; Configurable cfgV5MaxMatches{"cfgV5MaxMatches", 50, "v5: max ME replacements per SE pair (after all cuts)"}; Configurable cfgMixSeed{"cfgMixSeed", 0xdecafbadULL, "RNG seed for downsampling matches (deterministic)"}; + Configurable cfgV6CarryUnmatched{"cfgV6CarryUnmatched", false, "Carry data and MC V6 replacement branches with zero matches to later data frames"}; + Configurable cfgV6MaxPendingBranches{"cfgV6MaxPendingBranches", 0, "Maximum retained V6 branches per data or MC buffer; <=0 means unlimited"}; + Configurable cfgV6MaxPendingAge{"cfgV6MaxPendingAge", 0, "Maximum later data frames searched by a retained V6 branch; <=0 means unlimited"}; + Configurable cfgV6LogPending{"cfgV6LogPending", false, "Print one V6 pending-branch summary per data frame"}; + + // Event and candidate mixing cuts Configurable centMin{"centMin", 0, "Minimum Centrality"}; Configurable centMax{"centMax", 80, "Maximum Centrality"}; - Configurable rngSeed{"rngSeed", 12345, "Seed for random mixing (reproducible)"}; - std::mt19937 rng{12345}; Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; ConfigurableAxis CfgVtxBins{"CfgVtxBins", {VARIABLE_WIDTH, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10}, "Mixing bins - z-vertex"}; ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0, 110}, "Mixing bins - centrality"}; @@ -258,22 +269,28 @@ struct lambdaspincorrderived { Configurable fillWeightQAHistos{"fillWeightQAHistos", false, "Fill weighted/final-weighted REP/FIX QA maps"}; Configurable fillAnalysisSparses{"fillAnalysisSparses", false, "Fill extra deltaR/deltaRap/deltaPhi Analysis THnSparse objects"}; Configurable fillAdditionalSparses{"fillAdditionalSparses", false, "Fill extra rapidity/dphi/pair-mass THnSparse objects"}; - Configurable checkDoubleStatus{"checkDoubleStatus", 0, "Check Double status"}; - Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; - Configurable radiusMin{"radiusMin", 3, "Minimum V0 radius"}; - Configurable radiusMax{"radiusMax", 30, "Maximum V0 radius"}; - Configurable dcaProton{"dcaProton", 0.1, "DCA Proton"}; - Configurable dcaPion{"dcaPion", 0.2, "DCA Pion"}; - Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; + Configurable ptMin{"ptMin", 0.5, "V0 Pt minimum"}; Configurable ptMax{"ptMax", 3.0, "V0 Pt maximum"}; Configurable MassMin{"MassMin", 1.09, "V0 Mass minimum"}; Configurable MassMax{"MassMax", 1.14, "V0 Mass maximum"}; - Configurable rapidity{"rapidity", 0.5, "Rapidity cut on lambda"}; Configurable v0etaMixBuffer{"v0etaMixBuffer", 0.8, "Eta cut on mix event buffer"}; + Configurable rapidity{"rapidity", 0.5, "Rapidity cut on lambda"}; Configurable v0eta{"v0eta", 0.8, "Eta cut on lambda"}; + struct : ConfigurableGroup { + std::string prefix = "v0Configuration"; + Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; + Configurable radiusMin{"radiusMin", 3, "Minimum V0 radius"}; + Configurable radiusMax{"radiusMax", 30, "Maximum V0 radius"}; + Configurable dcaProton{"dcaProton", 0.1, "DCA Proton"}; + Configurable dcaPion{"dcaPion", 0.2, "DCA Pion"}; + Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; + Configurable dcaV0ToPV{"dcaV0ToPV", 1.2, "DCA V0 to PV cut on lambda"}; + + } v0Configurations; + // Event Mixing Configurable cosDef{"cosDef", 1, "Defination of cos"}; @@ -478,7 +495,6 @@ struct lambdaspincorrderived { histos.add("hSparsePairMassAntiLambdaLambdaMixed", "hSparsePairMassAntiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); histos.add("hSparsePairMassAntiLambdaAntiLambdaMixed", "hSparsePairMassAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); } - rng.seed(static_cast(rngSeed.value)); ccdb->setURL(cfgCcdbParam.cfgURL); ccdbApi.init("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -571,25 +587,30 @@ struct lambdaspincorrderived { if (candidate.lambdaMass() < MassMin || candidate.lambdaMass() > MassMax) { return false; } - if (candidate.v0Cospa() < cosPA) { + if (candidate.v0Cospa() < v0Configurations.cosPA) { return false; } if (checkDoubleStatus && candidate.doubleStatus()) { return false; } - if (candidate.v0Radius() > radiusMax) { + if (candidate.v0Radius() > v0Configurations.radiusMax) { + return false; + } + if (candidate.v0Radius() < v0Configurations.radiusMin) { return false; } - if (candidate.v0Radius() < radiusMin) { + if (candidate.dcaBetweenDaughter() > v0Configurations.dcaDaughters) { return false; } - if (candidate.dcaBetweenDaughter() > dcaDaughters) { + + if (candidate.dcaV0ToPV() > v0Configurations.dcaV0ToPV) { return false; } - if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < dcaProton || std::abs(candidate.dcaNegative()) < dcaPion)) { + + if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < v0Configurations.dcaProton || std::abs(candidate.dcaNegative()) < v0Configurations.dcaPion)) { return false; } - if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < dcaPion || std::abs(candidate.dcaNegative()) < dcaProton)) { + if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < v0Configurations.dcaPion || std::abs(candidate.dcaNegative()) < v0Configurations.dcaProton)) { return false; } if (candidate.lambdaPt() < ptMin) { @@ -1587,8 +1608,6 @@ struct lambdaspincorrderived { inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } - inline int massBin(float m) const { return binFromValue(m, mMin, mStep, nM_); } - inline int radiusBin(float r) const { if (!std::isfinite(r) || nR_ <= 0) { @@ -1609,6 +1628,210 @@ struct lambdaspincorrderived { uint16_t ptBin, etaBin, phiBin, mBin, rBin; }; + struct StoredV6Candidate { + int64_t collisionIdx = -1; + int64_t globalIdx = -1; + int status = -1; + bool isDouble = false; + float cospa = 0.f; + float radius = 0.f; + float dcaPos = 0.f; + float dcaNeg = 0.f; + float dcaDau = 0.f; + float lPt = 0.f; + float lEta = 0.f; + float lPhi = 0.f; + float lMass = 0.f; + float pPt = 0.f; + float pEta = 0.f; + float pPhi = 0.f; + int64_t pIndex = -1; + int64_t piIndex = -1; + + int v0Status() const { return status; } + bool doubleStatus() const { return isDouble; } + float v0Cospa() const { return cospa; } + float v0Radius() const { return radius; } + float dcaPositive() const { return dcaPos; } + float dcaNegative() const { return dcaNeg; } + float dcaBetweenDaughter() const { return dcaDau; } + float lambdaPt() const { return lPt; } + float lambdaEta() const { return lEta; } + float lambdaPhi() const { return lPhi; } + float lambdaMass() const { return lMass; } + float protonPt() const { return pPt; } + float protonEta() const { return pEta; } + float protonPhi() const { return pPhi; } + int64_t protonIndex() const { return pIndex; } + int64_t pionIndex() const { return piIndex; } + int64_t globalIndex() const { return globalIdx; } + }; + + struct PendingV6Branch { + StoredV6Candidate target; + StoredV6Candidate fixed; + int colBin = -1; + int replacedLeg = 1; + int age = 0; + uint64_t seed = 0; + }; + + template + StoredV6Candidate storeV6Candidate(T const& t, int64_t collisionIdx) const + { + return {collisionIdx, static_cast(t.globalIndex()), static_cast(t.v0Status()), static_cast(t.doubleStatus()), + t.v0Cospa(), t.v0Radius(), t.dcaPositive(), t.dcaNegative(), t.dcaBetweenDaughter(), + t.lambdaPt(), t.lambdaEta(), t.lambdaPhi(), t.lambdaMass(), + t.protonPt(), t.protonEta(), t.protonPhi(), + static_cast(t.protonIndex()), static_cast(t.pionIndex())}; + } + + template + void fillV6MixedBranch(TRep const& replacement, TFixed const& fixed, int replacedLeg, float controlWeight, float mixWeight) + { + const auto repProton = ROOT::Math::PtEtaPhiMVector(replacement.protonPt(), replacement.protonEta(), replacement.protonPhi(), o2::constants::physics::MassProton); + const auto repLambda = ROOT::Math::PtEtaPhiMVector(replacement.lambdaPt(), replacement.lambdaEta(), replacement.lambdaPhi(), replacement.lambdaMass()); + const auto fixedProton = ROOT::Math::PtEtaPhiMVector(fixed.protonPt(), fixed.protonEta(), fixed.protonPhi(), o2::constants::physics::MassProton); + const auto fixedLambda = ROOT::Math::PtEtaPhiMVector(fixed.lambdaPt(), fixed.lambdaEta(), fixed.lambdaPhi(), fixed.lambdaMass()); + const int repStatus = replacement.v0Status(); + const int fixedStatus = fixed.v0Status(); + + if (replacedLeg == 1) { + fillReplacementControlMap(repStatus, fixedStatus, 1, false, repLambda, controlWeight); + fillFixedLegControlMap(repStatus, fixedStatus, 1, false, fixedLambda, controlWeight); + if ((repStatus == 0 && fixedStatus == 1) || (repStatus == 1 && fixedStatus == 0)) { + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)repLambda.Phi(), (float)fixedLambda.Phi()), mixWeight); + } + } + if (repStatus == 0 && fixedStatus == 1) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } else if (repStatus == 1 && fixedStatus == 0) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 1); + } else { + fillHistograms(repStatus, fixedStatus, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } + return; + } + + fillReplacementControlMap(fixedStatus, repStatus, 2, false, repLambda, controlWeight); + fillFixedLegControlMap(fixedStatus, repStatus, 2, false, fixedLambda, controlWeight); + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)fixedLambda.Phi(), (float)repLambda.Phi()), mixWeight); + } + if (fixedStatus == 0 && repStatus == 1) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } else if (fixedStatus == 1 && repStatus == 0) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 2); + } else { + fillHistograms(fixedStatus, repStatus, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } + } + + struct StoredV6CandidateMC { + int64_t globalIdx = -1; + int status = -1; + bool isDouble = false; + float cospa = 0.f; + float radius = 0.f; + float dcaPos = 0.f; + float dcaNeg = 0.f; + float dcaDau = 0.f; + float lPt = 0.f; + float lEta = 0.f; + float lPhi = 0.f; + float lMass = 0.f; + float pPt = 0.f; + float pEta = 0.f; + float pPhi = 0.f; + int64_t pIndex = -1; + int64_t piIndex = -1; + + int v0Statusmc() const { return status; } + bool doubleStatusmc() const { return isDouble; } + float v0Cospamc() const { return cospa; } + float v0Radiusmc() const { return radius; } + float dcaPositivemc() const { return dcaPos; } + float dcaNegativemc() const { return dcaNeg; } + float dcaBetweenDaughtermc() const { return dcaDau; } + float lambdaPtmc() const { return lPt; } + float lambdaEtamc() const { return lEta; } + float lambdaPhimc() const { return lPhi; } + float lambdaMassmc() const { return lMass; } + float protonPtmc() const { return pPt; } + float protonEtamc() const { return pEta; } + float protonPhimc() const { return pPhi; } + int64_t protonIndexmc() const { return pIndex; } + int64_t pionIndexmc() const { return piIndex; } + int64_t globalIndex() const { return globalIdx; } + }; + + struct PendingV6BranchMC { + StoredV6CandidateMC target; + StoredV6CandidateMC fixed; + int colBin = -1; + int replacedLeg = 1; + int age = 0; + uint64_t seed = 0; + }; + + struct V6PendingState { + std::deque data; + std::deque mc; + }; + + V6PendingState v6Pending; + + template + StoredV6CandidateMC storeV6CandidateMC(T const& t) const + { + return {static_cast(t.globalIndex()), mcacc::v0Status(t), mcacc::doubleStatus(t), + mcacc::v0CosPA(t), mcacc::v0Radius(t), mcacc::dcaPos(t), mcacc::dcaNeg(t), mcacc::dcaDau(t), + mcacc::lamPt(t), mcacc::lamEta(t), mcacc::lamPhi(t), mcacc::lamMass(t), + mcacc::prPt(t), mcacc::prEta(t), mcacc::prPhi(t), + static_cast(mcacc::prIdx(t)), static_cast(mcacc::piIdx(t))}; + } + + template + void fillV6MixedBranchMC(TRep const& replacement, TFixed const& fixed, int replacedLeg, float controlWeight, float mixWeight) + { + const auto repProton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(replacement), mcacc::prEta(replacement), mcacc::prPhi(replacement), o2::constants::physics::MassProton); + const auto repLambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(replacement), mcacc::lamEta(replacement), mcacc::lamPhi(replacement), mcacc::lamMass(replacement)); + const auto fixedProton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(fixed), mcacc::prEta(fixed), mcacc::prPhi(fixed), o2::constants::physics::MassProton); + const auto fixedLambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(fixed), mcacc::lamEta(fixed), mcacc::lamPhi(fixed), mcacc::lamMass(fixed)); + const int repStatus = mcacc::v0Status(replacement); + const int fixedStatus = mcacc::v0Status(fixed); + + if (replacedLeg == 1) { + fillReplacementControlMap(repStatus, fixedStatus, 1, false, repLambda, controlWeight); + fillFixedLegControlMap(repStatus, fixedStatus, 1, false, fixedLambda, controlWeight); + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)repLambda.Phi(), (float)fixedLambda.Phi()), mixWeight); + } + if (repStatus == 0 && fixedStatus == 1) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } else if (repStatus == 1 && fixedStatus == 0) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 1); + } else { + fillHistograms(repStatus, fixedStatus, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } + return; + } + + fillReplacementControlMap(fixedStatus, repStatus, 2, false, repLambda, controlWeight); + fillFixedLegControlMap(fixedStatus, repStatus, 2, false, fixedLambda, controlWeight); + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)fixedLambda.Phi(), (float)repLambda.Phi()), mixWeight); + } + if (fixedStatus == 0 && repStatus == 1) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } else if (fixedStatus == 1 && repStatus == 0) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 2); + } else { + fillHistograms(fixedStatus, repStatus, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } + } + static inline size_t linearKeyR(int colBin, int statBin, int ptBin, int etaBin, int phiBin, int mBin, int rBin, int nStatus, int nPt, int nEta, int nPhi, int nM, int nR) @@ -1632,25 +1855,30 @@ struct lambdaspincorrderived { if (mcacc::lamMass(candidate) < MassMin || mcacc::lamMass(candidate) > MassMax) { return false; } - if (mcacc::v0CosPA(candidate) < cosPA) { + if (mcacc::v0CosPA(candidate) < v0Configurations.cosPA) { return false; } if (checkDoubleStatus && mcacc::doubleStatus(candidate)) { return false; } - if (mcacc::v0Radius(candidate) > radiusMax) { + if (mcacc::v0Radius(candidate) > v0Configurations.radiusMax) { return false; } - if (mcacc::v0Radius(candidate) < radiusMin) { + if (mcacc::v0Radius(candidate) < v0Configurations.radiusMin) { return false; } - if (mcacc::dcaDau(candidate) > dcaDaughters) { + if (mcacc::dcaDau(candidate) > v0Configurations.dcaDaughters) { return false; } - if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < dcaProton || std::abs(mcacc::dcaNeg(candidate)) < dcaPion)) { + + if (mcacc::dcaV0ToPVMC(candidate) > v0Configurations.dcaV0ToPV) { + return false; + } + + if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaProton || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaPion)) { return false; } - if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < dcaPion || std::abs(mcacc::dcaNeg(candidate)) < dcaProton)) { + if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaPion || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaProton)) { return false; } if (mcacc::lamPt(candidate) < ptMin) { @@ -2129,6 +2357,68 @@ struct lambdaspincorrderived { } }; + const size_t pendingAtStart = v6Pending.data.size(); + size_t pendingMatched = 0; + size_t pendingExpired = 0; + size_t pendingAdded = 0; + if (!cfgV6CarryUnmatched) { + v6Pending.data.clear(); + } else { + for (auto it = v6Pending.data.begin(); it != v6Pending.data.end();) { + auto& pending = *it; + ++pending.age; + if (cfgV6MaxPendingAge.value > 0 && pending.age > cfgV6MaxPendingAge.value) { + ++pendingExpired; + it = v6Pending.data.erase(it); + continue; + } + + auto& matches = pending.replacedLeg == 1 ? matches1 : matches2; + collectMatchesForReplacedLeg(pending.target, pending.fixed, pending.colBin, -1, matches); + limitMatchesToNEvents(matches, nEvtMixing.value); + downsampleMatches(matches, pending.seed ^ splitmix64(static_cast(pending.age))); + + int nAccepted = 0; + for (auto const& m : matches) { + auto replacement = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(replacement) || !checkKinematics(pending.target, replacement)) { + continue; + } + if (replacement.globalIndex() == pending.target.globalIndex() || replacement.globalIndex() == pending.fixed.globalIndex()) { + continue; + } + if (hasSharedDaughters(replacement, pending.target) || hasSharedDaughters(replacement, pending.fixed)) { + continue; + } + ++nAccepted; + } + + if (nAccepted == 0) { + ++it; + continue; + } + + const float controlWeight = 1.0f / static_cast(nAccepted); + const float branchNorm = cfgMixLegMode.value == 2 ? 0.5f : 1.0f; + const float mixWeight = branchNorm * controlWeight; + for (auto const& m : matches) { + auto replacement = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(replacement) || !checkKinematics(pending.target, replacement)) { + continue; + } + if (replacement.globalIndex() == pending.target.globalIndex() || replacement.globalIndex() == pending.fixed.globalIndex()) { + continue; + } + if (hasSharedDaughters(replacement, pending.target) || hasSharedDaughters(replacement, pending.fixed)) { + continue; + } + fillV6MixedBranch(replacement, pending.fixed, pending.replacedLeg, controlWeight, mixWeight); + } + ++pendingMatched; + it = v6Pending.data.erase(it); + } + } + // -------- PASS 2: configurable one-leg / two-leg mixing -------- for (auto const& col1 : collisions) { const int colBin = colBinning.getBin(std::make_tuple(col1.posz(), col1.cent())); @@ -2235,6 +2525,22 @@ struct lambdaspincorrderived { } } + if (cfgV6CarryUnmatched) { + const auto hasPendingSpace = [&]() { + return cfgV6MaxPendingBranches.value <= 0 || static_cast(v6Pending.data.size()) < cfgV6MaxPendingBranches.value; + }; + if (doMixLeg1 && nFill1 == 0 && hasPendingSpace()) { + v6Pending.data.push_back({storeV6Candidate(t1, curColIdx), storeV6Candidate(t2, curColIdx), colBin, 1, 0, + static_cast(t1.globalIndex()) ^ splitmix64(static_cast(t2.globalIndex())) ^ splitmix64(static_cast(curColIdx))}); + ++pendingAdded; + } + if (doMixLeg2 && nFill2 == 0 && hasPendingSpace()) { + v6Pending.data.push_back({storeV6Candidate(t2, curColIdx), storeV6Candidate(t1, curColIdx), colBin, 2, 0, + static_cast(t2.globalIndex()) ^ splitmix64(static_cast(t1.globalIndex())) ^ splitmix64(static_cast(curColIdx))}); + ++pendingAdded; + } + } + if (nFill1 <= 0 && nFill2 <= 0) { continue; } @@ -2246,9 +2552,10 @@ struct lambdaspincorrderived { const int nActiveMixBranches = ((doMixLeg1 && nFill1 > 0) ? 1 : 0) + ((doMixLeg2 && nFill2 > 0) ? 1 : 0); - const float branchNorm = (cfgMixLegMode.value == 2 && nActiveMixBranches > 0) - ? 1.0f / static_cast(nActiveMixBranches) - : 1.0f; + float branchNorm = 1.0f; + if (cfgMixLegMode.value == 2) { + branchNorm = cfgV6CarryUnmatched ? 0.5f : 1.0f / static_cast(nActiveMixBranches); + } const float finalMixWeightLeg1 = branchNorm * wSELeg1; const float finalMixWeightLeg2 = branchNorm * wSELeg2; @@ -2356,6 +2663,10 @@ struct lambdaspincorrderived { } } } + if (cfgV6LogPending) { + LOGF(info, "MEV6 data pending branches: carriedIn=%zu matched=%zu expired=%zu newlyPropagated=%zu carriedToNext=%zu", + pendingAtStart, pendingMatched, pendingExpired, pendingAdded, v6Pending.data.size()); + } } PROCESS_SWITCH(lambdaspincorrderived, processMEV6, "Process data ME v6 with radius buffer", false); @@ -2592,6 +2903,68 @@ struct lambdaspincorrderived { } }; + const size_t pendingAtStartMC = v6Pending.mc.size(); + size_t pendingMatchedMC = 0; + size_t pendingExpiredMC = 0; + size_t pendingAddedMC = 0; + if (!cfgV6CarryUnmatched) { + v6Pending.mc.clear(); + } else { + for (auto it = v6Pending.mc.begin(); it != v6Pending.mc.end();) { + auto& pending = *it; + ++pending.age; + if (cfgV6MaxPendingAge.value > 0 && pending.age > cfgV6MaxPendingAge.value) { + ++pendingExpiredMC; + it = v6Pending.mc.erase(it); + continue; + } + + auto& matches = pending.replacedLeg == 1 ? matches1 : matches2; + collectMatchesForReplacedLeg(pending.target, pending.fixed, pending.colBin, -1, matches); + limitMatchesToNEvents(matches, nEvtMixing.value); + downsampleMatches(matches, pending.seed ^ splitmix64(static_cast(pending.age))); + + int nAccepted = 0; + for (auto const& m : matches) { + auto replacement = V0sMC.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0MC(replacement) || !checkKinematicsMC(pending.target, replacement)) { + continue; + } + if (replacement.globalIndex() == pending.target.globalIndex() || replacement.globalIndex() == pending.fixed.globalIndex()) { + continue; + } + if (hasSharedDaughtersMC(replacement, pending.target) || hasSharedDaughtersMC(replacement, pending.fixed)) { + continue; + } + ++nAccepted; + } + + if (nAccepted == 0) { + ++it; + continue; + } + + const float controlWeight = 1.0f / static_cast(nAccepted); + const float branchNorm = cfgMixLegMode.value == 2 ? 0.5f : 1.0f; + const float mixWeight = branchNorm * controlWeight; + for (auto const& m : matches) { + auto replacement = V0sMC.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0MC(replacement) || !checkKinematicsMC(pending.target, replacement)) { + continue; + } + if (replacement.globalIndex() == pending.target.globalIndex() || replacement.globalIndex() == pending.fixed.globalIndex()) { + continue; + } + if (hasSharedDaughtersMC(replacement, pending.target) || hasSharedDaughtersMC(replacement, pending.fixed)) { + continue; + } + fillV6MixedBranchMC(replacement, pending.fixed, pending.replacedLeg, controlWeight, mixWeight); + } + ++pendingMatchedMC; + it = v6Pending.mc.erase(it); + } + } + // -------- PASS 2: configurable one-leg / two-leg mixing -------- for (auto const& col1 : collisions) { const int colBin = colBinning.getBin(std::make_tuple(mcacc::posz(col1), mcacc::cent(col1))); @@ -2699,6 +3072,22 @@ struct lambdaspincorrderived { } } + if (cfgV6CarryUnmatched) { + const auto hasPendingSpace = [&]() { + return cfgV6MaxPendingBranches.value <= 0 || static_cast(v6Pending.mc.size()) < cfgV6MaxPendingBranches.value; + }; + if (doMixLeg1 && nFill1 == 0 && hasPendingSpace()) { + v6Pending.mc.push_back({storeV6CandidateMC(t1), storeV6CandidateMC(t2), colBin, 1, 0, + static_cast(t1.globalIndex()) ^ splitmix64(static_cast(t2.globalIndex())) ^ splitmix64(static_cast(curColIdx))}); + ++pendingAddedMC; + } + if (doMixLeg2 && nFill2 == 0 && hasPendingSpace()) { + v6Pending.mc.push_back({storeV6CandidateMC(t2), storeV6CandidateMC(t1), colBin, 2, 0, + static_cast(t2.globalIndex()) ^ splitmix64(static_cast(t1.globalIndex())) ^ splitmix64(static_cast(curColIdx))}); + ++pendingAddedMC; + } + } + if (nFill1 <= 0 && nFill2 <= 0) { continue; } @@ -2708,9 +3097,10 @@ struct lambdaspincorrderived { const int nActiveMixBranches = ((doMixLeg1 && nFill1 > 0) ? 1 : 0) + ((doMixLeg2 && nFill2 > 0) ? 1 : 0); - const float branchNorm = (cfgMixLegMode.value == 2 && nActiveMixBranches > 0) - ? 1.0f / static_cast(nActiveMixBranches) - : 1.0f; + float branchNorm = 1.0f; + if (cfgMixLegMode.value == 2) { + branchNorm = cfgV6CarryUnmatched ? 0.5f : 1.0f / static_cast(nActiveMixBranches); + } const float finalMixWeightLeg1 = branchNorm * wSELeg1; const float finalMixWeightLeg2 = branchNorm * wSELeg2; @@ -2826,8 +3216,21 @@ struct lambdaspincorrderived { } } } + if (cfgV6LogPending) { + LOGF(info, "MEV6 MC pending branches: carriedIn=%zu matched=%zu expired=%zu newlyPropagated=%zu carriedToNext=%zu", + pendingAtStartMC, pendingMatchedMC, pendingExpiredMC, pendingAddedMC, v6Pending.mc.size()); + } } PROCESS_SWITCH(lambdaspincorrderived, processMCMEV6, "Process MC ME v6 with radius buffer", false); + + void endOfStream(EndOfStreamContext&) + { + if (cfgV6LogPending) { + LOGF(info, "MEV6 end of stream: unmatchedData=%zu unmatchedMC=%zu", v6Pending.data.size(), v6Pending.mc.size()); + } + v6Pending.data.clear(); + v6Pending.mc.clear(); + } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx index 8d2790a38a0..5ef6d65cd3c 100644 --- a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx +++ b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx @@ -305,7 +305,6 @@ struct NonPromptCascadeTask { AxisSpec nTracksAxis = {100, 0., 100., "NTracksGlobal"}; AxisSpec nTracksAxisMC = {100, 0., 100., "NTracksMC"}; std::vector centBinning; - std::vector multBinning; std::vector trackBinning; std::vector runsBinning; double cent = -0.0; @@ -841,6 +840,29 @@ struct NonPromptCascadeTask { return q != 0; }; + static constexpr float MinEtaFT0A = 3.5f; + static constexpr float MaxEtaFT0A = 4.9f; + static constexpr float MinEtaFT0C = -3.3f; + static constexpr float MaxEtaFT0C = -2.1f; + static constexpr float InvalidEta = -999.f; + + auto isAcceptedMCParticleFT0 = [&](auto const& mcp) { + if (!mcp.isPhysicalPrimary()) { + return false; + } + + const float eta = mcp.eta(); + if (!((eta > MinEtaFT0A && eta < MaxEtaFT0A) || (eta > MinEtaFT0C && eta < MaxEtaFT0C))) { + return false; + } + + int q = 0; + if (auto pdg = pdgDB->GetParticle(mcp.pdgCode())) { + q = static_cast(std::round(pdg->Charge() / 3.0)); + } + return q != 0; + }; + // ------------------------------------------------------------ // Helper: accepted reconstructed track // Use same cuts as data. @@ -866,6 +888,7 @@ struct NonPromptCascadeTask { // mcid: mc collision row of mc particle // ------------------------------------------------------------ std::vector mcMult(mcCollisions.size(), 0); + std::vector mcMultFT0(mcCollisions.size(), 0); // std::cout << "mcCollisions size:" << mcCollisions.size() << std::endl; for (auto const& mcp : mcParticles) { const int mcid = mcp.mcCollisionId(); @@ -874,10 +897,12 @@ struct NonPromptCascadeTask { LOG(info) << "0 This should never happen ?"; continue; } - if (!isAcceptedMCParticle(mcp)) { - continue; + if (isAcceptedMCParticle(mcp)) { + ++mcMult[mcid]; + } + if (isAcceptedMCParticleFT0(mcp)) { + ++mcMultFT0[mcid]; } - ++mcMult[mcid]; } // ------------------------------------------------------------ @@ -990,11 +1015,12 @@ struct NonPromptCascadeTask { const int mcCollId = col.mcCollisionId(); const float multReco = recoMultDense[dIdx]; const float ptReco = trk.pt(); + const float etaReco = trk.eta(); if (mcCollId < 0 || static_cast(mcCollId) >= mcCollisions.size()) { if (writeRecoCollision[dIdx]) { // Fake: accepted reco track whose reconstructed collision has no valid MC collision label. - NPMCNTable(-1.f, ptReco, multReco, -1.f); + NPMCNTable(-1.f, ptReco, InvalidEta, etaReco, multReco, -1.f, -1.f); } continue; } @@ -1003,7 +1029,7 @@ struct NonPromptCascadeTask { if (mcPid < 0 || static_cast(mcPid) >= mcParticles.size()) { if (writeMcCollision[mcCollId]) { // Fake: accepted reco track with invalid or missing MC particle label. - NPMCNTable(-2.f, ptReco, multReco, -2.f); + NPMCNTable(-2.f, ptReco, InvalidEta, etaReco, multReco, -2.f, mcMultFT0[mcCollId]); } continue; } @@ -1014,7 +1040,7 @@ struct NonPromptCascadeTask { if (mcParCollId != mcCollId) { if (writeMcCollision[mcCollId]) { // Fake: reco collision and particle label point to different MC collisions. - NPMCNTable(-3.f, ptReco, multReco, -3.f); + NPMCNTable(-3.f, ptReco, InvalidEta, etaReco, multReco, -3.f, mcMultFT0[mcCollId]); } continue; } @@ -1022,7 +1048,7 @@ struct NonPromptCascadeTask { if (!isAcceptedMCParticle(mcPar)) { if (writeMcCollision[mcCollId]) { // Feed-in: accepted reco track matched to truth outside fiducial phase space. - NPMCNTable(-4.f, ptReco, multReco, -4.f); + NPMCNTable(-4.f, ptReco, mcPar.eta(), etaReco, multReco, -4.f, mcMultFT0[mcCollId]); } continue; } @@ -1031,6 +1057,7 @@ struct NonPromptCascadeTask { const float multMC = mcMult[mcCollId]; const float ptMC = mcPar.pt(); + const float etaMC = mcPar.eta(); mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRM"), multMC, @@ -1040,7 +1067,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcCollId]) { // Matched: accepted truth particle reconstructed inside the fiducial reco phase space. - NPMCNTable(ptMC, ptReco, multReco, multMC); + NPMCNTable(ptMC, ptReco, etaMC, etaReco, multReco, multMC, mcMultFT0[mcCollId]); } } @@ -1069,6 +1096,7 @@ struct NonPromptCascadeTask { } const float multMC = mcMult[mcid]; + const float multMCFT0 = mcMultFT0[mcid]; mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRMNotInRecoTrk"), multMC, @@ -1076,7 +1104,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcid]) { // Missed track: accepted truth particle in a reconstructed MC collision, but no accepted reco track. - NPMCNTable(mcp.pt(), -1.f, -1.f, multMC); + NPMCNTable(mcp.pt(), -1.f, mcp.eta(), InvalidEta, -1.f, multMC, multMCFT0); } } @@ -1089,6 +1117,7 @@ struct NonPromptCascadeTask { } const float multMC = mcMult[mcid]; + const float multMCFT0 = mcMultFT0[mcid]; for (auto const& mcp : mcParticles) { if (mcp.mcCollisionId() != mcid) { @@ -1105,7 +1134,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcid]) { // Missed collision: accepted truth particle from an MC collision with no reconstructed collision. - NPMCNTable(mcp.pt(), -2.f, -2.f, multMC); + NPMCNTable(mcp.pt(), -2.f, mcp.eta(), InvalidEta, -2.f, multMC, multMCFT0); } } } @@ -1134,6 +1163,7 @@ struct NonPromptCascadeTask { auto tracksThisColl = tracks.sliceBy(perCollisionSel, coll.globalIndex()); int multreco = 0; std::vector recoPts; + std::vector recoEtas; // std::cout << "tracks:" << tracksThisColl.size() << std::endl; for (auto const& track : tracksThisColl) { // std::cout << track.pt() << " tracks " << track.isGlobalTrack() << std::endl; @@ -1141,6 +1171,7 @@ struct NonPromptCascadeTask { if (track.isGlobalTrack()) { multreco++; recoPts.push_back(track.pt()); + recoEtas.push_back(track.eta()); } } } @@ -1158,8 +1189,8 @@ struct NonPromptCascadeTask { coll.multFT0M(), coll.selection_bit(aod::evsel::kNoSameBunchPileup)); auto collIdx = NPCollsTable.lastIndex(); - for (auto const& pt : recoPts) { - NPRecoCandTable(collIdx, pt); + for (size_t i = 0; i < recoPts.size(); ++i) { + NPRecoCandTable(collIdx, recoPts[i], recoEtas[i]); } } } diff --git a/PWGLF/Utils/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h index 66646a38cad..7888def137a 100644 --- a/PWGLF/Utils/decay3bodyBuilderHelper.h +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/PWGLF/Utils/strangenessBuilderModule.h b/PWGLF/Utils/strangenessBuilderModule.h index 63ee3198b6d..563b75e6d95 100644 --- a/PWGLF/Utils/strangenessBuilderModule.h +++ b/PWGLF/Utils/strangenessBuilderModule.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/Utils/svPoolCreator.h b/PWGLF/Utils/svPoolCreator.h index bcb62b95f61..fedcaa95ce7 100644 --- a/PWGLF/Utils/svPoolCreator.h +++ b/PWGLF/Utils/svPoolCreator.h @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file svPoolCreator.h +/// \brief Time-compatible secondary-vertex track-pair and triplet pools +/// \author ALICE Collaboration + #ifndef PWGLF_UTILS_SVPOOLCREATOR_H_ #define PWGLF_UTILS_SVPOOLCREATOR_H_ @@ -32,6 +36,7 @@ using CollBracket = o2::math_utils::Bracket; constexpr uint64_t bOffsetMax = 241; // track compatibility can never go beyond 6 mus (ITS) +constexpr int NChargeSigns = 2; struct TrackCand { int Idxtr; @@ -44,6 +49,13 @@ struct SVCand { CollBracket collBracket{}; }; +struct SVCand3 { + int tr0Idx; + int tr1Idx; + int tr2Idx; + CollBracket collBracket{}; +}; + class svPoolCreator { public: @@ -61,7 +73,7 @@ class svPoolCreator void clearPools() { - for (auto& pool : trackCandPool) { + for (auto& pool : trackCandPool) { // o2-linter: disable=const-ref-in-for-loop (The pool is cleared in place.) pool.clear(); } tmap.clear(); @@ -200,15 +212,15 @@ class svPoolCreator template std::vector& getSVCandPool(const C& collisions, bool combineLikeSign = false) { - gsl::span> track0Pool{trackCandPool.data(), 2}; - gsl::span> track1Pool{trackCandPool.data() + 2, 2}; - std::array, 2> mVtxTrack0{}; // 1st pos. and neg. track of the kink pool for each vertex + gsl::span> track0Pool{trackCandPool.data(), NChargeSigns}; + gsl::span> track1Pool{trackCandPool.data() + NChargeSigns, NChargeSigns}; + std::array, NChargeSigns> mVtxTrack0{}; // 1st pos. and neg. track of the kink pool for each vertex - for (int i = 0; i < 2; i++) { + for (int i = 0; i < NChargeSigns; i++) { mVtxTrack0[i].clear(); mVtxTrack0[i].resize(collisions.size(), -1); } - for (int iCharge = 0; iCharge < 2; iCharge++) { + for (int iCharge = 0; iCharge < NChargeSigns; iCharge++) { auto& vtxFirstT = mVtxTrack0[iCharge]; const auto& signTrack0Pool = track0Pool[iCharge]; for (unsigned i = 0; i < signTrack0Pool.size(); i++) { @@ -271,4 +283,108 @@ class svPoolCreator TrackCand trForpool; }; +/// Build time-compatible three-track combinations by joining two svPoolCreator +/// pools on a common first prong. The class deliberately only handles +/// combinatorics; the caller remains responsible for fitting and physics +/// selections. +class svPoolCreator3Body +{ + public: + svPoolCreator3Body() = default; + svPoolCreator3Body(int track0Pdg, int track1Pdg, int track2Pdg) + : track0Pdg(track0Pdg), + track1Pdg(track1Pdg), + track2Pdg(track2Pdg), + pool01(track0Pdg, track1Pdg), + pool02(track0Pdg, track2Pdg) + { + } + + void setPDGs(int pdg0, int pdg1, int pdg2) + { + track0Pdg = pdg0; + track1Pdg = pdg1; + track2Pdg = pdg2; + pool01.setPDGs(track0Pdg, track1Pdg); + pool02.setPDGs(track0Pdg, track2Pdg); + } + + void clearPools() + { + pool01.clearPools(); + pool02.clearPools(); + svCandPool.clear(); + } + + void setTimeMargin(float timeMargin) + { + pool01.setTimeMargin(timeMargin); + pool02.setTimeMargin(timeMargin); + } + + void setSkipAmbiTracks() + { + pool01.setSkipAmbiTracks(); + pool02.setSkipAmbiTracks(); + } + + template + void fillBC2Coll(const C& collisions, BC const& bcs) + { + pool01.fillBC2Coll(collisions, bcs); + pool02.fillBC2Coll(collisions, bcs); + } + + template + void appendTrackCand(const T& trackCand, const C& collisions, int pdgHypo, const AT& ambiTracks, BC const& bcs) + { + if (pdgHypo == track0Pdg) { + pool01.appendTrackCand(trackCand, collisions, pdgHypo, ambiTracks, bcs); + pool02.appendTrackCand(trackCand, collisions, pdgHypo, ambiTracks, bcs); + } else if (pdgHypo == track1Pdg) { + pool01.appendTrackCand(trackCand, collisions, pdgHypo, ambiTracks, bcs); + } else if (pdgHypo == track2Pdg) { + pool02.appendTrackCand(trackCand, collisions, pdgHypo, ambiTracks, bcs); + } else { + LOGP(debug, "Wrong PDG hypothesis for three-body pool"); + } + } + + template + std::vector& getSVCandPool(const C& collisions, bool combineLikeSign01 = false, bool combineLikeSign02 = false) + { + auto& candidates01 = pool01.getSVCandPool(collisions, combineLikeSign01); + auto& candidates02 = pool02.getSVCandPool(collisions, combineLikeSign02); + std::unordered_multimap candidates02ByTrack0; + candidates02ByTrack0.reserve(candidates02.size()); + for (const auto& candidate02 : candidates02) { + candidates02ByTrack0.emplace(candidate02.tr0Idx, &candidate02); + } + + for (const auto& candidate01 : candidates01) { + const auto [begin, end] = candidates02ByTrack0.equal_range(candidate01.tr0Idx); + for (auto candidate02It = begin; candidate02It != end; ++candidate02It) { + const auto& candidate02 = *candidate02It->second; + if (candidate01.tr1Idx == candidate02.tr1Idx || + candidate01.collBracket.isOutside(candidate02.collBracket)) { + continue; + } + svCandPool.emplace_back(SVCand3{candidate01.tr0Idx, + candidate01.tr1Idx, + candidate02.tr1Idx, + candidate01.collBracket.getOverlap(candidate02.collBracket)}); + } + } + return svCandPool; + } + + private: + int track0Pdg = 0; + int track1Pdg = 0; + int track2Pdg = 0; + svPoolCreator pool01; + svPoolCreator pool02; + std::vector svCandPool; +}; + #endif // PWGLF_UTILS_SVPOOLCREATOR_H_ diff --git a/PWGMM/Lumi/Tasks/CMakeLists.txt b/PWGMM/Lumi/Tasks/CMakeLists.txt index 000f831a5c8..d684780eeea 100644 --- a/PWGMM/Lumi/Tasks/CMakeLists.txt +++ b/PWGMM/Lumi/Tasks/CMakeLists.txt @@ -17,7 +17,15 @@ o2physics_add_dpl_workflow(lumi O2::DetectorsCommonDataFormats O2::DetectorsVertexing COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lumifddft0 +o2physics_add_dpl_workflow(lumi-vertex + SOURCES lumiVertex.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCCDB O2Physics::AnalysisCore + O2::ReconstructionDataFormats + O2::DetectorsBase + O2::DetectorsCommonDataFormats + O2::DetectorsVertexing + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lumifddft0 # o2-linter: disable=name/o2-workflow (legacy workflow keeps its existing file name) SOURCES LumiFDDFT0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats @@ -26,7 +34,7 @@ o2physics_add_dpl_workflow(lumifddft0 O2::DetectorsVertexing COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(fitvdm +o2physics_add_dpl_workflow(fitvdm # o2-linter: disable=name/o2-workflow (legacy workflow keeps its existing name) SOURCES fitLumi.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats @@ -35,7 +43,7 @@ o2physics_add_dpl_workflow(fitvdm O2::DetectorsVertexing COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lumistab +o2physics_add_dpl_workflow(lumistab # o2-linter: disable=name/o2-workflow (legacy workflow keeps its existing name) SOURCES lumiStability.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats diff --git a/PWGMM/Lumi/Tasks/lumiVertex.cxx b/PWGMM/Lumi/Tasks/lumiVertex.cxx new file mode 100644 index 00000000000..d31f74b8159 --- /dev/null +++ b/PWGMM/Lumi/Tasks/lumiVertex.cxx @@ -0,0 +1,760 @@ +// 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 lumiVertex.cxx +/// \brief Codes for the vdM scan analysis based on the Primary Vertex reconstruction. The code is based on the lumiTask in O2Physics/PWGMM/Lumi/Tasks/lumi.cxx. +/// +/// \author Minjae Kim +/// \since Aug.06. 2026 + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/trackUtilities.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 +#include +#include +#include +#include + +namespace o2::aod +{ +namespace full +{ +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, uint64_t); +DECLARE_SOA_COLUMN(VertexX, vertexX, double); +DECLARE_SOA_COLUMN(VertexY, vertexY, double); +DECLARE_SOA_COLUMN(VertexZ, vertexZ, double); + +DECLARE_SOA_COLUMN(VertexXX, vertexXX, double); +DECLARE_SOA_COLUMN(VertexYY, vertexYY, double); +DECLARE_SOA_COLUMN(VertexXY, vertexXY, double); + +DECLARE_SOA_COLUMN(VertexChi2, vertexChi2, double); +DECLARE_SOA_COLUMN(NContrib, nContrib, int); +DECLARE_SOA_COLUMN(Bcid, bcid, int32_t); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); +DECLARE_SOA_COLUMN(LocalBC, localBC, int32_t); +DECLARE_SOA_COLUMN(InputMask, inputMask, uint64_t); +DECLARE_SOA_COLUMN(HasFT0, hasFT0, bool); +DECLARE_SOA_COLUMN(HasFoundFT0, hasFoundFT0, bool); +DECLARE_SOA_COLUMN(HasFT0TVX, hasFT0TVX, bool); +DECLARE_SOA_COLUMN(IsCollisionTVX, isCollisionTVX, bool); +DECLARE_SOA_COLUMN(HasAnyFT0Trigger, hasAnyFT0Trigger, bool); +DECLARE_SOA_COLUMN(HasFT0AC, hasFT0AC, bool); +DECLARE_SOA_COLUMN(Ft0TriggerMask, ft0TriggerMask, uint8_t); +DECLARE_SOA_COLUMN(Ft0Rate, ft0Rate, float); +DECLARE_SOA_COLUMN(NCollisions, nCollisions, int32_t); +DECLARE_SOA_COLUMN(NSelectedCollisions, nSelectedCollisions, int32_t); +DECLARE_SOA_COLUMN(IsCollidingBC, isCollidingBC, bool); +DECLARE_SOA_COLUMN(IsFT0SuperLeading, isFT0SuperLeading, bool); +DECLARE_SOA_COLUMN(HasPreviousFT0Activity, hasPreviousFT0Activity, bool); //! Whether a preceding FT0 CTP activity was observed +DECLARE_SOA_COLUMN(BcsSinceLastFT0Activity, bcsSinceLastFT0Activity, int64_t); //! -1 when the preceding activity is unknown +DECLARE_SOA_COLUMN(PvRefitValid, pvRefitValid, bool); +} // namespace full +DECLARE_SOA_TABLE(EventInfo, "AOD", "EventInfo", full::TimeStamp, full::VertexX, + full::VertexY, full::VertexZ, + + full::VertexXX, full::VertexYY, full::VertexXY, + + full::VertexChi2, full::NContrib, full::Bcid, full::RunNumber, + full::GlobalBC, full::HasFT0TVX, full::IsCollisionTVX, + full::HasAnyFT0Trigger, + full::IsCollidingBC, full::IsFT0SuperLeading, + full::HasPreviousFT0Activity, full::BcsSinceLastFT0Activity, + full::PvRefitValid); +DECLARE_SOA_TABLE(EventInfoBC, "AOD", "EventInfoBC", full::RunNumber, + full::TimeStamp, full::GlobalBC, full::LocalBC, + full::InputMask, full::HasFT0, full::HasFoundFT0, + full::HasFT0TVX, full::HasAnyFT0Trigger, full::HasFT0AC, + full::Ft0TriggerMask, full::Ft0Rate, full::NCollisions, + full::NSelectedCollisions, full::IsCollidingBC, + full::IsFT0SuperLeading, full::HasPreviousFT0Activity, + full::BcsSinceLastFT0Activity); +} // namespace o2::aod + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using MyBCs = soa::Join; +using CollisionsWithEvSels = soa::Join; +using UnfilteredTracks = soa::Join; + +struct LumiVertex { + Produces rowEventInfo; + Produces rowEventInfoBC; + Service ccdb{}; + const char* ccdbPathGrp = "GLO/Config/GRPMagField"; + const char* ccdbPathLut = "GLO/Param/MatLUT"; + const char* ccdburl = "http://alice-ccdb.cern.ch"; + int mFieldRunNumber = -1; + o2::base::MatLayerCylSet* mMatLUT = nullptr; + int mLHCIFRunNumber = -1; + o2::parameters::GRPLHCIFData* mLHCIFData = nullptr; + std::bitset mCollidingBCPattern; + + bool mHasPreviousFT0Activity = false; + uint64_t mGlobalBCOfLastFT0Activity = 0; + bool mHasLastProcessedBC = false; + uint64_t mLastProcessedGlobalBC = 0; + uint64_t mSkippedZeroTimestampBCs = 0; + + ctpRateFetcher mRateFetcher; + SliceCache cache; + PresliceUnsorted collisionsPerFoundBC = + aod::evsel::foundBCId; + Preslice tracksPerCollision = + aod::track::collisionId; + + struct : ConfigurableGroup { + Configurable ftts{"ftts", 0, + "Timestamp reference in ms; zero uses the fill start from GRPLHCIF"}; + Configurable nContribMax{"nContribMax", 2500, + "Maximum number of contributors"}; + Configurable nContribMin{"nContribMin", 1, + "Minimum number of contributors"}; + Configurable minVertexChi2{"minVertexChi2", 0, + "Minimum chi2 for PV selection"}; + Configurable maxVertexChi2PerContributor{"maxVertexChi2PerContributor", 999, + "Maximum refitted-vertex chi2 per contributor"}; + Configurable doBasicCheck{"doBasicCheck", true, + "Perform basic checks on the refitted vertex"}; + Configurable doCheckTVXCollision{"doCheckTVXCollision", true, + "Require the collision-level kIsTriggerTVX selection bit"}; + Configurable doPVrefit{"doPVrefit", true, + "Refit the primary vertex"}; + Configurable useMatCorrLUT{"useMatCorrLUT", true, + "Use the CCDB material LUT during PV refit; false disables material correction"}; + Configurable doHistogramAnalyisis{"doHistogramAnalyisis", true, + "Fill histograms for PV refit analysis"}; + Configurable doFetchFT0Rate{"doFetchFT0Rate", false, + "Fetch T0VTX rate from CTP scalers and store it in the BC table"}; + Configurable nBCsBeforeFT0SuperLeading{"nBCsBeforeFT0SuperLeading", 1, + "Minimum global-BC distance from the previous FT0 CTP activity"}; + + } basicConfig; + + struct : ConfigurableGroup { + Configurable requirePVContributor{"requirePVContributor", true, + "Use only tracks marked as PV contributors in the refit"}; + Configurable itsTrackPt{"itsTrackPt", 0.5, + "Minimum pt of tracks used for PV refit"}; + Configurable itsNCls{"itsNCls", 5, + "Minimum number of ITS clusters for tracks used for PV refit"}; + } trackConfig; + + HistogramRegistry histos{ + "histos", + {{"vertexx", "", {HistType::kTH1F, {{1000, -1, 1, "x"}}}}, // + {"vertexy", "", {HistType::kTH1F, {{1000, -1, 1, "y"}}}}, // + {"timestamp", "", {HistType::kTH1F, {{20000, 0, 2e7, "t"}}}}, // + {"vertexx_timestamp", + "", + {HistType::kTH2F, {{1000, 0, 4e6, "t"}, {2000, -1, 1, "x"}}}}, // + {"vertexy_timestamp", + "", + {HistType::kTH2F, {{1000, 0, 4e6, "t"}, {2000, -1, 1, "y"}}}}, // + {"chisquare", "", {HistType::kTH1F, {{1000, 0, 100, "#chi^{2}"}}}}, // + + {"vertexx_Refitted", "", {HistType::kTH1F, {{1000, -1, 1, "x"}}}}, // + {"vertexy_Refitted", "", {HistType::kTH1F, {{1000, -1, 1, "y"}}}}, // + {"vertexx_Refitted_timestamp", + "", + {HistType::kTH2F, {{1000, 0, 4e6, "t"}, {2000, -1, 1, "x"}}}}, // + {"vertexy_Refitted_timestamp", + "", + {HistType::kTH2F, {{1000, 0, 4e6, "t"}, {2000, -1, 1, "y"}}}}, // + {"chisquare_Refitted", + "", + {HistType::kTH1F, {{1000, 0, 100, "#chi^{2}"}}}}, // + + {"vertexx_Refitted_vertexx", + "", + {HistType::kTH2F, {{1000, -1, 1, "x"}, {1000, -1, 1, "rx"}}}}, // + {"vertexy_Refitted_vertexy", + "", + {HistType::kTH2F, {{1000, -1, 1, "y"}, {1000, -1, 1, "ry"}}}}, // + + {"bc/nStoredBCsVsBCID", + "Stored BC rows;BC ID in orbit;Entries", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"bc/nSkippedZeroTimestamp", + "BC rows skipped because timestamp is zero;;Entries", + {HistType::kTH1D, {{1, 0.5, 1.5}}}}, + {"bc/nCollidingBCsVsBCID", + "Stored colliding BC rows;BC ID in orbit;Entries", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"bc/nFT0ActivityBCsVsBCID", + "Stored BC rows with any FT0 CTP activity;BC ID in orbit;Entries", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"bc/nSuperLeadingFT0BCsVsBCID", + "TVX super-leading colliding BC rows;BC ID in orbit;Entries", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"bc/nNonSuperLeadingFT0BCsVsBCID", + "TVX non-super-leading colliding BC rows;BC ID in orbit;Entries", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"bc/nNoPreviousFT0ActivityBCsVsBCID", + "Colliding TVX BC rows without an observed preceding FT0 activity;BC ID in orbit;Entries", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + + {"collision/nCollisionsVsBCID", + "Collisions after the optional collision-TVX selection;found BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/nSelectedCollisionsVsBCID", + "Collisions passing the basic PV-refit selection;BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/nSuperLeadingFT0CollisionsVsBCID", + "Collisions in TVX super-leading BCs;BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/nNonSuperLeadingFT0CollisionsVsBCID", + "Collisions in TVX non-super-leading BCs;BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/nNoPreviousFT0ActivityCollisionsVsBCID", + "Collisions in TVX BCs without an observed preceding FT0 activity;BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/nSelectedSuperLeadingFT0CollisionsVsBCID", + "Selected collisions in TVX super-leading BCs;BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/nSelectedNonSuperLeadingFT0CollisionsVsBCID", + "Selected collisions in TVX non-super-leading BCs;BC ID in orbit;Collisions", + {HistType::kTH1D, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanVertexXVsBCID", + "Mean original vertex x by BC ID;BC ID in orbit;#LT x #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanVertexYVsBCID", + "Mean original vertex y by BC ID;BC ID in orbit;#LT y #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanRefittedVertexXVsBCID", + "Mean refitted vertex x by BC ID;BC ID in orbit;#LT x_{refit} #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanRefittedVertexYVsBCID", + "Mean refitted vertex y by BC ID;BC ID in orbit;#LT y_{refit} #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanRefittedVertexXSuperLeadingVsBCID", + "Mean refitted vertex x in TVX super-leading BCs;BC ID in orbit;#LT x_{refit} #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanRefittedVertexYSuperLeadingVsBCID", + "Mean refitted vertex y in TVX super-leading BCs;BC ID in orbit;#LT y_{refit} #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanRefittedVertexXNonSuperLeadingVsBCID", + "Mean refitted vertex x in TVX non-super-leading BCs;BC ID in orbit;#LT x_{refit} #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}, + {"collision/meanRefittedVertexYNonSuperLeadingVsBCID", + "Mean refitted vertex y in TVX non-super-leading BCs;BC ID in orbit;#LT y_{refit} #GT (cm)", + {HistType::kTProfile, {{o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches - 0.5, "BC ID in orbit"}}}}}}; + // CTP input 3 is MTVX; std::bitset uses a zero-based bit index. + static constexpr uint8_t FT0TVXInputBit = 2; + + static bool hasFT0ACCoincidence(uint8_t triggerMask) + { + return (triggerMask & (1U << o2::ft0::Triggers::bitA)) != 0U && + (triggerMask & (1U << o2::ft0::Triggers::bitC)) != 0U; + } + + static bool hasAnyFT0Trigger(const std::bitset<64>& ctpInputMask) + { + return ctpInputMask.test(0) || ctpInputMask.test(1) || + ctpInputMask.test(FT0TVXInputBit) || ctpInputMask.test(3) || + ctpInputMask.test(4); + } + + struct FT0SuperLeadingInfo { + bool isCollidingBC = false; + bool isSuperLeading = false; + bool hasPreviousFT0Activity = false; + bool hasFT0Activity = false; + bool hasFT0TVX = false; + int64_t bcsSinceLastActivity = -1; + }; + + void resetFT0SuperLeadingHistory() + { + mHasPreviousFT0Activity = false; + mGlobalBCOfLastFT0Activity = 0; + mHasLastProcessedBC = false; + mLastProcessedGlobalBC = 0; + } + + void setLHCIFData(const auto& bc) + { + if (mLHCIFRunNumber == bc.runNumber()) { + return; + } + if (mLHCIFRunNumber >= 0 && basicConfig.doHistogramAnalyisis) { + LOGF(warn, + "Run changed from %d to %d: BCID histograms aggregate runs. " + "Use EventInfo tables or one run per job for run-separated results.", + mLHCIFRunNumber, bc.runNumber()); + } + + mLHCIFData = ccdb->getForTimeStamp( + "GLO/Config/GRPLHCIF", bc.timestamp()); + if (mLHCIFData == nullptr) { + LOGF(fatal, + "GRPLHCIFData is not available for run=%d at timestamp=%llu", + bc.runNumber(), bc.timestamp()); + return; + } + + const auto beamPatternA = + mLHCIFData->getBunchFilling().getBeamPattern(0); + const auto beamPatternC = + mLHCIFData->getBunchFilling().getBeamPattern(1); + mCollidingBCPattern = beamPatternA & beamPatternC; + mLHCIFRunNumber = bc.runNumber(); + resetFT0SuperLeadingHistory(); + + LOGF(info, "Loaded filling scheme for run %d: %zu colliding BC IDs", + mLHCIFRunNumber, mCollidingBCPattern.count()); + } + + uint64_t getRelativeTimestamp(const auto& bc) const + { + const uint64_t referenceTimestamp = + basicConfig.ftts.value > 0 + ? basicConfig.ftts.value + : static_cast(mLHCIFData->getFillNumberTime()); + if (bc.timestamp() < referenceTimestamp) { + return 0; + } + return bc.timestamp() - referenceTimestamp; + } + + FT0SuperLeadingInfo classifyFT0SuperLeading( + uint64_t globalBC, + int32_t localBC, + const std::bitset<64>& ctpInputMask) + { + if (mHasLastProcessedBC && globalBC <= mLastProcessedGlobalBC) { + LOGF(warn, + "Non-increasing global BC sequence (%llu after %llu); " + "resetting FT0 super-leading history", + globalBC, mLastProcessedGlobalBC); + resetFT0SuperLeadingHistory(); + } + + FT0SuperLeadingInfo result; + result.isCollidingBC = mCollidingBCPattern.test(localBC); + result.hasFT0Activity = hasAnyFT0Trigger(ctpInputMask); + result.hasFT0TVX = ctpInputMask.test(FT0TVXInputBit); + result.hasPreviousFT0Activity = + mHasPreviousFT0Activity && globalBC > mGlobalBCOfLastFT0Activity; + + if (result.hasPreviousFT0Activity) { + result.bcsSinceLastActivity = + static_cast(globalBC - mGlobalBCOfLastFT0Activity); + } + const bool hasSufficientFT0Gap = + !result.hasPreviousFT0Activity || + result.bcsSinceLastActivity >= + static_cast(basicConfig.nBCsBeforeFT0SuperLeading.value); + result.isSuperLeading = result.hasFT0TVX && + result.isCollidingBC && + hasSufficientFT0Gap; + + // The current BC must be classified against preceding activity, so update + // the state only after the classification above. + if (result.hasFT0Activity) { + mGlobalBCOfLastFT0Activity = globalBC; + mHasPreviousFT0Activity = true; + } + mLastProcessedGlobalBC = globalBC; + mHasLastProcessedBC = true; + return result; + } + + void updateFieldAndMaterial(const auto& bc) + { + if (mFieldRunNumber == bc.runNumber()) { + return; + } + + auto* grpo = ccdb->getForTimeStamp( + ccdbPathGrp, bc.timestamp()); + if (grpo == nullptr) { + LOGF(fatal, + "GRP object is not available in CCDB for run=%d at timestamp=%llu", + bc.runNumber(), bc.timestamp()); + } + o2::base::Propagator::initFieldFromGRP(grpo); + + if (basicConfig.useMatCorrLUT) { + auto* rawLUT = ccdb->getForTimeStamp( + ccdbPathLut, bc.timestamp()); + if (rawLUT == nullptr) { + LOGF(fatal, + "Material LUT is not available in CCDB for run=%d at timestamp=%llu", + bc.runNumber(), bc.timestamp()); + } + mMatLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(rawLUT); + o2::base::Propagator::Instance()->setMatLUT(mMatLUT); + } + + mFieldRunNumber = bc.runNumber(); + } + + void init(InitContext&) + { + if (basicConfig.nBCsBeforeFT0SuperLeading < 1) { + LOGF(fatal, + "nBCsBeforeFT0SuperLeading must be at least 1 (received %d)", + basicConfig.nBCsBeforeFT0SuperLeading.value); + } + if (basicConfig.nContribMin < 0 || + basicConfig.nContribMax <= basicConfig.nContribMin) { + LOG(fatal) << "Require 0 <= nContribMin < nContribMax"; + } + if (basicConfig.maxVertexChi2PerContributor <= 0) { + LOG(fatal) << "maxVertexChi2PerContributor must be positive"; + } + if (!basicConfig.doPVrefit && basicConfig.doBasicCheck) { + LOG(warn) << "doPVrefit=false with doBasicCheck=true will reject all " + "collision rows; set doBasicCheck=false to store them"; + } + + // A mean-vertex constraint requires loading and passing the CCDB mean + // vertex object to PVertexer. This standalone task intentionally refits + // without that external constraint. + o2::conf::ConfigurableParam::updateFromString( + "pvertexer.useMeanVertexConstraint=true"); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + uint64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + } + + bool processCollision(auto const& collision, + auto const& bc, + auto const& unfilteredTracks, + uint64_t relativeTimestamp, + uint64_t globalBC, + int32_t localBC, + const FT0SuperLeadingInfo& ft0SLInfo) + { + // Check only the collision-level TVX bit. EvSels::sel8() would also apply + // the time-frame and ITS readout-frame border selections. + const bool isCollisionTVX = + collision.selection_bit(o2::aod::evsel::kIsTriggerTVX); + if (basicConfig.doCheckTVXCollision && !isCollisionTVX) { + return false; + } + + std::vector pvContributorTracks; + int nContrib = 0; + for (const auto& track : unfilteredTracks) { + if (trackConfig.requirePVContributor && !track.isPVContributor()) { + continue; + } + if (!track.hasITS()) { + continue; + } + if (track.pt() < trackConfig.itsTrackPt || + track.itsNCls() < trackConfig.itsNCls) { + continue; + } + pvContributorTracks.push_back(getTrackParCov(track)); + nContrib++; + } + + o2::dataformats::VertexBase primaryVertex; + primaryVertex.setX(collision.posX()); + primaryVertex.setY(collision.posY()); + primaryVertex.setZ(collision.posZ()); + primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), + collision.covXZ(), collision.covYZ(), collision.covZZ()); + + double chi2 = -1.; + double refitX = -9999.; + double refitY = -9999.; + double refitZ = -9999.; + double refitXX = -9999.; + double refitYY = -9999.; + double refitXY = -9999.; + + bool pvRefitValid = false; + if (basicConfig.doPVrefit && !pvContributorTracks.empty()) { + updateFieldAndMaterial(bc); + o2::vertexing::PVertexer vertexer; + vertexer.init(); + vertexer.setMatCorrType( + basicConfig.useMatCorrLUT + ? o2::base::Propagator::MatCorrType::USEMatCorrLUT + : o2::base::Propagator::MatCorrType::USEMatCorrNONE); + + const bool pvRefitDoable = + vertexer.prepareVertexRefit(pvContributorTracks, primaryVertex); + nContrib = static_cast(vertexer.getTracksPool().size()); + if (pvRefitDoable) { + std::vector useTrackForPVRefit(pvContributorTracks.size(), true); + const auto refittedVertex = + vertexer.refitVertex(useTrackForPVRefit, primaryVertex); + const double candidateChi2 = refittedVertex.getChi2(); + if (candidateChi2 >= 0. && + std::isfinite(candidateChi2) && + std::isfinite(refittedVertex.getX()) && + std::isfinite(refittedVertex.getY()) && + std::isfinite(refittedVertex.getZ())) { + pvRefitValid = true; + nContrib = refittedVertex.getNContributors(); + chi2 = candidateChi2; + refitX = refittedVertex.getX(); + refitY = refittedVertex.getY(); + refitZ = refittedVertex.getZ(); + refitXX = refittedVertex.getSigmaX2(); + refitYY = refittedVertex.getSigmaY2(); + refitXY = refittedVertex.getSigmaXY(); + } + } + } + + const bool passesBasicCheck = + pvRefitValid && + chi2 >= basicConfig.minVertexChi2 && + nContrib >= basicConfig.nContribMin && + nContrib <= basicConfig.nContribMax && + (chi2 / nContrib) <= + basicConfig.maxVertexChi2PerContributor; + const bool passesOutputSelection = + !basicConfig.doBasicCheck || passesBasicCheck; + if (passesOutputSelection) { + rowEventInfo(relativeTimestamp, refitX, refitY, refitZ, refitXX, + refitYY, refitXY, chi2, nContrib, localBC, + static_cast(bc.runNumber()), globalBC, + ft0SLInfo.hasFT0TVX, isCollisionTVX, + ft0SLInfo.hasFT0Activity, + ft0SLInfo.isCollidingBC, ft0SLInfo.isSuperLeading, + ft0SLInfo.hasPreviousFT0Activity, + ft0SLInfo.bcsSinceLastActivity, pvRefitValid); + } + + if (!basicConfig.doHistogramAnalyisis) { + return passesOutputSelection; + } + + histos.fill(HIST("collision/nCollisionsVsBCID"), localBC); + const bool isCollidingTVX = + ft0SLInfo.isCollidingBC && ft0SLInfo.hasFT0TVX && isCollisionTVX; + if (isCollidingTVX) { + if (!ft0SLInfo.hasPreviousFT0Activity) { + histos.fill( + HIST("collision/nNoPreviousFT0ActivityCollisionsVsBCID"), + localBC); + } + if (ft0SLInfo.isSuperLeading) { + histos.fill( + HIST("collision/nSuperLeadingFT0CollisionsVsBCID"), localBC); + } else { + histos.fill( + HIST("collision/nNonSuperLeadingFT0CollisionsVsBCID"), + localBC); + } + } + if (passesBasicCheck) { + histos.fill(HIST("collision/nSelectedCollisionsVsBCID"), localBC); + if (isCollidingTVX) { + if (ft0SLInfo.isSuperLeading) { + histos.fill( + HIST("collision/nSelectedSuperLeadingFT0CollisionsVsBCID"), + localBC); + } else { + histos.fill( + HIST("collision/nSelectedNonSuperLeadingFT0CollisionsVsBCID"), + localBC); + } + } + } + + if (pvRefitValid) { + histos.fill(HIST("chisquare_Refitted"), chi2); + } + const bool passesRefitHistogramSelection = passesBasicCheck; + if (passesRefitHistogramSelection) { + histos.fill(HIST("vertexx_Refitted"), refitX); + histos.fill(HIST("vertexy_Refitted"), refitY); + histos.fill(HIST("vertexx_Refitted_timestamp"), relativeTimestamp, + refitX); + histos.fill(HIST("vertexy_Refitted_timestamp"), relativeTimestamp, + refitY); + histos.fill(HIST("collision/meanRefittedVertexXVsBCID"), localBC, + refitX); + histos.fill(HIST("collision/meanRefittedVertexYVsBCID"), localBC, + refitY); + + if (isCollidingTVX) { + if (ft0SLInfo.isSuperLeading) { + histos.fill( + HIST("collision/meanRefittedVertexXSuperLeadingVsBCID"), + localBC, refitX); + histos.fill( + HIST("collision/meanRefittedVertexYSuperLeadingVsBCID"), + localBC, refitY); + } else { + histos.fill( + HIST("collision/meanRefittedVertexXNonSuperLeadingVsBCID"), + localBC, refitX); + histos.fill( + HIST("collision/meanRefittedVertexYNonSuperLeadingVsBCID"), + localBC, refitY); + } + } + } + + histos.fill(HIST("chisquare"), collision.chi2()); + const int originalNContrib = collision.numContrib(); + const bool passesOriginalHistogramSelection = + originalNContrib > 0 && + originalNContrib >= basicConfig.nContribMin && + originalNContrib <= basicConfig.nContribMax && + (collision.chi2() / originalNContrib) <= + basicConfig.maxVertexChi2PerContributor; + if (passesOriginalHistogramSelection) { + histos.fill(HIST("vertexx"), collision.posX()); + histos.fill(HIST("vertexy"), collision.posY()); + histos.fill(HIST("timestamp"), relativeTimestamp); + histos.fill(HIST("vertexx_timestamp"), relativeTimestamp, + collision.posX()); + histos.fill(HIST("vertexy_timestamp"), relativeTimestamp, + collision.posY()); + histos.fill(HIST("collision/meanVertexXVsBCID"), localBC, + collision.posX()); + histos.fill(HIST("collision/meanVertexYVsBCID"), localBC, + collision.posY()); + } + + if (passesOriginalHistogramSelection && + passesRefitHistogramSelection) { + histos.fill(HIST("vertexx_Refitted_vertexx"), collision.posX(), + refitX); + histos.fill(HIST("vertexy_Refitted_vertexy"), collision.posY(), + refitY); + } + return passesOutputSelection; + } + + void process(MyBCs const& bcs, CollisionsWithEvSels const& collisions, + UnfilteredTracks const& unfilteredTracks, aod::FT0s const&) + { + for (const auto& bc : bcs) { + if (bc.timestamp() == 0) { + mSkippedZeroTimestampBCs++; + resetFT0SuperLeadingHistory(); + if (basicConfig.doHistogramAnalyisis) { + histos.fill(HIST("bc/nSkippedZeroTimestamp"), 1.); + } + if (mSkippedZeroTimestampBCs == 1) { + LOG(warn) << "Skipping BC rows with timestamp zero and resetting " + "the FT0 super-leading history"; + } + continue; + } + + setLHCIFData(bc); + + const uint64_t relativeTimestamp = getRelativeTimestamp(bc); + const uint64_t globalBC = bc.globalBC(); + const auto localBC = static_cast(globalBC % o2::constants::lhc::LHCMaxBunches); + const std::bitset<64> ctpInputMask(bc.inputMask()); + const bool hasFT0 = bc.has_ft0(); + const uint8_t ft0TriggerMask = + hasFT0 ? bc.ft0().triggerMask() : 0; + const auto ft0SLInfo = + classifyFT0SuperLeading(globalBC, localBC, ctpInputMask); + + const bool hasFoundFT0 = bc.has_foundFT0(); + const bool hasFT0TVX = ft0SLInfo.hasFT0TVX; + const bool hasFT0AC = hasFT0ACCoincidence(ft0TriggerMask); + const float ft0Rate = basicConfig.doFetchFT0Rate ? static_cast(mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), "T0VTX", true) * 1.e-3) : -1.f; + + // EvSel TVX is evaluated on the collision's found BC, so group + // collisions by foundBCId rather than the nominal collision::bcId. + auto collisionsInBC = + collisions.sliceBy(collisionsPerFoundBC, bc.globalIndex()); + + if (basicConfig.doHistogramAnalyisis) { + histos.fill(HIST("bc/nStoredBCsVsBCID"), localBC); + if (ft0SLInfo.hasFT0Activity) { + histos.fill(HIST("bc/nFT0ActivityBCsVsBCID"), localBC); + } + if (ft0SLInfo.isCollidingBC) { + histos.fill(HIST("bc/nCollidingBCsVsBCID"), localBC); + if (ft0SLInfo.hasFT0TVX) { + if (!ft0SLInfo.hasPreviousFT0Activity) { + histos.fill( + HIST("bc/nNoPreviousFT0ActivityBCsVsBCID"), localBC); + } + if (ft0SLInfo.isSuperLeading) { + histos.fill( + HIST("bc/nSuperLeadingFT0BCsVsBCID"), localBC); + } else { + histos.fill( + HIST("bc/nNonSuperLeadingFT0BCsVsBCID"), localBC); + } + } + } + } + + int32_t nSelectedCollisions = 0; + for (const auto& collision : collisionsInBC) { + auto tracksInCollision = + unfilteredTracks.sliceBy( + tracksPerCollision, + collision.globalIndex()); + + if (processCollision(collision, bc, tracksInCollision, + relativeTimestamp, globalBC, localBC, + ft0SLInfo)) { + nSelectedCollisions++; + } + } + + rowEventInfoBC( + static_cast(bc.runNumber()), relativeTimestamp, globalBC, + localBC, bc.inputMask(), hasFT0, hasFoundFT0, hasFT0TVX, + ft0SLInfo.hasFT0Activity, hasFT0AC, ft0TriggerMask, ft0Rate, + static_cast(collisionsInBC.size()), nSelectedCollisions, + ft0SLInfo.isCollidingBC, ft0SLInfo.isSuperLeading, + ft0SLInfo.hasPreviousFT0Activity, + ft0SLInfo.bcsSinceLastActivity); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec w{adaptAnalysisTask(cfgc)}; + return w; +} diff --git a/PWGMM/Mult/Tasks/dndeta.cxx b/PWGMM/Mult/Tasks/dndeta.cxx index df1ebc63cd8..ae99e5f8205 100644 --- a/PWGMM/Mult/Tasks/dndeta.cxx +++ b/PWGMM/Mult/Tasks/dndeta.cxx @@ -842,7 +842,10 @@ struct MultiplicityCounter { using LabeledTracksEx = soa::Join; using FiLTracks = soa::Filtered; using ParticlesI = soa::Filtered>; - expressions::Filter primaries = ncheckbit(aod::mcparticle::flags, (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); + expressions::Filter primaries = + ifnode(nsqrt(aod::mcparticle::vx * aod::mcparticle::vx + aod::mcparticle::vy * aod::mcparticle::vy) > 5.f, + false, + ncheckbit(aod::mcparticle_v2::storedFlags, (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary)); bool isChargedParticle(int code) { diff --git a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx index f92319d5263..8d1d3af6736 100644 --- a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx +++ b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -3938,7 +3939,7 @@ struct DndetaMFTPbPb { } } - if (ids.size() > 0) { + if (!ids.empty()) { if (ids.size() == 1) { registry.fill(HIST("TimeAssocMC/hVTXkSelNonAmb"), deltaXv2, deltaYv2, deltaZv2); registry.fill(HIST("TimeAssocMC/hAmbTrkTypeAssocFlag"), static_cast(AmbTrkTypeAssocFlag::kSelNonAmb)); @@ -4444,8 +4445,6 @@ struct DndetaMFTPbPb { PROCESS_SWITCH(DndetaMFTPbPb, processAssocMC, "Process collision-association information, requires extra table from TrackToCollisionAssociation task (fillTableOfCollIdsPerTrack=true)", false); - PresliceUnsorted perColBest = aod::fwdtrack::bestCollisionId; - template void processReAssocMC(typename soa::Join const& collisions, B const& besttracks, @@ -4544,9 +4543,7 @@ struct DndetaMFTPbPb { } registry.fill(HIST("ReAssocMC/hReAssocMCEventStatus"), static_cast(ReAssocMCEventStatus::kEvtReAsZVtxCutMC), crec, occ); - auto perCollisionASample = besttracks.sliceBy(perColBest, collision.globalIndex()); - for (auto const& atrack : perCollisionASample) { - // for (auto const& atrack : besttracks) { + for (auto const& atrack : besttracks) { registry.fill(HIST("ReAssocMC/hReAssocMCTrackStatus"), static_cast(ReAssocMCTrackStatus::kTrkReAssocAll), crec, occ); if (!isBestTrackSelected(atrack)) { continue; diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx index 9159bb73607..4ff477d25d0 100644 --- a/PWGUD/Tasks/flowCorrelationsUpc.cxx +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -92,6 +91,8 @@ struct FlowCorrelationsUpc { O2_DEFINE_CONFIGURABLE(cfgRctFlagEnabled, bool, false, "use run condition table flag") O2_DEFINE_CONFIGURABLE(cfgRctFlagIndex, int, 1, "1: isCBTOk; 2:isCBTZdcOk; 3: isCBTHadronOk; 4:isCBTHadronZdcOk ") O2_DEFINE_CONFIGURABLE(cfgIRMaxCut, double, 50, "maximum interaction rate for UPC events") + O2_DEFINE_CONFIGURABLE(cfgZdcTime, bool, false, "choose zdc time cut") + O2_DEFINE_CONFIGURABLE(cfgZdcTimeCut, float, 2.0, "zdc time cut") ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; @@ -161,13 +162,16 @@ struct FlowCorrelationsUpc { registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisIndependent, axisPtTrigger}}}); - registry.add("eventcont", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many events are in the same and mixed event + registry.add("eventcont", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many events are in the same and mixed event registry.get(HIST("eventcont"))->GetXaxis()->SetBinLabel(4, "same"); registry.get(HIST("eventcont"))->GetXaxis()->SetBinLabel(5, "mix pair"); registry.add("deltaPhi_deltaEta_same", "deltaphi-deltaeta", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // histogram to check the delta eta and delta phi distribution registry.add("deltaPhi_deltaEta_mixed", "deltaphi-deltaeta", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // histogram to check the delta eta and delta phi distribution registry.add("Nch_raw_vs_independent", "Raw vs Independent", {HistType::kTH2D, {axisMultiplicity, axisIndependent}}); registry.add("interactionRate", "kHz", {HistType::kTH1F, {{50, 0, 50, "kHz"}}}); + registry.add("ZDCEnergy", "ZNA; ZNC; Count", {HistType::kTH2D, {{100, 0, 100}, {100, 0, 100}}}); + registry.add("ZDCTime", "ZNA; ZNC; Count", {HistType::kTH2D, {{100, -10, 10}, {100, -10, 10}}}); + registry.add("neutronClass", "ZNA; ZNC; Count", {HistType::kTH2D, {{2, 0, 2}, {2, 0, 2}}}); if (cfgUseNchRoughMCCorrected) { fnchRoughMCFunc = new TF1("fnchRoughMCFunc", cfgNchRoughMCFunction->c_str(), 0, 100); @@ -226,6 +230,59 @@ struct FlowCorrelationsUpc { } } + template + // zdc time cut + bool zdcTimeCut(const C& collision) + { + if (!cfgZdcTime) { + return true; + } + int neutronClass = -1; + float energyCommonZNA = collision.energyCommonZNA(), energyCommonZNC = collision.energyCommonZNC(); + float timeZNA = collision.timeZNA(), timeZNC = collision.timeZNC(); + if (std::isinf(energyCommonZNA)) + energyCommonZNA = -999; + if (std::isinf(energyCommonZNC)) + energyCommonZNC = -999; + if (std::isinf(timeZNA)) + timeZNA = -999; + if (std::isinf(timeZNC)) + timeZNC = -999; + registry.fill(HIST("ZDCEnergy"), energyCommonZNC, energyCommonZNA); + registry.fill(HIST("ZDCTime"), timeZNC, timeZNA); + if (std::abs(timeZNA) > cfgZdcTimeCut && std::abs(timeZNC) > cfgZdcTimeCut) { + neutronClass = 0; + registry.fill(HIST("neutronClass"), 0, 0); + } + if (std::abs(timeZNA) <= cfgZdcTimeCut && std::abs(timeZNC) > cfgZdcTimeCut) { + neutronClass = 1; + registry.fill(HIST("neutronClass"), 0, 1); + } + if (std::abs(timeZNA) > cfgZdcTimeCut && std::abs(timeZNC) <= cfgZdcTimeCut) { + neutronClass = 2; + registry.fill(HIST("neutronClass"), 1, 0); + } + if (std::abs(timeZNA) <= cfgZdcTimeCut && std::abs(timeZNC) <= cfgZdcTimeCut) { + neutronClass = 3; + registry.fill(HIST("neutronClass"), 1, 1); + } + if (cfgZdcTime) { + // reject 0n0n and XnXn + if (neutronClass == 0 || neutronClass == 3) { // o2-linter: disable=magic-number (ZDC time cut) + 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; + } + } + } + return true; + } + template bool eventSelected(const C& collision) { @@ -257,6 +314,10 @@ struct FlowCorrelationsUpc { return false; } + if (!zdcTimeCut(collision)) { + return false; + } + return true; } diff --git a/PWGUD/Tasks/flowCumulantsUpc.cxx b/PWGUD/Tasks/flowCumulantsUpc.cxx index 52df93c8f24..42ce67577ee 100644 --- a/PWGUD/Tasks/flowCumulantsUpc.cxx +++ b/PWGUD/Tasks/flowCumulantsUpc.cxx @@ -304,9 +304,20 @@ struct FlowCumulantsUpc { oba->Add(new TNamed(Form("Ch10Gap24_pt_%i", i + 1), "Ch10Gap24_pTDiff")); std::vector userDefineGFWCorr = cfgUserDefineGFWCorr; std::vector userDefineGFWName = cfgUserDefineGFWName; + if (userDefineGFWName.size() != userDefineGFWCorr.size()) { + LOGF(fatal, "The GFWConfig names you provided are NOT matching with configurations. userDefineGFWName.size(): %d, userDefineGFWCorr.size(): %d", userDefineGFWName.size(), userDefineGFWCorr.size()); + } + LOGF(info, "User adding FlowContainer Array:"); if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { for (uint i = 0; i < userDefineGFWName.size(); i++) { - oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + if (userDefineGFWCorr.at(i).find("poi") != std::string::npos) { + LOGF(info, "%d: pT-diff array %s", i, userDefineGFWName.at(i).c_str()); + for (auto iPt = 0; iPt < fPtAxis->GetNbins(); iPt++) + oba->Add(new TNamed(Form("%s_pt_%i", userDefineGFWName.at(i).c_str(), iPt + 1), Form("%s_pTDiff", userDefineGFWName.at(i).c_str()))); + } else { + LOGF(info, "%d: %s", i, userDefineGFWName.at(i).c_str()); + oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + } } } fFC->SetName("FlowContainer"); @@ -341,10 +352,24 @@ struct FlowCumulantsUpc { fGFW->AddRegion("refP", 0.4, maxEta, 1, 1); fGFW->AddRegion("refM", -0.4, 0.4, 1, 1); fGFW->AddRegion("poiN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN00", minEta, 0., 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); fGFW->AddRegion("poiN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 2); fGFW->AddRegion("poifull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 2); fGFW->AddRegion("olN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN00", minEta, 0., 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); fGFW->AddRegion("olN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 4); fGFW->AddRegion("olfull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 4); // eta region for MC, can be different from data to study the effect of acceptance @@ -369,10 +394,24 @@ struct FlowCumulantsUpc { fGFWMC->AddRegion("refP", 0.4, maxEta, 1, 1); fGFWMC->AddRegion("refM", -0.4, 0.4, 1, 1); fGFWMC->AddRegion("poiN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN00", minEta, 0., 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); fGFWMC->AddRegion("poiN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 2); fGFWMC->AddRegion("poifull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 2); fGFWMC->AddRegion("olN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN00", minEta, 0., 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); fGFWMC->AddRegion("olN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 4); fGFWMC->AddRegion("olfull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 4); corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); diff --git a/Tools/ML/MlResponse.h b/Tools/ML/MlResponse.h index 508d39123f5..cdc5a130714 100644 --- a/Tools/ML/MlResponse.h +++ b/Tools/ML/MlResponse.h @@ -163,7 +163,7 @@ class MlResponse { setAvailableInputFeatures(); for (const auto& inputFeature : cfgInputFeatures) { - if (mAvailableInputFeatures.count(inputFeature)) { + if (mAvailableInputFeatures.contains(inputFeature)) { mCachedIndices.emplace_back(mAvailableInputFeatures[inputFeature]); } else { LOG(fatal) << "Input feature " << inputFeature << " not available! Please check your configurables."; @@ -279,18 +279,18 @@ class MlResponse std::vector mModels; // OnnxModel objects, one for each bin uint8_t mNModels = 1; // number of bins uint8_t mNClasses = 3; // number of model classes - std::vector mBinsLimits = {}; // bin limits of the variable (e.g. pT) used to select which model to use - std::vector mBinsLimitsVar2 = {}; // bin limits of a second variable (e.g. multiplicity) used to select which model to use (not used in this base class) - std::vector mPaths = {""}; // paths to the models, one for each bin - std::vector mCutDir = {}; // direction of the cuts on the model scores (no cut is also supported) - o2::framework::LabeledArray mCuts = {}; // array of cut values to apply on the model scores + std::vector mBinsLimits; // bin limits of the variable (e.g. pT) used to select which model to use + std::vector mBinsLimitsVar2; // bin limits of a second variable (e.g. multiplicity) used to select which model to use (not used in this base class) + std::vector mPaths; // paths to the models, one for each bin + std::vector mCutDir; // direction of the cuts on the model scores (no cut is also supported) + o2::framework::LabeledArray mCuts; // array of cut values to apply on the model scores std::map mAvailableInputFeatures; // map of available input features std::vector mCachedIndices; // vector of index correspondance between configurables and available input features uint8_t mNVar1Bins = 1; // number of bins of the first variable (e.g. pT) used to select which model to use uint8_t mNVar2Bins = 1; // number of bins of the second variable (e.g. multiplicity) used to select which model to use bool mUse2DBinning = false; // switch to enable/disable 2D binning - virtual void setAvailableInputFeatures() { return; } // method to fill the map of available input features + virtual void setAvailableInputFeatures() {} // method to fill the map of available input features private: /// Finds matching bin in mBinsLimits