G4UserStackingAction::ClassifyNewTrack processes the same track multiple times

Hi,

I have a class which inherits from G4UserStackingAction, and I’ve noticed that the same track gets processed by the ClassifyNewTrack function multiple times. Stepping through an event with gdb, I’ve seen the same track many times. Is this an expected behavior, is it documented somewhere in the application developer or toolkit developer guides?

Thanks,
Chris

How could you identify the same track appears more than once? By pointer?
Within a single event, one track won’t be examined by ClassifyNewTrack method more than once unless 1) it is suspended by your steppingAction, or 2) you request ReClassify().

It’s the same track ID (also the same particle type, creator process, etc.), I haven’t compared pointers. This from breaking in ClassifyNewtrack with gdb on a single event run (e.g. /run/beamOn 1).

  1. My stepping action isn’t suspending anything. The stepping action simply creates some local variable which I can examine in the debugger.
  2. My stacking action method is meant to just count particles. It leaves all tracks in the urgent stack, and I haven’t made any calls to ReClassify anywhere in my codebase.

Thanks,
C

What particle type was it? Do you have physics processes that generate optical photon?

I see this for what looks like the primary electron from the generator process. The process name is “”.

But, more commonly, I see an e+ (positron) from a conversion (*conv") process.

Also, I checked that it is the same track pointer in these instances as well.

Given G4Track uses G4Allocator, exactly same address can be reused. So seeing same address itself is not a strange thing. And it seems you have electromagnetic shower, you would have many electrons, positrons and gammas. But the track ID has to be different to each track. Could you please double-check you really see tracks with the same track ID many times? Parent Track ID can be common for many tracks, as one track may generate many secondaries.

I ran gdb breaking at ClassifyNewTrack for a particular track id of a single event.

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00007ffff7b67a87 in SSEStackingAction::ClassifyNewTrack(G4Track const*) at src/SSEStackingAction.cc:35
        stop only if id == 73
        breakpoint already hit 38 times

Could you please post your SSEStackingAction.cc?

It’s a little sloppy since I’ve been making several changes during my debugging.


#include "SSEStackingAction.h"

#include "G4Track.hh"
#include "G4SDManager.hh"
#include "G4RunManager.hh"

#include "SSEAbsorberHit.h"


SSEStackingAction::SSEStackingAction()
:G4UserStackingAction()
{ }

SSEStackingAction::~SSEStackingAction()
{ }


G4ClassificationOfNewTrack SSEStackingAction::ClassifyNewTrack(const G4Track * track)
{

  // check if the track is in the absorber, break out if not
  auto logvol = track->GetLogicalVolumeAtVertex();
  auto pv = track->GetVolume();
  auto pvn = track->GetNextVolume();

  int pdg = track->GetParticleDefinition()->GetPDGEncoding();
  auto name = track->GetParticleDefinition()->GetParticleName();
  auto id = track->GetTrackID();
  auto pid = track->GetParentID();
  G4String procname;
  if ( track->GetCreatorProcess() )
    procname = track->GetCreatorProcess()->GetProcessName();

  if ( pv) {
    const G4String & logName = pv->GetLogicalVolume()->GetName();
    if ( logName == "Box" ) {

      // get the run manager and the current event
      G4RunManager* runMan = G4RunManager::GetRunManager();
      const G4Event* event = runMan->GetCurrentEvent();

      G4SDManager* SDMan = G4SDManager::GetSDMpointer();
      G4int colID = SDMan->GetCollectionID("SSEAbsorber");

      // get the hit collection  for this event
      G4HCofThisEvent *hce = event->GetHCofThisEvent();

      // get the hit collection for the absorber
      auto abshit = (SSEAbsorberHitsCollection*)hce->GetHC(colID);

      // increment count of tracks
      (*abshit)[0]->AddTrack(track);

    }
  }

  // return everyting to the urgent stack
  return fUrgent;
}

void SSEStackingAction::NewStage()
{ }

void SSEStackingAction::PrepareNewEvent()
{ }


Thanks.

I don’t see anything wrong in your code except one suggestion that is NOT related to the current issue so I will write it in the footnote.

To diagnose the issue, could you please run one event (don’t run more than one) with the following two UI commands and post the output?
/event/verbose 2
/event/stack/verbose 2
/run/beamOn 1

Output may be long. So, please make a text file and upload.

Footnote:
GetCollectionID(“SSEAbsorber”) is a heavy operation. I’d suggest to make colID as a private data member of your SSEStackingAction class and initialize it to -1. Then access to GetCollectionID() method only if collide is negative.

Thanks for the tip. That’s a good idea.

The log file is rather large (~150MB). Here is a link.

It looks like tracks processed with stopping code 4 get repeated in my stacking action. You can get a list from the log file with the following:

grep "stopping code 4" multitrack_debug_event.txt | sed "s/G4WT0 > Track (trackID \([0-9]*\),.*/\1/" | sort -n | uniq

I set breakpoint conditions for the first few in the list, here is what I see in gdb:

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00007ffff7b67a87 in SSEStackingAction::ClassifyNewTrack(G4Track const*) at src/SSEStackingAction.cc:35
        stop only if id == 1
        breakpoint already hit 267 times
        ignore next 435 hits
2       breakpoint     keep y   0x00007ffff7b67a87 in SSEStackingAction::ClassifyNewTrack(G4Track const*) at src/SSEStackingAction.cc:35
        stop only if id == 73
        breakpoint already hit 38 times
        ignore next 62 hits
3       breakpoint     keep y   0x00007ffff7b67a87 in SSEStackingAction::ClassifyNewTrack(G4Track const*) at src/SSEStackingAction.cc:35
        stop only if id == 72
        breakpoint already hit 80 times
        ignore next 20 hits
4       breakpoint     keep y   0x00007ffff7b67a87 in SSEStackingAction::ClassifyNewTrack(G4Track const*) at src/SSEStackingAction.cc:35
        stop only if id == 199
        breakpoint already hit 18 times
        ignore next 82 hits

OK, now mystery is really close to be solved. Stopping code 4 is “fSuspended” of G4TrackStatus. So, for sure someone is suspending a track in the middle of its way. And once a track is suspended, it is sent back to the stack and hence sent to G4UserStackingAction::ClassifyNewTrack.

If you don’t set fSuspend by yourself in your stepping action, it may be suspended by a process that generates optical photons. As I asked in my previous question, do you have any physics process that generates optical photons?

It seems you are fluent to gdb. So you may want to set a break point here
https://geant4.kek.jp/lxr/source/track/include/G4Track.icc#L266
to see who sets fSuspended.

Also please check the particle type of the secondaries that were generated by the track that was suspended?

Ah! Sorry, I misunderstood your question. Yes, I do have optical photons, G4OpticalPhysics.

I’m working on tracing the caller for the track status.

I know there are many optical photons generated, but I will see what others may be there as well.

Optical processes suspend any charged track if there are enough number of optical photons are generated along the way of that charged track. Being suspended are the charged tracks, not optical photon tracks.

OK. That seems solve the mystery. I haven’t been able to trace the process which suspends the track. It must use a different method to suspend the track than SetTrackStatus.

Thanks so much for your help!