6464using namespace o2 ;
6565using namespace o2 ::framework;
6666
67+ namespace
68+ {
69+
70+ enum trackQuality {
71+ kNoCuts = 0 ,
72+ kEtaCut = 1 ,
73+ kPtpcCut = 2 ,
74+ kNclsItsCut = 3 ,
75+ kNclsTpcCut = 4 ,
76+ kNCrossedRowsCut = 5 ,
77+ kTpcChi2Cut = 6 ,
78+ kItsChi2Cut = 7 ,
79+ kNtrackQuality = 8
80+ };
81+
82+ std::array<std::string, trackQuality::kNtrackQuality > trackQualityLabels{" All" , " #eta cut" , " #it{p}_{TPC}^{min} cut" , " #it{N}_{cls}^{ITS} cut" , " #it{N}_{cls}^{TPC} cut" , " Crossed rows cut" , " #chi^{2}_{TPC} cut" , " #chi^{2}_{ITS} cut" };
83+
84+ } // namespace
85+
6786struct nucleiQC {
6887
6988 using TrackCandidates = soa::Join<aod::TracksIU, aod::TracksExtra, aod::TracksCovIU, aod::TOFSignal, aod::TOFEvTime, aod::pidTPCPr, aod::pidTOFPr, aod::pidTPCDe, aod::pidTOFDe, aod::pidTPCTr, aod::pidTOFTr, aod::pidTPCHe, aod::pidTOFHe, aod::pidTPCAl, aod::pidTOFAl>;
7089 using TrackCandidatesMC = soa::Join<aod::TracksIU, aod::TracksExtra, aod::TracksCovIU, aod::TOFSignal, aod::TOFEvTime, aod::pidTPCPr, aod::pidTOFPr, aod::pidTPCDe, aod::pidTOFDe, aod::pidTPCTr, aod::pidTOFTr, aod::pidTPCHe, aod::pidTOFHe, aod::pidTPCAl, aod::pidTOFAl, aod::McTrackLabels>;
7190 using Collision = soa::Join<aod::Collisions, aod::EvSels, aod::CentFV0As, aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs, aod::CentNTPVs, aod::McCollisionLabels>::iterator;
91+ using Collisions = soa::Join<aod::Collisions, aod::EvSels, aod::CentFV0As, aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs, aod::CentNTPVs, aod::McCollisionLabels>;
92+ Preslice<TrackCandidatesMC> mTracksPerCollision = aod::track::collisionId;
7293 Preslice<aod::McParticles> mMcParticlesPerCollision = o2::aod::mcparticle::mcCollisionId;
7394
7495 Configurable<bool > cfgFillTable{" cfgFillTable" , true , " Fill output tree" };
@@ -77,6 +98,9 @@ struct nucleiQC {
7798 Configurable<LabeledArray<int >> cfgSpeciesToProcess{" cfgSpeciesToProcess" , {nuclei::speciesToProcessDefault[0 ], nuclei::Species::kNspecies , 1 , nuclei::names, {" processNucleus" }}, " Nuclei to process" };
7899 Configurable<LabeledArray<int >> cfgEventSelections{" cfgEventSelections" , {nuclei::EvSelDefault[0 ], 8 , 1 , nuclei::eventSelectionLabels, nuclei::eventSelectionTitle}, " Event selections" };
79100 Configurable<int > cfgCentralityEstimator{" cfgCentralityEstimator" , 0 , " Centrality estimator (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3)" };
101+ Configurable<bool > cfgPerformPidSelectionInIts{" cfgPerformPidSelectionInIts" , false , " Perform PID selections in ITS" };
102+ Configurable<bool > cfgPerformPidSelectionInTpc{" cfgPerformPidSelectionInTpc" , false , " Perform PID selections in TPC" };
103+ Configurable<bool > cfgPerformPidSelectionInTof{" cfgPerformPidSelectionInTof" , false , " Perform PID selections in TOF" };
80104 Configurable<LabeledArray<double >> cfgBetheBlochParams{" cfgBetheBlochParams" , {nuclei::betheBlochDefault[0 ], nuclei::Species::kNspecies , 6 , nuclei::names, nuclei::betheBlochParNames}, " TPC Bethe-Bloch parameterisation for light nuclei" };
81105 Configurable<LabeledArray<int >> cfgUseCentralTpcCalibration{" cfgUseCentralTpcCalibration" , {nuclei::useCentralTpcCalibrationDefault[0 ], nuclei::Species::kNspecies , 1 , nuclei::names, {" UseCentralTpcCalibration" }}, " Use central TPC calibration" };
82106 Configurable<LabeledArray<double >> cfgDownscalingFactor{" cfgDownscalingFactor" , {nuclei::DownscalingDefault[0 ], nuclei::Species::kNspecies , 1 , nuclei::names, {" DownscalingFactor" }}, " Save to the AO2D with a downscaling factor" };
@@ -95,6 +119,9 @@ struct nucleiQC {
95119 Configurable<float > cfgCutTpcMom{" cfgCutTpcMom" , 0 .2f , " Minimum TPC momentum for tracks" };
96120 Configurable<float > cfgCutNclusITS{" cfgCutNclusITS" , 5 , " Minimum number of ITS clusters" };
97121 Configurable<float > cfgCutNclusTPC{" cfgCutNclusTPC" , 70 , " Minimum number of TPC clusters" };
122+ Configurable<float > cfgCutNclusCrossedRowsTPC{" cfgCutNclusCrossedRowsTPC" , 70 , " Minimum number of TPC clusters crossed rows" };
123+ Configurable<float > cfgCutChi2PerClusterTPC{" cfgCutChi2PerClusterTPC" , 4 .f , " Maximum chi2 per TPC cluster" };
124+ Configurable<float > cfgCutChi2PerClusterITS{" cfgCutChi2PerClusterITS" , 36 .f , " Maximum chi2 per ITS cluster" };
98125
99126 Configurable<LabeledArray<double >> cfgNsigmaTPC{" cfgNsigmaTPC" , {nuclei::nSigmaTPCdefault[0 ], nuclei::Species::kNspecies , 2 , nuclei::names, nuclei::nSigmaConfigName}, " TPC nsigma selection for light nuclei" };
100127 Configurable<LabeledArray<double >> cfgNsigmaTOF{" cfgNsigmaTOF" , {nuclei::nSigmaTOFdefault[0 ], nuclei::Species::kNspecies , 2 , nuclei::names, nuclei::nSigmaConfigName}, " TPC nsigma selection for light nuclei" };
@@ -123,6 +150,7 @@ struct nucleiQC {
123150
124151 std::vector<int > mSpeciesToProcess ;
125152 Produces<aod::NucleiTableRed> mNucleiTableRed ;
153+ Produces<aod::NucleiTableExt> mNucleiTableExt ;
126154
127155 std::vector<nuclei::SlimCandidate> mNucleiCandidates ;
128156 std::vector<int > mFilledMcParticleIds ;
@@ -166,6 +194,10 @@ struct nucleiQC {
166194 }
167195
168196 nuclei::createHistogramRegistryNucleus<kSpeciesCt >(mHistograms );
197+ mHistograms .add (fmt::format (" {}/hTrackQuality" , nuclei::cNames[kSpeciesRt ]).c_str (), (fmt::format (" {} track quality;" , nuclei::cNames[kSpeciesRt ]) + std::string (" #it{p}_{T} / #it{Z} (GeV/#it{c}); Selection step; Counts" )).c_str (), o2::framework::HistType::kTH2D , {{400 , -10 .0f , 10 .0f }, {trackQuality::kNtrackQuality , -0 .5f , static_cast <float >(trackQuality::kNtrackQuality ) - 0 .5f }});
198+ for (size_t iSel = 0 ; iSel < trackQuality::kNtrackQuality ; iSel++) {
199+ mHistograms .get <TH2>(HIST (nuclei::cNames[kSpeciesRt ]) + HIST (" /hTrackQuality" ))->GetYaxis ()->SetBinLabel (iSel + 1 , trackQualityLabels[iSel].c_str ());
200+ }
169201
170202 if (cfgUseCentralTpcCalibration->get (static_cast <uint32_t >(kSpeciesRt ), static_cast <uint32_t >(0 )) == 0 ) {
171203 mPidManagers [kSpeciesRt ] = nuclei::PidManager (kSpeciesRt , tpcBetheBlochParams);
@@ -217,19 +249,39 @@ struct nucleiQC {
217249 LOGF (info, " Retrieved GRP for timestamp %ull (%i) with magnetic field of %1.2f kZG" , timestamp, mRunNumber , mBz );
218250 }
219251
220- template <typename Ttrack>
252+ template <int iSpecies, typename Ttrack>
221253 bool trackSelection (const Ttrack& track)
222254 {
223- if (std::abs (track.eta ()) > cfgCutEta ||
224- track.tpcInnerParam () < cfgCutTpcMom ||
225- track.itsNCls () < cfgCutNclusITS ||
226- track.tpcNClsFound () < cfgCutNclusTPC ||
227- track.tpcNClsCrossedRows () < 70 ||
228- track.tpcNClsCrossedRows () < 0.8 * track.tpcNClsFindable () ||
229- track.tpcChi2NCl () > 4 .f ||
230- track.itsChi2NCl () > 36 .f ) {
255+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kNoCuts );
256+
257+ if (std::abs (track.eta ()) > cfgCutEta)
231258 return false ;
232- }
259+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kEtaCut );
260+
261+ if (track.tpcInnerParam () < cfgCutTpcMom)
262+ return false ;
263+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kPtpcCut );
264+
265+ if (track.itsNCls () < cfgCutNclusITS)
266+ return false ;
267+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kNclsItsCut );
268+
269+ if (track.tpcNClsFound () < cfgCutNclusTPC)
270+ return false ;
271+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kNclsTpcCut );
272+
273+ if (track.tpcNClsCrossedRows () < cfgCutNclusCrossedRowsTPC)
274+ return false ;
275+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kNCrossedRowsCut );
276+
277+ if (track.tpcChi2NCl () > cfgCutChi2PerClusterTPC)
278+ return false ;
279+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kTpcChi2Cut );
280+
281+ if (track.itsChi2NCl () > cfgCutChi2PerClusterITS)
282+ return false ;
283+ mHistograms .fill (HIST (nuclei::cNames[iSpecies]) + HIST (" /hTrackQuality" ), track.sign () * track.pt (), trackQuality::kItsChi2Cut );
284+
233285 return true ;
234286 }
235287
@@ -243,7 +295,7 @@ struct nucleiQC {
243295 float centrality = nuclei::getCentrality (collision, cfgCentralityEstimator);
244296 float nsigmaTPC = mPidManagers [kIndex ].getNSigmaTPC (track);
245297 mHistograms .fill (HIST (nuclei::cNames[kIndex ]) + HIST (" /h3NsigmaTPC_preselectionVsCentrality" ), track.pt () * track.sign (), nsigmaTPC, centrality);
246- if (std::abs (nsigmaTPC) > cfgNsigmaTPC->get (kIndex , 1 ))
298+ if (std::abs (nsigmaTPC) > cfgNsigmaTPC->get (kIndex , 1 ) && cfgPerformPidSelectionInTpc )
247299 return false ;
248300 mHistograms .fill (HIST (nuclei::cNames[kIndex ]) + HIST (" /h3NsigmaTPCVsCentrality" ), track.pt () * track.sign (), nsigmaTPC, centrality);
249301
@@ -254,7 +306,7 @@ struct nucleiQC {
254306
255307 float nsigmaTOF = mPidManagers [kIndex ].getNSigmaTOF (track);
256308 mHistograms .fill (HIST (nuclei::cNames[kIndex ]) + HIST (" /h3NsigmaTOF_preselectionVsCentrality" ), track.sign () * track.pt (), nsigmaTOF, centrality);
257- if (std::abs (nsigmaTOF) > cfgNsigmaTOF->get (kIndex , 1 ) && track.hasTOF ())
309+ if (std::abs (nsigmaTOF) > cfgNsigmaTOF->get (kIndex , 1 ) && track.hasTOF () && cfgPerformPidSelectionInTof )
258310 return false ;
259311 mHistograms .fill (HIST (nuclei::cNames[kIndex ]) + HIST (" /h3NsigmaTOFVsCentrality" ), track.sign () * track.pt (), nsigmaTOF, centrality);
260312
@@ -390,7 +442,9 @@ struct nucleiQC {
390442 .yGenerated = 0 .f ,
391443 .phiGenerated = 0 .f ,
392444 .centrality = nuclei::getCentrality (collision, cfgCentralityEstimator, mHistFailCentrality ),
393- .mcProcess = TMCProcess::kPNoProcess };
445+ .mcProcess = TMCProcess::kPNoProcess ,
446+ .nsigmaTpc = mPidManagers [iSpecies].getNSigmaTPC (track),
447+ .nsigmaTof = mPidManagers [iSpecies].getNSigmaTOF (track)};
394448
395449 fillNucleusFlagsPdgs (iSpecies, collision, track, candidate);
396450
@@ -456,6 +510,7 @@ struct nucleiQC {
456510
457511 void processMc (const Collision& collision, const TrackCandidatesMC& tracks, const aod::BCsWithTimestamps&, const aod::McParticles& mcParticles)
458512 {
513+
459514 gRandom ->SetSeed (67 );
460515 mNucleiCandidates .clear ();
461516 mFilledMcParticleIds .clear ();
@@ -480,6 +535,9 @@ struct nucleiQC {
480535 mTrackTuner .getDcaGraphs ();
481536 }
482537
538+ auto tracksThisCollision = tracks.sliceBy (mTracksPerCollision , collision.globalIndex ());
539+ tracksThisCollision.bindExternalIndices (&tracks);
540+
483541 for (const auto & track : tracks) {
484542
485543 static_for<0 , nuclei::kNspecies - 1 >([&](auto iSpecies) {
@@ -510,7 +568,7 @@ struct nucleiQC {
510568 return ;
511569
512570 mHistograms .fill (HIST (nuclei::cNames[kSpeciesCt ]) + HIST (" /hTrackSelections" ), nuclei::trackSelection::kNoCuts );
513- if (!trackSelection (track))
571+ if (!trackSelection< kSpeciesRt > (track))
514572 return ;
515573 mHistograms .fill (HIST (nuclei::cNames[kSpeciesCt ]) + HIST (" /hTrackSelections" ), nuclei::trackSelection::kTrackCuts );
516574
@@ -547,6 +605,11 @@ struct nucleiQC {
547605 if (std::find (mSpeciesToProcess .begin (), mSpeciesToProcess .end (), iSpecies) == mSpeciesToProcess .end ())
548606 continue ;
549607
608+ if (cfgDownscalingFactor->get (iSpecies) < 1 .) {
609+ if ((gRandom ->Uniform ()) > cfgDownscalingFactor->get (iSpecies))
610+ return ;
611+ }
612+
550613 nuclei::SlimCandidate candidate;
551614 candidate.centrality = nuclei::getCentrality (collision, cfgCentralityEstimator, mHistFailCentrality );
552615 fillNucleusFlagsPdgsMc (particle, candidate);
@@ -576,6 +639,9 @@ struct nucleiQC {
576639 candidate.mcProcess ,
577640 candidate.pdgCode ,
578641 candidate.motherPdgCode );
642+ mNucleiTableExt (
643+ candidate.nsigmaTpc ,
644+ candidate.nsigmaTof );
579645 }
580646 }
581647 PROCESS_SWITCH (nucleiQC, processMc, " Mc analysis" , false );
0 commit comments