Warning, /snippets/Tracking/track2particle/README.md is written in an unsupported language. File is not indexed.
0001 # Hit-based track-to-particle analysis for background study
0002 Shujie Li, 08.2026, code generated with assistance from OpenAI Codex.
0003
0004
0005 ## Goal
0006
0007 This package traces reconstructed central-tracker trajectories to Monte Carlo
0008 particles, then measures:
0009
0010 - signal-particle reconstruction efficiency;
0011 - candidate-track purity and background/fake-track fractions;
0012 - hits per trajectory;
0013 - momentum and polar-angle resolutions.
0014
0015 The expensive ROOT/PODIO event loop is run once. Later changes to eta or
0016 momentum plotting bins reuse the compressed per-file CSV chunks.
0017
0018 ## Code structure
0019
0020 - `track2particle.py`: event processing, per-file chunks, aggregation, and
0021 efficiency/purity/track-quality plots.
0022 - `track2particle_resol.py`: resolution fits and the fixed seven-eta-panel
0023 plots, using existing chunks only.
0024 - `epic_analysis_base.py`: uproot readers, shared cuts, coordinate utilities,
0025 and Gaussian fitting.
0026 - `epic_analysis_podio.py`: PODIO relation tracing used during event
0027 processing. This file is a required runtime dependency and should be
0028 distributed with the other three files.
0029
0030 `track2particle_resol.py` depends only on `track2particle.py` and
0031 `epic_analysis_base.py`; it does not depend on the separate single-particle
0032 performance package.
0033
0034 ## Environment
0035
0036 Run within eic-shell to get PODIO suport. The
0037 Python environment needs PODIO/EDM4hep plus `numpy`, `pandas`, `awkward`,
0038 `uproot`, `matplotlib`, `seaborn`, `particle`, and `lmfit`.
0039
0040 The default input and output roots are relative paths named `rootfiles/` and
0041 `track2particle_output/`. For reproducible work, pass both paths explicitly.
0042
0043 ## Input
0044
0045 The input is an EICrecon ROOT file containing at least:
0046
0047 - `CentralCKFTrajectories` and `CentralCKFTrackParameters`;
0048 - `MCParticles`;
0049 - the central tracking hit-to-sim-hit-to-MC-particle relation chain expected
0050 by `epic_analysis_podio.py`.
0051
0052 For a numbered campaign, files are expected under
0053 `INPUT_ROOT/CONFIG/` with names of the form:
0054
0055 ```text
0056 rec_pythia8NCDIS_..._1.0001_CONFIG_n99_skip0.root
0057 ```
0058
0059 Use repeated `--input-file /full/path/file.root` arguments for files that do
0060 not follow this convention.
0061
0062 ## Minimal use
0063
0064 Process one file first:
0065
0066 ```bash
0067 python track2particle.py \
0068 --input-file /path/to/rec_file.root \
0069 --output-root /path/to/track2particle_output \
0070 --analysis-label my_configuration \
0071 --events 10 --workers 1 \
0072 --process-only --require-all-events
0073 ```
0074
0075 Process and aggregate a 100-file campaign:
0076
0077 ```bash
0078 python track2particle.py \
0079 --config epic \
0080 --input-root /path/to/rootfiles \
0081 --output-root /path/to/track2particle_output \
0082 --file-start 1 --file-stop 100 \
0083 --events 99 --workers 8 \
0084 --eta-range -1 1 0.1 \
0085 --require-all-events
0086 ```
0087
0088 Rebuild performance plots without reopening ROOT files:
0089
0090 ```bash
0091 python track2particle.py \
0092 --config epic \
0093 --input-root /path/to/rootfiles \
0094 --output-root /path/to/track2particle_output \
0095 --file-start 1 --file-stop 100 \
0096 --eta-range -1 1 0.1 \
0097 --aggregate-only --require-all-events
0098 ```
0099
0100 Build the resolution tables and fixed seven-eta-panel plots:
0101
0102 ```bash
0103 python track2particle_resol.py \
0104 --config epic \
0105 --input-root /path/to/rootfiles \
0106 --chunk-root /path/to/track2particle_output \
0107 --file-start 1 --file-stop 100
0108 ```
0109
0110 Run either script with `--help` for all options.
0111
0112 ## Physics definitions
0113
0114 The default cuts are imported from `epic_analysis_base.py`. At the time of
0115 this benchmark they are:
0116
0117 ```text
0118 generated momentum > 0.2 GeV
0119 |vertex r| < 1 mm
0120 |vertex z| < 100 mm
0121 at least 4 hits per candidate track
0122 strict majority: dominant hit fraction > 0.5
0123 ```
0124
0125 Every trajectory hit enters the hit-fraction denominator. Invalid or noise
0126 relations use particle ID `-1`.
0127
0128 - `good_signal`: strict-majority match to generator status 1 or 2.
0129 - `background_track`: strict-majority match to another real MC particle.
0130 - `fake_or_ghost`: no strict-majority real-particle match.
0131
0132 These three classes are mutually exclusive and exhaustive for candidate
0133 tracks. A selected signal particle is reconstructed when at least one
0134 candidate track has a strict-majority match to that particle.
0135
0136 Efficiency uses truth momentum and eta:
0137
0138 ```text
0139 selected signal particles with a matched track / selected signal particles
0140 ```
0141
0142 Purity uses reconstructed momentum and eta:
0143
0144 ```text
0145 good signal tracks / all candidate tracks
0146 ```
0147
0148 Resolution bins use truth momentum and eta. The stored residuals are:
0149
0150 ```text
0151 dp/p [%] = 100 * (p_reco - p_truth) / p_truth
0152 delta theta = theta_reco - theta_truth
0153 theta_reco = 2 * atan(exp(-eta_reco))
0154 ```
0155
0156 Gaussian widths are fitted with the robust clipping procedure in
0157 `epic_analysis_base.hist_gaus`. Empty or under-populated bins are written as
0158 `NaN`, not zero.
0159
0160 ## Output layout
0161
0162 ```text
0163 track2particle_output/
0164 ├── per_run_analysis/
0165 │ └── rec_<input-file-tag>/
0166 │ ├── analysis_settings.json
0167 │ ├── analysis.log
0168 │ ├── manifest.csv
0169 │ ├── summary.csv
0170 │ └── chunks/
0171 │ ├── particles_<event-range>.csv.gz
0172 │ └── trajectories_<event-range>.csv.gz
0173 ├── <analysis-label>/performance/
0174 │ └── eta_<range>_step_<width>/
0175 │ ├── file_summary.csv
0176 │ ├── efficiency_bins.csv
0177 │ ├── purity_bins.csv
0178 │ ├── performance_summary.csv
0179 │ ├── track_class_bins.csv
0180 │ ├── track_class_summary.csv
0181 │ ├── hits_per_trajectory.csv
0182 │ └── *.png
0183 └── resolution/<configuration>/
0184 ├── input_file_summary.csv
0185 ├── resolution_tracks.csv.gz
0186 ├── resolution_summary.csv
0187 └── *.png, *.pdf
0188 ```
0189
0190 Manifest chunk paths are relative to the per-file directory, so the complete
0191 output tree can be moved. Older manifests with absolute paths are still
0192 readable.
0193
0194 Important chunk columns are:
0195
0196 - particle chunks: `event`, `particle_id`, `mom`, `theta`, `eta`, `PDG`, and
0197 `generatorStatus`;
0198 - trajectory chunks: `event`, `traj_id`, `reco_mom`, `reco_eta`, `reco_pt`,
0199 `total_count`, `max_count`, `max_fraction`, `most_common_source`, and
0200 `part_status`.
0201
0202 The binned efficiency/purity tables contain bin edges, numerator,
0203 denominator, value, and a 68% Wilson interval. `resolution_summary.csv`
0204 contains the fitted mean, sigma, and sigma uncertainty for every one of the
0205 seven eta regions and every truth-momentum bin.
0206
0207 ## Resume and changing cuts
0208
0209 `--resume` reuses an existing per-file result only when its recorded input,
0210 event range, and event-level cuts match and every named chunk exists.
0211
0212 Changing `--momentum-min` changes which MC particles are saved during event
0213 processing; use a new output root and rerun the event loop. Eta ranges,
0214 momentum plot bins, and track hit-count/fraction cuts are applied during
0215 aggregation and can reuse existing chunks, provided the needed particles were
0216 saved.
0217
0218 ## Performance benchmark
0219
0220 Measured on NERSC Perlmutter CPU nodes with files on local NERSC storage:
0221
0222 | Stage | Data | Wall time | Peak memory |
0223 |---|---:|---:|---:|
0224 | Event processing, one worker | 99 events in one file | median 57.4 s; 95th percentile 58.6 s | median 1.69 GiB; 95th percentile 1.70 GiB |
0225 | Aggregation | 100 files, 9,900 events | 12.2 s | 226 MiB |
0226 | Resolution join, fits, and plots | 100 files, 9,900 events | 9.0 s | 242 MiB |
0227
0228 The event-processing statistics use 200 independently measured noise-sample
0229 files. Memory scales approximately with the number of simultaneous file
0230 workers, so choose `--workers` from both available CPU cores and roughly
0231 1.8 GiB of memory per worker. Aggregation and resolution are single-process
0232 and much lighter.