Setup
World: Air. Detector: Water cylinder placed in air.
Beam Source: GPS muons (0-25 MeV) aimed at the cylinder.
Goal: Count only primary muons that stop inside the water; also record their initial kinetic energy at generation. I don’t need any secondaries or their info.
Request:
· Pointers to minimal examples/docs/any resources that show:
1. A reliable logic to detect stopped particles in a specific logical volume
2. A simple pattern to link initial KE at birth to a later stop condition (e.g., using per-track info)
Draft code so far (SteppingAction.cc):
```
#include “MargaritaSteppingAction.hh”
#include “RunAction.hh”
#include “G4Step.hh”
#include “G4Track.hh”
#include “G4StepPoint.hh”
#include “G4VPhysicalVolume.hh”
#include “G4ParticleDefinition.hh”
#include “G4SystemOfUnits.hh”
#include “G4AnalysisManager.hh”
MargaritaSteppingAction::MargaritaSteppingAction(RunAction* runAction)
: fRunAction(runAction) {}
MargaritaSteppingAction::~MargaritaSteppingAction() = default;
void MargaritaSteppingAction::UserSteppingAction(const G4Step* aStep)
{
// Handles
G4StepPoint\* pre = aStep->GetPreStepPoint();
G4StepPoint\* post = aStep->GetPostStepPoint();
G4Track\* trk = aStep->GetTrack();
// Volume at post-step
G4VPhysicalVolume\* volPost =
post->GetTouchableHandle() ? post->GetTouchableHandle()->GetVolume() : **nullptr**;
**if** (!volPost) **return**;
**const** G4String namePost = volPost->GetName();
// Target volume name
**static** **const** G4String kTargetVolumeName = "CylPV";
// Particle selection: mu- only (PDG 13)
**const** G4int pdg = trk->GetDefinition()->GetPDGEncoding();
**if** (pdg != 13) **return**;
// Primaries only
**if** (trk->GetParentID() != 0) **return**;
// Stop condition: inside target and KE \~ 0
**const** G4double eKinPost = post->GetKineticEnergy();
**const** G4double keEps = 1.0\*eV;
**if** (namePost != kTargetVolumeName || eKinPost > keEps) **return**;
// Initial KE at creation (GPS)
**const** G4double eKinInit = trk->GetVertexKineticEnergy();
// Values at stop
**const** G4ThreeVector pos = post->GetPosition();
**const** G4ThreeVector momDir = trk->GetMomentumDirection();
**const** G4double x = pos.x(), y = pos.y(), z = pos.z();
**const** G4double costh = momDir.cosTheta();
// ---- Fill histograms/ntuple only ----
**static** **const** G4int kH1_KE_Stop_Id = 5; // KE at stop
**static** **const** G4int kH1_Z_Stop_Id = 6; // Z at stop
**static** **const** G4int kH2_XY_Stop_Id = 6; // XY at stop (H2 id space)
**static** **const** G4int kH1_CosTh_Id = 7; // cos(theta)
**static** **const** G4int kH1_InitKE_Id = 8; // initial KE
**auto** am = G4AnalysisManager::Instance();
am->FillH1(kH1_KE_Stop_Id, eKinPost);
am->FillH1(kH1_Z_Stop_Id, z);
am->FillH2(kH2_XY_Stop_Id, x, y);
am->FillH1(kH1_CosTh_Id, costh);
am->FillH1(kH1_InitKE_Id, eKinInit);
**const** G4int nt = 1; // e.g., ntuple id for "stopped muons"
am->FillNtupleDColumn(nt, 0, eKinPost);
am->FillNtupleDColumn(nt, 1, x);
am->FillNtupleDColumn(nt, 2, y);
am->FillNtupleDColumn(nt, 3, z);
am->FillNtupleDColumn(nt, 4, momDir.x());
am->FillNtupleDColumn(nt, 5, momDir.y());
am->FillNtupleDColumn(nt, 6, momDir.z());
am->FillNtupleIColumn(nt, 7, pdg);
am->FillNtupleDColumn(nt, 8, eKinInit);
am->AddNtupleRow(nt);
// Ensuring no double counting from at-rest processing
trk->SetTrackStatus(fStopAndKill);
}
```
Geant4 Version: geant4-v11.3.2
Operating System: MacOS
Compiler/Version: Clang 17.0.0
CMake Version: Cmake 4.0.3