add per-step kinematics ntuple ("Steps") to ROOT output

Adds a second ntuple alongside the existing "Hits" ntuple with one row
per Geant4 step. Records event_id, track_id, step_no, PDG code, and
pre/post position + kinetic energy for every step in the simulation.

Also extends run_batch() with return_steps=False; when True, returns
(hits_mf, steps_mf) instead of just hits_mf.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 11:37:39 +02:00
parent 91020714e7
commit 19b1ef125b
3 changed files with 53 additions and 11 deletions
+15
View File
@@ -80,7 +80,22 @@ RunAction::RunAction()
analysisManager->CreateNtupleIColumn("sensor_layer",hitLayer);
analysisManager->CreateNtupleIColumn("sensor_copy_number",hitCopyNumber);
analysisManager->FinishNtuple();
// Steps ntuple (one row per step, ntuple id=1)
analysisManager->CreateNtuple("Steps", "Steps");
analysisManager->CreateNtupleIColumn("event_id"); // col 0
analysisManager->CreateNtupleIColumn("track_id"); // col 1
analysisManager->CreateNtupleIColumn("step_no"); // col 2
analysisManager->CreateNtupleIColumn("pdg"); // col 3
analysisManager->CreateNtupleDColumn("pre_x"); // col 4
analysisManager->CreateNtupleDColumn("pre_y"); // col 5
analysisManager->CreateNtupleDColumn("pre_z"); // col 6
analysisManager->CreateNtupleDColumn("pre_E"); // col 7
analysisManager->CreateNtupleDColumn("post_x"); // col 8
analysisManager->CreateNtupleDColumn("post_y"); // col 9
analysisManager->CreateNtupleDColumn("post_z"); // col 10
analysisManager->CreateNtupleDColumn("post_E"); // col 11
analysisManager->FinishNtuple();
}
+25 -7
View File
@@ -33,6 +33,9 @@
#include "G4Step.hh"
#include "G4RunManager.hh"
#include "G4AnalysisManager.hh"
#include "G4Track.hh"
#include "G4ParticleDefinition.hh"
using namespace B4;
@@ -68,16 +71,31 @@ void SteppingAction::UserSteppingAction(const G4Step* step)
auto sensor = DetectorConstruction::getDetectorConstruction()->getGeometryDescriptor()->getSensorByVolume(volume);
if(sensor == nullptr){
//can simply be not an active volume, so no need to throw an error
//G4cout << "Sensor not found in" << volume->GetName() << G4endl; //DEBUG
return;
if(sensor != nullptr){
//G4cout << "Sensor found in " << volume->GetName() << " with copy number " << volume->GetCopyNo()<< G4endl; //DEBUG
sensor->energy += edep;
}
//G4cout << "Sensor found in " << volume->GetName() << " with copy number " << volume->GetCopyNo()<< G4endl; //DEBUG
sensor->energy += edep;
//find sensor by volume copy number
// Record step kinematics for every step
auto analysisManager = G4AnalysisManager::Instance();
auto pre = step->GetPreStepPoint();
auto post = step->GetPostStepPoint();
auto track = step->GetTrack();
int evtId = G4RunManager::GetRunManager()->GetCurrentEvent()->GetEventID();
analysisManager->FillNtupleIColumn(1, 0, evtId);
analysisManager->FillNtupleIColumn(1, 1, track->GetTrackID());
analysisManager->FillNtupleIColumn(1, 2, track->GetCurrentStepNumber());
analysisManager->FillNtupleIColumn(1, 3, track->GetDefinition()->GetPDGEncoding());
analysisManager->FillNtupleDColumn(1, 4, pre->GetPosition().x());
analysisManager->FillNtupleDColumn(1, 5, pre->GetPosition().y());
analysisManager->FillNtupleDColumn(1, 6, pre->GetPosition().z());
analysisManager->FillNtupleDColumn(1, 7, pre->GetKineticEnergy());
analysisManager->FillNtupleDColumn(1, 8, post->GetPosition().x());
analysisManager->FillNtupleDColumn(1, 9, post->GetPosition().y());
analysisManager->FillNtupleDColumn(1, 10, post->GetPosition().z());
analysisManager->FillNtupleDColumn(1, 11, post->GetKineticEnergy());
analysisManager->AddNtupleRow(1);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......