Skip to content

MatchCosmics: cosmics in collision data + raw-cluster writer with TOF - #15915

Open
matthias-kleiner wants to merge 8 commits into
AliceO2Group:devfrom
matthias-kleiner:cosmics-matcher-writer-clean
Open

matthias-kleiner wants to merge 8 commits into
AliceO2Group:devfrom
matthias-kleiner:cosmics-matcher-writer-clean

Conversation

@matthias-kleiner

Copy link
Copy Markdown
Contributor

Collect cosmic muons in the PbPb async reconstruction for TPC calibration (distortion correction with tracks that do not come from the vertex). This PR makes the matcher usable in collision data and adds an optional writer of the raw data needed for an offline refit. Details and validation are in the commit messages.

  1. MatchCosmics: include the last compatible vertex in the DCA veto (off-by-one fix, affects --use-pv-info).
  2. MatchCosmics: selection of cosmics in collision data, named presets (--cosmics-preset physics-v1; all new cuts off by default).
  3. MatchCosmics: energy-loss sign along the muon's flight; optional eLossSign in GPUO2InterfaceRefit / GPUTrackingRefit (default 0: unchanged for other users).
  4. Cosmics: raw clusters of matched cosmics with TOF tag (--enable-cluster-output → o2_cosmics_full.root): TPC road clusters, ITS / TOF / TRD hits, TOF time, refit at the TOF time.
  5. MatchCosmics: same-side TPC-only legs compared at a common time (option, off; not in the preset, it adds fakes in PbPb).
  6. MatchCosmics: TOF flight pair of the legs as selection criterion (on in physics-v1).

Default behaviour changes: muon mass for seeds and refit, energy-loss sign along the flight (cosmics run 562658: 357 → 358 cosmics, q/pt within ±1 %); the veto fix with --use-pv-info. Everything else is opt-in.

Usage (PbPb async; O2DPG wiring is a follow-up):
o2-cosmics-match-workflow --track-sources TPC --cosmics-preset physics-v1 --enable-cluster-output

Validation: PbPb 568041 from CTF with physics-v1 (19684 TFs): 0.29 cosmics per TF, 15 % TOF-tagged; matcher 0.50 + collector 0.16 CPU s per TF; 1.1 kB per TF. Cosmic MC with PbPb-like distortions: 79.5 % of the muons matched, 0 wrong pairs.

Open points: purity of the untagged cosmics is not yet measured on data (the TOF-tagged sample is the clean one); the collector repeats parts of the matcher's TOF and refit code (a shared helper is possible).

final5_best50 final5_first50

Left: 50 TOF-tagged cosmics from PbPb 568041 with physics-v1 (TOF-tagged, refitted at the TOF time, > 150 TPC clusters, p > 2 GeV). Right: the first 50 cosmics without quality cuts, as written to o2_cosmics_full.root. TPC clusters of both legs, ITS clusters, TOF hits; one colour per cosmic.

matthias-kleiner and others added 4 commits October 8, 2026 08:57
vtIDMax is the id of the last compatible vertex (inclusive), but the veto
loop stopped before it: a seed associated to a single vertex (vtIDMin ==
vtIDMax) was never checked, so with --use-pv-info the DCA cut never
removed collision tracks associated to one vertex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In collision data nearly all seeds are collision tracks and TPC-only legs had their z ignored, so any two tracks back-to-back in
the transverse plane were paired (PbPb: minutes per TF, tens of thousands of fake pairs). New settings, all off by default and
switched on together by the preset physics-v1 (o2-cosmics-match-workflow --cosmics-preset physics-v1; --configKeyValues can still
override single keys, unknown names are fatal):

- Seed cuts: minSeedNClTPC, minSeedDCAxy and minSeedDCAxyNSigma reject short TPC fragments and seeds passing the beam line
  (cosmics through the beam line are indistinguishable from collision tracks anyway).
- z test of TPC-only legs (constrainTPCOnlyZ): a one-side TPC-only track has z relative to its time0, z(t) = z + side*vD*(t-time0);
  a CE-crossing or non-TPC-only track has an absolute z. The legs are compared at a common time (same side, or one leg with known
  time); for legs on opposite sides z continuity fixes the common time, which must lie in both time brackets. That time, with its
  error sigma_z / (2 vD) (~0.3 mus), is used for the refit and as the time of the cosmic (before: the centre of the bracket overlap,
  tens of mus, which put the legs at the wrong z: cosmics run 562658 A x C chi2Match median 3.5e4 -> 43). For all other pairs the
  time error of the cosmic stays the half-width of the bracket overlap.
- Same-half veto (vetoSameHalf): pairs whose two legs lie on the same side of the closest approach in the transverse plane (two
  pieces of one leg) are rejected; skipped when a leg's reference point is within 20 cm of the closest approach.
- maxChi2Match: cut on the chi2 of the refitted top/bottom legs.
- minPtOppositeSides: for TPC-only legs on opposite sides z continuity defines the time, so z does not reject random pairs (94 % of
  the PbPb candidates). Both legs (in checkPair, before the winner selection) and the refitted cosmic need pT above it (scaled with
  the field).

Unconditionally, the seeds and the refit use the muon mass (and charge 1) for the material corrections instead of the TPC track's
PID from dE/dx (a leg tagged as kaon or proton got that mass): cosmic MC 6987 -> 7003 correct pairs (0 wrong), cosmics run 562658
357 -> 358; the refitted q/pt changes by +-0.4 % (MC) and +-1 % (562658) (q16-q84, pT < 20 GeV).

physics-v1: pT > 1 GeV, |DCA_xy| > 3 cm and > 10 sigma, >= 30 TPC clusters; systematic errors for the leg comparison y 0.5 cm,
snp 0.02, q/pt 0.05 (true pairs had pulls 2-4x too wide) with crude chi2 < 50; open per-parameter windows except tgl (3 sigma);
chi2Match < 1000; z test and same-half veto on; minPtOppositeSides 2 GeV.
Validation, TPC-only legs: cosmic MC with PbPb-like distortions 7003 of 8638 cosmics correct (81.1 %, 0 wrong pairs); cosmics run
562658 358 cosmics; PbPb 2025 LHC25an 567939 (19 kHz) 0.37 cosmics per TF (3.90 without the pT cut), 568041 reconstructed from
CTF 0.30 per TF (3203 in 10546 TFs; the PbPb numbers before the muon mass, which leaves 4 PbPb TFs unchanged).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gy-loss sign in the TPC refit

The propagator applies the energy-loss correction along the direction of the track parameters (loss forward, gain backward), and
refitWinners fits a cosmic from the bottom leg to the top one: after the inward refit of the bottom leg its parameters are inverted
and carried up through the top leg, i.e. they describe a particle moving upward. A cosmic muon flies downward, from the top leg to
the bottom leg, so only the inward refit of the bottom leg (backward along its parameters = backward along the flight) had the
physical sign; the propagation of the inverted bottom leg to the top leg, the outward refit of the top leg, the inward refit of the
top leg, its propagation to the bottom parameter and the propagation of the top seeds to the DCA had the opposite one. The sign is
now imposed along the flight in all of them, with the propagator's signCorr argument.

GPUO2InterfaceRefit / GPUTrackingRefit::RefitTrackAsTrackParCov (TrackParCov + cluster references) get the analogous optional last
argument eLossSign, passed to their propagations (0 = along the parameters as before, +1 gain, -1 loss; flipped on the optional
way to the reference X when that runs against the refit direction); the default keeps the behaviour for all other users.

MC truth (cosmic MC, 1073 muons crossing the inner region; true parameters at the bottom TPC inner radius propagated back through
the closest approach to the top one, compared to the true momentum there, q16 / q50 / q84 in MeV): true loss between the two
14.5 / 16.1 / 19.9 MeV (median for |z| at the closest approach 0-25 / 25-50 / 50-75 cm); predicted - true with the sign of the
upward fit -14.5 / -15.2 / -18.6 MeV (as without material: the gain inward and the loss outward cancel), with the sign along the
flight +1.2 / +2.1 / +1.0 MeV (spread q16-q84 about -2 ... +9 MeV). The matched cosmics hardly change because the two halves'
errors cancel in their average: cosmic MC 7003 -> 7006 correct pairs (0 wrong), chi2Match median unchanged; cosmics run 562658
358 cosmics before and after; refitted q/pt within +-0.05 %. The halves themselves (e.g. the momentum at the TPC entrance) change
by the full loss.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h TOF (--enable-cluster-output)

The async reconstruction stores neither TPC tracks nor TPC clusters, so the leg references of TrackCosmics cannot be resolved
offline. New device cosmics-cluster-collector (+ cosmics-full-writer -> o2_cosmics_full.root, tree cosmicsFull, one entry per TF):
- per cosmic (o2::dataformats::CosmicTrack, DataFormatsGlobalTracking): the TrackCosmics, the TPC tracks of both legs, the raw
  ClusterNative + sector/row of each leg's attached clusters and of all clusters in a road around the leg (flags: attached / road /
  used by any TPC track / found with the absolute time on the other TPC side), the ITS compact clusters (chip, anchor pixel, pattern
  ID, ROF BC; pattern bytes for patterns not in the dictionary), TOF clusters (raw time, ToT, channel), TRD tracklet words (+ trigger
  BC), MC label; per TF: TFIDInfo and vDrift / t0 of the TPC transformation. Only raw detector data are stored: TPC transformation,
  TOF calibration, ITS dictionary and geometry are applied offline.
- TPC road: each leg's helix through all pad rows of its side, in the frame of its own time0, at the real x of the row, points beyond
  the leg's closest approach skipped; predicted real (y, z) mapped to nominal coordinates with the inverse correction; clusters within
  --corridor-width (1 cm) taken. The other TPC side is searched when the time of the cosmic is known (CE-crossing leg, z-continuity
  time with error < --max-abs-time-err 0.5 mus, or a TOF time).
- TOF tag: all TOF clusters within the cosmic's time window and the road (--tof-road-width 5 cm) are candidates per leg; the top/bottom
  pair whose time difference matches the muon's flight along the helix (|t_top - t_bottom + L/c| < --tof-flight-tolerance 2 ns, z of
  one-side legs shifted to the pair's mean time) gets HitTOFFlight and the cosmic its TOF time (CosmicTrack::timeTOFMUS); without such a
  pair the closest hit per leg is kept. The same search in the impossible order (bottom hit first) only finds accidental pairs: its
  best score is stored next to the flagged pair's (scoreTOFPair / scoreTOFReversed) as QA of the flag's background.
- The TOF time (--tof-time-error 0.1 mus) then fixes the other-side TPC corridor, the TRD road (trigger and z, --trd-road-width) and the
  ITS road (readout frame and z, --its-road-width); without it the TPC time is used.
- Duplicates: per TF the cosmics are ranked (TOF time first, then more attached TPC clusters); one sharing >= 30 % of the smaller one's
  TPC clusters with a better one gets duplicateOf = that one's entry (a leg split into two TPC tracks). Nothing is removed.
- Polish: cosmics with a TOF time are refitted at it (TPC-only legs: bottom leg inward to the closest approach to the beam line, top
  leg inward to the same point, halves combined; muon mass and energy loss along the flight as in the matcher), CosmicTrack::polished
  with chi2MatchPolished (< 0: not polished). The matcher's time is the bracket-overlap centre for one-side legs on the same side
  (tens of mus off), which puts the inner material at the wrong z. Check: polished at the matcher's time instead, the cosmic MC
  reproduces the matcher (chi2Match median 79.1 vs 79.2, q/pt within 7e-4).
- Legs nearly parallel to the pad rows (closest approach to the beam line inside the TPC or at its inner edge): the row-by-row road
  cannot reach the rows, there the helix is followed in steps of path length and the rows within the road width are searched.
- A TOF time can be negative (cosmic just before the TF start): the flag is CosmicTrack::hasTOFTime() (scoreTOFPair >= 0).
- At most --max-cosmics-per-tf (100) cosmics per TF are written (protection against fake-dominated settings).
- --debug-tree: cosmics_collector_debug.root, tree "cosmics" with one entry per cosmic (matching and timing quantities, vectors of the
  transformed TPC clusters, road points, ITS / TOF / TRD hits). Off by default.

Validation: the road re-finds 99.8 % of the legs' own clusters in the cosmics run 562658 and 97 % in PbPb 2025 with the v10n correction
map. PbPb 2025 LHC25an 567939 (600 TFs, preset physics-v1): 30 of 224 cosmics TOF-tagged (10 with legs on opposite TPC sides, 20 on one
side), 0 pairs in the impossible order (flag purity >= 90 % at 95 % CL), flight-time residual centred at 0 within 0.2 ns; 10 duplicates.
568041 reconstructed from CTF (10546 TFs): 3203 cosmics, 435 TOF-tagged non-duplicates, 90 duplicates. CPU: matcher + collector
~0.6 s per PbPb TF; output ~1.5 kB per TF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
matthias-kleiner and others added 2 commits October 8, 2026 16:04
A TPC-only track has no time measurement: its time0 is the tracker's guess
(GPUTPCGMTrackParam::ShiftZ: z = 0 at the beam line if the helix can come
from it, otherwise the latest cluster at z = 0.521 * x, then clamped to the
drift volume). For a cosmic, which does not come from the beam line, the
two legs get independent guesses, typically tens of mus apart, so their
clusters were distortion-corrected at different z and the legs disagree
(y, snp, q/pt) although they are one track. For legs on opposite sides the
time comes from z continuity, but legs on the same side were compared as
tracked.

New MatchCosmicsParams refitSameSideAtCommonTime (default false, not in
the preset physics-v1, see below): after the cheap cuts (tgl, q/pt, same half), same-side
TPC-only legs are refitted at the centre of their brackets' overlap (the
time the refit of the winners uses) and compared there
(MatchCosmics::refitSeedAtTime: TPC refit from the outer parameters, then the
propagation to the DCA as for the seeds; energy loss along the muon's flight
as in refitWinners). The TPC refitter is created once per TF in process() and
shared with refitWinners. The matcher debug tree writes the legs compared
and a commonTime flag.

Cosmic MC with PbPb-like distortions (190 TFs, preset physics-v1, off -> on):
correctly matched muons 6848 -> 7324 of 8639 (79.3 -> 84.8 %); same side
77.0 -> 84.2 %, its loss to the crude chi2 cut 6.9 -> 0.8 %; A×C unchanged;
0 wrong-muon pairs in both; matcher +12 ms per TF (~100 refits). With the
true MC time instead of the window centre the same-side pass rate of the
chi2 cut would be 99.2 % (centre 98.0 %, legs at their own time0s 84.7 %).
PbPb 2025 (4 TFs): ~530 refits per TF, +15 ms per TF.

Not in the preset: in PbPb (568041, 310 CTFs, 16541 TFs) it adds mostly
pairs of collision tracks, whose time0 was about right and which the
refit at the window centre mis-corrects: +352 same-side cosmics but only
+5 TOF-tagged (2.6 % of the new ones vs 15.3 % of the common ones), and
~35 A×C cosmics lose a leg to a refitted same-side pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New MatchCosmicsParams tofFlightSelection (default off, on in the preset
physics-v1; needs TOF clusters, the workflow then adds them to the
matcher's inputs): every pair of TPC-only legs accepted by checkPair is
tested for a top / bottom TOF cluster pair along the outward
continuations of its legs whose time difference matches the muon's
flight between them along the helix (tofFlightTolerance), with the mean
time in the pair's time window and both legs' y and z within tofRoad at
that time (the test of the cluster collector). A confirmed pair takes
the TOF time as its common time (error tofTimeError), so the winner is
refitted at it, and is put in front of all unconfirmed partners of both
legs (chi2 order within each group): the mutual-best selection prefers
it, and a random pair can no longer take a leg of a TOF-confirmed cosmic.

If the refit of a confirmed winner at the TOF time fails (in practice
chi2Match > maxChi2Match), it is refitted at the time it has without its
TOF flight pair (z-continuity time of legs on opposite sides, else the
centre of the overlap of the legs' time brackets): the winner selection
has already released the other candidates of both legs, so dropping the
winner loses both legs. PbPb 568041: 24 TOF-tagged same-side cosmics,
all real (legs on one line far from the beam line, TOF pair in the
physical order without a reversed-order alternative), mostly on the C
side nearer the readout at the TOF time; A-C cosmics show no TOF-TPC
time offset there. The refit loop body is a lambda refitting a winner at
a given time.

The TOF candidates of a leg are searched once per TF, in the time-sorted
TOF clusters of its time bracket and in the sector it points to and its
neighbours. Debug tree "match": tofScore.

Distorted cosmic MC (19 x 10 TFs, PbPb-like distortions, physics-v1
without the common-time refit, without -> with tofFlightSelection):
matched muons 6848 -> 6871 of 8639, 0 wrong pairs both, 2134 confirmed
pairs, 9 fallbacks.

PbPb 568041 reconstructed from CTF (310 CTFs, 16541 TFs, vs. the same
CTFs without the TOF selection, older code, before the fallback):
cosmics 4782 -> 4760, TOF-tagged 681 -> 697; A-C: 11 untagged pairings
replaced by 12 TOF-tagged ones. Matcher CPU 0.536 -> 0.545 s per TF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@matthias-kleiner
matthias-kleiner force-pushed the cosmics-matcher-writer-clean branch from 18a44b6 to 9a493f4 Compare October 8, 2026 14:04
…in async

With CALIB_ASYNC_EXTRACTCOSMICS=1 (set by O2DPG from the JDL), the async
calibration workflows add o2-cosmics-match-workflow on the TPC-only tracks
with the preset COSMICS_PRESET (default physics-v1) and the raw-cluster
output (o2_cosmics_full.root, always written, as the TPC time series).
The road detectors are those of ITS, TOF, TRD reconstructed in the job;
without TOF the preset's TOF flight selection is switched off.

Checked in print mode with the O2DPG counterpart: the switch adds only this
workflow; no workflow without TPC, in sync mode, or with the switch unset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@shahor02 shahor02 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good as far as I could follow w/o running with AI over it. A small cosmetic comment: the CosmicTrack containing TrackCosmic might be confusing, could you ask Claude to rename it, e.g. to TrackCosmicExtended or something like that?

// the common-time refit of same-side legs (refitSameSideAtCommonTime) is not used: in PbPb it added mostly collision-track pairs
static const std::map<std::string, std::string> presets{
{"physics-v1",
"cosmicsMatch.minSeedPt=1;cosmicsMatch.minSeedDCAxy=3;cosmicsMatch.minSeedDCAxyNSigma=10;cosmicsMatch.minSeedNClTPC=30;"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would not 3cm cut damage ITS IB coverage?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @shahor02 , yes, you are right. With this cut we lose the cosmics crossing the IB. I am running a test on GSI to see whether a lower cut is feasible in PbPb (CPU and fake pairs).

@matthias-kleiner
matthias-kleiner requested a review from a team as a code owner October 8, 2026 15:29
The per-cosmic output of the cluster collector contains the matcher's
TrackCosmics plus the raw hits of its legs; the new name makes that
relation explicit (review comment). Header CosmicTrack.h is now
TrackCosmicsExtended.h; content and branch names are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alibuild

alibuild commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Error while checking build/O2/fullCI_slc9 for 22bdf41 at 2026-10-08 18:19:

No log files found

Full log here.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants