Dynamic parametrisations#
Dynamic parametrisations provide a user-facing way to change parts of a
simulation from one run to the next. They are used for dynamic geometry, such
as moving or rotating volumes, and also for dynamic sources, such as a
VoxelSource whose activity image changes over time.
The key idea is simple:
a simulation is split into several internal runs,
each run corresponds to one time interval,
a dynamic object provides one value per run for each dynamic parameter.
Run timing intervals#
The temporal structure of a dynamic simulation is defined by
sim.run_timing_intervals.
Example:
sec = gate.g4_units.s
sim.run_timing_intervals = [
(0.0 * sec, 0.5 * sec),
(0.5 * sec, 1.0 * sec),
(1.5 * sec, 2.0 * sec),
]
Each tuple corresponds to one Geant4 run. The intervals do not need to be continuous: gaps are allowed.
For dynamic parametrisations, the important rule is:
if there are
Nrun timing intervals, there must beNvalues for each dynamic parameter.
General user interface#
Dynamic objects use the method:
obj.add_dynamic_parametrisation(...)
The arguments of this method are the dynamic parameters and their values for each run.
For example, a translation evolving over three runs could be specified as:
box.add_dynamic_parametrisation(
translation=[
[0 * mm, 0 * mm, 0 * mm],
[5 * mm, 0 * mm, 0 * mm],
[10 * mm, 0 * mm, 0 * mm],
]
)
The same interface is used for other dynamic parameters, such as rotation or image.
Dynamic geometry#
Moving a volume#
Volumes can be moved dynamically by providing one translation per run:
import opengate as gate
sim = gate.Simulation()
mm = gate.g4_units.mm
sec = gate.g4_units.s
sim.run_timing_intervals = [
(0.0 * sec, 1.0 * sec),
(1.0 * sec, 2.0 * sec),
(2.0 * sec, 3.0 * sec),
]
box = sim.add_volume("Box", "moving_box")
box.size = [50 * mm, 50 * mm, 50 * mm]
box.material = "G4_WATER"
box.add_dynamic_parametrisation(
translation=[
[0 * mm, 0 * mm, 0 * mm],
[10 * mm, 0 * mm, 0 * mm],
[20 * mm, 0 * mm, 0 * mm],
]
)
Rotating a volume#
Rotations follow the same pattern. One rotation matrix is provided per run:
from scipy.spatial.transform import Rotation
rot0 = Rotation.from_euler("z", 0, degrees=True).as_matrix()
rot1 = Rotation.from_euler("z", 20, degrees=True).as_matrix()
rot2 = Rotation.from_euler("z", 40, degrees=True).as_matrix()
box.add_dynamic_parametrisation(
rotation=[rot0, rot1, rot2]
)
Translation and rotation can also be combined in a single dynamic parametrisation.
Dynamic image volumes#
ImageVolume also supports a dynamic image parameter. This allows, for
example, the use of a 4D CT where the image changes from run to run.
patient = sim.add_volume("Image", "patient")
patient.image = "ct_0.mhd"
patient.material = "G4_AIR"
patient.voxel_materials = [[0, 10000, "G4_WATER"]]
patient.add_dynamic_parametrisation(
image=[
"ct_0.mhd",
"ct_1.mhd",
"ct_2.mhd",
]
)
This uses the same interface as dynamic translations and rotations: one value per run.
Dynamic voxel source#
VoxelSource supports a dynamic image parameter for the activity map.
This means that the source distribution can change from one run to the next
while keeping the same source object.
The image is used as a relative spatial activity distribution for position
sampling. Scaling all voxel values by the same constant does not change the
total emitted activity; it leaves the same normalized spatial distribution.
The total source strength is controlled separately by activity,
half_life, TAC parameters, or n.
Example:
source = sim.add_source("VoxelSource", "vox_source")
source.attached_to = patient.name
source.particle = "alpha"
source.image = "activity_0.mhd"
source.direction.type = "iso"
source.energy.mono = 1 * MeV
source.n = [2000, 2000, 2000]
source.add_dynamic_parametrisation(
image=[
"activity_0.mhd",
"activity_1.mhd",
"activity_2.mhd",
]
)
This follows the same user interface as the dynamic image of an
ImageVolume.
Aligning activity and CT images#
When the activity image and the CT image share the same image coordinate system, the voxel source should usually be translated so that both image centers match in the GATE convention.
This can be done with:
source.position.translation = gate.image.get_translation_between_images_center(
patient.image, "activity_0.mhd"
)
See also the voxel source reference page for additional details on image alignment.
Automatic changers#
In the normal user workflow, no extra setup is needed beyond
add_dynamic_parametrisation(...). For supported dynamic parameters, GATE
creates and configures the required runtime changer automatically.
So for most users, dynamic parametrisations are simply:
define
sim.run_timing_intervals,call
add_dynamic_parametrisation(...),provide one value per run.
Advanced users can also create custom changers manually, but this is typically not needed for standard moving-geometry or dynamic-voxel-source use cases.
Per-run output#
When a simulation contains dynamic components, it is often useful to retrieve actor outputs separately for each run.
Many outputs support this with:
actor_output.keep_data_per_run = True
This is particularly useful to inspect how a moving geometry or changing source affects the result from one run to the next.