Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-10-15 08:17:19

0001 #ifndef corral_h
0002 #define corral_h
0003 
0004 #include <iostream>
0005 #include <vector>
0006 #include <TROOT.h>
0007 #include <TRandom3.h>
0008 #include <TChain.h>
0009 #include <TTreeReader.h>
0010 #include <TTreeReaderValue.h>
0011 #include <TTreeReaderArray.h>
0012 #include <TFile.h>
0013 #include <TH1D.h>
0014 #include <TH2D.h>
0015 #include <TError.h>
0016 #include <unordered_map>
0017 #include <deque>
0018 
0019 using std::vector;
0020 using std::cout;
0021 using std::endl;
0022 
0023 static const bool USESEEDTRACKS     = false;    // get eta,phi,pt from tpc seed not svtxtrack...
0024 static const bool NOCORRELATIONS    = false;    // skip the correlations classes for speed...
0025 // per-run QA histogram axis, one bin per run: Run-3 pp only, just outside the first and last run
0026 // of the Run-3 pp golden tracking list (79340-81667, 306 runs, lists/Golden_run3pp_tracking_list_
0027 // 20260917.txt). Was 49700-54200 (Run 2), where every Run-3 run landed in overflow.
0028 static const int    RUNAXIS_NBIN    = 2400;
0029 static const double RUNAXIS_LO      = 79300.5;
0030 static const double RUNAXIS_HI      = 81700.5;
0031 // KILLSPLITTRACKS (same-Si-seed proxy pre-pass) retired 2026-09-19 -- see README_SplitTracks.md
0032 // sec 9/10. Replaced by the split-track removal pre-pass (doSplitRemoval/valSLCut/valSiKeyCut
0033 // below, corral_loop.cxx, finalized sec 17.6) plus a diagnostic-only SL/SKF monitor that fills
0034 // the same "flagged (split-candidate)" QA page the old pruner used to (sec 10.9).
0035 
0036 //------------------------------------------------------------------------------------
0037 // corral -- TTreeReader-based replacement for the old MakeClass skeleton.
0038 //
0039 //   No more fixed-size C arrays (NTRKMAX/NV0MAX) mapped onto branches via
0040 //   SetBranchAddress: every per-track/per-V0 branch below is a TTreeReaderArray,
0041 //   which ROOT sizes to the *actual* per-entry leaf count (ntr / nv0) every time
0042 //   GetEntry-equivalent happens. There is therefore no way for a high-multiplicity
0043 //   event to overflow a fixed buffer and silently corrupt adjacent class members
0044 //   (the old failure mode this class used to be vulnerable to).
0045 //------------------------------------------------------------------------------------
0046 class corral {
0047 public :
0048     //
0049     corral(TTree *tree=0, int ntd=0, TString rs="", TString outname="");
0050     virtual ~corral();
0051     virtual void     Loop();
0052     virtual void     Finalize();        // README_Finalize.md: combine chunk outputs (RunString "Finalize")
0053     TString          SettingsText();    // every switch and cut value in force, one per line (info/settings, Finalize title page)
0054     void             WriteInfo(TDirectory *top, const std::vector<std::pair<TString,TString>> &texts, const std::vector<std::pair<TString,double>> &counts);    // info/ (README.md)
0055     //
0056     virtual bool    AcceptEvent();
0057     virtual bool    AcceptTrack(int it);                // AcceptTrackBase and, if doSiPhiMask, not InSiPhiMask
0058     virtual bool    AcceptTrackBase(int it);            // pt, ntpc, dca limits
0059     virtual bool    InSiPhiMask(int it);
0060     virtual bool    InCMMask(int it);                       // README_SplitTracks573 sec 38: w = (eta + CMMASK_K vtxz) sign(-vtxz) in [valCMMaskLo, valCMMaskHi)                    // vertex phi inside a PHIMASK window (README_PID.md sec 10.3)
0061     virtual void    BuildXTFLosers(Long64_t nentries);  // sec 18.22, see doXTFClean
0062     virtual void    BuildTFDupRows(Long64_t nentries);  // see doTFDup
0063     //
0064     virtual int     GetSpecies(int ipid){
0065         int ival    = -1;
0066         if (ipid<  5){ ival = ipid; } else
0067         if (ipid< 10){ ival = ipid-5; } else
0068         if (ipid==10){ ival = 5; } else
0069         if (ipid==11){ ival = 6; } else
0070         if (ipid==12){ ival = 7; } else
0071         if (ipid==13 || ipid==14){ ival = 0; }  // h+, h-: pion y and pT limits (2026-10-11)
0072         return ival;
0073     }
0074     //
0075     int     ntodo;
0076     TString RunString;
0077     TString OutputName;     // -o: output base name (root/<name>.root, pdf/<name>.pdf); empty -> corral_<class>[_<RunString>]
0078     TString Dataset;        // -d: dataset for Finalize (lists|root/<dataset>/); empty -> FINALIZE_SET (finalize_hists.h)
0079     bool    doCrossing;
0080     bool    doOldPID;       // README_PID.md: "oldpid" -> legacy PID (pi = dedx70s<400, no p or K); default is the KFP dE/dx gates
0081     bool    doSiPhiMask;        // README_PID.md sec 10.3: drop tracks in the ana573 vertex-phi windows SIPHIMASK_LO/HI (default on; "nosiphimask" off)
0082     bool    doCMMask;       // README_SplitTracks573 sec 38: drop tracks in the central-membrane hole (default ON, w in [-0.07,0.10); "nocmmask" off; "cmmaskAABB" = [-0.AA, 0.BB))
0083     bool    doSegVeto;      // README.md "segveto": skip the events of the (run, DST segment)s in bad_segments.txt (next to the -l list,
0084                     // or $CORRAL_SEGVETO), made by ana573/SegCellsView_ana573.C; default OFF
0085     TString ListName;       // -l: the job list (segveto finds bad_segments.txt next to it)
0086     bool    doSepMaps;      // README_CQcomparison sec 2.3: (track, nearer V0 daughter) separation maps, own mixing, ~+5 min/chunk; OFF, "sepmaps" on
0087     double  valCMMaskLo, valCMMaskHi;
0088     int     nSiPhiMask;     // README_PID.md sec 10.4: windows used, NSIPHIMASK_MAIN (default) or NSIPHIMASK ("siphimaskall")
0089     bool    doQCut;
0090     bool    FinePhiBinning;
0091     double  valQCut;
0092     double  valSLCut;   // production pre-pass's SL threshold, default 0.18 (sec 17.6)
0093     double  valSiKeyCut;    // production pre-pass's SiSplitScore gate, default 0.10 (sec 17.6)
0094     double  valRadialGapCut;    // sec 17.14: SECOND flagging path's threshold -- pairs that share a Si
0095                                 // seed (SKF>=valSiKeyCut) but fail the SL<valSLCut "duplicate" test are
0096                                 // flagged anyway if RadialGap>=this (the "complementary"/STAR-fig-1b
0097                                 // mechanism SL cannot see, sec 17.11). Default 0.45 -- sec 17.16's 12-point
0098                                 // survey (SL/SKF held fixed) confirms this lands inside the good window:
0099                                 // visible overcut hole below ~0.35, ridge fully returns above ~0.55.
0100     bool    DISABLE_LScuts; // sec 17.9: "noLS" in RunString -> true, and the pregate + SL/SKF/RadialGap
0101                             // split-track pre-pass are NOT applied (sec 17.14 folds the RadialGap path into
0102                             // the SAME switch -- it's a refinement of this pre-pass, not a separate
0103                             // mechanism). New philosophy as of sec 17.6/17.9: once a cut is finalized it
0104                             // defaults ON (doSplitRemoval below = !DISABLE_LScuts), and the RunString
0105                             // provides only the OFF switch -- no separate "enable" token needed.
0106     //---- README_SplitTracks573 sec 18 (token trim, 2026-09-27): LS pregate and path 3. CONSTANTS (no token):
0107     //---- deta semi-axis 0.040 (sec 8.3/15.3), path 3 at >= 2 matched MVTX layers with no abs(1/pt1-1/pt2)
0108     //---- floor (sec 8.2/15.3), dphi0 at R = 0.06 m. The pregate is the flat ellipse CENTRED ON THE SPLIT
0109     //---- PEAK (sec 12): (deta/a)^2 + ((abs(dphi) - dphi0)/w)^2 < 1, dphi0 = the azimuth difference the two
0110     //---- fragments build up by R; its half-width w (valDPsW, default 2.0 deg) is the only token ("dpsNN").
0111     int     valFullMVTX;        // path 3: >= this many MVTX layers with the same cluster on both tracks (2)
0112     double  valFullMVTXdinv;    // path 3: abs(1/pt1-1/pt2) floor (0)
0113     double  valPregateDEta;     // pregate deta semi-axis (0.040)
0114     double  valDPsW, valDPsR;   // pregate dphi half-width (deg, "dpsNN") and the radius of dphi0 (m)
0115     double  DPsCentre(double ptA, double ptB) const {   // dphi0 (rad): abs(asin(aR/ptA) - asin(aR/ptB)), a = 0.3*1.4/2
0116         const double aR = 0.3*1.4/2.0*valDPsR;
0117         double xA = std::min(1.0,aR/ptA), xB = std::min(1.0,aR/ptB);
0118         return fabs(asin(xA)-asin(xB));
0119     }
0120     //---- README_SplitTracks573 sec 33 (2026-09-29): the split stripe's dphi spread grows with dphi0 (rms ~ 0.22 + 0.13*dphi0
0121     //---- deg), so the half-width is max(valDPsW, 3 rms): valDPsW (2 deg) up to dphi0 ~ 3.4 deg, 3.1 deg at dphi0 = 6.2
0122     static constexpr double PREGATE_S0 = 0.22, PREGATE_S1 = 0.13, PREGATE_NSIG = 3.0;
0123     double  DPsWidth(double c) const {          // c = dphi0 (rad) -> half-width (rad)
0124         double cdeg = c*180.0/M_PI;
0125         return std::max(valDPsW, PREGATE_NSIG*(PREGATE_S0 + PREGATE_S1*cdeg))*M_PI/180.0;
0126     }
0127     bool    InLSPregate(double deta, double dphi, double ptA, double ptB) const {   // dphi in rad
0128         double c    = DPsCentre(ptA,ptB);
0129         double w    = DPsWidth(c);
0130         double u    = (fabs(dphi)-c)/w;
0131         return (deta/valPregateDEta)*(deta/valPregateDEta) + u*u < 1.0;
0132     }
0133     //---- two-track-resolution LS pair cut (sec 11/13): abs(dy) < valTSepDy && min over R = 0.30-0.78 m of
0134     //---- abs(dphi*) < valTSepDphi, sibling and mixed alike. "tsepmYYPP" sets both, "notsep" turns it off.
0135     double  valTSepDy, valTSepDphi;
0136     //---- near-vertex two-track pair cut (README_SplitTracks573 sec 29): reject abs(dphi*(R = 3 cm)) < valISepDphi (deg) at
0137     //---- abs(dy) < 1.0, LS and ULS, sibling and mixed alike. Default 2.0 deg; "isepPPP" (deg x 10, 0.3-4.0) / "noisep" (off).
0138     double  valISepDphi;
0139     //---- event |zvtx| max (cm), README_SplitTracks573 sec 30: "vzNN" (6-16), default 16 (under discussion: R2 per Zvtx
0140     //---- slice is flat only at abs(zvtx) < ~6-8 cm)
0141     double  valVzMax;
0142     //---- event multiplicity class (README_CQcomparison.md sec 2.1): only events with valNchLo <= N_ch <= valNchHi (N_ch =
0143     //---- accepted tracks, ntrkept = hntrk) reach CalcRm, so siblings, mixing pools and r2 are all within the class.
0144     //---- "nchLLHH" sets both (LL 0-40, HH LL-99); default 0-9999 (all events).
0145     int     valNchLo, valNchHi;
0146     //---- Finalize: the abs(zvtx) range for physics (cm), README_SplitTracks573 sec 30 (user, 2026-09-28): the chunks keep
0147     //---- every Zvtx slice (abs(zvtx) < 16); Finalize averages only the slices inside abs(zvtx) < valFinZMax (whole 2 cm
0148     //---- slices). Default 8; "fzNN" in the Finalize run string (Finalize_fzNN, 2-16) overrides it.
0149     double  valFinZMax;
0150     bool    DISABLE_RG; // sec 17.17: "noRG" in RunString -> true, and ONLY the RadialGap path (path 2)
0151                         // is skipped -- path 1 (SL/SKF "duplicate" flagging) stays live. Finer-grained
0152                         // than DISABLE_LScuts (which turns off both paths together): lets a run isolate
0153                         // the RadialGap path's own before/after effect specifically.
0154     bool    doSplitRemoval; // split-track REMOVAL pre-pass (corral_loop.cxx, sec 13.8.4/13.8.6/13.8.18,
0155                             // values finalized sec 17.6, RadialGap path added sec 17.14) -- the production
0156                             // split-track mitigation. Driven by !DISABLE_LScuts (sec 17.9); uses
0157                             // valSLCut/valSiKeyCut/valRadialGapCut as its threshold values.
0158     bool    doLooperVeto;   // README_SplitTracks573 sec 35: looper veto (OS back-to-back halves of one curling track), ON; "nolooper" off
0159     static constexpr double LOOPER_PMAX = 0.20; // sec 35: both |p| below (GeV/c)
0160     double  valLooperRSum;  // sec 35: relative 3-momentum sum below (default 0.08; "looperNN" = 0.NN, 0.02-0.10)
0161     int     valZvtxNB;      // sec 38: zvtx slices over +-16 cm for the mixing and the Zvtx average (default 16 = 2 cm; sec 38: 1-cm slices tested, no change)
0162     bool    doULSTest;  // ULS opposite-charge SiSplitScore removal (README sec 15) -- ON by default since
0163                         // 2026-09-22 ("noulstest" turns it off); "ulstestNN" sets the threshold. sec 18.10:
0164                         // converted from a CalcRm::PairInfo sibling-only PAIR veto to a TRACK-level removal
0165                         // (folded into corral_loop.cxx's nSplitFlagged_thisevt, same mechanism as
0166                         // doSplitRemoval/LS below) -- the pair-only version left the loser track sitting in
0167                         // Pvec_1/Pvec_2 and hence in the mixing buffer for every OTHER pairtype, which sec
0168                         // 18's own survey found as a genuine compact spike in the raw MIXED density
0169                         // (hzoomM_0) at the same (dy,dphi) as the sibling ridge -- a single-particle-density
0170                         // defect no sibling-only veto could ever reach. sec 18.24: CalcRm's own sibling-only
0171                         // pair veto (fDoULSTest) is REMOVED -- it was not a no-op (it caught 0.40% of sibling
0172                         // pi+pi- pairs beyond the 4.1deg pregate); instead this track-level veto no longer
0173                         // uses any angular gate, which covers the same pairs symmetrically.
0174     double  valULSTestCut;  // SiSplitScore threshold for the above, default 0.05 (sec 15.7, reconfirmed 18.7)
0175     bool    doDauCheck; // README_CQcomparison sec 2.2: split partners of in-peak Lambda/Lbar daughters (LS paths dR<0.05 except pion-tagged partners of a p/pbar, ULS never an (anti)proton partner of a pion daughter); not K0S; ON, "nodau" off
0176     static constexpr double DAU_DRMAX = 0.05;   // sec 2.2 (2026-10-03, option 2): daughter-partner check only inside dR(t,d) < 0.05
0177     bool    doXTFClean; // sec 18.22: ON by default since sec 18.25 ("noXTF" turns it off, see corral_utils.cxx). Cross-crossing
0178                             // duplicate-track cleaner. Cause (sec 18.22): the tracking matcher lets ONE
0179                             // silicon seed join SEVERAL TPC seeds, each combination gets its own crossing,
0180                             // so copies of one Si seed land in DIFFERENT crossing rows of the same TF and
0181                             // survive into mixed pairs (the ULS rho2(M) ridge / LS mixed-origin excess).
0182                             // A pre-pass (BuildXTFLosers) groups consecutive rows by (run,evt); any two
0183                             // accepted tracks in DIFFERENT rows sharing >=2 siclukey slots (within one TF a
0184                             // shared key IS the same physical cluster) are duplicates; the loser is the
0185                             // one whose row crossing != its own INTT bucket, else the worse `quality`.
0186                             // Losers join nSplitFlagged_thisevt (track-level removal, like LS/ULS).
0187     bool    doXTFStrict;    // sec 18.22 variant, ON by default since sec 18.25 (plain "XTFclean" = non-strict): in the "neither" case
0188                             // (both copies have INTT, neither row crossing == its INTT bucket, ~12%) drop
0189                             // BOTH copies instead of keeping the better-quality one (SDCC-claude's view:
0190                             // neither copy's crossing can be trusted there).
0191     bool    doMixNoAdjTF;   // sec 18.23: ON by default since sec 18.25 ("noXTF" or "mixAdjTF" turns it off). Mixed EVENT pairs from
0192                             // neighboring trigger frames (same run, |devt|==1) are skipped in every pairtype's
0193                             // mixing, with per-zvtx-bin mixed normalization (CalcRm::SetExcludeAdjTF). With
0194                             // doXTFClean off it also skips same-TF event pairs (|devt|<=1), since those are
0195                             // only safe to mix after the same-TF cleaner.
0196     std::unordered_map<Long64_t,std::vector<int>> xtfLosers;    // chain entry -> track indices to drop
0197     bool    doTFDup;    // 2026-09-26: ON by default ("noTFdup" turns it off). Collision duplicated across
0198                         // OVERLAPPING trigger frames: when two triggers are closer in time than a TF's
0199                         // readout window, the collisions in the overlap are reconstructed in both TFs
0200                         // (same vertex, crossing shifted by exactly the TFs' GL1 BCO difference). Such
0201                         // copies are whole-EVENT duplicates in different (run,evt) rows, invisible to the
0202                         // siclukey-based XTF cleaner (keys are only comparable within one TF). Needs the
0203                         // Collect "bco" branch (ana573 on): key = (run, bco+crossing) = absolute crossing;
0204                         // the first row with a key is kept, later rows with the same key are skipped
0205                         // entirely (sibling AND mixing). Without a bco branch this does nothing.
0206     std::vector<bool> tfDupRows;            // [chain entry] -> skip (see doTFDup); 1 bit/row, fine at 1e9 rows
0207     bool    doIsoVtx;       // README.md "isovtxNNZZ" (2026-10-12, default OFF): keep only ISOLATED vertices -- no other vertex of
0208                             // the run within +-NN crossings (absolute crossing bco+crossing) and |dz| < ZZ cm. Copies (same
0209                             // absolute crossing) are not neighbours (doTFDup handles them). Test of track-vertex misassignment.
0210     int     valIsoNX;       // NN, crossings (1-50)
0211     double  valIsoDZ;       // ZZ, cm (1-30)
0212     std::vector<bool> nonIsoRows;           // [chain entry] -> skip (see doIsoVtx)
0213     virtual void    BuildIsoRows(Long64_t nentries);
0214     long    nTFDup_rows;                    // rows skipped as overlapping-TF copies
0215     std::map<int,long> nTFDup_byDevt;       // evt(copy) - evt(kept), for the log
0216     double  TFDup_maxAbsDvz;                // largest |vtxz(copy)-vtxz(kept)| seen (should be ~0)
0217     long    nXTF_pairs, nXTF_byINTT, nXTF_byQuality, nXTF_neither, nXTF_losers;
0218     bool    ONLY_FIRST_XINGPOS; // sec 18.21 follow-up 2: opt-in, OFF by default ("XingPos" turns it on).
0219                             // Keeps only the FIRST row with crossing>0 in each (run,evt) TF, skips every
0220                             // other row -- pure STREAMING (non-triggered) events, still <=1 row/TF.
0221                             // Complement of the old exactly-crossing-0 cut (pure triggered, <=1 row/TF). Rows within a
0222                             // TF are written in ascending crossing order (checked: 4681/4681 TFs,
0223                             // outputCollect_79510_0.root), so "first positive row" == lowest crossing>0.
0224     int     xingSel;    // 2026-10-08: crossing selection, three distinct samples; DEFAULT = 3 (ZB), "AllX" -> 0 = all crossings.
0225                         // 1 "Xing0"     crossing==0 only: the triggered collision (biased by jet/photon triggers:
0226                         //               <N_trk> 6.2 vs 4.3, <pT> 0.59 vs 0.48 in jet-trigger TFs).
0227                         // 2 "NearX0"    XNEAR_LO<=crossing<=XNEAR_HI, crossing!=0: the neighbours of the trigger.
0228                         //               No leakage seen, but <N_trk> is ~6% low in every trigger class (4.0-4.25
0229                         //               vs the 4.40 plateau; 2M-event test, ana573_795xx). The limits are where the
0230                         //               dip ends: -5 and +3 are back on the plateau.
0231                         // 3 "ZB"        (default) ZB_LO<=crossing<=ZB_HI outside the NearX0 window: streaming, away from the
0232                         //               trigger. The limits drop the readout-window ramps: <N_trk> is on its 4.40
0233                         //               plateau from -20 to ~260, within 3% up to 390, then falls (3.90 at 401-410,
0234                         //               2.0 at 475); below -20 it falls too (4.27 at -30..-21, 2.8 at -100). ~15% of
0235                         //               all events are outside [ZB_LO,ZB_HI] and are in none of the three samples.
0236     static constexpr int XNEAR_LO = -4;
0237     static constexpr int XNEAR_HI =  2;
0238     static constexpr int ZB_LO    = -20;
0239     static constexpr int ZB_HI    = 390;
0240     bool    ONLY_FIRST_TF;  // sec 18.21: opt-in diagnostic, OFF by default ("onlyfirsttf" turns it on).
0241                             // Keeps only the FIRST row seen for each (run,evt) -- evt IS the trigger
0242                             // frame's own EvtSequence (SDCC-claude, sec 18.20), constant across every row
0243                             // from that TF -- and skips every subsequent row from the same TF entirely,
0244                             // before ANY processing. Makes same-TF mixed-pair contamination structurally
0245                             // impossible (no two rows that ever enter the pipeline can share a TF), unlike
0246                             // sec 18.20's per-pair exclusion (which left single-particle multiplicities
0247                             // inconsistent with the reduced pair count -- a real normalization bug the user
0248                             // caught). Costs ~85% of statistics (~1/6-7 rows survive per TF) -- diagnostic
0249                             // only, never a production default.
0250     int     NTPCCUT;
0251     double  valDcaxyCut;    // README.md "dxyNN" (2026-10-12): track |dcaxy| < NN/100 cm, default 1.5 cm (sane 0.05-0.99)
0252     double  valDcazCut;     // README.md "dczNN" (2026-10-12): track |dcaz| < NN/10 cm, default 1.5 cm (sane 0.2-1.5)
0253     double  PTMINCUT;   // track pT floor, "ptminNN" = 0.NN GeV/c (default 0.1 = ana573 Collect floor; ana532 trees start at 0.2)
0254     bool    KILLETA0SPIKE;
0255     //
0256     //
0257     Long64_t    nentriesfile;
0258     //
0259 private:
0260     // builds/returns the input TChain; must be callable before any other member exists
0261     // (it runs in the constructor's member-initializer-list, ahead of fReader).
0262     static TChain* BuildInputChain(TTree *tree);
0263     //
0264     TChain      *fChain;    // owns the input chain for the lifetime of this object
0265     TTreeReader fReader;    // drives fChain; every reader value/array below binds to this
0266     //
0267 public:
0268     // Tree contents, read via TTreeReader (declaration order here MUST match the
0269     // member-initializer-list order in corral_utils.cxx, since fChain must be
0270     // constructed before fReader, and fReader before everything that follows).
0271     TTreeReaderValue<Int_t>            run;
0272     TTreeReaderValue<Int_t>            segment;
0273     TTreeReaderValue<Int_t>            evt;
0274     TTreeReaderValue<vector<bool> >    trigVec;
0275     TTreeReaderValue<Int_t>            nvtx;
0276     TTreeReaderValue<Int_t>            vtxntr;
0277     TTreeReaderValue<Double_t>         vtxx;
0278     TTreeReaderValue<Double_t>         vtxy;
0279     TTreeReaderValue<Double_t>         vtxz;
0280     TTreeReaderValue<Int_t>            crossing;
0281     TTreeReaderValue<Double_t>         etotem;
0282     TTreeReaderValue<Double_t>         etotih;
0283     TTreeReaderValue<Double_t>         etotoh;
0284     TTreeReaderValue<Double_t>         etotioh;
0285     TTreeReaderValue<Double_t>         etotepd;
0286     TTreeReaderValue<Int_t>            ntr;
0287     TTreeReaderArray<Char_t>           pid;
0288     TTreeReaderArray<Short_t>          indv0;
0289     TTreeReaderArray<Char_t>           primary;
0290     TTreeReaderArray<Float_t>          quality;
0291     TTreeReaderArray<Float_t>          chisq;
0292     TTreeReaderArray<Float_t>          chg;
0293     TTreeReaderArray<Float_t>          ptot;
0294     TTreeReaderArray<Float_t>          eta;
0295     TTreeReaderArray<Float_t>          phi;
0296     TTreeReaderArray<Float_t>          pt;
0297     TTreeReaderArray<Float_t>          seedeta;
0298     TTreeReaderArray<Float_t>          seedphi;
0299     TTreeReaderArray<Float_t>          seedpt;
0300     TTreeReaderArray<UChar_t>          ntpc;
0301     TTreeReaderArray<UChar_t>          nmvtx;
0302     TTreeReaderArray<UChar_t>          nintt;
0303     TTreeReaderArray<Float_t>          dcaxy;
0304     TTreeReaderArray<Float_t>          dcaz;
0305     TTreeReaderArray<UChar_t>          dedx70n;
0306     TTreeReaderArray<Float_t>          dedx70s;
0307     TTreeReaderArray<Float_t>          dedxKFP; // dedx value KFP actually cuts on (PID set via CDB, not ours) -- for QA vs dedxQA bands
0308     TTreeReaderArray<ULong64_t>        layermask;   // bit per absolute TrkrDefs layer w/ a cluster on this track (0-2 MVTX, 3-6 INTT, 7-54 TPC) -- see README_SplitTracks.md sec 9/10
0309     // siclukey/tpcsector/tpcarclen/tpcz below are new-this-round raw per-track/per-Si-or-TPC-layer
0310     // data (README_SplitTracks.md sec 12a.1/12b.5) -- NOT yet used by any pairwise cut logic here
0311     // (that's sec 12a.4/12b, deliberately deferred). TTreeReaderArray flattens the tree's fixed
0312     // second dimension into one contiguous ntr*N array; index element (itrk, slot) as
0313     // arr[itrk*N + slot] where N=7 for siclukey (Si layer slot, bit 0-6 of layermask) or N=48 for
0314     // the tpc* triplet (TPC layer slot = absolute layer - 7, range 0-47 for layers 7-54).
0315     TTreeReaderArray<ULong64_t>        siclukey;    // [ntr][7], sentinel ~0ULL == no cluster in that Si slot -- sec 12a.1/12a.2
0316     TTreeReaderArray<UChar_t>          tpcsector;   // [ntr][48], sentinel 255 == no TPC cluster on that layer -- sec 12b.5
0317     TTreeReaderArray<Char_t>           tpcarclen;   // [ntr][48], 2.0 mm/count local arc-length, valid only where tpcsector!=255 -- sec 12b.5
0318     TTreeReaderArray<Short_t>          tpcz;        // [ntr][48], 0.1 mm/count crossing-corrected global z, valid only where tpcsector!=255 -- sec 12b.5
0319     TTreeReaderValue<Int_t>            nv0;
0320     TTreeReaderArray<Int_t>            v0pid;
0321     TTreeReaderArray<Double_t>         v0x;
0322     TTreeReaderArray<Double_t>         v0y;
0323     TTreeReaderArray<Double_t>         v0z;
0324     TTreeReaderArray<Double_t>         v0px;
0325     TTreeReaderArray<Double_t>         v0py;
0326     TTreeReaderArray<Double_t>         v0pz;
0327     TTreeReaderArray<Double_t>         v0pt;
0328     TTreeReaderArray<Double_t>         v0ptot;
0329     TTreeReaderArray<Double_t>         v0eta;
0330     TTreeReaderArray<Double_t>         v0phi;
0331     TTreeReaderArray<Double_t>         v0ene;
0332     TTreeReaderArray<Double_t>         v0mass;
0333     TTreeReaderArray<Double_t>         v0ctau;
0334     TTreeReaderArray<Double_t>         v0decaylen;
0335     TTreeReaderArray<Double_t>         v0chi2ndf;
0336     TTreeReaderArray<Double_t>         v0dira;
0337     TTreeReaderArray<Double_t>         v0pvdca;
0338     TTreeReaderArray<Double_t>         v0decayx;
0339     TTreeReaderArray<Double_t>         v0decayy;
0340     TTreeReaderArray<Double_t>         v0decayz;
0341     TTreeReaderArray<Int_t>            v0indtr1;
0342     TTreeReaderArray<Int_t>            v0indtr2;
0343     //
0344 };
0345 
0346 #endif