Warning, /analysis/Corral/README.md is written in an unsupported language. File is not indexed.
0001 # Corral
0002
0003 **CORRelation AnaLysis.** Corral is a general-purpose code that produces correlation functions from
0004 sPHENIX data, three whole-acceptance ones and a femtoscopic one:
0005
0006 | variables | correlation function | what it is for |
0007 |---|---|---|
0008 | (y1, y2) | rapidity CF | correlations projected onto the rapidity of each particle |
0009 | (dy, dphi) | angular CF | correlations projected onto difference variables, in rapidity and azimuth |
0010 | (Q_inv, pT_pair) | resonance CF | correlations allowing the measurement of the pT distribution of resonances identified via C(Q) |
0011 | Q_inv (and kT) | femtoscopic C(Q) | correlations projected onto the invariant relative momentum of the pair |
0012
0013 Any pair of reconstructed particles can be studied: the pair types are a simple table
0014 in `src/PairTypes.h`, easy to edit. The code expects trees written by
0015 [Collect](https://github.com/sPHENIX-Collaboration/analysis/tree/master/Collect), which provides the track,
0016 V0, and calorimeter energy information used here. Charged tracks are identified as pi, K or p from their
0017 dE/dx (the KFParticle gates in `dedxGates_KFP.root`). The code includes sensitive removal of the different
0018 kinds of split and duplicate tracks in the Run-3 p+p (polyseeder) data -- like-sign and opposite-charge
0019 split tracks, copies across bunch crossings and trigger frames, and loopers -- as well as a correction for
0020 track crossing. `ana573/SplitTrackTypes_ana573.pdf` shows what each kind looks like, and
0021 `ana573/SplitTrackLogic_ana573.pdf` every decision in processing order (3 pages each).
0022
0023 Correlations are measured by comparing **sibling** pairs (both particles from the same event) with
0024 **mixed** pairs (particles from different events with a similar vertex position zvtx, NMIX=10 events per
0025 zvtx bin, 16 bins over -16 < zvtx < 16 cm), which see the same acceptance but carry no physical
0026 correlation.
0027
0028 The default `src/PairTypes.h` has 49 pair types (the lighter species first, a charged hadron before a V0):
0029
0030 | pairs | index: pair type |
0031 |---|---|
0032 | pi pi | 0 pi+pi-, 1 pi-pi+, 2 pi+pi+, 3 pi-pi- |
0033 | K K | 4 K+K- (phi), 5 K+K+, 6 K-K- |
0034 | p p | 7 p pbar, 8 p p, 9 pbar pbar |
0035 | pi K | 10 pi+K-, 11 pi-K+, 12 pi+K+, 13 pi-K- |
0036 | pi p | 14 pi+pbar, 15 pi-p (Lambda, Delta0), 16 pi+p (Delta++), 17 pi-pbar |
0037 | K p | 18 K+pbar, 19 K-p, 20 K+p, 21 K-pbar |
0038 | K Lambda | 22 K+Lambda, 23 K+Lbar, 24 K-Lambda, 25 K-Lbar |
0039 | p Lambda | 26 p Lambda, 27 p Lbar, 28 pbar Lambda, 29 pbar Lbar |
0040 | pi V0 | 30 pi+K0S (K*+), 31 pi-K0S (K*-), 32 pi+Lambda (Sigma*+), 33 pi-Lambda (Sigma*-, Xi-), 34 pi+Lbar, 35 pi-Lbar |
0041 | K, p with K0S | 36 K+K0S, 37 K-K0S, 38 p K0S, 39 pbar K0S |
0042 | V0 V0 | 40 K0S K0S, 41 Lambda Lambda, 42 Lbar Lbar, 43 K0S Lambda, 44 K0S Lbar, 45 Lambda Lbar |
0043 | h h | 46 h+h-, 47 h+h+, 48 h-h- (PID info ignored, pion binning) |
0044
0045 h+ and h- are every accepted charged track, with the dE/dx PID ignored (the charged-hadron CFs of many
0046 papers). They are filled in pseudorapidity, not y, over the whole track acceptance abs(eta) < 1.1, with the
0047 pion pT cut and bin width (0.04), and their pages and maps are labelled in eta. CalcRm knows from the particle ID that such a leg
0048 carries eta and builds its 4-momentum from eta with the pion mass (Q_inv, M_inv, kT). Like every other
0049 track, they stay out when they are a daughter of a V0 in its mass peak.
0050
0051 The pair densities are filled in rapidity y (from the identified mass), inside abs(eta) < 1.1 and each species'
0052 y window abs(y) < `Species_yu` (fluct_common.h): pi 1.0, K 0.7, p 0.6, K0s / Lambda / Lbar 0.7. Each pair type has
0053 one y bin width (4th field of `PairTypes_Info`, PairTypes.h, units of 0.01) used for y1, y2 and dy; it must divide
0054 both species' windows (each row lists its allowed values), and dy always has an odd number of bins with dy = 0 at a
0055 bin centre. Each pair type gets as many bins as its data support (canary: empty mixed-event bins). Protons and antiprotons enter pairs only above pT = 0.4 GeV/c (beam-pipe
0056 spallation protons). Tracks used by a V0 in its mass peak (+-3 sigma) stay out of every pair type.
0057
0058 ## The physics plots
0059
0060 For every pair type, Corral makes:
0061
0062 - **Single-particle and pair multiplicities.** The number of particles per event and its moments. The
0063 sibling-to-mixed level of the correlation functions is set by these (a factorial-cumulant baseline),
0064 so they are shown next to the correlation functions.
0065 - **R2 and C2 versus (y1, y2) and (dy, dphi).** R2 = rho2 / (rho1 rho1) - 1 is the normalized pair
0066 correlation, where rho2 is the sibling pair density per event and rho1 rho1 is the mixed pair density;
0067 C2 = rho2 - rho1 rho1 is the same excess in absolute units (pairs per event). The (dy, dphi) maps --
0068 rapidity difference versus azimuthal-angle difference -- show the near-side peak from jets and
0069 resonances around (0,0), and the away-side structure around dphi = 180 deg. Projections onto dy and
0070 onto dphi are shown too, and R2(dy) is also obtained independently from the (y1, y2) map (as sum rho2 /
0071 sum rho1 rho1 along each dy diagonal), as a check.
0072 - **The crossing-corrected (dy, dphi) map** (charged-charged pairs), with the uncorrected map, the
0073 difference between the two, and the projections, so the size of the correction is visible (see
0074 "Crossing correction", below).
0075 - **The resonance CF, C(Q_inv, pT_pair)** (one page per pair type): C(Q) over all pT_pair with the
0076 decay signposts, the (Q, pT_pair) map, C(Q) in pT_pair slices, and the mean pT_pair per Q bin for
0077 sibling and mixed pairs. Q has variable-width bins (`src/CQResonances.h`): 2 MeV below 0.1 GeV, 5 MeV
0078 to 0.2 GeV, fine bins around every listed peak of that pair type, 20 MeV elsewhere; the page says so.
0079 - **Femtoscopic C(Q).** The ratio of sibling to mixed pairs versus the invariant relative momentum Q, in
0080 fine (5 MeV) bins over 0-1.2 GeV and in bins of the pair transverse momentum kT. At small Q it shows
0081 the HBT enhancement (identical pions) and final-state interactions. Resonances that decay into the
0082 pair show up as peaks at a known Q; the plots carry signposts at those Q values (for example K0S and
0083 rho0 in pi+pi-, K*(892) in K0S pi, Sigma*(1385) and Xi in Lambda pi).
0084 - **Quality-assurance pages.** Vertex, track (pt, eta, phi, TPC/MVTX/INTT hits, dE/dx, calorimeter
0085 energy) and V0 (mass, momentum, eta, phi, daughter dE/dx) distributions, and the tracks flagged as
0086 split-track candidates, drawn against the kept tracks. A **"Track cuts in force"** page lists every
0087 track cut with the vertex-phi mask drawn on the distributions it cuts, followed by the DCA of each
0088 species vs pT, (eta, phi) and phi; a **notch monitor** page follows the one known pair loss (below).
0089
0090 A single `corral` job writes all of these for its own events. For a large production, the data are
0091 cut into chunks, one job runs per chunk, and **Finalize** combines them (see "Running"): it adds up the
0092 chunks zvtx bin by zvtx bin, forms the final crossing-corrected, zvtx-averaged correlation functions,
0093 takes the uncertainties from the chunk-to-chunk scatter, and writes the physics pages (five per pair
0094 type: overview, C(Q), resonance CF, crossing correction, and the size of the correction versus time and
0095 detector occupancy), followed by diagnostic pages.
0096
0097 ## What Corral does to correct and check the correlations
0098
0099 Correlation functions are ratios of pair densities, so even a small population of tracks that come in
0100 correlated copies, or a small pair inefficiency, makes order-one features in the narrow region where
0101 the pairs land. Most of the work in Corral is about finding and removing these, with the same rules in
0102 the sibling and mixed pairs. The defaults (no run-string needed) are the validated best effort; for
0103 ana573 they were re-derived on 2026-09-27/29 (README_SplitTracks573.md, whose "Final state" section gives
0104 what each step removes). Two charts in the repository draw them, and each item below points to its page:
0105 `ana573/SplitTrackTypes_ana573.pdf`, pictures (page 1: like-sign split tracks and whole-event copies, panels
0106 1-3; page 2: opposite-sign pairs, panels 4-6; page 3: the central-membrane hole, panels 7-9), and
0107 `ana573/SplitTrackLogic_ana573.pdf`, the decisions in processing order (page 1, stages 0-2: events and
0108 tracks; page 2, stage 3: pairs and the maps, and what is watched; page 3: the V0s and their daughters):
0109
0110 - **Vertex-phi mask (SiPhiMask), ana573.** Two vertex-phi windows, [70,83) and [94,115) deg, where the
0111 tracks are few and their DCA is large (a feature fixed at the silicon radius, for this data only), are
0112 left out: 4.4% of the tracks. `nosiphimask` turns it off; `siphimaskall` adds six small windows.
0113 Charts: SplitTrackLogic page 1, stage 1.
0114
0115 - **Central-membrane mask (CM mask), ana573.** Tracks that cross z = 0 inside the TPC (eta ~ asinh(-zvtx/R),
0116 R = 0.30-0.78 m) are often lost, and how often changes from event to event; same-event pairs in that hole
0117 are then enhanced over mixed ones, which made a peak at y1 = y2 ~ 0 in R2(y1,y2). Tracks with
0118 w = (eta + 0.018 z_c) sign(-z_c) in [-0.07,0.10) are left out, z_c = the centre of the event's 2 cm zvtx
0119 slice (a mask that follows each event's own zvtx does not cancel in S/M): 2.8% of the tracks.
0120 `nocmmask` turns it off; `cmmaskAABB` sets the window [-0.AA,0.BB) (README_SplitTracks573.md sec 38).
0121 Charts: SplitTrackTypes page 3, panels 7-9; SplitTrackLogic page 1, stage 1.
0122
0123 - **Like-sign split-track removal.** A single real particle is sometimes reconstructed as two tracks
0124 that share the same silicon (MVTX/INTT) seed. Before any pairs are formed, every like-sign pair of
0125 tracks in an event is tested. Candidates are pre-selected by a small ellipse in (deta, dphi) that is
0126 centred on where split fragments land: two fragments that share the silicon hits but were fitted with
0127 different curvatures are separated in dphi by the azimuth difference they build up by the outer
0128 silicon (R = 6 cm), which grows with abs(1/pT1 - 1/pT2); its dphi half-width follows the measured
0129 spread of the fragments (max(2 deg, 3 sigma)). Inside it, `SiSplitScore` (the fraction of
0130 shared silicon cluster keys, MVTX-led) together with a STAR-style **Splitting Level** SL (from the TPC
0131 pad-row hit patterns) catches "duplicate" splits, a **RadialGap** test catches "complementary" splits
0132 where the TPC clusters are divided between an inner and an outer piece, and a pair whose two tracks
0133 carry the same cluster on at least two MVTX layers is flagged whatever its SL (two particles from one
0134 vertex cannot share two MVTX clusters unless their momenta are nearly equal). The extra copy is
0135 removed from the event.
0136 Charts: SplitTrackTypes page 1, panels 1-2; SplitTrackLogic page 1, stage 2, same charge (paths 1-3).
0137 - **Opposite-charge split-track veto.** The same silicon seed can also be attached to two TPC tracks of
0138 opposite charge. These are removed by a track-level veto on the shared silicon clusters.
0139 Charts: SplitTrackTypes page 2, panel 4; SplitTrackLogic page 1, stage 2, opposite charge.
0140 - **V0 daughters.** A V0 inside its mass peak (+-3 sigma) claims its two daughters: they leave every track
0141 pair type and are never the loser of a split-track test. For Lambda and anti-Lambda only (not K0S), an
0142 accepted track that is a split copy of a daughter is removed: like-sign within dR < 0.05 (except a
0143 pion-tagged partner of a p/pbar), opposite-sign by shared silicon, where a proton-tagged partner of the
0144 (anti)proton daughter is its wrong-sign copy. `nodau` turns this off.
0145 Charts: SplitTrackLogic page 3.
0146 - **Looper veto.** A track with pT below ~0.17 GeV/c curls back inside the TPC, and its returning half,
0147 read outward, is a second track of the opposite charge, exactly back to back with the same momentum.
0148 Opposite-charge pairs with both |p| < 0.20 GeV/c, dphi >= 170 deg and a relative momentum sum
0149 |p1 + p2| / (|p1| + |p2|) < 0.08 are one particle: the worse half is removed (0.01% of the tracks, 0.08%
0150 of those at pT 0.1-0.2 GeV/c). Without it the pi+pi- away side has a spike at dy ~ 0.
0151 Charts: SplitTrackTypes page 2, panel 5; SplitTrackLogic page 1, stage 2, opposite charge.
0152 - **Cross-crossing duplicate cleaner.** sPHENIX reads out continuously; one trigger frame (TF) holds
0153 several bunch crossings, and each crossing with a vertex is one event. One silicon seed can be
0154 attached to TPC tracks in different crossings of the same TF, so the "same" particle appears in two
0155 events -- and then a mixed pair made of the two copies is correlated. The cleaner finds tracks in
0156 different events of one TF that share silicon clusters (cluster keys are unique within one TF) and
0157 keeps the copy whose own INTT time bucket matches its event's crossing; if neither matches, both are
0158 dropped (strict mode, the default); remaining ties go to the better fit.
0159 Charts: SplitTrackTypes page 2, panel 4; SplitTrackLogic page 1, stage 0 (b).
0160 - **No mixing with adjacent trigger frames.** A smaller residual of the same effect comes from events in
0161 neighbouring TFs, where cluster keys cannot be compared. Whole mixed event pairs from adjacent TFs of
0162 the same run are therefore skipped (2-10% of the mixed event pairs, depending on the zvtx bin). The mixed
0163 normalization is kept per zvtx bin, so the exclusion does not bias it.
0164 Charts: SplitTrackTypes page 2, panel 4; SplitTrackLogic page 2, stage 3.
0165 - **Collisions copied into overlapping trigger frames.** When two triggers are closer in time than a
0166 TF's readout window, both TFs reconstruct the collisions in the overlap: the same vertex appears in two
0167 events of different TFs, with the crossing shifted by exactly the difference of the two TFs' GL1 BCO.
0168 The cluster keys cannot be compared across TFs, so the cleaner above cannot see these. With the
0169 Collect `bco` branch, `bco + crossing` is the absolute crossing, and (run, `bco + crossing`) identifies
0170 the bunch crossing: the first event with a given value is kept, and later copies are skipped entirely
0171 (sibling and mixed). In ana573 about 13% of events are such copies, most in the next TF but some two
0172 TFs later (which the adjacent-TF mixing exclusion does not reach). Trees without `bco` (ana532 and
0173 older) are processed exactly as before; the log says the removal was not possible.
0174 Charts: SplitTrackTypes page 1, panel 3; SplitTrackLogic page 1, stage 0 (a).
0175 - **Two-track resolution cut.** Two like-sign tracks that stay close through the TPC are lost to
0176 merging. Like-sign pairs with abs(dy) < 0.06 whose minimum azimuthal separation anywhere in the TPC
0177 (dphi* over R = 0.30-0.78 m) is below 2 deg are removed from sibling and mixed pairs alike, so the
0178 loss cancels in the ratio. It is visible mostly in C(Q) at Q < ~20 MeV.
0179 Charts: SplitTrackLogic page 2, stage 3.
0180 - **Near-vertex two-track cut.** Sibling tracks at nearly the same phi near the vertex are lost; charged
0181 pairs with abs(dphi*(R = 3 cm)) < 2 deg at abs(dy) < 1 are removed from sibling and mixed pairs alike
0182 (0.9% of the pion pairs). The log prints the fraction of pairs each pair cut removes.
0183 Charts: SplitTrackLogic page 2, stage 3.
0184 - **Watched, not removed: the +-15 deg notch.** Opposite-charge tracks bend toward each other; a pair
0185 whose two tracks meet in phi between the INTT and the TPC (R ~ 0.10-0.30 m) is lost in the silicon-TPC
0186 matching, which leaves a ~4% deficit of pi+pi- pairs at 10-20 deg in dphi (README_SplitTracks573.md secs
0187 32-34). It is upstream of Corral; the notch monitor page shows it in every production.
0188 Charts: SplitTrackTypes page 2, panel 6; SplitTrackLogic page 2, WATCH.
0189 - **Crossing correction.** When two real tracks cross in the TPC, one can lose hits to the other and
0190 fail the hit requirement: a pair inefficiency that a single-track efficiency cannot see. Pairs are
0191 pt-ordered when filled, so that every instance of this loss falls on the same ("dirty") side of dphi
0192 for a given magnetic-field sign. After the correlation functions are formed, each dirty near-side bin
0193 is replaced by its mirror bin from the clean side, and the away side is symmetrized in dphi. Only dphi
0194 is ever symmetrized; dy stays y1 - y2. Pairs with a neutral V0 leg are not pt-ordered and are left
0195 untouched.
0196 Charts: SplitTrackLogic page 2, stage 3 (the maps).
0197 - **V0 zero-value repair.** Some V0 getters return exactly 0 for eta, phi, mass or decay length when the
0198 value was not filled; Corral recomputes these from the V0 momentum and decay geometry instead of
0199 using the zero.
0200 - **Mixed-event reference: no Zajc-style correction needed.** If the singles of a mixed-event reference come
0201 only from events that already hold a correlated pair (pair-triggered samples, pools filled only from events
0202 with >= 2 candidates), the reference carries a smeared copy of the correlation, and dividing by it cancels
0203 part of the signal (lambda low, C(Q) distorted at small Q). Zajc et al., Phys. Rev. C 29, 2173 (1984), correct
0204 for this by reweighting the mixed pairs and iterating. Corral avoids it by construction: `CalcRm::Increment`
0205 puts every event, with all its accepted particles of the pair type, into the mixing pool -- there is no
0206 ">= 2 particles" condition, and V0s are pooled from all events. The mixed
0207 singles are the inclusive single-particle distributions, so the reference is the true rho1 rho1.
0208 Remaining caveat: the pool is per zvtx class (NMIX = 10 events), not per multiplicity class. Sibling pairs
0209 weight each event by n(n-1), mixed pairs by n n', so if the single-particle spectra change with multiplicity
0210 the sibling and mixed singles differ slightly in kinematics. Check: panel 4 of the C(Q, pT_pair) page
0211 (`src/QPTPage.h`) draws <pT_pair> per Q bin for sibling and mixed pairs; a gap at large Q common to all pair
0212 types is this multiplicity effect, one seen only in like-sign or V0-V0 pairs would need a closer look.
0213 - **Empty-denominator protection and zvtx averaging.** A bin is empty only if its mixed density is zero
0214 (a zero sibling count is a valid measurement). Correlation functions are formed per zvtx bin and then
0215 averaged over the zvtx bins that are valid for that bin -- the mixed density is non-zero and enough
0216 pairs are expected there (a minimum per pair type, in `src/PairTypes.h`).
0217 - **Uncertainties from subgroups.** Finalize runs every chunk through the same chain, with the
0218 full-statistics zvtx weights and masks, and takes the error from the chunk-to-chunk scatter. It also
0219 fits the per-chunk values versus time and versus occupancy, to catch any drift.
0220 - **Built-in cross-checks.** pi- pi+ is the pi+ pi- system with the species order swapped (dy -> -dy),
0221 a check of the sign and crossing conventions; R2(dy) is computed both
0222 from the (dy, dphi) map and from the (y1, y2) map; Finalize compares every histogram with a
0223 single-job full-statistics reference and reports the pulls; and the logs count every removed track,
0224 vetoed pair and skipped mixed pair.
0225
0226 ## Building
0227
0228 Needs ROOT 6 (tested with 6.34) with its CMake configuration available (e.g. after
0229 `source thisroot.sh`), CMake >= 3.16, a C++17 compiler, and `ps2pdf` (Ghostscript) for the PDF output.
0230
0231 ```sh
0232 cmake -S Corral -B Corral/build
0233 make -C Corral/build
0234 ```
0235
0236 This builds the executable `corral` in the Corral directory (not in `build/`). The pair types are set in
0237 `src/PairTypes.h` (number and order change now and then; a pions-only study edits that table, it gets no
0238 separate binary). Until 2026-09-27 the executable and its
0239 output files were called `corral_m`; files made before then keep that name. Finalize knows which datasets
0240 use it (`CorralFilePrefix` in `src/finalize_hists.h`: ana532 uses `corral_m`, later datasets use `corral`).
0241
0242 ## Running
0243
0244 `corral` writes `root/<name>.root` and `pdf/<name>.pdf` below the directory it is run in, so run it in a
0245 work directory that has `root/` and `pdf/` subdirectories. The default name is `corral`.
0246
0247 ```sh
0248 mkdir -p work/root work/pdf && cd work
0249 /path/to/Corral/corral -n 200000 -l /path/to/list.txt # 200k events from the files in list.txt
0250 ```
0251
0252 ### Options
0253
0254 | option | meaning |
0255 |---|---|
0256 | `-h` | help: all options and run-string tokens, with the current defaults |
0257 | `-n N` | process N events (tree entries; one entry = one crossing with a vertex); 0 = all |
0258 | `-l file` | read the Collect files listed in `file`, one path per line |
0259 | `-d dataset` | dataset for Finalize (default: `FINALIZE_SET` in `src/finalize_hists.h`) |
0260 | `-o name` | output base name: `root/name.root`, `pdf/name.pdf` (not scanned for run-string tokens) |
0261 | `-s string` | run string: appended to the output name (`corral_<string>`) and scanned for the tokens below |
0262
0263 Without `-l`, all files matching the environment variable `CORRAL_TREES` are read in one job
0264 (for example `export CORRAL_TREES='/path/to/production/outputCollect_*.root'`, quoted). This is
0265 useful for tests; if it is not set, a site default (the WSU copy of the production) is used, and the log
0266 says which glob was used and how many files matched.
0267
0268 ### Run-string tokens
0269
0270 Most runs need no run string, or one of the main tokens below. Tokens are matched as substrings,
0271 case-insensitively; join several with `_`.
0272
0273 | token | effect |
0274 |---|---|
0275 | *(none)* | the defaults: every split-track cleaner, the masks and the crossing correction ON; zero-bias crossing selection (below) |
0276 | `Raw` | every cleaner and correction OFF: shorthand for `noLS_noulstest_noXTF_noTFdup_nolooper_notsep_noisep_nocross_nocmmask`, and all crossings (`AllX`) unless a crossing token is given too (e.g. `Raw_Xing0`) |
0277 | `nocross` | turn off only the crossing correction (pt-ordering at fill + (dy, dphi) bin correction) |
0278 | `Xing0` | keep only crossing 0: the triggered collision (not zero bias) |
0279 | `NearX0` | keep only −4 ≤ crossing ≤ 2 without 0: the neighbours of the trigger (monitoring) |
0280 | `AllX` | keep all crossings |
0281
0282 **Default crossing selection = zero bias** (`ZB`; the token is accepted but not needed): −20 ≤ crossing ≤ 390,
0283 outside the NearX0 window. It is protected against three things:
0284 1. **crossing 0** is the triggered collision, not zero bias (in jet/photon-trigger TFs ⟨N_trk⟩ 6.2 vs 4.3,
0285 ⟨pT⟩ 0.59 vs 0.48 GeV);
0286 2. **the crossings next to 0** (NearX0, −4..+2): ⟨N_trk⟩ ~6% low in every trigger class, and their
0287 correlations differ from ZB; kept out so they can be monitored separately with `NearX0`;
0288 3. **extreme crossings** (< −20 or > 390), at the readout-window edges, where ⟨N_trk⟩ per event sags from its
0289 plateau value in the bulk of the zero-bias region (4.27 at −30..−21, 3.90 at 401-410).
0290
0291 Xing0, NearX0 and ZB exclude each other (~15% of events, the extreme crossings, are in none of them); giving
0292 more than one of Xing0 / NearX0 / ZB / AllX stops the job. The limits are constants in `src/corral_class.h`
0293 (`XNEAR_LO/HI`, `ZB_LO/HI`); the QA pages show ⟨N_trk⟩ and ⟨pT⟩ vs crossing per trigger class, before and
0294 after the selection.
0295
0296 `-s Finalize` is special: see the end of this section.
0297
0298 #### Expert switches: split-track cleaners
0299
0300 These are expert-level switches that turn individual split-track cleaners (and the related two-track pair
0301 cuts) off or on, or move their important cuts. `Raw` turns all of them off at once. `NN` is two digits, read as
0302 0.NN. A value outside its sane range (given in the table) stops the job with a message; it is never clamped
0303 silently. Cuts that are not listed are fixed constants (see README_SplitTracks573.md sec 18 for the like-sign
0304 split-track ones).
0305
0306 | token | effect |
0307 |---|---|
0308 | **like-sign split tracks** | |
0309 | `noLS` | turn off the whole like-sign split-track removal |
0310 | `noRG` | turn off only the RadialGap path (the SL/SiSplitScore path stays on) |
0311 | `removecutNN` | SL threshold 0.NN (default 0.18; sane range 0.05-0.60) |
0312 | `skfNN` | SiSplitScore gate 0.NN (default 0.10; 0.05-0.95) |
0313 | `radialgapNN` | RadialGap threshold 0.NN (default 0.45; 0.20-0.90) |
0314 | `noMVTX` | turn off the third LS path (pairs with >= 2 matched MVTX layers, whatever the SL) |
0315 | `nolooper` | turn off the looper veto |
0316 | `looperNN` | looper veto relative momentum sum below 0.NN (default 0.08; 0.02-0.10) |
0317 | `dpsNN` | pregate half-width: the pregate is centred on the split peak, (deta/0.040)^2 + ((abs(dphi) - dphi0)/w)^2 < 1, dphi0 = the azimuth difference the two fragments build up by R = 6 cm, w = NN/10 deg (default `dps20`; 1.0-4.0 deg). The third LS path (>= 2 matched MVTX layers) has a fixed threshold; `noMVTX` turns it off. |
0318 | `tsepmYYPP` | two-track-resolution LS pair cut, sibling and mixed alike: reject abs(dy) < 0.YY and min over R = 0.30-0.78 m of abs(dphi*) < P.P deg (default `tsepm0620`; dy 0.02-0.10, dphi* 1.0-4.0) |
0319 | `notsep` | turn off the two-track pair cut (`noLS` does not: it is a pair cut, not a split-track path) |
0320 | **near-vertex two-track loss (LS and ULS)** | |
0321 | `isepPPP` | near-vertex two-track pair cut, sibling and mixed alike, LS and ULS: reject abs(dy) < 1.0 and abs(dphi*(R = 3 cm)) < P.P deg (default `isep020` = 2.0 deg; 0.3-4.0). Sibling tracks at nearly the same phi near the vertex are lost out to abs(dy) ~ 0.8 (README_SplitTracks573.md sec 28-29); the PDF page "Near-vertex two-track loss" draws the cut on the loss. |
0322 | `noisep` | turn off the near-vertex two-track cut |
0323 | **opposite-charge split tracks** | |
0324 | `noulstest` | turn off the opposite-charge veto |
0325 | `ulstestNN` | opposite-charge veto at SiSplitScore 0.NN (default 0.05; 0.02-0.95) |
0326 | **V0-daughter split partners** | |
0327 | `nodau` | turn off the split-partner check of Lambda/Lbar daughters (see "V0 daughters" above) |
0328 | **cross-crossing duplicates and mixing** | |
0329 | `noXTF` | turn off the duplicate cleaner and the adjacent-TF mixing exclusion |
0330 | `XTFclean` | cleaner non-strict (if neither copy matches the INTT timing, keep the better one; strict is the default) |
0331 | `mixAdjTF` | allow mixing with adjacent TFs |
0332 | `noTFdup` | keep collisions copied into overlapping TFs (default: skip the later copies; needs the Collect `bco` branch, no effect without it) |
0333
0334 #### Expert switches: other
0335
0336 | token | effect |
0337 |---|---|
0338 | **PID, masks and multiplicity class (README_PID.md)** | |
0339 | `oldpid` | legacy PID: pi = dedx70s < 400 at any momentum, no p or K, split-track candidates = those pions (default: KFP dE/dx gates on dedxKFP, pi then p (outside the K band) then K (outside the p band), all accepted tracks are split-track candidates) |
0340 | `isovtxNNZZ` | isolated vertices only: skip every row (vertex) that has another vertex of the same run within +-NN crossings (absolute crossing bco+crossing, across TF boundaries) and abs(dz) < ZZ cm; copies of the same crossing are not neighbours (`noTFdup` territory). Test of track-to-vertex misassignment at high rate (README_ana573.md). NN 01-50, ZZ 01-30 cm. Default OFF |
0341 | `segveto` | skip the events of the (run, DST segment)s listed in `bad_segments.txt` before any processing (segCells keeps the segment with `veto` = 1 and only `nraw` filled); the file is `$CORRAL_SEGVETO`, else `bad_segments.txt` in the folder of the `-l` list. Made by `lists/make_bad_segments.C` from the segCells of a production run without `segveto`: segments below their run's live-fraction band (README_ana573.md). Default OFF |
0342 | `nosiphimask` | turn off the ana573 vertex-phi mask (default: the two windows [70,83) and [94,115) deg) |
0343 | `siphimaskall` | use all eight vertex-phi mask windows (the two above and six small ones; a study option) |
0344 | `nocmmask` | turn off the ana573 central-membrane mask (default: w in [-0.07,0.10), see above) |
0345 | `cmmaskAABB` | the central-membrane mask window w in [-0.AA,0.BB) (each 0.00-0.20) |
0346 | `nchLLHH` | multiplicity class: only events with LL <= N_ch <= HH (accepted tracks, `hntrk`) reach CalcRm, so siblings, mixing pools and hmult (r2) stay inside the class (default all events; LL 0-40, HH LL-99; e.g. `nch0607`). The loop's QA pages still see every event. |
0347 | **event selections (diagnostics; they cost statistics)** | |
0348 | `onlyfirsttf` | keep only the first event of each TF |
0349 | `XingPos` | keep only the first event with crossing > 0 of each TF |
0350 | **other** | |
0351 | `ntpcNN` | track cut: at least NN TPC clusters (default 18; 10-40) |
0352 | `dczNN` | track abs(dcaz) < NN/10 cm instead of 1.5 cm (sane 0.2-1.5). Under the dcaz peak lies a flat pedestal of tracks from other collisions, 3.5% of the tracks in abs(dcaz) < 1.5 at the 795xx rate and 7.6% at the 8158x rate (`ana573/CutFlow_ana573.C`) |
0353 | `dxyNN` | track abs(dcaxy) < NN/100 cm instead of 1.5 cm (sane 0.05-0.99). Tracks attached from other collisions point back 5-7x worse in xy than the vertex's own (rms 0.2-0.25 cm vs 0.037 cm; `ana573/CutFlow_ana573.C`); 0.10 cm keeps 98.5% of own tracks and removes about a quarter of the attached background |
0354 | `qcut` | reject pairs with Q < 0.150 GeV |
0355 | `548` | fine (dy, dphi) binning, 5 x 48 (default 32 x 36) |
0356 | **acceptance box (studies)** | |
0357 | `vzNN` | event abs(zvtx) < NN cm (default 16; 6-16). For physics the Zvtx range is chosen in Finalize (`fzNN`), not here. |
0358
0359 Watch for substring collisions when choosing a run string: `mixNoAdjTF` contains `NoAdjTF`,
0360 `XTFcleanStrict` contains `XTFclean`, `noulstest` contains `ulstest`, `nolooper` contains `looper`, `nocmmask`
0361 contains `cmmask`, `siphimaskallX...` (no `_`) contains `AllX`, any word containing `raw` means `Raw`, and any
0362 word containing `nocross` turns off the crossing correction.
0363
0364 `-s Finalize` is special: instead of processing events, it runs Finalize (below). `-s Finalize_<tokens>`
0365 also runs Finalize; its token `fzNN` sets the Zvtx range for physics: Finalize averages only the 2 cm Zvtx
0366 slices inside abs(zvtx) < NN cm (default **8**; 2-16). The chunks keep every slice (abs(zvtx) < 16), so the
0367 choice can be changed without rerunning. R2 per Zvtx slice is flat only at abs(zvtx) < ~6-8 cm
0368 (README_SplitTracks573.md sec 30); the output names record the tokens (`corral_Finalize_fz16.*`).
0369 A bin-zvtx enters the Zvtx average only if N_exp = nevt rho2(M) >= N_min (PairTypes.h; env `FINALIZE_NEXPMIN`)
0370 and rho2(M) >= 0.3 x the bin's largest rho2(M) over the slices (partial-acceptance edges such as the
0371 central-membrane mask; env `FINALIZE_MFRAC`, 0 = off; README_SplitTracks573.md sec 38). The log counts both.
0372
0373 ### A full production
0374
0375 Everything belonging to one dataset (for example `ana532`) uses the dataset name as its folder, see
0376 "Data layout" below.
0377
0378 1. **Make job lists** from a Collect production directory, about N events per list:
0379 ```sh
0380 Corral/lists/make_lists.bash /path/to/collect_dir 1000000 <dataset>
0381 ```
0382 This writes `lists/<dataset>/` with `list_NN.txt`, `list_all.txt` (all lists together), `manifest.txt`,
0383 `lists_summary.txt` and `segment_entries.txt`. Each list holds contiguous segments of one run, so the
0384 chunks follow the data-taking time order. `<dataset>` defaults to the name of the Collect directory.
0385 The Collect files may sit in the directory itself or in run-number subfolders (`<collect_dir>/<run>/`).
0386 An optional 4th argument keeps only some runs, so one production can be split into run groups.
0387 ana573 is split this way: `ana573_795xx` (runs 79514-79516), `ana573_8156x` (81566) and `ana573_8158x`
0388 (81584-81586), with plain `ana573` for all runs together:
0389 ```sh
0390 Corral/lists/make_lists.bash /rs/rs_grp_rhi/sPHENIX/ana573 10000000 ana573_8158x 81584,81585,81586
0391 ```
0392 If `lists/<dataset>/segment_entries.txt` already exists, it is used and nothing is recounted. For
0393 all-runs `ana573`, join the run groups' `segment_entries.txt` into it first.
0394 2. **Run one job per list** as a SLURM array (the partition and time limit in the scripts are set for the
0395 WSU grid; adjust them for your site):
0396 ```sh
0397 Corral/run_m_array.bash <dataset> [array-range]
0398 ```
0399 The binary is snapshotted first, so every task runs the same code. The run scripts keep jobs off the
0400 hax* and rpr* nodes by default (`EXCLUDE="..."` replaces the list, `EXCLUDE=` allows every node). Outputs go to
0401 `root/<dataset>/chunks/corral_NN.root`, and the same under `pdf/` and `log/`.
0402 A **variant** of the dataset (the same lists with a run string) is
0403 `CORRAL_VARIANT=<name> CORRAL_RS=<runstring> Corral/run_m_array.bash <dataset>` (and the same for
0404 `run_m.bash`): outputs go under `<dataset>_<name>/`, and `lists/<dataset>_<name>` is made as a link to the
0405 dataset's lists, so Finalize runs with `-d <dataset>_<name>`. For example, everything off:
0406 `CORRAL_VARIANT=raw CORRAL_RS=noLS_noulstest_noXTF_noTFdup_nolooper_notsep_noisep_nocross`.
0407 3. **Run the single full-statistics job**, which reads `list_all.txt` and is the reference Finalize
0408 compares against:
0409 ```sh
0410 Corral/run_m.bash <dataset>
0411 ```
0412 Output: `root/<dataset>/corral.root`, `pdf/<dataset>/corral.pdf`, `log/<dataset>/corral.log`. It asks for
0413 16 GB and 7 days (`MEM=`, `TIME=` override). With 28 pair types a job took about 2 h 15 min and
0414 3 GB per 50M events (ana573, 642M events: ~29 h, MEM=32G); with 46 a 10M-event chunk takes ~1.5 h.
0415 This job also snapshots its binary.
0416 4. **Finalize**, as a SLURM job (about 5 min, under 1 GB):
0417 ```sh
0418 Corral/run_finalize.bash <dataset> # abs(zvtx) < 8 cm for the physics (fz08)
0419 Corral/run_finalize.bash <dataset> Finalize_fz16 # the whole zvtx range
0420 Corral/run_finalize.bash ana573_795xx ana573_8156x ana573_8158x ana573 # one job per dataset
0421 ```
0422 It reads `lists/<dataset>/`, `root/<dataset>/chunks/` and `root/<dataset>/corral.root`, runs in a
0423 scratch directory on the worker node and writes `root/<dataset>/corral_Finalize.root`,
0424 `pdf/<dataset>/corral_Finalize.pdf` and `log/<dataset>/corral_Finalize.log` (`corral_Finalize_fz16.*` for
0425 `Finalize_fz16`). The binary is snapshotted first; `FINALIZE_NEXPMIN` / `FINALIZE_MFRAC` are passed on.
0426 By hand, in a work directory with `root/` and `pdf/`: `corral -d <dataset> -s Finalize` writes to
0427 `./root` and `./pdf`.
0428 Finalize also writes the tree `work/chunkStats`, one entry per chunk (run, chunk, events, occupancy =
0429 mean raw vertices per TF of the events used), with the multiplicity moments from each chunk's hmult,
0430 for |zvtx| < 8 cm ([0]) and all zvtx ([1]): per pair type 1+r2 and its error, f2 (pairs per event),
0431 <n1>, <n2>, P0; per particle <n>, P0 and P(n); and the totals over pi/K/p, over pions and over h+-
0432 (<N>, f2, R2 = f2/<N>^2). Pair-type names are in the tree's UserInfo. The whole-sample totals, with
0433 subgroup errors, are in the log and in `work/R2tot_*`.
0434 Each chunk file also holds the tree `segCells` (TPC acceptance vs time): one entry per (run, DST segment,
0435 ~8.5k events) with nevt, ntrk (accepted charged tracks, the hphieta list) and `fee[624]`, the TPC hits of
0436 those tracks per FEE: cell = tpcsector*26 + feeMap (tpcsector = 2*sectorId+side, side 0 = South z<0; feeMap
0437 0-25 = TPC_FEE_CHANNEL_MAP index, R1 0-5, R2 6-13, R3 14-25). A hit's FEE = that of the nearest pad in
0438 (tpcsector, layer, tpcarclen*2mm / pad radius) from `tpcFeeMap/tpc_pad_fee_map_all.txt` (read at run time;
0439 made at SDCC from the CDB, 2026-10-12). tpcarclen is the distortion-corrected phi, so hits at FEE edges can
0440 land in the neighbour. Chunk files made before 2026-10-12 hold `hits[1152]` (a generic grid, 24 tpcsector x
0441 3 modules x 2 layer halves x 8 angle slices) instead; `ana573/SegCellsView_ana573.C` reads both.
0442 Since 2026-10-12 segCells has one entry for every segment read (also those `segveto` skips: `veto` = 1)
0443 and per-segment QA sums: `nraw` (rows read), `nvtx` (raw vertices per TF, summed over nevt), `sumpt`,
0444 `sumntpc`, `sumadcaxy`, `sumadcaz` (summed over ntrk), `nid[6]` (identified pi+ pi- K+ K- p pbar) and
0445 `nv0[3]` (K0S, Lambda, Lbar in the pair mass window).
0446 **Run record `info/`** (chunk files since 2026-10-12): text objects `runstring`, `settings` (every switch
0447 and cut value, one per line), `list`, `segveto` (mask file and number of segments) and `code` (git commit
0448 of the source, `-dirty` if it had uncommitted changes, and build time; stamped at build time by
0449 `corral_version.cmake`), counters `count_*` (rows read, rows skipped as TF copies / by segveto / by isovtx,
0450 events outside the crossing selection, events reaching the track loop) and cut values `cut_*`. Read
0451 one with `f->Get("info/settings")->GetTitle()`.
0452 **Finalize front pages:** a title page (left: the chunks' `info/`, event counts, a red line for every chunk
0453 that disagrees; right: contents and the pair-type list), then the QA histograms summed over the chunks
0454 with every cut drawn (events and vertices with the event flow, tracks, dE/dx PID with the KFP gates, V0
0455 mass peaks with the pair window), then two pages versus DST segment in time order (events/rows,
0456 vertices per TF, tracks per event, <pT>, <ntpc>, <|dca_xy|>, <|dca_z|>, TPC live fraction all/South/North
0457 with the segveto rule from `src/SegLive.h`, identified particles and V0s per event; segveto segments
0458 shaded, run boundaries dashed). Then the pair-type pages as before. The root file gets `info/` (the
0459 chunks' texts, the counters summed, plus `chunks` and `finalize`), `work/qa/` (the summed QA histograms)
0460 and `work/segQA` (the per-segment table of the vs-segment pages, live fractions included).
0461 Without `corral.root` (the single job still running) it skips only the pages that compare with it. The
0462 crossing correction follows the chunks: a `nocross` production stays uncorrected in Finalize too.
0463
0464 ### Where things are looked for
0465
0466 The project directory (holding `lists/` and `root/` for Finalize, and `dedxGates_KFP.root` for the PID)
0467 defaults to the source directory `corral` was built from. Set `CORRAL_DIR` to use another one. The run scripts find their own
0468 directory, or use `CORRAL_DIR` if it is set, and pass it on to the SLURM jobs.
0469
0470 ## Data layout
0471
0472 Outputs are kept per dataset, so that productions never mix:
0473
0474 ```
0475 lists/<dataset>/ job lists (made by lists/make_lists.bash)
0476 root/<dataset>/corral.root single full-statistics job (the Finalize reference)
0477 root/<dataset>/corral_Finalize.root
0478 root/<dataset>/chunks/ one file per job list
0479 root/<dataset>_<variant>/ the same for a variant (run_m*.bash CORRAL_VARIANT=; lists/<dataset>_<variant> -> <dataset>)
0480 DATASET_<dataset>.md what the dataset is: trees, events, runs, job IDs (in the Corral
0481 directory itself, so it survives when a superseded dataset is deleted)
0482 pdf/<dataset>/, log/<dataset>/ the same structure
0483 root/Development/, pdf/Development/, log/Development/ study and test outputs
0484 ```
0485
0486 The input trees at WSU are in `/rs/rs_grp_rhi/sPHENIX/<dataset>/`. None of these output folders are in
0487 the repository.
0488
0489 ## Code layout
0490
0491 | file | contents |
0492 |---|---|
0493 | `src/corral_main.cxx` | command line, help text |
0494 | `src/corral_utils.cxx` | input chain, run-string parsing, defaults |
0495 | `src/corral_loop.cxx` | the event loop: track and V0 selection, split-track and duplicate removal, QA histograms, PDF pages |
0496 | `src/CalcRm.cxx`, `.h` | pair filling (sibling and mixed), correlation functions per zvtx bin, C(Q) |
0497 | `src/corral_finalize.cxx`, `finalize_hists.h` | Finalize and its configuration |
0498 | `src/FinalizeQA.h` | Finalize's title page, QA pages, vs-segment pages, reading `info/` of the chunks |
0499 | `src/SegLive.h` | TPC live fraction per segment from segCells (used by Finalize and `lists/make_bad_segments.C`) |
0500 | `src/CrossingCorrect.h`, `ZvtxAverage.h` | crossing correction and zvtx averaging, shared by CalcRm and Finalize |
0501 | `src/PairTypes.h` | the pair-type table and the per-type minimum expected pairs |
0502 | `src/fluct_common.h`, `corral_class.h` | shared definitions (species, PID caps and pT minima, the SiPhiMask windows, the V0 mass peaks); `NOCORRELATIONS` in `corral_class.h` skips all pair work (fast QA runs) |
0503 | `dedxGates_KFP.root` | the KFParticle dE/dx gates (lower/upper edge vs momentum for pi, K, p, d), read at run time |
0504 | `ana573/SplitTrackTypes_ana573.pdf` | pictures of each split / duplicate case the ana573 default removes, the notch, and the central-membrane hole with its mask (3 pages) |
0505 | `ana573/SplitTrackLogic_ana573.pdf` | flowchart of every removal decision in processing order, with the fractions removed (3 pages) |
0506
0507 ## The name
0508
0509 - A corral is the pen where cattle or horses are rounded up and held before you work with them. That is
0510 what the code does: it rounds up the particles of each event into species (pions, K0S, Lambda, ...) and
0511 pairs them.
0512 - The event-mixing buffer is literally a holding pen: NMIX events are kept corralled together until the
0513 mixed pairs are formed.
0514 - **CORR**elation an**AL**ysis -> C-O-R-R-A-L.