add child_track_ids array column to Steps; remove parent_id

Each Steps row now carries a variable-length child_track_ids int array
containing the track IDs of all secondaries spawned during that step.
The parent_id column is removed — parentage is now expressed
unidirectionally (parent→children) via child_track_ids and the Spawning
ntuple, rather than bidirectionally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 10:30:36 +02:00
parent 9ea0718139
commit 517ba2ecb2
5 changed files with 37 additions and 29 deletions
+17 -16
View File
@@ -87,10 +87,13 @@ void SteppingAction::UserSteppingAction(const G4Step* step)
auto track = step->GetTrack();
int evtId = G4RunManager::GetRunManager()->GetCurrentEvent()->GetEventID();
// Write one Spawning row per secondary born in this step (track IDs pre-assigned)
// Write one Spawning row per secondary born in this step (track IDs pre-assigned);
// also populate stepChildIds for the child_track_ids vector column in Steps.
fRunAction->stepChildIds.clear();
const auto* secondaries = step->GetSecondaryInCurrentStep();
if (secondaries) {
for (const G4Track* sec : *secondaries) {
fRunAction->stepChildIds.push_back(sec->GetTrackID());
analysisManager->FillNtupleIColumn(2, 0, evtId);
analysisManager->FillNtupleIColumn(2, 1, track->GetTrackID());
analysisManager->FillNtupleIColumn(2, 2, track->GetCurrentStepNumber());
@@ -118,14 +121,11 @@ void SteppingAction::UserSteppingAction(const G4Step* step)
// B: geometric step length
analysisManager->FillNtupleDColumn(1, 13, step->GetStepLength());
// C: parent track ID (0 for primary)
analysisManager->FillNtupleIColumn(1, 14, track->GetParentID());
// D: process that ended this step
G4String processName = "";
const auto* postProc = post->GetProcessDefinedStep();
if (postProc) processName = postProc->GetProcessName();
analysisManager->FillNtupleSColumn(1, 15, processName);
analysisManager->FillNtupleSColumn(1, 14, processName);
// E: layer index (-1 if outside all layers) and material name at pre-step point
int layerId = -1;
@@ -134,14 +134,14 @@ void SteppingAction::UserSteppingAction(const G4Step* step)
if (layers[i].physicalVolume == volume) { layerId = i; break; }
}
G4String materialName = pre->GetMaterial() ? pre->GetMaterial()->GetName() : "";
analysisManager->FillNtupleIColumn(1, 16, layerId);
analysisManager->FillNtupleSColumn(1, 17, materialName);
analysisManager->FillNtupleIColumn(1, 15, layerId);
analysisManager->FillNtupleSColumn(1, 16, materialName);
// F: pre-step momentum direction (unit vector)
const auto dir = pre->GetMomentumDirection();
analysisManager->FillNtupleDColumn(1, 18, dir.x());
analysisManager->FillNtupleDColumn(1, 19, dir.y());
analysisManager->FillNtupleDColumn(1, 20, dir.z());
analysisManager->FillNtupleDColumn(1, 17, dir.x());
analysisManager->FillNtupleDColumn(1, 18, dir.y());
analysisManager->FillNtupleDColumn(1, 19, dir.z());
// Field: B [T] and E [V/m] at pre-step position; zero if no field is registered
G4double Bx=0, By=0, Bz=0, Ex=0, Ey=0, Ez=0;
@@ -161,12 +161,13 @@ void SteppingAction::UserSteppingAction(const G4Step* step)
Ez = fieldVal[5] / (volt/m);
}
}
analysisManager->FillNtupleDColumn(1, 21, Bx);
analysisManager->FillNtupleDColumn(1, 22, By);
analysisManager->FillNtupleDColumn(1, 23, Bz);
analysisManager->FillNtupleDColumn(1, 24, Ex);
analysisManager->FillNtupleDColumn(1, 25, Ey);
analysisManager->FillNtupleDColumn(1, 26, Ez);
analysisManager->FillNtupleDColumn(1, 20, Bx);
analysisManager->FillNtupleDColumn(1, 21, By);
analysisManager->FillNtupleDColumn(1, 22, Bz);
analysisManager->FillNtupleDColumn(1, 23, Ex);
analysisManager->FillNtupleDColumn(1, 24, Ey);
analysisManager->FillNtupleDColumn(1, 25, Ez);
// col 26 child_track_ids: vector column, auto-read from fRunAction->stepChildIds at AddNtupleRow
analysisManager->AddNtupleRow(1);
}