1818#include " PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h"
1919#include " PWGCF/FemtoUniverse/DataModel/FemtoDerived.h"
2020
21+ #include " Common/CCDB/EventSelectionParams.h"
22+ #include " Common/CCDB/RCTSelectionFlags.h"
2123#include " Common/CCDB/TriggerAliases.h"
2224#include " Common/Core/RecoDecay.h"
2325#include " Common/DataModel/EventSelection.h"
4042#include < chrono>
4143#include < cstddef>
4244#include < cstdint>
45+ #include < set>
4346#include < vector>
4447
4548using namespace o2 ;
4649using namespace o2 ::analysis::femto_universe;
4750using namespace o2 ::framework;
4851using namespace o2 ::framework::expressions;
4952using namespace o2 ::constants::physics;
53+ using namespace o2 ::aod::rctsel;
5054
5155namespace o2 ::aod
5256{
@@ -76,22 +80,26 @@ int getRowDaughters(int daughID, T const& vecID)
7680}
7781
7882struct FemtoUniverseProducerMCTruthTask {
79- int mRunNumber ;
80- float mMagField ;
81- Service<o2::ccdb::BasicCCDBManager> ccdb; // / Accessing the CCDB
83+
84+ float mMagField = 0 . ;
85+ Service<o2::ccdb::BasicCCDBManager> ccdb{} ; // / Accessing the CCDB
8286
8387 // Tables being produced
8488 Produces<aod::FdCollisions> outputCollision;
8589 Produces<aod::FDParticles> outputParts;
8690 // Produces<aod::FDMCLabels> outputPartsMCLabels;
8791 // Produces<aod::FdMCParticles> outputPartsMC;
8892
93+ RCTFlagsChecker rctChecker;
94+
95+ static constexpr int kHadElasticScatt = 20 ; // kPHElastic - hadronic elastic scattering
96+ static constexpr int kHadInelasticScatt = 23 ; // kPHInhelastic - hadronic inelastic scattering
97+
8998 // Analysis configs
9099 Configurable<bool > confIsRun3{" confIsRun3" , false , " Running on Run3 or pilot" };
91- Configurable<bool > confIsMC{" confIsMC" , false , " Running on MC; implemented only for Run3" };
92- Configurable<bool > confIsForceGRP{" confIsForceGRP" , false , " Set true if the magnetic field configuration is not available in the usual CCDB directory (e.g. for Run 2 converted data or unanchorad Monte Carlo)" };
93100 Configurable<std::vector<int >> confPDGCodes{" confPDGCodes" , std::vector<int >{211 , -211 , 2212 , -2212 , 333 }, " PDG of particles to be stored" };
94101 Configurable<bool > confAnalysisWithPID{" confAnalysisWithPID" , true , " 1: take only particles with specified PDG, 0: all particles" };
102+ Configurable<bool > confStoreMotherPDG{" confStoreMotherPDG" , false , " Store mother's PDG in tempFitVar." };
95103
96104 // / Event cuts
97105 Configurable<float > confEvtZvtx{" confEvtZvtx" , 10 .f , " Evt sel: Max. z-Vertex (cm)" };
@@ -101,6 +109,7 @@ struct FemtoUniverseProducerMCTruthTask {
101109 Configurable<float > confCentFT0Min{" confCentFT0Min" , 0 .f , " Min CentFT0 value for centrality selection" };
102110 Configurable<float > confCentFT0Max{" confCentFT0Max" , 200 .f , " Max CentFT0 value for centrality selection" };
103111 Configurable<bool > confDoSpher{" confDoSpher" , false , " Calculate sphericity. If false sphericity will take value of 2." };
112+ Configurable<bool > confIsCheckRCTFlags{" confIsCheckRCTFlags" , true , " Use RCTFlags" };
104113
105114 // Track cuts
106115 struct : o2::framework::ConfigurableGroup {
@@ -113,21 +122,26 @@ struct FemtoUniverseProducerMCTruthTask {
113122 Configurable<float > yD0CandGenMax{" yD0CandGenMax" , 0.5 , " Rapidity cut for the D0/D0bar mesons" };
114123
115124 FemtoUniverseCollisionSelection colCuts;
125+ FemtoUniverseCollisionSelection recoCollCuts;
116126 FemtoUniverseTrackSelection trackCuts;
117127 HistogramRegistry qaRegistry{" QAHistos" , {}, OutputObjHandlingPolicy::QAObject};
128+ HistogramRegistry qaRecoRegistry{" QARecoHistos" , {}, OutputObjHandlingPolicy::QAObject};
118129
119130 void init (InitContext&)
120131 {
121- if (( doprocessTrackMC) == false ) {
122- LOGF (fatal, " Neither processFullData nor processFullMC enabled. Please choose one." );
132+ if (! doprocessTrackMC || !doprocessTrackMcOnlyRecoColl ) {
133+ LOGF (fatal, " Neither processTrackMC nor processTrackMcOnlyRecoColl enabled. Please choose one." );
123134 }
124-
135+ rctChecker.init (" CBT_hadronPID" , false , true );
136+ // MC Truth collisions
125137 colCuts.setCuts (confEvtZvtx, confEvtTriggerCheck, confEvtTriggerSel, confEvtOfflineCheck, confIsRun3, confCentFT0Min, confCentFT0Max);
126-
127138 colCuts.init (&qaRegistry);
139+ // MC Reco collisions
140+ recoCollCuts.setCuts (confEvtZvtx, confEvtTriggerCheck, confEvtTriggerSel, confEvtOfflineCheck, confIsRun3, confCentFT0Min, confCentFT0Max);
141+ recoCollCuts.init (&qaRecoRegistry);
142+
128143 trackCuts.init <aod::femtouniverseparticle::ParticleType::kTrack , aod::femtouniverseparticle::TrackType::kNoChild , aod::femtouniverseparticle::CutContainerType>(&qaRegistry);
129144
130- mRunNumber = 0 ;
131145 mMagField = 0.0 ;
132146
133147 // / Initializing CCDB
@@ -159,6 +173,43 @@ struct FemtoUniverseProducerMCTruthTask {
159173 }
160174 }
161175
176+ template <typename CollisionType>
177+ bool checkMcRecoCollisions (CollisionType const & col)
178+ {
179+ if (confIsCheckRCTFlags && !rctChecker (col)) {
180+ return false ;
181+ }
182+
183+ // check whether the basic event selection criteria are fulfilled
184+ // if the basic selection is NOT fulfilled MC Truth collision is rejected
185+ if (!recoCollCuts.isSelected (col)) {
186+ return false ;
187+ }
188+ // additional checks on the reconstructed collisions
189+ if (col.selection_bit (aod::evsel::kNoSameBunchPileup ) && col.selection_bit (aod::evsel::kIsGoodZvtxFT0vsPV ) && col.selection_bit (aod::evsel::kIsVertexITSTPC )) {
190+ recoCollCuts.fillQA (col);
191+ return true ;
192+ }
193+ return false ;
194+ }
195+
196+ template <typename ParticleType>
197+ int getMotherPDG (ParticleType const & particle)
198+ {
199+ if (particle.isPhysicalPrimary ()) {
200+ return 0 ;
201+ }
202+ if (particle.has_mothers ()) {
203+ if (particle.getProcess () == kHadElasticScatt || particle.getProcess () == kHadInelasticScatt ) { // treat particles from hadronic scattering (20, 23) as primary
204+ return 0 ;
205+ }
206+ auto motherparticlesMC = particle.template mothers_as <aod::McParticles>();
207+ const auto & motherparticleMC = motherparticlesMC.front ();
208+ return motherparticleMC.pdgCode ();
209+ }
210+ return 999 ;
211+ }
212+
162213 template <typename TrackType>
163214 void fillParticles (TrackType const & tracks)
164215 {
@@ -168,28 +219,27 @@ struct FemtoUniverseProducerMCTruthTask {
168219 // / if the most open selection criteria are not fulfilled there is no
169220 // / point looking further at the track
170221
171- if (particle.pt () < ConfFilteringTracks.confPtLowFilterCut || particle.pt () > ConfFilteringTracks.confPtHighFilterCut )
222+ if (particle.pt () < ConfFilteringTracks.confPtLowFilterCut || particle.pt () > ConfFilteringTracks.confPtHighFilterCut ) {
172223 continue ;
224+ }
173225
174226 int pdgCode = particle.pdgCode ();
175227
176228 if (confAnalysisWithPID) {
177229 bool pass = false ;
178230 std::vector<int > tmpPDGCodes = confPDGCodes; // necessary due to some features of the Configurable
179231 for (auto const & pdg : tmpPDGCodes) {
180- if (pdgCode == Pdg::kPhi ) { // phi meson
181- pass = true ;
182- } else if (std::abs (pdgCode) == Pdg::kD0 ) { // D0(bar) meson
183- pass = true ;
184- } else if (pdgCode == Pdg::kDPlus ) { // D+ meson
232+ if (pdgCode == Pdg::kPhi || // phi meson
233+ std::abs (pdgCode) == Pdg::kD0 || // D0(bar) meson
234+ pdgCode == Pdg::kDPlus || // D+ meson
235+ (pdg == pdgCode && particle.isPhysicalPrimary ())) {
185236 pass = true ;
186- } else if (static_cast <int >(pdg) == static_cast <int >(pdgCode)) {
187- if (particle.isPhysicalPrimary ())
188- pass = true ;
237+ break ; // Exit early once a match is found
189238 }
190239 }
191- if (!pass)
240+ if (!pass) {
192241 continue ;
242+ }
193243 }
194244
195245 // check if D0/D0bar mesons pass the rapidity cut
@@ -199,15 +249,10 @@ struct FemtoUniverseProducerMCTruthTask {
199249 if (std::abs (particle.pdgCode ()) == Pdg::kD0 ) {
200250 if (std::abs (particle.y ()) > yD0CandGenMax) {
201251 continue ;
202- } else {
203- origin = RecoDecay::getCharmHadronOrigin (tracks, particle);
204- }
205- } else {
206- if (std::abs (particle.eta ()) > ConfFilteringTracks.confEtaFilterCut ) {
207- continue ;
208- } else {
209- origin = -99 ;
210252 }
253+ origin = RecoDecay::getCharmHadronOrigin (tracks, particle);
254+ } else if (std::abs (particle.eta ()) > ConfFilteringTracks.confEtaFilterCut ) {
255+ continue ;
211256 }
212257
213258 // / check if we end-up with the correct final state using MC info
@@ -216,7 +261,8 @@ struct FemtoUniverseProducerMCTruthTask {
216261 // / check if we have D0(bar) → π± K∓
217262 continue ;
218263 }
219-
264+ // Getting the PDG code of the mother particle
265+ int motherPDG = confStoreMotherPDG ? getMotherPDG (particle) : particle.pdgCode ();
220266 // we cannot use isSelectedMinimal since it takes Ncls
221267 // if (!trackCuts.isSelectedMinimal(track)) {
222268 // continue;
@@ -239,22 +285,54 @@ struct FemtoUniverseProducerMCTruthTask {
239285 pdgCode,
240286 childIDs,
241287 origin,
242- - 999 . );
288+ motherPDG );
243289 }
244290 }
245291
246- void
247- processTrackMC (aod::McCollision const &,
248- soa::SmallGroups<soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels>> const & collisions,
249- aod::McParticles const & mcParticles,
250- aod::BCsWithTimestamps const &)
292+ void processTrackMC (aod::McCollision const &,
293+ soa::SmallGroups<soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels>> const & collisions,
294+ aod::McParticles const & mcParticles,
295+ aod::BCsWithTimestamps const &)
251296 {
252297 // magnetic field for run not needed for mc truth
253298 // fill the tables
254299 fillCollisions (collisions, mcParticles);
255300 fillParticles (mcParticles);
256301 }
257302 PROCESS_SWITCH (FemtoUniverseProducerMCTruthTask, processTrackMC, " Provide MC data for track analysis" , true );
303+
304+ Preslice<aod::McParticles> perMCCollision = aod::mcparticle::mcCollisionId;
305+ PresliceUnsorted<soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels>> recoCollsPerMCColl = aod::mcparticle::mcCollisionId;
306+
307+ void processTrackMcOnlyRecoColl (aod::McCollisions const & mccols,
308+ soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels> const & collisions,
309+ aod::McParticles const & mcParticles,
310+ aod::BCsWithTimestamps const &)
311+ {
312+ // check on the reco collisions
313+ static std::set<int > mcColIds;
314+ mcColIds.clear ();
315+
316+ for (const auto & col : collisions) {
317+ const auto colcheck = checkMcRecoCollisions (col);
318+ if (colcheck) {
319+ mcColIds.insert (col.mcCollisionId ());
320+ }
321+ }
322+ // filling truth collisions and particles
323+ for (const auto & mccol : mccols) {
324+ if (!mcColIds.contains (mccol.globalIndex ())) {
325+ continue ;
326+ }
327+ auto groupedMCParticles = mcParticles.sliceBy (perMCCollision, mccol.globalIndex ());
328+ auto groupedCollisions = collisions.sliceBy (recoCollsPerMCColl, mccol.globalIndex ());
329+ // magnetic field for run not needed for mc truth
330+ // fill the tables
331+ fillCollisions (groupedCollisions, groupedMCParticles);
332+ fillParticles (groupedMCParticles);
333+ }
334+ }
335+ PROCESS_SWITCH (FemtoUniverseProducerMCTruthTask, processTrackMcOnlyRecoColl, " Provide MC data for track analysis from truth coll which were recontructed " , false );
258336};
259337
260338WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments