refactor(alert): move AHDC track-finding from AHDCEngine to ALERTEngine#1242
refactor(alert): move AHDC track-finding from AHDCEngine to ALERTEngine#1242mathieuouillon wants to merge 14 commits into
Conversation
|
Note: AHDC::hits.adc is stored as int (calibrated ADC truncated). Track.get_sum_adc rounds Hit.getADC() per hit, so when track-finding ran inside AHDCEngine it summed the original full-precision double. Reading back from the bank here gives integer adc values, so sum_adc and dEdx in AHDC::track can drift by 0-1 per hit relative to the pre-refactor output (≈1-6 counts in sum_adc on ~1% of events). Eliminating the drift would require widening AHDC::hits.adc from I to F/D in the schema. |
|
Compared
GNN finds ~3.9× more tracks overall. Per-event breakdown (1000 events)
|
26ba2cb to
d09f721
Compare
|
Tested on 100 files for the run 22991, no error or warning with clara |
187e956 to
f21c966
Compare
f21c966 to
dc61b1e
Compare
dc61b1e to
36f990b
Compare
|
Now the default for the track finding is the GNN |
|
Ok @whit2333 I think I fix all the problems you mention. |
3278d25 to
8693354
Compare
AHDCEngine now only reads AHDC::adc, applies calibration via HitReader, and writes AHDC::hits. The full track-finding pipeline (preclustering, AI/CV_Distance/CV_Hough finder, DOCA refinement, helix fit) runs in ALERTEngine on top of AHDC::hits + ATOF::hits/clusters, alongside the existing projection / matching / prePID / Kalman steps. The track finder is selected via the ALERT.Mode YAML key (was AHDC.Mode); ModelTrackFinding only loads when AI_Track_Finding is selected. The ATOF::tdc gate now fires after the AHDC pipeline so events without ATOF still get their AHDC::* banks, matching the pre-refactor behavior.
…erface
Introduce TrackFinder { findTracks(hits) -> TrackFinderResult } with three implementations — AITrackFinder, DistanceTrackFinder, HoughTrackFinder — each owning its own preclustering, cluster building, and mode-specific logic. AITrackFinder owns ModelTrackFinding, the MAX_HITS_FOR_AI Distance fallback, and the greedy non-overlap selection; the "too many candidates" exit becomes TrackFinderResult.invalid() instead of a return-false from processDataEvent. ALERTEngine becomes a thin dispatcher: init() picks the strategy from ALERT.Mode via a switch, and processDataEvent calls findTracks(hits) once. Output is byte-identical to the prior refactor (same 9/999 sum_adc/dEdx precision drift, no new mismatches).
Introduce GNN_Track_Finding as a fourth track-finding mode alongside the renamed MLP_Track_Finding (was AI_Track_Finding), CV_Distance, and CV_Hough. The new path runs a GravNet edge scorer (TorchScript via DJL) on a per-event AHDC + ATOF hit graph, extracts tracks as connected components on edges with sigmoid score >= 0.1, then re-preclusters each surviving track's AHDC hits and pairs them into per-superlayer Clusters so the existing DOCA refinement + helix fit + Kalman stages consume them unchanged. Selected via ALERT.Mode in YAML. MLP regression is bit-identical (same pre-existing AHDC::track sum_adc/ dEdx precision drift); only COAT::config changes, reflecting the renamed mode.
…tching prediction handling
…Track (fit result) The AHDC track finders produced org.jlab.rec.ahdc.Track.Track, and the helix fit + Kalman filter then mutated that same object in place. One class was doing two jobs: a track-finder output (hits + clusters) and a fit result (vertex, momentum, chi2). A "Track" should mean the result of track fitting. Split the conflated class into two: - TrackCandidate: the track-finder output. Owns hits, clusters, and interclusters. Carries a CandidateType (AHDC_ONLY / AHDC_ATOF, plus a reserved AHDC_VERTEX) describing its specialization; the type is what will dictate how the candidate is fitted. The two old Track constructors (from Clusters, from Hits) move here. - Track: the fit result, produced by fitting a TrackCandidate. Composes the candidate it was fitted from and adds the fitted vertex, momentum, chi2, path, dEdx, p_drift, sum_residuals. It stays a full facade: every accessor the old Track exposed still works, and the candidate-side ones are delegated to the underlying TrackCandidate. All four finders (MLP / Distance / Hough / GNN) plus Distance and HoughTransform now produce TrackCandidate; TrackFinderResult wraps List<TrackCandidate>. ALERTEngine's fit stage turns each candidate into a Track, with a switch (CandidateType) dispatch seam.
…/AI_GNN, document modes
Add a YAML-config section to the ALERTEngine class javadoc listing every key the engine reads (currently just Mode) together with the valid values of TrackFindingMode. Flip the default track-finding mode from AI_MLP to AI_GNN: GNN is now the default.
…not DataBank ove bank I/O to the ALERTEngine boundary: - TrackFinder.findTracks now takes List<AtofHitStub>. The interface speaks pure domain types; the ATOF-blind finders simply ignore it. - GNNPrediction / GNNGraphBuilder accept the list directly and iterate it instead of reading from the bank. Verified byte-identical end-to-end: recon_output on clas_021903.evio.00000 (config_p0v9.local.yaml, AI_MLP, 1000 events) is unchanged vs development AHDC::track has the same pre-existing 9/999 sum_adc/dEdx precision drift
…alert The TrackFinding strategy, the Track/TrackCandidate value types, and the AI/* models live in rec.ahdc today, but they are ALERT-level orchestration across AHDC and ATOF (GNN literally builds a joint AHDC+ATOF graph). They belong in rec.alert.* alongside the existing rec.alert.TrackMatchingAI, rec.alert.AIPID, rec.alert.banks, rec.alert.projections.
8693354 to
67662b2
Compare
AHDCEngine now only reads AHDC::adc, applies calibration via HitReader, and writes AHDC::hits. The full track-finding pipeline (preclustering, AI/CV_Distance/CV_Hough finder, DOCA refinement, helix fit) runs in ALERTEngine on top of AHDC::hits + ATOF::hits/clusters, alongside the existing projection / matching / prePID / Kalman steps.
The track finder is selected via the ALERT.Mode YAML key (was AHDC.Mode); ModelTrackFinding only loads when AI_Track_Finding is selected. The ATOF::tdc gate now fires after the AHDC pipeline so events without ATOF still get their AHDC::* banks, matching the pre-refactor behavior.