diff --git a/core/opengate_core/opengate_lib/GateOptnComptSplitting.cpp b/core/opengate_core/opengate_lib/GateOptnComptSplitting.cpp index be7799cd8..d7272a32f 100644 --- a/core/opengate_core/opengate_lib/GateOptnComptSplitting.cpp +++ b/core/opengate_core/opengate_lib/GateOptnComptSplitting.cpp @@ -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; diff --git a/core/opengate_core/opengate_lib/GateOptnComptSplitting.h b/core/opengate_core/opengate_lib/GateOptnComptSplitting.h index 5b3397b59..9e7522726 100644 --- a/core/opengate_core/opengate_lib/GateOptnComptSplitting.h +++ b/core/opengate_core/opengate_lib/GateOptnComptSplitting.h @@ -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; } @@ -111,7 +106,6 @@ class GateOptnComptSplitting : public G4VBiasingOperation { private: G4double fSplittingFactor; - G4double fWeightThreshold; G4ParticleChange fParticleChange; G4bool fRussianRoulette; G4ThreeVector fVectorDirector; diff --git a/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.cpp b/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.cpp index 9327f8a6b..3b0be069d 100644 --- a/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.cpp +++ b/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.cpp @@ -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 @@ -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); diff --git a/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.h b/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.h index 402fdaa42..5fb0c2963 100644 --- a/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.h +++ b/core/opengate_core/opengate_lib/GateOptrComptSplittingActor.h @@ -58,7 +58,6 @@ class GateOptrComptSplittingActor : public G4VBiasingOperator, G4double fSplittingFactor; G4double fMinWeightOfParticle; - G4double fWeightThreshold; G4bool fBiasPrimaryOnly; G4bool fBiasOnlyOnce; G4int fNInteractions = 0; diff --git a/docs/source/user_guide/user_guide_reference_actors.rst b/docs/source/user_guide/user_guide_reference_actors.rst index 66ac2db7e..bafe3a8af 100644 --- a/docs/source/user_guide/user_guide_reference_actors.rst +++ b/docs/source/user_guide/user_guide_reference_actors.rst @@ -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 --------- @@ -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") @@ -74,10 +98,14 @@ 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. @@ -85,10 +113,9 @@ Like any image, the output dose map will have an origin, spacing and orientation .. 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() @@ -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 `_. 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 ~~~~~~~~~ @@ -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 --------------------- @@ -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") @@ -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: @@ -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 diff --git a/opengate/actors/miscactors.py b/opengate/actors/miscactors.py index cfc270348..c81a8299f 100644 --- a/opengate/actors/miscactors.py +++ b/opengate/actors/miscactors.py @@ -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) @@ -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 @@ -302,19 +314,19 @@ 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": ( @@ -322,7 +334,7 @@ class SplittingActorBase(ActorBase): "all", ], { - "doc": "FIXME", + "doc": "Specifies the particles to split. The default value, all, includes all particles", "setter_hook": _setter_hook_particles, }, ), @@ -330,8 +342,15 @@ class SplittingActorBase(ActorBase): 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 @@ -339,40 +358,34 @@ class ComptSplittingActor(SplittingActorBase, g4.GateOptrComptSplittingActor): 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.", }, ), } @@ -393,6 +406,12 @@ 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 @@ -400,7 +419,7 @@ class BremSplittingActor(SplittingActorBase, g4.GateBOptrBremSplittingActor): "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.", }, ), }