Skip to content

Step death record restore handover#2368

Closed
rahmans1 wants to merge 18 commits into
celeritas-project:developfrom
rahmans1:step-death-record-restore-handover
Closed

Step death record restore handover#2368
rahmans1 wants to merge 18 commits into
celeritas-project:developfrom
rahmans1:step-death-record-restore-handover

Conversation

@rahmans1

@rahmans1 rahmans1 commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Title

Save and restore initial handover state for PreUserTrackingAction dispatch

Depends on: #2367
Pre-requisite for: #2363

Description

  • Store initial kinematic state (position, direction, energy, time) and G4PrimaryParticle pointer in AcquiredData
  • Add restore_initial() to prepare a track with handover-time state
  • Add view_initial() on GeantTrackReconstruction for PreUserTrackingAction dispatch
  • Add is_generator_primary() to filter by parent_id == 0
  • Add for_each_primary() template iterator

Assisted by: Claude-Opus-4-6 and Claude-Sonnet-4-6

@github-actions

github-actions Bot commented Apr 17, 2026

Copy link
Copy Markdown

Test summary

 6 020 files   9 757 suites   19m 7s ⏱️
 2 289 tests  2 246 ✅  43 💤 0 ❌
34 212 runs  34 025 ✅ 187 💤 0 ❌

Results for commit 9017363.

♻️ This comment has been updated with latest results.

@rahmans1 rahmans1 force-pushed the step-death-record-restore-handover branch 3 times, most recently from d917412 to 8d28604 Compare April 18, 2026 00:40
Sakib Rahman added 5 commits April 17, 2026 20:58
Add ParticleId to AcquiredData so the Celeritas particle type is preserved
alongside track ID, parent ID, user info, and creator process. Update
acquire() to accept ParticleId. Fix view() to subtract the flush-local
start_ offset from primary_id before indexing g4_track_data_, which was
incorrect after the first clear() call when start_ advances past zero.
Add for_each_primary() template that iterates all acquired primaries and
invokes a callback with the restored G4Track.

Prompt: "Store ParticleId in AcquiredData and pass it through acquire(); fix the multi-flush bug in view() where primary_id was used as a raw index without subtracting start_; add for_each_primary() to iterate all acquired primaries with their restored G4Tracks"
Assisted-by: Claude Code (claude-sonnet-4-6)
The primary_id field was missing from operator|=, operator bool, all(), and
resize() in StepSelection/StepStateDataImpl. This caused primary_id to be
silently dropped even when selected, resulting in empty primary_id vectors
in DetectorStepOutput and incorrect trackID on reconstructed G4Tracks.

Prompt: "Fix primary_id being silently dropped from step data despite being selected, causing hits to carry trackID=0"
Assisted-by: Claude Code (claude-opus-4-6)
Add selection_.primary_id = setup.track so that primary_id is collected
alongside particle type in step data. Without this, HitProcessor receives
empty primary_id vectors and cannot restore the original G4 track ID on
reconstructed tracks before calling ProcessHits.

Prompt: "Enable primary_id in GeantSd step selection so hits carry the correct G4 track ID for MC-truth association"
Assisted-by: Claude Code (claude-opus-4-6)
Update GeantTrackReconstruction tests to pass ParticleId to acquire() and
add a multi_flush_view test verifying that view() returns the correct track
after clear() advances the start_ offset.

Prompt: "Add unit tests for the new acquire(G4Track&, ParticleId) signature and verify view() flush-local indexing across multiple clear() cycles"
Assisted-by: Claude Code (claude-opus-4-6)
The acquire() signature was updated to store the particle type in
AcquiredData alongside the G4Track, but the call site in
LocalTransporter::Push was not updated. Move the particle_id lookup
before the acquire() call so the value is available to pass.

Prompt: "acquire() call-site was missing ParticleId after signature change; move particle_id lookup before acquire() so it can be passed"
Assisted-by: Claude Code (claude-sonnet-4-6)
@rahmans1 rahmans1 force-pushed the step-death-record-restore-handover branch 4 times, most recently from b4b0e0a to 8a54e13 Compare April 18, 2026 22:29
@codecov

codecov Bot commented Apr 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.47287% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.26%. Comparing base (4eea2c0) to head (9017363).

Files with missing lines Patch % Lines
src/celeritas/user/StepData.hh 80.76% 5 Missing ⚠️
src/celeritas/ext/detail/HitProcessor.cc 50.00% 3 Missing ⚠️
src/celeritas/user/DetectorSteps.hh 0.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #2368      +/-   ##
===========================================
- Coverage    87.26%   87.26%   -0.01%     
===========================================
  Files         1386     1386              
  Lines        43985    44086     +101     
  Branches     13483    13502      +19     
===========================================
+ Hits         38385    38473      +88     
- Misses        4374     4386      +12     
- Partials      1226     1227       +1     
Files with missing lines Coverage Δ
src/accel/LocalTransporter.cc 68.81% <100.00%> (-0.76%) ⬇️
src/celeritas/ext/GeantSd.cc 85.43% <100.00%> (+0.28%) ⬆️
src/celeritas/ext/GeantTrackReconstruction.cc 96.20% <100.00%> (+1.46%) ⬆️
src/celeritas/ext/GeantTrackReconstruction.hh 100.00% <100.00%> (ø)
src/celeritas/ext/detail/HitProcessor.hh 100.00% <ø> (ø)
src/celeritas/user/DetectorSteps.cc 98.76% <100.00%> (+0.35%) ⬆️
src/celeritas/user/StepInterface.hh 100.00% <100.00%> (ø)
src/celeritas/user/detail/StepGatherExecutor.hh 100.00% <100.00%> (ø)
src/celeritas/user/detail/StepParams.cc 100.00% <100.00%> (ø)
src/celeritas/ext/detail/HitProcessor.cc 83.46% <50.00%> (-1.66%) ⬇️
... and 2 more

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sakib Rahman added 9 commits April 18, 2026 18:57
Remove the event-scoped start_ offset and init_event() from
GeantTrackReconstruction. Primary IDs are now 0-based indices directly
into g4_track_data_, eliminating the subtract-start arithmetic in
view(), acquire(), and for_each_primary(). clear() remains at the end
of Flush() so that track data is available during hit processing and
reset before the next flush. Remove the erroneous primary_id +=
G4TrackID line in Push() that corrupted the acquire index.

Prompt: "Fix CI-failing UserActionIntegration tests caused by primary_id
indexing bugs. Remove the event-scoped start_ offset and init_event()
from GeantTrackReconstruction and replace with flush-local 0-based
direct indexing into g4_track_data_. Keep clear() at end of Flush()
so data is available during hit processing. Remove the erroneous
primary_id += G4TrackID corruption in LocalTransporter::Push(). Update
multi_flush_view test to expect flush-local id=0 after clear()."

Assisted-by: Claude Code (claude-opus-4-6)
…patch

Add TrackDeathRecord struct to DetectorStepOutput to hold the terminal GPU
state (position, direction, energy, time, primary_id, particle) of killed
tracks. Add track_death flag to StepParamsData and StepInterface::Filters,
and add corresponding death_* fields to StepStateDataImpl that are
conditionally allocated when track_death is enabled.

Also add copy_deaths() template declarations (host and device
specializations) for compacting valid death records from the scratch buffer,
a deaths vector in DetectorStepOutput for the compacted results, and a
death_valid_id field in StepStateData for GPU compaction indexing.

Prompt: "Add TrackDeathRecord struct, death_* state fields, copy_deaths declarations, deaths output vector, and death_valid_id compaction index to capture the final state of GPU-killed tracks, gated on a new track_death flag in StepParamsData and StepInterface::Filters"
Assisted-by: Claude Code (claude-opus-4-6)
…yExecutor

At the post-step gather, write position, direction, energy, time, particle,
and primary ID into death_* state fields for any track whose status is killed.
Clear death_track_id at the pre-step gather so each track produces exactly one
death record. The death gather runs before the detector-filter early returns so
tracks that die outside sensitive detectors are still captured. Add
DeathScratchCopyExecutor to compact death records from full slot arrays into
contiguous scratch storage indexed by death_valid_id.

Prompt: "In StepGatherExecutor post-step, write death_* fields for killed tracks before the detector filter so tracks dying outside SDs are captured; clear death_track_id at pre-step so each track records exactly one death. Add DeathScratchCopyExecutor to compact death records into scratch storage."
Assisted-by: Claude Code (claude-sonnet-4-6)
Verify that death record fields (track_id, primary_id, particle, pos, dir,
energy, time) are allocated when track_death is set in StepParamsData and
not allocated when it is unset.

Prompt: "Test that StepStateData death fields are conditionally allocated based on the track_death flag in StepParamsData"
Assisted-by: Claude Code (claude-opus-4-6)
Add copy_deaths<MemSpace::host> that scans death_track_id and compacts valid
entries into DetectorStepOutput::deaths. Add copy_deaths<MemSpace::device>
that uses thrust::copy_if to populate death_valid_id, launches a
gather-death-scratch kernel via DeathScratchCopyExecutor, then copies each
field device-to-host and assembles TrackDeathRecord entries. Propagate the
track_death flag from StepInterface::Filters through StepParams into
StepParamsData, and enable it unconditionally in GeantSd::filters().

Prompt: "Implement copy_deaths for host (linear scan) and device (thrust compact + kernel + D2H copy), propagate track_death from StepInterface::Filters through StepParams into StepParamsData, and set track_death=true in GeantSd::filters()"
Assisted-by: Claude Code (claude-sonnet-4-6)
Replace two identical OpaqueId validity predicates (HasDetector, HasDeath)
with a single templated IsValid<T> functor. Both performed the same
static_cast<bool>() check on different OpaqueId types.

Prompt: "Deduplicate the HasDetector and HasDeath functors in
DetectorSteps.cu that both check OpaqueId validity with static_cast<bool>.
Replace them with a single generic IsValid<T> template predicate."

Assisted-by: Claude Code (claude-opus-4-6)
Replace two-pass approach (count deaths then reserve+fill) with a single
loop using push_back and aggregate initialization of TrackDeathRecord.

Prompt: "Simplify the host copy_deaths implementation in DetectorSteps.cc
from a two-pass count-then-fill loop to a single-pass push_back with
aggregate initialization of TrackDeathRecord."

Assisted-by: Claude Code (claude-opus-4-6)
Test that copy_deaths correctly compacts sparse death records (3 of 8
slots populated) into contiguous output with correct field values, and
that it clears output when death fields are not allocated.

Prompt: "Add unit tests for copy_deaths: one that populates 3 of 8 track
slots with death records and verifies compaction produces 3 correct
TrackDeathRecords, and one that verifies copy_deaths clears output when
track_death is disabled."

Assisted-by: Claude Code (claude-opus-4-6)
Disable volume_instance_ids in death_fields_allocated and copy_deaths_host
test setup since these tests set num_volume_levels=0, which triggers the
vi_depth > 0 assertion when volume_instance_ids is selected. The assertion
only fires in debug builds (CELERITAS_DEBUG=ON), which is why it passed
locally but failed in CI.

Prompt: "Fix CI failure in death record tests where this->selection()
inherits volume_instance_ids=true but num_volume_levels=0, triggering
the vi_depth > 0 assertion in StepData.hh resize. Disable
volume_instance_ids in the test-local selection since death records
do not use volume instances."

Assisted-by: Claude Code (claude-opus-4-6)
@rahmans1 rahmans1 force-pushed the step-death-record-restore-handover branch from 8a54e13 to 976d311 Compare April 18, 2026 22:59
@rahmans1 rahmans1 added enhancement New feature or request core Software engineering infrastructure (corecel) ai-assisted Generated/refactored substantially with agentic/LLM AI tools labels Apr 18, 2026
@rahmans1 rahmans1 marked this pull request as ready for review April 19, 2026 00:16
Sakib Rahman and others added 4 commits April 19, 2026 07:58
With multiple primaries per event, track slots can be reused across
stepper iterations within a single Flush(). The per-iteration
copy_deaths() clears and re-scans slot-indexed death records, so a
primary that dies in iteration N loses its record when the slot is
reused in iteration N+1.

Add an accumulated_deaths_ vector to HitProcessor that appends death
records from each stepper iteration. The last_deaths() accessor returns
this accumulator, and clear_deaths() resets it after consumption. Also
add the copy_deaths() call to both operator() overloads so death
gathering runs per iteration.

Prompt: "With multiple primaries per event, death records are lost when
track slots are reused across stepper iterations because copy_deaths
clears per iteration. Accumulate deaths in HitProcessor across all
iterations so every killed primary gets a death record for
PreUserTrackingAction dispatch."

Assisted-by: claude (claude-opus-4-6)
Store initial kinematic state (position, direction, energy, time) and the
G4PrimaryParticle pointer in AcquiredData at handover time. Add
restore_initial() to reconstruct the full handover state on a G4Track,
view_initial() to prepare a track for PreUserTrackingAction dispatch, and
is_generator_primary() to filter generator-level primaries from
re-offloaded secondaries.

Prompt: "Store handover-time kinematics and G4PrimaryParticle pointer so PreUserTrackingAction sees the original track state and MC-truth frameworks identify generator primaries"
Assisted-by: Claude Code (claude-opus-4-6)
Test that view_initial restores handover-time kinematics (position,
direction, energy, time) and track/parent IDs. Verify is_generator_primary
returns true for parent_id==0 and false for re-offloaded secondaries. Check
for_each_primary iterates all acquired tracks with correct restored state.

Prompt: "Add unit tests for the new GeantTrackReconstruction methods:
view_initial should restore original handover kinematics,
is_generator_primary should distinguish generator primaries from
re-offloaded secondaries by parent_id, and for_each_primary should iterate
all acquired primaries with restored track state."

Assisted-by: Claude Code (claude-opus-4-6)
This commit means that you must (please!) install pre-commit
on your development machine and run `pre-commit install --install-hooks`.
For more information, see
https://celeritas-project.github.io/celeritas/user/development/style.html#formatting

Autogenerated: https://pre-commit.ci
@rahmans1 rahmans1 force-pushed the step-death-record-restore-handover branch from 976d311 to 9017363 Compare April 19, 2026 18:39
@rahmans1 rahmans1 marked this pull request as draft April 20, 2026 12:11
@rahmans1 rahmans1 closed this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted Generated/refactored substantially with agentic/LLM AI tools core Software engineering infrastructure (corecel) enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant