How to: Actors and Filters#

Note

This section is a general guide on how to use actors in GATE. A detailed description of all actors is here: Details: Actors.

Introduction#

The “Actors” are scorers that can store information during simulation, such as dose map or phase-space (like a “tally” in MCNPX). They can also be used to modify the behavior of a simulation without actually scoring any quantity. For example, the KillActor removes particles ad-hoc from tracking when they reach some defined regions. This is why GATE uses the term “actors” rather than “scorers”.

In analogy to other components, an actor can be added to a simulation via the command add_actor(). Example:

import opengate as gate
sim = gate.Simulation()
dose_actor_patient = sim.add_actor("DoseActor", name="dose_actor_patient")

This creates a dose actor, adds it to the internal registry of actors of the simulation sim under the name ‘’dose_actor_patient’’ dose and returns a python object that we chose to call dose_actor_patient. Note: The name passed as argument to the function add_actor() dose not need to match the variable name of the returned actor object, but it makes the script clearer. The actor in this example can be configured via the object dose_actor_patient.

Attach the actor to a volume#

Many actors need to be attached to a certain volume in the simulation geometry because the actions of the actor are triggered when a particle enters, exits, or moved inside the volume, depending on the actor.

In the example above, you might want to attach the dose actor to an ImageVolume containing the patient anatomy via a CT image. You can achieve this with the parameter attached_to. Continuing the above example:

import opengate as gate
sim = gate.Simulation()
dose_actor_patient = sim.add_actor("DoseActor", name="dose_actor_patient")
patient = sim.add_volume("ImageVolume", name="patient")
dose_actor_patient.attached_to = patient

Actor output#

Many actors generate at least one kind of output. Some of them generate multiple outputs. The DoseActor, for example, can score deposited energy (edep), dose (dose), the uncertainty of the deposited energy (edep_uncertainty) and of the dose (dose_uncertainty), the number of deposits per voxels, (counts), and it can provide the density map on the same grid as used for scoring (density).

Other actors, e.g. many digitizers and the PhaseSpaceActor, only provide a single ROOT output, e.g. (root_output).

You can configure the output of an actor in different ways, depending whether the actor has one or multiple outputs.

Configure the output filename#

Actors with a single output#

The PhaseSpaceActor has only a single output, namely a ROOT file.

import opengate as gate
sim = gate.Simulation()
sim.output_dir = "/my/preferred/location/"
phsp_actor1 = sim.add_actor("PhaseSpaceActor", name="phsp_actor1")
phsp_actor1.output_filename = 'phsp1.root'
phsp_actor2 = sim.add_actor("PhaseSpaceActor", name="phsp_actor1")
phsp_actor2.output_filename = 'phsp2.root'

In the example above, we set the global output directory of the simulation to our preferred location via output_dir and define the filename for each actor via output_filename. GATE will automatically combine the filenames with the output path. You can also use relative paths including subfolders, like:

from pathlib import Path
subfolder = Path('phsp')
phsp_actor1.output_filename = subfolder / 'phsp1.root'
phsp_actor2.output_filename = subfolder / 'phsp2.root'

This will create a subfolder ‘’phsp’’ in your preferred output folder defined via sim.output_dir = "/my/preferred/location/" and save the ROOT files in there.

Note

We highly recommend the pathlib library to work with paths. It makes things very easier and platform independent.

You can also decide not to write data to disk, if you wish so. In the above example, set write_to_disk to False:

phsp_actor1.write_to_disk = False

Actors with multiple outputs#

If your actor handles more than one output, you can configure each output individually. The DoseActor is a good example. If you want to score deposited energy as well as dose and dose uncertainty, you can do this:

import opengate as gate
sim = gate.Simulation()
sim.output_dir = "/my/preferred/location/"

dose_actor_patient = sim.add_actor("DoseActor", name="dose_actor_patient")

dose_actor_patient.dose.active = True
dose_actor_patient.dose_uncertainty.active = True

This turns on dose and dose_uncertainty, which are inactive by default. Deposited energy scoring, edep, is always active.

You can specify the filename individually per output, e.g.

dose_actor_patient.edep.output_filename = "patient_deposited_energy.mhd"
dose_actor_patient.dose.output_filename = "patient_dose.mhd"
dose_actor_patient.dose_uncertainty.output_filename = "patient_dose_uncertainty.mhd"

or, you can set a filename via the actor:

dose_actor_patient = "dose_actor_patient.mhd"

In this latter case, GATE will automatically append a suffix to each output corresponding to the output name, i.e. ‘’dose_actor_patient-edep.mhd’’, ‘’dose_actor_patient-dose.mhd’’,m and ‘’dose_actor_patient-dose_uncertainty.mhd’’.

Accessing output data via file#

The common way of accessing actor output is by opening the file(s) the actor wrote to your disk. To this end, the most convenient way to get the output path is to ask the actor.

In case your actor handles a single output, as for example the PhaseSpaceActor, you can do:

# this gives you an absolute path as a pathlib.Path object
path_to_root_file = phsp_actor1.get_output_path()
# if you need the string, do
path_to_root_file_string = str(path_to_root_file)

In case your actor handles multiple outputs, get the path for the output you want. For the DoseActor, for example:

path_to_dose = dose_actor_patient.dose.get_output_path()
path_to_dose_uncertainty = dose_actor_patient.dose_uncertainty.get_output_path()

Accessing output data via directly from memory#

The nice thing about GATE 10 is that your simulation actually runs in a python session. So you might might want to do some post-processing right after the end of your simulation. In this case, you can directly access the output data from your actor without reading any file from disk.

If your actor supports this, like e.g. the DoseActor, you can do:

import numpy as np

# these are ITK images
dose_image = dose_actor_patient.dose.image
dose_uncertainty_image = dose_actor_patient.dose_uncertainty.image

# you can convert them to numpy arrays, if you want:
dose_array = np.asarray(dose_image)
dose_uncertainty_array = np.asarray(dose_uncertainty_image)

In the above example, you will get the dose and dose_uncertainty, respectively, scored over the entire simulation.

The property image is a shortcut specific to image-like output that is equivalent to

# these are ITK images
dose_image = dose_actor_patient.dose.get_data()
dose_uncertainty_image = dose_actor_patient.dose_uncertainty.get_data()

Note

Currently, actors with ROOT output do not support access to the ROOT structure via memory. You have to load the file from disk, e.g. with uproot.

Actor output in simulations with multiple runs#

You simulation might have multiple internal runs (G4Runs), e.g. because part of the geometry is dynamic (moving volumes, 4D CT image). In this case, many actors can store the output data per run additionally to the output data corresponding to the entire simulation. To activate that for specific output, use:

dose_actor_patient.dose.keep_data_per_run = True
dose_actor_patient.dose_uncertainty.keep_data_per_run = True

Alternatively, you can apply the setting to all outputs of the actor:

dose_actor_patient.keep_data_per_run = True
print(dose_actor_patient.dose.keep_data_per_run)
print(dose_actor_patient.dose_uncertainty.keep_data_per_run)

To access data from a specific run, you need to use the get_data() method with the keyword argument which:

# This is the dose image from the second run because indexing starts at 0
dose_runindex_1 = dose_actor_patient.dose.get_data(which=1)

References#

Common parameters and functions#

ActorManager.add_actor(actor, name)[source]#
ActorManager.remove_actor(name)[source]#
property ActorBase.attached_to[source]#

attached_to:

  • Default value: world

  • Description: Name of the volume to which the actor is attached.

property ActorBase.filters[source]#

filters:

  • Default value: []

  • Description: Filters used by this actor.

property ActorBase.priority[source]#

priority:

  • Default value: 100

  • Description: Indicates where the actions of this actor should be placed in the list of all actions in the simulation. Low values mean ‘early in the list’, large values mean ‘late in the list’.

Actor output#

BaseUserInterfaceToActorOutput.get_data(which='merged', **kwargs)[source]#

Get the data stored in this output, e.g. an ITK image. Use the argument ‘which’ to specify whether you refer to the cumulative output of the entire simulation (which=’merged’), or to a specific run, e.g. which=2 for run index 2 (run indices start at 0).

BaseUserInterfaceToActorOutput.get_output_path(which='merged', **kwargs)[source]#

Get the path (absolute) where GATE stores this output. Use the argument ‘which’ to specify whether you refer to the cumulative output of the entire simulation (which=’merged’), or to a specific run, e.g. which=2 for run index 2 (run indices start at 0).

property BaseUserInterfaceToActorOutput.output_filename[source]#

Output filename used for this output. An automatic suffix is appended for per-run data. You can also specify a relative path, i.e. relative to the simulation’s output directory, e.g. output_file = Path(‘dose_output’) / ‘patient_dose.mhd’.

property BaseUserInterfaceToActorOutput.write_to_disk[source]#

Should this output be stored on disk?

property BaseUserInterfaceToActorOutput.keep_data_per_run[source]#

Should data be kept in memory for individual runs? If False, only the cumulative data is kept. Note: Not every kind of user output supports this, e.g. ROOT output cannot per stored on a per-run basis.

property BaseUserInterfaceToActorOutput.active[source]#

Should the actor consider and score this output?