Back to home page

EIC code displayed by LXR

 
 

    


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.