Skip to content

Commit

Permalink
Merge pull request #584 from OpenGATE/improve_doc_jacquet
Browse files Browse the repository at this point in the history
Improve doc jacquet
  • Loading branch information
dsarrut authored Nov 20, 2024
2 parents 4bd6f24 + 942d038 commit 573401b
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 49 deletions.
3 changes: 2 additions & 1 deletion core/opengate_core/opengate_lib/GateOptnComptSplitting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ G4VParticleChange *GateOptnComptSplitting::ApplyFinalStateBiasing(
// splitting low weights particles.

if ((fSplittingFactor == 1 && fRussianRoulette == false) ||
track->GetWeight() < fWeightThreshold)
(track->GetWeight() < fMinWeightOfParticle &&
fRussianRoulette == false))
return processFinalState;

castedProcessInitFinalState = (G4ParticleChangeForGamma *)processFinalState;
Expand Down
6 changes: 0 additions & 6 deletions core/opengate_core/opengate_lib/GateOptnComptSplitting.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,6 @@ class GateOptnComptSplitting : public G4VBiasingOperation {
}
G4double GetSplittingFactor() const { return fSplittingFactor; }

void SetWeightThreshold(G4double weightThreshold) {
fWeightThreshold = weightThreshold;
}
G4double GetWeightThreshold() const { return fWeightThreshold; }

void SetRussianRoulette(G4bool russianRoulette) {
fRussianRoulette = russianRoulette;
}
Expand Down Expand Up @@ -111,7 +106,6 @@ class GateOptnComptSplitting : public G4VBiasingOperation {

private:
G4double fSplittingFactor;
G4double fWeightThreshold;
G4ParticleChange fParticleChange;
G4bool fRussianRoulette;
G4ThreeVector fVectorDirector;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ void GateOptrComptSplittingActor::InitializeUserInfo(py::dict &user_info) {
GateVActor::InitializeUserInfo(user_info);
// fAttachedToVolumeName = DictGetStr(user_info, "mother");
fSplittingFactor = DictGetDouble(user_info, "splitting_factor");
fWeightThreshold = DictGetDouble(user_info, "weight_threshold");
fMinWeightOfParticle = DictGetDouble(user_info, "min_weight_of_particle");
// Since the russian roulette uses as a probablity 1/splitting, we need to
// have a double, but the splitting factor provided by the user is logically
Expand Down Expand Up @@ -96,7 +95,6 @@ void GateOptrComptSplittingActor::StartSimulationAction() {
// AttachAllLogicalDaughtersVolumes.
AttachAllLogicalDaughtersVolumes(biasingVolume);
fComptSplittingOperation->SetSplittingFactor(fSplittingFactor);
fComptSplittingOperation->SetWeightThreshold(fWeightThreshold);
fComptSplittingOperation->SetMaxTheta(fMaxTheta);
fComptSplittingOperation->SetRussianRoulette(fRussianRoulette);
fComptSplittingOperation->SetMinWeightOfParticle(fMinWeightOfParticle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class GateOptrComptSplittingActor : public G4VBiasingOperator,

G4double fSplittingFactor;
G4double fMinWeightOfParticle;
G4double fWeightThreshold;
G4bool fBiasPrimaryOnly;
G4bool fBiasOnlyOnce;
G4int fNInteractions = 0;
Expand Down
110 changes: 92 additions & 18 deletions docs/source/user_guide/user_guide_reference_actors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ Reference



KillActor
---------

Description
~~~~~~~~~

The KillActor enables the user to "kill", i.e. to stop this particle tracking, during its first step in a defined volume where this actor is attached.
The number of killed particle can be retrieved printing the actor object.

.. code-block:: python
kill_actor = sim.add_actor("KillActor", "KillAct")
kill_actor.attached_to = kill_plane
print(kill_actor)
Refers tot the test064 for more details.

Reference
~~~~~~~~~
.. autoclass:: opengate.actors.miscactors.KillActor

=======

DoseActor
---------

Expand All @@ -65,6 +88,7 @@ Description
The DoseActor scores the energy deposition (edep) or absorbed dose map in a given volume. The dose map is a 3D matrix parameterized with: size (number of voxels), spacing (voxel size), and translation (according to the coordinate system of the attached volume) and rotation. By default, the matrix is centered according to the volume center. Note that this virtual scoring grid is independent of a potential geometric grid (e.g. simulation using a voxelized CT image as geometry). The dose map may also have singleton dimensions (dose.size values with 1) reducing its effecctive dimension.

A sample code to score the energy deposition (default) is shown below. Let's assume a geometry of type box with name "waterbox" is already defined and is [200, 200, 200] *mm big. The dose actor output would now cover the entire size of the "waterbox" and has the same center.
.. code-block:: python
dose_act_obj = sim.add_actor("DoseActor", "dose_act_obj")
Expand All @@ -74,21 +98,24 @@ A sample code to score the energy deposition (default) is shown below. Let's ass
mm = gate.g4_units.mm
dose_act_obj.spacing = [2 * mm, 2 * mm, 2 * mm]
Adding following lines

.. code-block:: python
dose_act_obj.user_output.dose.active True
dose_act_obj.user_output.uncertainty.active True
to the dose actor object will trigger an additional image scoring the dose. The unctertainty tag will additionally provide an uncertainty image for each of the scoring quantities. Set user_output.edep.active False to disable the edep computation and only return the dose.

Like any image, the output dose map will have an origin, spacing and orientation. By default, it will consider the coordinate system of the volume it is attached to, so at the center of the image volume. The user can manually change the output origin using the option `output_origin` of the DoseActor. Alternatively, if the option `img_coord_system` is set to `True`, the final output origin will be automatically computed from the image the DoseActor is attached to. This option calls the function `get_origin_wrt_images_g4_position` to compute the origin.

.. image:: ../figures/image_coord_system.png

Several tests depict the usage of DoseActor: test008, test009, test021, test035, etc.
Following would translate and rotate the scoring image:

.. code-block:: python
Following would translate and rotate the scoring image:
from scipy.spatial.transform import Rotation
dose_act_obj.translation = [2 * mm, 3 * mm, -2 * mm]
dose_act_obj.rotation = Rotation.from_euler("y", 90, degrees=True).as_matrix()
Expand Down Expand Up @@ -142,7 +169,29 @@ Description
~~~~~~~~~~~

This is a variant of the normal :class:`~.opengate.actors.doseactors.DoseActor` which scores dose due to low energy gammas in another way, namely via the track length in the given voxel. Most options as well as the output are identical to the :class:`~.opengate.actors.doseactors.DoseActor`.
It is based on the work of `Baldacci et al., 2014 <https://doi.org/10.1016/j.zemedi.2014.04.001>`_. It is designed to model a photon population instead of treating each photon as a single particle. This approach enables efficient and accurate dose calculation by enabling a multiple energy deposition by a single photon.

**How It Works**
During a step, where a typical photon would interact and deposit its energy stochastically, a TLE photon deposits dose based on the material's mass energy-absorption coefficient (`μ_en`) and the step length. This method implies a local dose deposition at the voxel scale, even though secondary electrons are emitted. This actor indeed do not interfer with the GEANT4 tracking.

Since the database does not take into account the radiative part during the TLE energy deposition calculation, this method is applied to all photons, whether originating from the primary source or from secondary radiative processes. This approach offers a computationally efficient alternative to traditional dose calculation methods.

**Energy Threshold Option**
A novel feature of the TLE actor is the ability to activate or deactivate the TLE mechanism based on a user-defined energy threshold. This provides flexibility in simulations, allowing users to tailor the behavior of the TLE actor according to the energy ranges of interest.

Here is the a classical way to use the TLEDoseActor :

.. code-block:: python
tle_dose_actor = sim.add_actor("TLEDoseActor", "tle_dose_actor")
tle_dose_actor.output_filename = "my_output.mhd"
tle_dose_actor.attached_to = irradiated_volume.name
tle_dose_actor.dose.active = True
tle_dose_actor.dose_uncertainty.active = True
tle_dose_actor.size = [200, 200, 200]
tle_dose_actor.spacing = [x / y for x, y in zip(irradiated_volume.size, tle_dose_actor.size)]
Refer to test081 for more details.

Reference
~~~~~~~~~
Expand Down Expand Up @@ -560,6 +609,38 @@ The associated publication is:
.. autoclass:: opengate.actors.arfactors.ARFTrainingDatasetActor
.. autoclass:: opengate.actors.arfactors.ARFActor

LETActor
--------

.. note::
Documentation TODO. Refer to test050 for current examples.


BremSplittingActor
---------------------


Description
~~~~~~~~~

This actor replicates the behaviour of the bremsstrahlung splitting which can be used using GEANT4 command line.
When an electron or a positron occurs a bremsstrahlung process, the interaction is split in splitting_factor particles, with
a weight of 1/splitting_factor.

.. code-block:: python
nb_split = 100
brem_splitting_actor = sim.add_actor("BremSplittingActor", "eBremSplittingW")
brem_splitting_actor.attached_to = W_tubs.name
brem_splitting_actor.splitting_factor = nb_split
brem_splitting_actor.particles = "e-", "e+"
To be noted that the GEANT4 command line is a more straightforward way to obtain the same result.

Reference
~~~~~~~~~

.. autoclass:: opengate.actors.miscactors.BremSplittingActor

ComptonSplittingActor
---------------------
Expand All @@ -569,10 +650,6 @@ Description

This actor generates N particles with reduced weight whenever a Compton process occurs. The options include:

- **splitting factor**: Number of splits.
- **Russian Roulette**: Option for selective elimination based on angle and probability.
- **Minimum Track Weight**: Avoids splitting very low-weight particles.

.. code-block:: python
compt_splitting_actor = sim.add_actor("ComptSplittingActor", name="compt_splitting")
Expand All @@ -582,6 +659,15 @@ This actor generates N particles with reduced weight whenever a Compton process
compt_splitting_actor.rotation_vector_director = True
compt_splitting_actor.vector_director = [0, 0, -1]
.. code-block:: python
compt_splitting_actor = sim.add_actor("ComptSplittingActor", "ComptSplitting")
compt_splitting_actor.attached_to = W_tubs.name
compt_splitting_actor.splitting_factor = nb_split
compt_splitting_actor.russian_roulette = True
compt_splitting_actor.rotation_vector_director = True
compt_splitting_actor.vector_director = [0, 0, -1]
Refer to test071 for more details.

The options include:
Expand All @@ -597,15 +683,3 @@ Reference
.. autoclass:: opengate.actors.miscactors.ComptSplittingActor


BremSplittingActor
------------------

Description
~~~~~~~~~~~

Similar to :class:`~.opengate.actors.miscactors.ComptSplittingActor`

Reference
~~~~~~~~~

.. autoclass:: opengate.actors.miscactors.BremSplittingActor
61 changes: 40 additions & 21 deletions opengate/actors/miscactors.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ def EndSimulationAction(self):


class KillActor(ActorBase, g4.GateKillActor):
"""
Actor which kill a particle entering in a volume with the following attached actor.
"""

def __init__(self, *args, **kwargs):
ActorBase.__init__(self, *args, **kwargs)
Expand Down Expand Up @@ -292,6 +296,14 @@ def _setter_hook_particles(self, value):


class SplittingActorBase(ActorBase):
"""
Actors based on the G4GenericBiasing class of GEANT4. This class provides tools to interact with GEANT4 processes
during a simulation, allowing direct modification of process properties. Additionally, it enables non-physics-based
particle splitting (e.g., pure geometrical splitting) to introduce biasing into simulations. SplittingActorBase
serves as a foundational class for particle splitting operations, with parameters for configuring the splitting
behavior based on various conditions.
"""

# hints for IDE
splitting_factor: int
bias_primary_only: bool
Expand All @@ -302,77 +314,78 @@ class SplittingActorBase(ActorBase):
"splitting_factor": (
1,
{
"doc": "FIXME",
"doc": "Specifies the number of particles to generate each time the splitting mechanism is applied",
},
),
"bias_primary_only": (
True,
{
"doc": "FIXME",
"doc": "If true, the splitting mechanism is applied only to particles with a ParentID of 1",
},
),
"bias_only_once": (
True,
{
"doc": "FIXME",
"doc": "If true, the splitting mechanism is applied only once per particle history",
},
),
"particles": (
[
"all",
],
{
"doc": "FIXME",
"doc": "Specifies the particles to split. The default value, all, includes all particles",
"setter_hook": _setter_hook_particles,
},
),
}


class ComptSplittingActor(SplittingActorBase, g4.GateOptrComptSplittingActor):
"""
This splitting actor enables process-based splitting specifically for Compton interactions. Each time a Compton
process occurs, its behavior is modified by generating multiple Compton scattering tracks
(splitting factor - 1 additional tracks plus the original) associated with the initial particle.
Compton electrons produced in the interaction are also included, in accordance with the secondary cut settings
provided by the user.
"""

# hints for IDE
weight_threshold: float
min_weight_of_particle: float
russian_roulette: bool
rotation_vector_director: bool
vector_director: list
max_theta: float

user_info_defaults = {
"weight_threshold": (
0,
{
"doc": "FIXME",
},
),
"min_weight_of_particle": (
0,
{
"doc": "FIXME",
"doc": "Defines a minimum weight for particles. Particles with weights below this threshold will not be split, limiting the splitting cascade of low-weight particles generated during Compton interactions.",
},
),
"russian_roulette": (
False,
{
"doc": "FIXME",
"doc": "If enabled (True), applies a Russian roulette mechanism. Particles emitted in undesired directions are discarded if a random number exceeds 1 / splitting_factor",
},
),
"rotation_vector_director": (
False,
"vector_director": (
[0, 0, 1],
{
"doc": "FIXME",
"doc": "Specifies the particle’s direction of interest for the Russian roulette. In this direction, the Russian roulette is not applied",
},
),
"vector_director": (
[0, 0, 1],
"rotation_vector_director": (
False,
{
"doc": "FIXME",
"doc": "If enabled, allows the vector_director to rotate based on any rotation applied to a volume to which this actor is attached",
},
),
"max_theta": (
90 * g4_units.deg,
{
"doc": "FIXME",
"doc": "Sets the angular range (in degrees) around vector_director within which the Russian roulette mechanism is not applied.",
},
),
}
Expand All @@ -393,14 +406,20 @@ def initialize(self):


class BremSplittingActor(SplittingActorBase, g4.GateBOptrBremSplittingActor):
"""
This splitting actor enables process-based splitting specifically for bremsstrahlung process. Each time a Brem
process occurs, its behavior is modified by generating multiple secondary Brem scattering tracks
(splitting factor) attached to the initial charged particle.
"""

# hints for IDE
processes: list

user_info_defaults = {
"processes": (
["eBrem"],
{
"doc": "FIXME",
"doc": "Specifies the process split by this actor. This parameter is set to eBrem, as the actor is specifically developed for this process. It is recommended not to modify this setting.",
},
),
}
Expand Down

0 comments on commit 573401b

Please sign in to comment.