99// granted to it by virtue of its status as an Intergovernmental Organization
1010// or submit itself to any jurisdiction.
1111
12- #include " Framework/runDataProcessing .h"
13- #include " Framework/AnalysisTask .h"
12+ #include " Common/DataModel/EventSelection .h"
13+ #include " Common/DataModel/PIDResponse .h"
1414#include " Common/DataModel/TrackSelectionTables.h"
15+
1516#include " Framework/ASoAHelpers.h"
16- #include " Common/DataModel/PIDResponse.h"
17- #include " Common/DataModel/EventSelection.h"
17+ #include " Framework/AnalysisTask.h"
18+ #include " Framework/runDataProcessing.h"
19+
1820#include " TFile.h"
1921#include " TTree.h"
20- # include < fstream >
22+
2123#include < cmath>
24+ #include < fstream>
2225
2326using namespace o2 ;
2427using namespace o2 ::framework;
@@ -51,50 +54,50 @@ struct PIDFeatureExtractor {
5154 // KINEMATIC VARIABLES - Track momentum and position information
5255 // ============================================================================
5356
54- int event_id; // / Unique identifier for each collision event
55- int track_id; // / Track index within the event
57+ int event_id; // / Unique identifier for each collision event
58+ int track_id; // / Track index within the event
5659
5760 // Momentum components (in GeV/c)
58- float px, py, pz; // / Cartesian momentum components
59- float pt, p; // / Transverse momentum and total momentum
61+ float px, py, pz; // / Cartesian momentum components
62+ float pt, p; // / Transverse momentum and total momentum
6063
6164 // Angular variables
62- float eta; // / Pseudorapidity
63- float phi; // / Azimuthal angle
64- float theta; // / Polar angle (calculated from eta)
65+ float eta; // / Pseudorapidity
66+ float phi; // / Azimuthal angle
67+ float theta; // / Polar angle (calculated from eta)
6568
6669 // Track properties
67- int charge; // / Track charge (+1 or -1)
68- int track_type; // / Type of track (e.g., 0=global, 1=TPC-only, etc.)
70+ int charge; // / Track charge (+1 or -1)
71+ int track_type; // / Type of track (e.g., 0=global, 1=TPC-only, etc.)
6972
7073 // ============================================================================
7174 // TPC VARIABLES - Time Projection Chamber PID information
7275 // ============================================================================
7376
74- float tpc_signal; // / dE/dx energy loss in TPC (specific ionization)
77+ float tpc_signal; // / dE/dx energy loss in TPC (specific ionization)
7578
7679 // n-sigma values: standard deviations from expected energy loss for each particle
77- float tpc_nsigma_pi; // / n-sigma for pion (π)
78- float tpc_nsigma_ka; // / n-sigma for kaon (K)
79- float tpc_nsigma_pr; // / n-sigma for proton (p)
80- float tpc_nsigma_el; // / n-sigma for electron (e)
80+ float tpc_nsigma_pi; // / n-sigma for pion (π)
81+ float tpc_nsigma_ka; // / n-sigma for kaon (K)
82+ float tpc_nsigma_pr; // / n-sigma for proton (p)
83+ float tpc_nsigma_el; // / n-sigma for electron (e)
8184
8285 // Track quality variables
83- int tpc_nclusters; // / Number of TPC clusters used in track fit
84- float tpc_chi2; // / Chi-square per degree of freedom of TPC fit
86+ int tpc_nclusters; // / Number of TPC clusters used in track fit
87+ float tpc_chi2; // / Chi-square per degree of freedom of TPC fit
8588
8689 // ============================================================================
8790 // TOF VARIABLES - Time-Of-Flight PID information
8891 // ============================================================================
8992
90- float tof_beta; // / β = v/c (velocity over speed of light)
91- float tof_mass; // / Reconstructed mass from TOF measurement
93+ float tof_beta; // / β = v/c (velocity over speed of light)
94+ float tof_mass; // / Reconstructed mass from TOF measurement
9295
9396 // n-sigma values for TOF detection
94- float tof_nsigma_pi; // / n-sigma for pion in TOF
95- float tof_nsigma_ka; // / n-sigma for kaon in TOF
96- float tof_nsigma_pr; // / n-sigma for proton in TOF
97- float tof_nsigma_el; // / n-sigma for electron in TOF
97+ float tof_nsigma_pi; // / n-sigma for pion in TOF
98+ float tof_nsigma_ka; // / n-sigma for kaon in TOF
99+ float tof_nsigma_pr; // / n-sigma for proton in TOF
100+ float tof_nsigma_el; // / n-sigma for electron in TOF
98101
99102 // ============================================================================
100103 // BAYESIAN PID VARIABLES - Combined PID probabilities
@@ -113,22 +116,22 @@ struct PIDFeatureExtractor {
113116 // MONTE CARLO TRUTH INFORMATION - For simulated data
114117 // ============================================================================
115118
116- int mc_pdg; // / PDG code of true particle (0 if no MC match)
117- float mc_px, mc_py, mc_pz; // / True momentum components from simulation
119+ int mc_pdg; // / PDG code of true particle (0 if no MC match)
120+ float mc_px, mc_py, mc_pz; // / True momentum components from simulation
118121
119122 // ============================================================================
120123 // DETECTOR AVAILABILITY FLAGS
121124 // ============================================================================
122125
123- bool has_tpc; // / Flag: track has TPC information
124- bool has_tof; // / Flag: track has TOF information
126+ bool has_tpc; // / Flag: track has TPC information
127+ bool has_tof; // / Flag: track has TOF information
125128
126129 // ============================================================================
127130 // TRACK IMPACT PARAMETERS - Quality and background rejection
128131 // ============================================================================
129132
130- float dca_xy; // / Distance of closest approach in xy-plane
131- float dca_z; // / Distance of closest approach in z-direction
133+ float dca_xy; // / Distance of closest approach in xy-plane
134+ float dca_z; // / Distance of closest approach in z-direction
132135
133136 // ============================================================================
134137 // HISTOGRAM REGISTRY - Quality control histograms
@@ -172,7 +175,8 @@ struct PIDFeatureExtractor {
172175 * Called once at task startup. Creates ROOT TTree and CSV file headers,
173176 * and initializes all quality control histograms.
174177 */
175- void init (InitContext const &) {
178+ void init (InitContext const &)
179+ {
176180 std::string base = outputPath.value ;
177181
178182 // ========================================================================
@@ -243,25 +247,24 @@ struct PIDFeatureExtractor {
243247 if (exportCSV) {
244248 csvFile.open ((base + " .csv" ).c_str ());
245249 // Write CSV header with all column names
246- csvFile <<
247- " event_id,track_id,px,py,pz,pt,p,eta,phi,theta,charge,track_type,"
248- " tpc_signal,tpc_nsigma_pi,tpc_nsigma_ka,tpc_nsigma_pr,tpc_nsigma_el,"
249- " tpc_nclusters,tpc_chi2,"
250- " tof_beta,tof_mass,tof_nsigma_pi,tof_nsigma_ka,tof_nsigma_pr,tof_nsigma_el,"
251- " bayes_prob_pi,bayes_prob_ka,bayes_prob_pr,bayes_prob_el,"
252- " mc_pdg,mc_px,mc_py,mc_pz,has_tpc,has_tof,dca_xy,dca_z\n " ;
250+ csvFile << " event_id,track_id,px,py,pz,pt,p,eta,phi,theta,charge,track_type,"
251+ " tpc_signal,tpc_nsigma_pi,tpc_nsigma_ka,tpc_nsigma_pr,tpc_nsigma_el,"
252+ " tpc_nclusters,tpc_chi2,"
253+ " tof_beta,tof_mass,tof_nsigma_pi,tof_nsigma_ka,tof_nsigma_pr,tof_nsigma_el,"
254+ " bayes_prob_pi,bayes_prob_ka,bayes_prob_pr,bayes_prob_el,"
255+ " mc_pdg,mc_px,mc_py,mc_pz,has_tpc,has_tof,dca_xy,dca_z\n " ;
253256 }
254257
255258 // ========================================================================
256259 // HISTOGRAM SETUP - Quality Control Plots
257260 // ========================================================================
258261
259262 // Define histogram axes with binning
260- const AxisSpec axisPt{200 , 0 , 10 , " pT" }; // 200 bins, 0-10 GeV/c
261- const AxisSpec axisEta{60 , -1.5 , 1.5 , " eta" }; // 60 bins, -1.5 to 1.5
262- const AxisSpec axisdEdx{300 , 0 , 300 , " dE/dx" }; // 300 bins, 0-300
263- const AxisSpec axisBeta{120 , 0 , 1.2 , " beta" }; // 120 bins, 0 to 1.2
264- const AxisSpec axisMass{100 , -0.2 , 2.0 , " mass" }; // 100 bins, -0.2 to 2.0 GeV/c²
263+ const AxisSpec axisPt{200 , 0 , 10 , " pT" }; // 200 bins, 0-10 GeV/c
264+ const AxisSpec axisEta{60 , -1.5 , 1.5 , " eta" }; // 60 bins, -1.5 to 1.5
265+ const AxisSpec axisdEdx{300 , 0 , 300 , " dE/dx" }; // 300 bins, 0-300
266+ const AxisSpec axisBeta{120 , 0 , 1.2 , " beta" }; // 120 bins, 0 to 1.2
267+ const AxisSpec axisMass{100 , -0.2 , 2.0 , " mass" }; // 100 bins, -0.2 to 2.0 GeV/c²
265268
266269 // Add histograms to registry
267270 histos.add (" QC/nTracks" , " Tracks" , kTH1F , {{10000 , 0 , 100000 }});
@@ -291,15 +294,16 @@ struct PIDFeatureExtractor {
291294 *
292295 * Likelihood: L_i = exp(-0.5 * (ns_TPC_i² + ns_TOF_i²))
293296 */
294- void computeBayesianPID (float nsTPC[4 ], float nsTOF[4 ], float pri[4 ], float out[4 ]) {
297+ void computeBayesianPID (float nsTPC[4 ], float nsTOF[4 ], float pri[4 ], float out[4 ])
298+ {
295299 float sum = 0 ;
296300
297301 // Calculate likelihood for each particle species
298302 for (int i = 0 ; i < 4 ; i++) {
299303 // Gaussian likelihood: exp(-0.5 * chi²)
300304 // Handle invalid TOF values (NaN) by replacing with 0 contribution
301- float l = std::exp (-0 .5f * (nsTPC[i]* nsTPC[i] +
302- (std::isfinite (nsTOF[i]) ? nsTOF[i]* nsTOF[i] : 0 .f )));
305+ float l = std::exp (-0 .5f * (nsTPC[i] * nsTPC[i] +
306+ (std::isfinite (nsTOF[i]) ? nsTOF[i] * nsTOF[i] : 0 .f )));
303307
304308 // Apply prior probability and accumulate
305309 out[i] = l * pri[i];
@@ -330,16 +334,16 @@ struct PIDFeatureExtractor {
330334 void process (
331335 aod::Collision const & collision,
332336 soa::Join<
333- aod::Tracks, // Base track properties
334- aod::TracksExtra, // Extended track info
335- aod::TracksDCA, // Impact parameters (DCA)
336- aod::pidTPCPi, aod::pidTPCKa, aod::pidTPCPr, // TPC PID for pion, kaon, proton
337- aod::pidTPCEl, // TPC PID for electron
338- aod::pidTOFPi, aod::pidTOFKa, aod::pidTOFPr, // TOF PID for pion, kaon, proton
339- aod::pidTOFEl, // TOF PID for electron
340- aod::pidTOFmass, aod::pidTOFbeta, // TOF mass and beta
341- aod::McTrackLabels // MC truth matching
342- > const & tracks,
337+ aod::Tracks, // Base track properties
338+ aod::TracksExtra, // Extended track info
339+ aod::TracksDCA, // Impact parameters (DCA)
340+ aod::pidTPCPi, aod::pidTPCKa, aod::pidTPCPr, // TPC PID for pion, kaon, proton
341+ aod::pidTPCEl, // TPC PID for electron
342+ aod::pidTOFPi, aod::pidTOFKa, aod::pidTOFPr, // TOF PID for pion, kaon, proton
343+ aod::pidTOFEl, // TOF PID for electron
344+ aod::pidTOFmass, aod::pidTOFbeta, // TOF mass and beta
345+ aod::McTrackLabels // MC truth matching
346+ > const & tracks,
343347 aod::McParticles const & mcParticles)
344348 {
345349 // Use static counter to maintain event numbering across process calls
@@ -355,8 +359,10 @@ struct PIDFeatureExtractor {
355359 // ====================================================================
356360 // TRACK SELECTION - Apply kinematic cuts
357361 // ====================================================================
358- if (t.pt () < ptMin || t.pt () > ptMax) continue ; // Apply pT cut
359- if (t.eta () < etaMin || t.eta () > etaMax) continue ; // Apply eta cut
362+ if (t.pt () < ptMin || t.pt () > ptMax)
363+ continue ; // Apply pT cut
364+ if (t.eta () < etaMin || t.eta () > etaMax)
365+ continue ; // Apply eta cut
360366
361367 track_id = idx++;
362368
@@ -372,22 +378,22 @@ struct PIDFeatureExtractor {
372378 phi = t.phi ();
373379 // Calculate polar angle from pseudorapidity: θ = 2*arctan(exp(-η))
374380 theta = 2 .f * atanf (expf (-eta));
375- charge = t.sign (); // Track charge
376- track_type = t.trackType (); // Track categorization
381+ charge = t.sign (); // Track charge
382+ track_type = t.trackType (); // Track categorization
377383
378384 // ====================================================================
379385 // EXTRACT TPC INFORMATION
380386 // ====================================================================
381387 has_tpc = t.hasTPC ();
382388 if (has_tpc) {
383389 // TPC has valid measurement
384- tpc_signal = t.tpcSignal (); // dE/dx specific ionization
385- tpc_nsigma_pi = t.tpcNSigmaPi (); // Deviation from pion hypothesis
386- tpc_nsigma_ka = t.tpcNSigmaKa (); // Deviation from kaon hypothesis
387- tpc_nsigma_pr = t.tpcNSigmaPr (); // Deviation from proton hypothesis
388- tpc_nsigma_el = t.tpcNSigmaEl (); // Deviation from electron hypothesis
389- tpc_nclusters = t.tpcNClsFound (); // Quality: number of clusters
390- tpc_chi2 = t.tpcChi2NCl (); // Quality: fit chi-square
390+ tpc_signal = t.tpcSignal (); // dE/dx specific ionization
391+ tpc_nsigma_pi = t.tpcNSigmaPi (); // Deviation from pion hypothesis
392+ tpc_nsigma_ka = t.tpcNSigmaKa (); // Deviation from kaon hypothesis
393+ tpc_nsigma_pr = t.tpcNSigmaPr (); // Deviation from proton hypothesis
394+ tpc_nsigma_el = t.tpcNSigmaEl (); // Deviation from electron hypothesis
395+ tpc_nclusters = t.tpcNClsFound (); // Quality: number of clusters
396+ tpc_chi2 = t.tpcChi2NCl (); // Quality: fit chi-square
391397 } else {
392398 // TPC has no valid measurement - set sentinel values
393399 tpc_signal = tpc_nsigma_pi = tpc_nsigma_ka = tpc_nsigma_pr = tpc_nsigma_el = -999 ;
@@ -401,12 +407,12 @@ struct PIDFeatureExtractor {
401407 has_tof = t.hasTOF ();
402408 if (has_tof) {
403409 // TOF has valid measurement
404- tof_beta = t.beta (); // Velocity over c
405- tof_mass = t.mass (); // Reconstructed mass
406- tof_nsigma_pi = t.tofNSigmaPi (); // Deviation from pion hypothesis
407- tof_nsigma_ka = t.tofNSigmaKa (); // Deviation from kaon hypothesis
408- tof_nsigma_pr = t.tofNSigmaPr (); // Deviation from proton hypothesis
409- tof_nsigma_el = t.tofNSigmaEl (); // Deviation from electron hypothesis
410+ tof_beta = t.beta (); // Velocity over c
411+ tof_mass = t.mass (); // Reconstructed mass
412+ tof_nsigma_pi = t.tofNSigmaPi (); // Deviation from pion hypothesis
413+ tof_nsigma_ka = t.tofNSigmaKa (); // Deviation from kaon hypothesis
414+ tof_nsigma_pr = t.tofNSigmaPr (); // Deviation from proton hypothesis
415+ tof_nsigma_el = t.tofNSigmaEl (); // Deviation from electron hypothesis
410416 } else {
411417 // TOF has no valid measurement - set sentinel values
412418 tof_beta = tof_mass = -999 ;
@@ -416,15 +422,15 @@ struct PIDFeatureExtractor {
416422 // ====================================================================
417423 // EXTRACT IMPACT PARAMETERS (track quality)
418424 // ====================================================================
419- dca_xy = t.dcaXY (); // Distance of closest approach in transverse plane
420- dca_z = t.dcaZ (); // Distance of closest approach along beam axis
425+ dca_xy = t.dcaXY (); // Distance of closest approach in transverse plane
426+ dca_z = t.dcaZ (); // Distance of closest approach along beam axis
421427
422428 // ====================================================================
423429 // COMPUTE BAYESIAN PID
424430 // ====================================================================
425431 float arrTPC[4 ] = {tpc_nsigma_pi, tpc_nsigma_ka, tpc_nsigma_pr, tpc_nsigma_el};
426432 float arrTOF[4 ] = {tof_nsigma_pi, tof_nsigma_ka, tof_nsigma_pr, tof_nsigma_el};
427- float priors[4 ] = {1 .f , 0 .2f , 0 .1f , 0 .05f }; // Prior prob: π, K, p, e
433+ float priors[4 ] = {1 .f , 0 .2f , 0 .1f , 0 .05f }; // Prior prob: π, K, p, e
428434 float probs[4 ];
429435
430436 // Compute combined PID probabilities
@@ -440,8 +446,8 @@ struct PIDFeatureExtractor {
440446 // Safely access MC particle information with existence check
441447 if (t.has_mcParticle ()) {
442448 auto mc = t.mcParticle ();
443- mc_pdg = mc.pdgCode (); // Particle identifier code
444- mc_px = mc.px (); // True momentum components
449+ mc_pdg = mc.pdgCode (); // Particle identifier code
450+ mc_px = mc.px (); // True momentum components
445451 mc_py = mc.py ();
446452 mc_pz = mc.pz ();
447453 } else {
@@ -455,7 +461,8 @@ struct PIDFeatureExtractor {
455461 // ====================================================================
456462
457463 // Write to ROOT TTree
458- if (exportROOT) featureTree->Fill ();
464+ if (exportROOT)
465+ featureTree->Fill ();
459466
460467 // Write to CSV file
461468 if (exportCSV) {
@@ -476,12 +483,13 @@ struct PIDFeatureExtractor {
476483 // ====================================================================
477484 // FILL QUALITY CONTROL HISTOGRAMS
478485 // ====================================================================
479- histos.fill (HIST (" QC/nTracks" ), 1 ); // Count total tracks processed
480- histos.fill (HIST (" QC/pt" ), pt); // pT distribution
481- histos.fill (HIST (" QC/eta" ), eta); // eta distribution
486+ histos.fill (HIST (" QC/nTracks" ), 1 ); // Count total tracks processed
487+ histos.fill (HIST (" QC/pt" ), pt); // pT distribution
488+ histos.fill (HIST (" QC/eta" ), eta); // eta distribution
482489
483490 // TPC dE/dx vs pT (only if TPC measurement exists)
484- if (has_tpc) histos.fill (HIST (" QC/tpc_dEdx_vs_pt" ), pt, tpc_signal);
491+ if (has_tpc)
492+ histos.fill (HIST (" QC/tpc_dEdx_vs_pt" ), pt, tpc_signal);
485493
486494 // TOF beta and mass vs momentum (only if TOF measurement exists)
487495 if (has_tof) {
@@ -500,7 +508,8 @@ struct PIDFeatureExtractor {
500508 *
501509 * Called at task completion. Writes TTree to file and closes all output files.
502510 */
503- void finalize () {
511+ void finalize ()
512+ {
504513 if (exportROOT) {
505514 // Write TTree to ROOT file and close
506515 outputFile->cd ();
@@ -524,6 +533,8 @@ struct PIDFeatureExtractor {
524533 * This function creates and registers the PIDFeatureExtractor task
525534 * into the O2 data processing workflow.
526535 */
527- WorkflowSpec defineDataProcessing (ConfigContext const & cfgc) {
536+ WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
537+ {
528538 return WorkflowSpec{adaptAnalysisTask<PIDFeatureExtractor>(cfgc)};
529- }
539+ }
540+
0 commit comments