Back to home page

sPhenix code displayed by LXR

 
 

    


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.