Use of "GetProcessDefinedStep"

Hi All,

What exactly is happening when the following method is used:

void SteppingAction::UserSteppingAction(const G4Step* theStep)
{
G4StepPoint* endPoint = theStep->GetPostStepPoint();
const G4VProcess* pds = endPoint->GetProcessDefinedStep();
if(pds->GetProcessName()) G4cout << pds->GetProcessName() << endl;
}

My understanding is that endPoint is a pointer to an instance of G4StepPoint, which is the end of a step. A G4StepPoint instance has a member GetProcessDefinedStep(), which is a G4VProcess pointer (as defined in G4StepPoint.hh). And if the pointer is true, it can be used to point to the name of the process, via GetProcessName().

First, is my understanding correct?

I am unsure as to how the GetProcessDefinedStep method works; how is it accessing a process? What process is it returning? Is it the process used to determine the step? Or something else?

Thank you all in advance for your help!

-Frank

1 Like

You may find $G4INCLUDE/G4StepPont.hh to be useful. Processes are instantiated by the physics list you use for your application. Each particle has processes associated with it (via pointer), and those processes (specifically, their pointers) stay the same for the duration of the job.

In G4StepPoint.hh, near the bottom, you’ll see that there is a local data member

const G4VProcess* fpProcessDefinedStep;

This is stored in the G4StepPoint by the tracking manager when the step-point is created or filled, and is what gets returned by GetProcessDefinedStep().

Hi @mkelsey,

Thank you so much for responding so quickly!

To check my understanding: does this mean that there is a list of processes (perhaps a G4ProcessVector) from which the program chooses from to determine how to calculate the step, with the choice depending on how the particle will move between volumes and the types of interactions it may have when doing so?

I notice upon running an adapted version of some methods from the OpNovice2 example within my stepping action:

G4OpBoundaryProcessStatus theStatus = Undefined;

      G4ProcessManager* OpManager = 
        G4OpticalPhoton::OpticalPhoton()->GetProcessManager();
      G4int MAXofPostStepLoops = 
        OpManager->GetPostStepProcessVector()->entries();
      G4ProcessVector* postStepDoItVector = 
        OpManager->GetPostStepProcessVector(typeDoIt);

      G4StepPoint* endPoint   = theStep->GetPostStepPoint();

      G4cout << "/////////////////////////////////////////////////////////////////////" << endl;
      G4cout << "Beginning of OpBoundaryProcess Statuses" << endl;
      for (G4int i=0; i<MAXofPostStepLoops; ++i)
      {
          G4VProcess* currentProcess = (*postStepDoItVector)[i];

          G4OpBoundaryProcess* opProc = 
            dynamic_cast<G4OpBoundaryProcess*>(currentProcess);

          endPoint = theStep->GetPostStepPoint();

          //G4cout << currentProcess->GetProcessName() << " at endpoint = " << endPoint->GetPosition() << endl;

          G4cout << currentProcess->GetProcessName() << endl;

          if (opProc)
          {
            theStatus = opProc->GetStatus();
            G4cout << "Choosen Process = " << currentProcess->GetProcessName() << endl;
            
            if(theStatus == Undefined)                    G4cout << "Boundary Process = Undefined" << endl;
            else if(theStatus == Transmission)            G4cout << "Boundary Process = Transmission" << endl;
            else if(theStatus == FresnelRefraction)       G4cout << "Boundary Process = Fresnel Refraction" << endl;
            else if(theStatus == FresnelReflection)       G4cout << "Boundary Process = Fresnel Reflection" << endl;
            else if(theStatus == TotalInternalReflection) G4cout << "Boundary Process = Total Internal Reflection" << endl;
            else if(theStatus == LambertianReflection)    G4cout << "Boundary Process = Lambertian Reflection" << endl;
            else if(theStatus == LobeReflection)          G4cout << "Boundary Process = Lobe Reflection" << endl;
            else if(theStatus == SpikeReflection)         G4cout << "Boundary Process = Spike Reflection" << endl;
            else if(theStatus == BackScattering)          G4cout << "Boundary Process = Back Scattering" << endl;
            else if(theStatus == Absorption)              G4cout << "Boundary Process = Absorption" << endl;
            else if(theStatus == Detection)               G4cout << "Boundary Process = Detection" << endl;
            else if(theStatus == NotAtBoundary)           G4cout << "Boundary Process = Not At Boundary" << endl;
            else if(theStatus == SameMaterial)            G4cout << "Boundary Process = Same Material" << endl;
            else if(theStatus == StepTooSmall)            G4cout << "Boundary Process = Step Too Small" << endl;
            else G4cout << "The status = " << theStatus << endl;
            G4cout << endl;
          }
      }
      G4cout << "End of OpBoundaryProcess Statuses" << endl;
      G4cout << "/////////////////////////////////////////////////////////////////////" << endl;


  /////////////////////////////////////////////////////////////////////

  G4cout << "/////////////////////////////////////////////////////////////////////" << endl;
  G4cout << "Beginning of ProcessDefinedStep Process Names" << endl;

  endPoint = theStep->GetPostStepPoint();
  //G4StepPoint* endPoint   = theStep->GetPostStepPoint();
  const G4VProcess* pds = endPoint->GetProcessDefinedStep();
  G4cout << "Endpoint = " << endPoint->GetPosition() << endl;
  if(pds->GetProcessName()) G4cout << pds->GetProcessName() << endl;

  G4cout << "End of ProcessDefinedStep Process Names" << endl;
  G4cout << "/////////////////////////////////////////////////////////////////////" << endl;

I get an output of:

/////////////////////////////////////////////////////////////////////
Beginning of OpBoundaryProcess Statuses
Transportation
OpAbsorption
OpRayleigh
OpMieHG
OpWLS
OpBoundary
Choosen Process = OpBoundary
Boundary Process = Fresnel Refraction

End of OpBoundaryProcess Statuses
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
Beginning of ProcessDefinedStep Process Names
Endpoint = (402.4,1.2948,-6.55091)
Transportation
End of ProcessDefinedStep Process Names
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
Beginning of OpBoundaryProcess Statuses
Transportation
OpAbsorption
OpRayleigh
OpMieHG
OpWLS
OpBoundary
Choosen Process = OpBoundary
Boundary Process = Fresnel Refraction

End of OpBoundaryProcess Statuses
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
Beginning of ProcessDefinedStep Process Names
Endpoint = (402.4,1.2948,-6.55091)
OpAbsorption
End of ProcessDefinedStep Process Names
/////////////////////////////////////////////////////////////////////

I included two steps. It seems as though, like I think you are saying there are a list of potential processes (Transportation, OpAbsorption, OpRayleigh, OpMieHG, OpWLS, OpBoundary), which is the same for every step, and from which the process OpBoundary is selected (this occurs at a boundary in my geometry, so that makes sense), and then either Transportation or OpAbsorption is returned by the ProcessDefinedStep.

With regards to what is returned from the use of: pds->GetProcessName, which is the ProcessDefinedStep(), in the first step shown the optical photon travels through a volume of glass, combination of OpBoundary (OpBoundaryProcess status) and Transportation (ProcessDefinedStep process name), and then in the second step the photon reaches a photocathode material and is absorbed, OpBoundary (OpBoundaryProcess status) and OpAbsorption (ProcessDefinedStep process name).

Is the process returned by the ProcessDefinedStep determined after OpBoundaryProcess one? Is what is returned for a ProcessDefinedStep, the process that was used to calculate that step or something else?

I know this is a lot and I am very appreciative of your help and time with this! You all have been very helpful!

-Frank

1 Like

No, in this instance that process returned by ProcessDefinedStep() is OpBoundaryProcess. You may wish to read the Geant4 documentation about tracking and physics to understand better how processes are selected and used at each step.

There are different kind of processes (just as there are many different physics interactions in real life), and usually multiple processes are applied to a track during each step. The specific “step limiting process” (which is what is returned by ProcessDefinedStep() is the process which had the shortest interaction length at that moment, and is therefore the process which determined what the step length would be.

Hi @mkelsey,

Thank you again for such a prompt response.

So as I take it now, and based off the link to the manual you provided, several processes will be applied, the one with the shortest step length is selected. This is the process that is stored in the ProcessDefinedStep().

For instance if the particle is subject to EM and optical physics, all of the processes possible are checked, i.e. interaction with another particle or EM field, or boundary process, and the closest/shortest will be selected. Will only one of these processes be selected per step, or is it possible to have multiple selected for a step?

Also, is it sufficient to view what processes a particle undergoes by using only the ProcessDefinedStep() method?

Thank you again so much for all of your help and time!

-Frank

1 Like

Now you’re getting into the details of the code. For processes which are discrete (i.e., they represent a point-like interaction), which inherit from G4VDiscreteProcess, only one of them will be selected per step as the step-limiting process.

Processes which are continuous (such as multiple-scattering, or ionization) are applied at every step, and do not have an interaction length as such. They make use of the already determined step length to figure out what they should do.

Finally, processes may also define a “force” condition (G4ForceCondition), in which case they will be applied at every step, whether or not their interaction length was shortest. This is especially useful for processes which do not represent physics per se, but rather do some sort of computation or apply a “state change” to the track.

That’s not sufficient because of the continuous and forced processes I mentioned above. The ProcessDefinedStep() is sufficient to know what kind of physics won the random number battle for the interaction.

Hi @mkelsey,

Thank you so much for being so responsive and helpful!

So to reiterate, there are discrete, continuous and force condition processes. From your description, would the process from ProcessDefinedStep() be a discrete process?

Also, is there a way to view the forced and continuous processes?

I apologize if some of my responses are obtuse and exhaustive; I am making sure I fully understand.

Thank you again for all of your help and time!

-Frank

Not exactly. As discussed in the documentation, there are discrete, continuous, and at-rest (e.g., particle decay) processes. There are also physics processes (such as particle decay) which may be combinations of these states. That’s why there are base classes such as G4VDiscreteContinuousProcess.

Any particular process, in any of these categories, may be “forced”, by the process code setting the G4ForceCondition pointer for that process. The easiest way to know if any particular process is forced is by looking at the code (.cc file).

To first order, yes. Only discrete processes are implemented such that they can limit the step length. I don’t recall how Geant4 handles decays. It may be that there’s an additional “zero length” step corresponding to a long-lived particle decaying at rest, in which case the decay process would be reported as the ProcessDefinedStep() process.

1 Like

Hi @mkelsey

Thank you so much for all of your responses and time.

From our discussion and from the documentation (5.1.1 Basic Concepts):

The process returned by ProcessDefinedStep can be either the active discrete or continuous process, or the “Safety” geometric step limiting (items 2-5 of the stepping algorithm)? Or can it be something else?

Overall, I am interested in viewing what was used to decide what the particle does along each step in its trajectory.

Thanks again for all of your help and explanations!

-Frank

Yeah, this is something lots of us are interested in at one time or another. Unfortunately, there’s no good way to identify after the fact all the processes which contributed to a step.

Hi @mkelsey,

Ah ok. I was looking through the other “G4V…Process” files (source and header), and didn’t happen to see any other ways to get the process name, like in G4VProcess (GetProcessName()).

I guess to encapsulate this discussion, use of ProcessDefinedStep()->GetProcessName() will return whichever process limited the step, with the processes that do not limit the step, such as forced, not accessible using this method.These processes need to be accessed through some type of manager or method in their respective base class?

Thank you again for all of your time and help, I can’t express how much I appreciate it.

-Frank

Sure, those are all subclasses of G4VProcess, so functionality which is common to all the subclasses belongs in the top-level base class.

So far as I know, there is not a way to unambigously identify all the processes which may have contributed to a step.

HI @mkelsey,

Thank you so much for all of your help, time, and patience. This discussion has been very helpful!

Best regards,

Frank