Transportation in Magnetic Field - Further Details¶
The challenge of integrating all tracks¶
What leads us to discard tracks looping in a magnetic field
The integration of charged particle tracks in magnetic field is an important part of the computational cost (CPU time). Part of this cost is due to integration of low-energy particles in a volume with low density and strong magnetic field.
In HEP applications the most important type of tracks causing such problems are electrons in the vacuum of beam pipes. Charged particles in volumes near decay volumes and muons in large volumes of air are other examples.
To limit this CPU cost, a type of tracking cut for charged particles
was introduced in Geant4
release 7.0 in G4Transportation
and G4CoupledTransportation
.
Tracks which require more than a threshold number of integration
steps [maxLoopCount] (currently 1,000)
during a physics/tracking step are marked as ‘looping’ and
are considered candidates for being killed - i.e. they can potentially be
abandoned after the current step, and have their energy deposited locally.
Enhancements introduced in release 10.6 provide more comprehensive
information about the tracks killed, in the form of G4Exception
warning
messages.
This section describes this policy, the parameters which the user is able to set to tune it, and recent refinements implemented in Geant4 10.5.
Cost of integration
Occasionally tracks ‘looping’ in a strong magnetic field, making little progress even over thousands of integration steps. This is due to a combination of a strong magnetic field and a thin material (gas or vacuum) in which the size of a physics step is substantially larger than the radius of curvature of the track.
The preferred integration method for tracks in an EM field is the Runge-Kutta method. This and other similar methods are well suited to variations in magnetic fields and step sizes up to a few times the radius of curvature of the charged tracks.
However when the step sizes are hundreds or thousands of times larger than the curvature of the track, these methods are expensive as they do not progress the integration of a track adequately.
The amount of CPU time which can be consumed by one or few such tracks can very large, sometimes contributing per cent increases to the simulation of some primary particles. Some tracks with a very small drift velocity (projection of the velocity along the vector of the magnetic field) can stop the progress of a simulation if they are not limited or integrated using alternative means.
So it is important to limit the number of integration steps spent on these tracks. The module for propagation in field in Geant4 flags tracks which take more than a certain number (default 1,000) integration steps without reaching the requested end of the step size, which was determined by the physics and geometry.
Parameters for eliminating or controling which particles are killed
The Geant4 G4Transportation
and G4CoupledTransportation
processes are
tasked to select which of the tracks flagged as looping are killed and which
survive.
To balance the potential significant cost of integrating looping particles,
three thresholds exist:
- the ‘Warning’ Energy: a track with energy below this value that is found to
loop is killed silently (no warning.) Above the ‘Warning Energy’, if a track
is selected for killing then a warning is generated.
- the ‘Important’ Energy: the threshold energy above which a track will survive
for multiple steps if found looping.
- the number of extra ‘tracking’ steps for important particles. These tracks
will be only be killed only if they still loop more than this number of
trial steps. ( So in effect the number of integration steps will be this
number times the maximum number of steps allowed in G4PropagatorInField
.
In versions of Geant4 from 7.0 up to release 10.4,
Transportation did not examine the types of a charged particle -
all types of particles were killed if they fulfilled the same criteria.
A short message was written in
the G4cout
output that gave the energy and location of the killed track.
This printout was under the G4VERBOSE
flag, so it was suppressed if
the G4_NO_VERBOSE
configuration option was chosen at installation.
In Geant4 10.5 several changes have been implemented:
only stable particles are killed. ( Re-enabling the killing of unstable particles as an option is envisioned. )
each particle with energy above the warning energy which is killed generates a detailed warning (using
G4Exception
) with the full information about the particle location, the current volume and its material, and the particle momentum and energy.for the first 5 tracks killed a detailed description is printed that describes the criteria and parameters which are used to decide what tracks are killed, and provides a first guidance regarding how to ‘save’ tracks by chaning the values of thresholds or by adopting different integration methods.
Below we discuss the different way in which a user can change the thresholds for killing ‘looping’ tracks, which criteria can be used to ensure that a track continues to propagate and for how many steps an ‘important’ track that is ‘looping’ can survive.
Two techniques are demonstrated below. An example of using them is available
in the extended example field01
, in the directory
examples/extended/field/field01
.
Using preset thresholds for killing loopers¶
This method is new in Geant4 release 10.5, and uses the G4PhysicsListHelper which has methods to choose a pre-selected set of parameter values. The choices are between a set each of low and high thresholds. Either one can be enabled by calling correspondingly method.
It is possible to select a set of pre-selected values of the parameters for looping particles using
New functionality in G4PhysicsListHelper
,
introduced in Geant4 release 10.5,
enables the Transportation
process chosen to be provided with this set of parameters. This reuses
the AddTransportation
method, which is called in each thread.
To configure with low values of the thresholds, appropriate for typical applications using low-energy physics, choose
#include "G4PhysicsListHelper.hh"
int main( int, char**)
{
auto plHelper = G4PhysicsListHelper::GetPhysicsListHelper();
plHelper->UseLowLooperThresholds();
//
// Use low values for the thresholds
// Warning 1 keV, Important 1 MeV, trials 10
auto physList = new FTFP_BERT();
// ...
}
The original high values of the parameters can be selected with a similar call
plHelper->UseHighLooperThresholds();
//
// Configures with the original (high) values of parameters. Currently:
// Warning 100 MeV, Important 250 MeV, trials 10
and are chosen as starting points for energy-frontier HEP experiments.
The above sequence is demonstrated in the main()
of field01.cc
, part of the
extended field examples ( examples/extended/field/field01
.)
This configuration method works only if modular physics lists are used, or if the AddTransportation() method is used to construct the transportation in a user physics list.
These calls must be done before a physics list is instantiated, in
particular before
G4PhysicsListHelper::AddTransportation()
is called during the construction
of a physics list.
Else the configuration of the parameters does not occur.
These methods must be called before the physics is constructed - i.e. typically
before G4RunManager
‘s Initialise
method is called.
In order for this method to work the physics list must be constructed in one of two ways:
a preconstructed physics lists, from the list of recommended physics lists, or
the list must be constructed using the
G4ModularPhysicsList
and itsAddTransportation
method.
Note that in each thread the AddTransportation
instantiates a single
common transportation process which is then used by all particles types.
Users who build a physics list without making use of
G4ModularPhysicsList
and its AddTransportation
method,
are responsible to register a Transportation
process to each
particle type, and to set its parameters appropriately.
This would allow the most finer grained control, and would also allow
different thresholds to be chosen for different particle types.
Finer-grain control of the parameters for killing looping particles¶
A new feature to set any value to these parameters is introduced in
Geant4 release 11.1 using the class G4TransportationParameters
.
If an instance of G4TransportationParameters
exists,
the constructor of G4Transportation
will utilise the values
it stored to inititalise its own parameters.
auto transportParams= G4TransportationParameters::Instance();
transportParams->SetWarningEnergy( warningE );
transportParams->SetImportantEnergy( importantE );
transportParams->SetNumberOfTrials( numTrials );
G4cout << "Using G4TransportationParameters to set looper parameters." << G4endl;
A couple of caveats exist. First is that its values will be used by default for all instances of G4Transporation and its derived classes: whether it is
the single instance typically registered for all particles (as is done in the modular physics lists), or
an instance created separately and registered by a user to one or more (charged) particles as a replacement.
Secondly, if it exists, the values of all the parameters that
G4TransportationParameters
stores are currently used to overwrite the
existing default values in G4Transportation
.
So, if you create G4TransportationParameters
it is your responsibility to set
the values of all of its parameters.
Full control of the parameters for killing looping particles¶
Whether you use one of the previous methods or not, it is possible to exercise full fine-grained control over each values for each type of particle separately.
The user can choose arbitrary values for the different parametes related to killing loopers and also refine the integration of charged particle propagation in particular volumes in order to eliminate or reduce the incidence of looping tracks.
This is also the only method which will work in all Geant4 versions since 7.0.
To obtain reliable configuration of the G4Transportation
(or
G4CoupledTransportation
) process in a potentially multi-threaded
application, we configure it using a G4VUserRunAction
. In particular such
configuration can be undertaken in the BeginOfRunAction
methods.
For example, to ensure that only looping particles with energy 10 keV are killed silently we change the value of the ‘Warning’ Energy
transport->SetThresholdWarningEnergy( 1.0 * CLHEP::keV );
After this each time a (stable) looping track with energy over 1.0 keV is killed by this transportation process, it will generate a warning.
The second configurable energy threshold is labelled the ‘important’ energy and it enables tracks above its value to survive a chosen number of ‘tracking’ steps. They will be only be killed only if they are still looping after the given number of tracking steps.
These are demonstrated also in the F01RunAction
’s ChangeLooperParameters
method,
which is called by the BeginOfRunAction
.
To obtain the appropriate Transportation object for a particular particle type
G4ParticleDefinition *particleDef;
either obtain it manually obtain directly if we know its type
G4VProcess* partclTransport =
particleDef->GetProcessManager()->GetProcess("G4Transportation");
auto transport= dynamic_cast<G4Transportation*>(partclTransport);
or write code which can adapt to different types to different types which
inherit from G4Transportation
G4Transportation* FindTransport( G4ParticleDefinition* particleDef )
{
G4Transportation *transport;
G4VProcess* cplTransport= nullptr, *transportMsc= nullptr;
auto pm= particleDef->GetProcessManager();
G4VProcess* ordTransport = pm->GetProcess("G4Transportation");
transport= dynamic_cast<G4Transportation*>(ordTransport);
if( !transport ) {
// Maybe it is G4CoupledTransportation ...
cplTransport= pm->GetProcess("G4CoupledTransportation");
if ( vpCoupledTransport) {
transport= dynamic_cast<G4Transportation*>(cplTransport);
}
}
return transport;
}
or else use (or copy) the helper method F01RunAction::FindTransportation
auto transport= FindTransportation(G4Electron::Definition(), true);
This example method returns returns a `G4Transportation *`
.
( whereas in release 11.0 it returned a pair
`std::pair<G4Transportation*, G4CoupledTransportation*>`
. )
Since Geant4 11.1, G4CoupledTransportation
and the new
G4TransportationWithMsc
classes inherit from G4Transportation
you can use common code to configure them (as shown in Listing 104).
In case a different Transportation type is used which does not
inherit from G4Transportation
, such as G4ITTransportation
,
and G4DNABrownianTransportation
(both relevant for Geant4 DNA)
similar code is required for each such class.
auto pm= particleDef->GetProcessManager();
G4VProcess* vpItTransport= pm->GetProcess("G4ITTransportation");
auto itTransport= dynamic_cast<G4ITTransportation*>(vpItTransport);
NOTE: Up to (and including) release 11.0 G4CoupledTransportation
was
an independent class, not inheriting from G4Transportation
.
If your application needs to be backward compatible with previous releases
of Geant4 (including release 10.1 through 10.7 and 11.0) you must
ignore this new inheritance relationship.
When using earlier version of Geant4 it was necessary to treat
instances of G4CoupledTransportation
separately:
G4VProcess* vProcCoupled= pm->GetProcess("G4CoupledTransportation");
G4CoupledTransportation* coupledTransport=
dynamic_cast<G4CoupledTransportation*>(vProcCoupled);
coupledTransport->SetThresholdWarningEnergy( 1.0 * CLHEP::keV );
coupledTransport->SetThresholdImportantEnergy( 1.0 * CLHEP::MeV );
coupledTransport->SetNumberOfTrials( 20 );
It is still possible to use this approach (listing Listing 105) if you are maintaining an application which must work both older versions and the current release 11.1.
However moving forward the code can now be simplified, as demonstrated in the
next two code excerpts.
First by obtaining a G4Transportation`
, e.g. as in
listing Listing 104.
Then using common code, as in listing Listing 106 to overwrite
the thresholds in a G4Transportation
(or derived) class
as found in F01RunAction
‘s ChangeLooperParameters
method
void ChangeLooperParameters(const G4ParticleDefinition* particleDef )
{
auto transport= FindTransportation( particleDef );
// Since Geant4 11.1 the following code works for several transportation
// classes:
// - ordinary G4Transporation,
// - G4CoupledTransportation used for parallel worlds, and
// - G4TransportationWithMsc used to speed up charged particles.
if( transport != nullptr )
{
// Change the values of the looping particle parameters of Transportation
transport->SetThresholdWarningEnergy( warningEnergy );
transport->SetThresholdImportantEnergy( importantEnergy );
transport->SetThresholdTrials( numberOfTrials );
}
}
Note that for all pre-configured and modular physics lists share a single Transportation process for all types of particles. So the parameters for killing loopers will be shared by all particle types in this case.
If this is not the desired behaviour, it is necessary to register a separate instance of the Transporation process for a particular type of particle. See the subsection ReplacingTransportation about how this can be done.
F01RunAction
plays the role of a helper object, which holds the proposed
(new) values of parameters, and which can allow them to be set, e.g., in the
main()
function
runAction->SetWarningEnergy( 10.0 * CLHEP::keV );
F01RunAction
then forwards them to the Transportation
object of each thread at the
start of each run.
Using a helper object to forward parameter changes¶
Since the type of the transportation
it can be useful to use a helper object to hold the desired
values for the parameters (thresholds, number of iterations),
and to forward them to the Transportation
class.
This is demonstrated in the class
F01RunAction
and its ChangeLooperParameters
method
of the field01 extended example.
It copes with either transportation class,
G4Transportation
or a G4CoupledTransportation
,
and passes new values of parameters as needed.
In field01
the methods of F01RunAction
runAction->SetImportantEnergy( 0.1 * CLHEP::MeV );
runAction->SetNumberOfTrials( 30 );
which the run action passes to the G4Transportation
or
G4CoupledTransportation
object registered for the electron
in F01RunAction
‘s method ChangeLooperParameters
.
How to replace the Transportation Process of a particle type¶
The most advanced use case of controling requires a separate instance of a G4Transporation (or G4CoupledTransporation or other process).
If you have configured your application to use G4TransporationWithMsc only for electrons
Currently in order to undertake this it is necessary to use the property of the transportation of being first in the process list and interact directly with the process manager:
G4ParticleDefinition* particleDef= G4Electron::Definition();
G4int verboseLevel= 0;
G4ProcessManager* procManager = particleDef->GetProcessManager();
auto plist = procManager->GetProcessList();
procManager->RemoveProcess(0); // Remove the current Transport
auto transport = new G4Transportation(verboseLevel);
// Here we can adjust the parameters for this instance/particle, e.g.
transport->SetThresholdWarningEnergy( 30.0 * CLHEP::keV );
transport->SetThresholdImportantEnergy( 3.0 * CLHEP::MeV );
transport->SetNumberOfTrials( 50 );
procManager->AddProcess(transport, -1, 0, 0);
// Add the new type of Transport(ation)
You can repeat this for positrons - but we recommend much lower thresholds
for positrons as their annihilation will produce two 0.5 MeV
gammas.
Avoiding loopers or reducing the incidence of looping particles¶
There are different ways to reduce the occurence of looping particles. This section will provide an overview, and refer the user to the detailed information on particle propagation in a magnetic field for details.
Volumes which have a strong field and contain vacuum, large air cavities or large volumes of gases are prime candidates for causing integration difficulties for low energy charged particles, which result in looping particles.
A very simple way to reduce the incidence of looping particles is to reduce the maximum step size which particles that interact very infrequently can travel. Geant4 attempts to estimate an effective maximum using the diameter of the world volume, and frequently the maximum step size is large if the experimental hall is used as the world volume and has large dimentions. A smaller value can be impose by using the method.
G4PropagatorInField::SetMaximumStepSize()
Another ways is to change the maximum number of integration substeps. The default value is 1000, but it can be obtained from
G4PropagatorInField
auto *transportMgr = G4TransportationManager::GetTransportationManager(); G4PropagatorInField* propFld= transportMgr->GetPropagatorInField(); G4cout << " The maximum number of substeps for integration is " << propFld->GetMaxLoopCount() << G4endl;
It can be also be changed simply by calling the corresponding set method, e.g.
propFld->SetMaxLoopCount(2500);
Assign a separate
G4FieldManager
class to each such volume. It can use adapted methods for the integration of the ODEs of motion.One solution is to use a helical stepper, such as
G4HelixImplicitEuler
orG4HelixHeum
which are inherently for steps over multiple ‘turns’ of a helix-like track. Their reason d’ etre is the ability to use the helix solution as baseline ‘first-order’ like solution and treat deviations from this as something like pertubations.A new integration driver
G4BFieldIntegrationDriver
, introduced in Geant4 10.6 samples the value of the magnetic field at the start of each step and using the estimated track curvature determines whether the current step will traverse an angler smaller or larger than \(2 * \pi\). For larger steps the hybrid-helical stepperG4HelixHeum
is used, and for smaller steps theG4DormandPrince745
stepper is used. This driver is the default driver in Geant4 10.6, created byG4ChordFinder
for magnetic fields, and whenG4FieldManager
‘sCreateChordFinder
method is called. Note that it is applicable only for charged particles in pure magnetic field.An older approach, usable before Geant4 10.6, is to use the
G4HelixMixedStepper
. This also combines a helix stepper for large steps with a Runge-Kutta stepper for small and intermediate step sizes. It does this by checking the value of the field at the start of every integration. As a result it is less efficient than the new methodG4BFieldIntegrationDriver
.
Ensuring progress for particles
To allow better progress for looping particles, the default behaviour was changed in Geant4 10.6, so that a track’s parameters are changed within a Geant4 step after it has undertaken 100 integration substeps.
For the remainder of the current step the track ‘tightness’ parameter delta chord is relaxed, first by a factor of 2 at the hundredth step, and again by another factor of 2 after every 100 subsequent steps. The original value of delta chord is restored at the end of the current Geant4 step.
This will allow tracks which are in a tight spiral with a radius of curvature less than the user-defined delta chord to make substantial progress.
Note that this applies only to particles below the ‘Important’ energy threshold, which would be killed if their integration is not completed within a single Geant4 step.