Understanding of "Transportation" process

Geant4 Version: 11.3.2
Operating System: Ubuntu 24.04 LTS (Noble Numbat)
Compiler/Version: g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
CMake Version: 3.28.3


Hi :slightly_smiling_face:

I’m trying to understand how the transportation process is working and how to extract the correct info from PreStep and PostStep points.

My current implementation to save hit information in the detector is this one:

// Called every time a step occurs in a volume associated with this sensitive detector
G4bool ActiveAreaSD::ProcessHits(G4Step *step, G4TouchableHistory *)
{
  // Get basic pointers
  const G4Track *track = step->GetTrack();
  const G4StepPoint *preStep = step->GetPreStepPoint();
  const G4StepPoint *postStep = step->GetPostStepPoint();
  const G4TouchableHandle touchablePreStep = preStep->GetTouchableHandle();

  // Energy deposit in this step
  G4double Edep = step->GetTotalEnergyDeposit();
  if (Edep == 0)
    return true;

  // Event ID
  G4int eventID = G4RunManager::GetRunManager()->GetCurrentEvent()->GetEventID();

  // Create new hit
  auto hit = new MyHit();

  G4bool isActive = fLayerMap[touchablePreStep->GetVolume()->GetLogicalVolume()->GetName()];
  if (isActive)
    hit->SetIsActiveArea(1);
  else
    hit->SetIsActiveArea(0);

  // Store spatial info
  hit->SetPreStepPos(preStep->GetPosition());
  hit->SetPostStepPos(postStep->GetPosition());

  if (preStep->GetStepStatus() == fGeomBoundary)
    hit->SetIsPreStepPointOnBoundary(1);
  else
    hit->SetIsPreStepPointOnBoundary(0);

  if (postStep->GetStepStatus() == fGeomBoundary)
    hit->SetIsPostStepPointOnBoundary(1);
  else
    hit->SetIsPostStepPointOnBoundary(0);

  G4ThreeVector mom = track->GetMomentum();
  hit->SetMomentum(mom);
  hit->SetEdep(Edep);

  // Time
  hit->SetTime(preStep->GetGlobalTime());

  // Volume and geometry info
  hit->SetVolumeName(touchablePreStep->GetVolume()->GetName());

  // Optional: layer ID if using copy numbers
  hit->SetCopyNumber(touchablePreStep->GetCopyNumber());

  // Particle info
  const G4ParticleDefinition *particleDef = track->GetParticleDefinition();
  hit->SetName(particleDef->GetParticleName());
  // hit->SetPDGCode(particleDef->GetPDGEncoding());
  hit->SetMass(particleDef->GetPDGMass());
  hit->SetCharge(particleDef->GetPDGCharge());

  // Track info
  hit->SetTrackID(track->GetTrackID());
  hit->SetParentTrackID(track->GetParentID());
  hit->SetEventID(eventID);
  hit->SetEnergy(track->GetKineticEnergy());
  // hit->SetTotalEnergy(track->GetTotalEnergy());

  // Process
  if (postStep->GetProcessDefinedStep())
    hit->SetProcess(postStep->GetProcessDefinedStep()->GetProcessName());
  else
    hit->SetProcess("unknown");

  // Optional: material names
  hit->SetPreStepMaterialName(preStep->GetMaterial()->GetName());
  hit->SetPostStepMaterialName(postStep->GetMaterial()->GetName());

  // Add to collection
  fHitsCollection->insert(hit);

  return true;
}

Basically, all the information I’m extracting is:

Field Type Description
IsActiveArea G4int Whether the hit occurred in an active area (1) or passive (0).
PreStepPos G4ThreeVector Position at the start of the step (global coordinates).
PostStepPos G4ThreeVector Position at the end of the step (global coordinates).
IsPreStepPointOnBoundary G4int 1 if the pre-step point is at a geometry boundary, else 0.
IsPostStepPointOnBoundary G4int 1 if the post-step point is at a geometry boundary, else 0.
Momentum G4ThreeVector Momentum of the particle at the current step.
Edep G4double Total energy deposited during the step (step->GetTotalEnergyDeposit()).
Time G4double Global time of the hit (preStep->GetGlobalTime(), in ns).
VolumeName G4String Name of the volume where the hit occurred.
CopyNumber G4int Volume copy number (used for repeated structures or layers).
Name G4String Name of the particle (e.g., "alpha", "proton", "neutron").
Mass G4double Mass of the particle (in MeV/c²).
Charge G4double Electric charge of the particle (in e units).
TrackID G4int Unique ID of the track.
ParentTrackID G4int ID of the parent track (if secondary particle).
EventID G4int Event number (from G4RunManager).
Energy G4double Kinetic energy of the particle at the hit (in MeV).
Process G4String Name of the process that ended the step (e.g., "hIoni", "alphaInelastic").
PreStepMaterialName G4String Name of the material at the pre-step point.
PostStepMaterialName G4String Name of the material at the post-step point.

I don’t understand how I may have some hits where the E deposited is != 0 and the PostStep point process is equal to “Transportation”, (I was imagining transportation just as a process with E deposited == 0)

Especially if I try to plot spectra of energy for each specific process, what I see is that this “Transportation” leads to an extra counting, see spectra2.pdf:
spectra2.pdf (17.8 KB)

  • x-axis: E deposited MeV
  • y-axis: Counts

While if I’m excluding from the counting all the hits where the post-step point is on a geometrical boundary (e.g. on the boundary between two layers in the detector), this Transportation contribution in terms of energy is zero:
spectra1.pdf (17.2 KB)

  • x-axis: E deposited MeV
  • y-axis: Counts

I’m wondering if I’m interpreting this information correctly, and if I can safely exclude these boundary points from the count of the deposited energy.

Thanks a lot in advance,
Michael

If you’re dealing with charged tracks, then some of the energy deposit comes from dE/dx (continuous energy loss) along the step. If Transportation limited the step, that just means the track got to the boundary of the volume. It still travelled to the boundary, and so it had dE/dx during the step.

1 Like

@mkelsey thanks a lot for the quick reply :slightly_smiling_face:

So just to confirmation if I have a NTuple containing all the single hits info as shown above, if I want to get the total energy deposited in an event, I should account for the energy deposited in the step that is terminated with process transportation, right?

Thanks a lot,
Michael

That’s correct. If you want the total energy deposited in your volume, then you should sum the GetEnergyDeposit() values from all steps in that volume. Do not include secondaries’ kinetic energy! That will be double counting, since those secondaries will lose their kinetic energy by depositiing it.

1 Like

Understood. Thanks a lot!

Michael