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"
@@ -47,6 +49,7 @@ using namespace o2::analysis::femto_universe;
4749using namespace o2 ::framework;
4850using namespace o2 ::framework::expressions;
4951using namespace o2 ::constants::physics;
52+ using namespace o2 ::aod::rctsel;
5053
5154namespace o2 ::aod
5255{
@@ -76,22 +79,23 @@ int getRowDaughters(int daughID, T const& vecID)
7679}
7780
7881struct FemtoUniverseProducerMCTruthTask {
79- int mRunNumber ;
80- float mMagField ;
81- Service<o2::ccdb::BasicCCDBManager> ccdb; // / Accessing the CCDB
82+
83+ float mMagField = 0 . ;
84+ Service<o2::ccdb::BasicCCDBManager> ccdb{} ; // / Accessing the CCDB
8285
8386 // Tables being produced
8487 Produces<aod::FdCollisions> outputCollision;
8588 Produces<aod::FDParticles> outputParts;
8689 // Produces<aod::FDMCLabels> outputPartsMCLabels;
8790 // Produces<aod::FdMCParticles> outputPartsMC;
8891
92+ RCTFlagsChecker rctChecker;
93+
8994 // Analysis configs
9095 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)" };
9396 Configurable<std::vector<int >> confPDGCodes{" confPDGCodes" , std::vector<int >{211 , -211 , 2212 , -2212 , 333 }, " PDG of particles to be stored" };
9497 Configurable<bool > confAnalysisWithPID{" confAnalysisWithPID" , true , " 1: take only particles with specified PDG, 0: all particles" };
98+ Configurable<bool > confStoreMotherPDG{" confStoreMotherPDG" , false , " Store mother's PDG in tempFitVar." };
9599
96100 // / Event cuts
97101 Configurable<float > confEvtZvtx{" confEvtZvtx" , 10 .f , " Evt sel: Max. z-Vertex (cm)" };
@@ -101,6 +105,7 @@ struct FemtoUniverseProducerMCTruthTask {
101105 Configurable<float > confCentFT0Min{" confCentFT0Min" , 0 .f , " Min CentFT0 value for centrality selection" };
102106 Configurable<float > confCentFT0Max{" confCentFT0Max" , 200 .f , " Max CentFT0 value for centrality selection" };
103107 Configurable<bool > confDoSpher{" confDoSpher" , false , " Calculate sphericity. If false sphericity will take value of 2." };
108+ Configurable<bool > confIsCheckRCTFlags{" confIsCheckRCTFlags" , true , " Use RCTFlags" };
104109
105110 // Track cuts
106111 struct : o2::framework::ConfigurableGroup {
@@ -113,21 +118,26 @@ struct FemtoUniverseProducerMCTruthTask {
113118 Configurable<float > yD0CandGenMax{" yD0CandGenMax" , 0.5 , " Rapidity cut for the D0/D0bar mesons" };
114119
115120 FemtoUniverseCollisionSelection colCuts;
121+ FemtoUniverseCollisionSelection recoCollCuts;
116122 FemtoUniverseTrackSelection trackCuts;
117123 HistogramRegistry qaRegistry{" QAHistos" , {}, OutputObjHandlingPolicy::QAObject};
124+ HistogramRegistry qaRecoRegistry{" QARecoHistos" , {}, OutputObjHandlingPolicy::QAObject};
118125
119126 void init (InitContext&)
120127 {
121- if (( doprocessTrackMC) == false ) {
122- LOGF (fatal, " Neither processFullData nor processFullMC enabled. Please choose one." );
128+ if (! doprocessTrackMC || !doprocessTrackMcOnlyRecoColl ) {
129+ LOGF (fatal, " Neither processTrackMC nor processTrackMcOnlyRecoColl enabled. Please choose one." );
123130 }
124-
131+ rctChecker.init (" CBT_hadronPID" , false , true );
132+ // MC Truth collisions
125133 colCuts.setCuts (confEvtZvtx, confEvtTriggerCheck, confEvtTriggerSel, confEvtOfflineCheck, confIsRun3, confCentFT0Min, confCentFT0Max);
126-
127134 colCuts.init (&qaRegistry);
135+ // MC Reco collisions
136+ recoCollCuts.setCuts (confEvtZvtx, confEvtTriggerCheck, confEvtTriggerSel, confEvtOfflineCheck, confIsRun3, confCentFT0Min, confCentFT0Max);
137+ recoCollCuts.init (&qaRecoRegistry);
138+
128139 trackCuts.init <aod::femtouniverseparticle::ParticleType::kTrack , aod::femtouniverseparticle::TrackType::kNoChild , aod::femtouniverseparticle::CutContainerType>(&qaRegistry);
129140
130- mRunNumber = 0 ;
131141 mMagField = 0.0 ;
132142
133143 // / Initializing CCDB
@@ -159,6 +169,44 @@ struct FemtoUniverseProducerMCTruthTask {
159169 }
160170 }
161171
172+ template <typename CollisionType>
173+ bool checkMcRecoCollisions (CollisionType const & col)
174+ {
175+ if (confIsCheckRCTFlags && !rctChecker (col)) {
176+ return false ;
177+ }
178+
179+ // check whether the basic event selection criteria are fulfilled
180+ // if the basic selection is NOT fulfilled MC Truth collision is rejected
181+ if (!recoCollCuts.isSelected (col)) {
182+ return false ;
183+ }
184+ // additional checks on the reconstructed collisions
185+ if (col.selection_bit (aod::evsel::kNoSameBunchPileup ) && col.selection_bit (aod::evsel::kIsGoodZvtxFT0vsPV ) && col.selection_bit (aod::evsel::kIsVertexITSTPC )) {
186+ recoCollCuts.fillQA (col);
187+ return true ;
188+ } else {
189+ return false ;
190+ }
191+ }
192+
193+ template <typename ParticleType>
194+ int getMotherPDG (ParticleType particle)
195+ {
196+ if (particle.isPhysicalPrimary ()) {
197+ return 0 ;
198+ } else if (particle.has_mothers ()) {
199+ if (particle.getProcess () == 20 || particle.getProcess () == 23 ) { // treat particles from hadronic scattering (20, 23) as primary
200+ return 0 ;
201+ }
202+ auto motherparticlesMC = particle.template mothers_as <aod::McParticles>();
203+ auto motherparticleMC = motherparticlesMC.front ();
204+ return motherparticleMC.pdgCode ();
205+ } else {
206+ return 999 ;
207+ }
208+ }
209+
162210 template <typename TrackType>
163211 void fillParticles (TrackType const & tracks)
164212 {
@@ -168,28 +216,27 @@ struct FemtoUniverseProducerMCTruthTask {
168216 // / if the most open selection criteria are not fulfilled there is no
169217 // / point looking further at the track
170218
171- if (particle.pt () < ConfFilteringTracks.confPtLowFilterCut || particle.pt () > ConfFilteringTracks.confPtHighFilterCut )
219+ if (particle.pt () < ConfFilteringTracks.confPtLowFilterCut || particle.pt () > ConfFilteringTracks.confPtHighFilterCut ) {
172220 continue ;
221+ }
173222
174223 int pdgCode = particle.pdgCode ();
175224
176225 if (confAnalysisWithPID) {
177226 bool pass = false ;
178227 std::vector<int > tmpPDGCodes = confPDGCodes; // necessary due to some features of the Configurable
179228 for (auto const & pdg : tmpPDGCodes) {
180- if (pdgCode == Pdg::kPhi ) { // phi meson
229+ if (pdgCode == Pdg::kPhi || // phi meson
230+ std::abs (pdgCode) == Pdg::kD0 || // D0(bar) meson
231+ pdgCode == Pdg::kDPlus || // D+ meson
232+ (pdg == pdgCode && particle.isPhysicalPrimary ())) {
181233 pass = true ;
182- } else if (std::abs (pdgCode) == Pdg::kD0 ) { // D0(bar) meson
183- pass = true ;
184- } else if (pdgCode == Pdg::kDPlus ) { // D+ meson
185- pass = true ;
186- } else if (static_cast <int >(pdg) == static_cast <int >(pdgCode)) {
187- if (particle.isPhysicalPrimary ())
188- pass = true ;
234+ break ; // Exit early once a match is found
189235 }
190236 }
191- if (!pass)
237+ if (!pass) {
192238 continue ;
239+ }
193240 }
194241
195242 // check if D0/D0bar mesons pass the rapidity cut
@@ -199,15 +246,10 @@ struct FemtoUniverseProducerMCTruthTask {
199246 if (std::abs (particle.pdgCode ()) == Pdg::kD0 ) {
200247 if (std::abs (particle.y ()) > yD0CandGenMax) {
201248 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 ;
210249 }
250+ origin = RecoDecay::getCharmHadronOrigin (tracks, particle);
251+ } else if (std::abs (particle.eta ()) > ConfFilteringTracks.confEtaFilterCut ) {
252+ continue ;
211253 }
212254
213255 // / check if we end-up with the correct final state using MC info
@@ -216,7 +258,8 @@ struct FemtoUniverseProducerMCTruthTask {
216258 // / check if we have D0(bar) → π± K∓
217259 continue ;
218260 }
219-
261+ // Getting the PDG code of the mother particle
262+ int motherPDG = confStoreMotherPDG ? getMotherPDG (particle) : particle.pdgCode ();
220263 // we cannot use isSelectedMinimal since it takes Ncls
221264 // if (!trackCuts.isSelectedMinimal(track)) {
222265 // continue;
@@ -239,22 +282,54 @@ struct FemtoUniverseProducerMCTruthTask {
239282 pdgCode,
240283 childIDs,
241284 origin,
242- - 999 . );
285+ motherPDG );
243286 }
244287 }
245288
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 &)
289+ void processTrackMC (aod::McCollision const &,
290+ soa::SmallGroups<soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels>> const & collisions,
291+ aod::McParticles const & mcParticles,
292+ aod::BCsWithTimestamps const &)
251293 {
252294 // magnetic field for run not needed for mc truth
253295 // fill the tables
254296 fillCollisions (collisions, mcParticles);
255297 fillParticles (mcParticles);
256298 }
257299 PROCESS_SWITCH (FemtoUniverseProducerMCTruthTask, processTrackMC, " Provide MC data for track analysis" , true );
300+
301+ Preslice<aod::McParticles> perMCCollision = aod::mcparticle::mcCollisionId;
302+ PresliceUnsorted<soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels>> recoCollsPerMCColl = aod::mcparticle::mcCollisionId;
303+
304+ void processTrackMcOnlyRecoColl (aod::McCollisions const & mccols,
305+ soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::McCollisionLabels> const & collisions,
306+ aod::McParticles const & mcParticles,
307+ aod::BCsWithTimestamps const &)
308+ {
309+ // check on the reco collisions
310+ static std::set<int > mcColIds;
311+ mcColIds.clear ();
312+
313+ for (const auto & col : collisions) {
314+ const auto colcheck = checkMcRecoCollisions (col);
315+ if (colcheck) {
316+ mcColIds.insert (col.mcCollisionId ());
317+ }
318+ }
319+ // filling truth collisions and particles
320+ for (const auto & mccol : mccols) {
321+ if (!mcColIds.contains (mccol.globalIndex ())) {
322+ continue ;
323+ }
324+ auto groupedMCParticles = mcParticles.sliceBy (perMCCollision, mccol.globalIndex ());
325+ auto groupedCollisions = collisions.sliceBy (recoCollsPerMCColl, mccol.globalIndex ());
326+ // magnetic field for run not needed for mc truth
327+ // fill the tables
328+ fillCollisions (groupedCollisions, groupedMCParticles);
329+ fillParticles (groupedMCParticles);
330+ }
331+ }
332+ PROCESS_SWITCH (FemtoUniverseProducerMCTruthTask, processTrackMcOnlyRecoColl, " Provide MC data for track analysis from truth coll which were recontructed " , false );
258333};
259334
260335WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments