Volumes¶
Volumes are the elements that describe solid objects. There is a default volume called world (lowercase) automatically created. All volumes can be created with the add_volume command. The parameters of the resulting volume can be easily set as follows:
vol = sim.add_volume('Box', 'mybox')
print(vol) # to display the default parameter values
vol.material = 'G4_AIR'
vol.mother = 'world' # by default
cm = gate.g4_units('cm')
mm = gate.g4_units('mm')
vol.size = [10 * cm, 5 * cm, 15 * mm]
# print the list of available volumes types:
print('Volume types :', sim.dump_volume_types())
The return of add_volume is a UserInfo object (that can be view as a dict). All volumes must have a material (G4_AIR by default) and a mother (world by default). Volumes must follow a hierarchy like volumes in Geant4. All volumes have a default list of parameters you can print with print(vol).
Here is a list of available volumes: Box, Sphere, Trap, Image, Tubs, Polyhedra, Cons, Trd, Boolean, RepeatParametrised (this list may not be uptodate). You can find the way Geant4 parametrize the volumes here. user_guide_2_1_volumes.md
Common parameters¶
Some parameters are specific to one volume type (for example size for Box, or radius for Sphere), but all volumes share some common parameters:
mother: the name of the mother volume (worldby default) in the hierarchy of volume. The volume will consider its coordinates system the one of his mother.material: the name of the material that compose the volume (G4_WATERfor example).translation: the translation (list of 3 values), such as[0, 2*cm, 3*mm], to place the volume according to his coordinate system (the one from his mother). In Geant4, the coordinate system is always according to the center of the shape.rotation: a 3x3 rotation matrix. We advocate the use ofscipy.spatial.transformRotationobject to manage rotation matrix.repeat: a list of dictionary of ‘name’ + ‘translation’ + ‘rotation’. Each element of the list will create a repeated copy of the volume, positionned according to the translation and rotation (seetest017)color: a color as a list of 4 values[1, 0, 0, 0.5](Red, Green, Blue, Opacity) between 0 and 1. Only use when visualization is on.
See for example test007 and test017 test files for more details.
Materials¶
The Geant4 default materials are available. The list is available here.
Additional materials can be created by the user, with a simple text file, like in the previous GATE versions. The text file can be loaded with:
sim.add_material_database("GateMaterials.db")
After this command, all materials names defined in the “GateMaterials.db” are known and can be used for any volume. The format of the “.db” text file can be seen in the file tests/data/GateMaterials.
Alternatively, materials can be created dynamically with the following:
gate.new_material("mylar", 1.38 * gcm3, ["H", "C", "O"], [0.04196, 0.625016, 0.333024])
This function creates a material named “mylar”, with the given mass density and the composition (H C and O here) described as a vector of percentages. Note that the weights are normalized. The created material can then be used for any volume.
Images (voxelized volumes)¶
A 3D image can be inserted in the scene with the following command:
patient = sim.add_volume("Image", "patient")
patient.image = "data/myimage.mhd"
patient.mother = "world"
patient.material = "G4_AIR" # material used by default
patient.voxel_materials = [
[-2000, -900, "G4_AIR"],
[-900, -100, "Lung"],
[-100, 0, "G4_ADIPOSE_TISSUE_ICRP"],
[0, 300, "G4_TISSUE_SOFT_ICRP"],
[300, 800, "G4_B-100_BONE"],
[800, 6000, "G4_BONE_COMPACT_ICRU"],
]
The user info named patient. image on the second line must be the path to the image filename, that must be readable by itk. In general, we advocate the use of mhd/raw file format, but other file format can be used. The image must be 3D, with any pixel type (float, int, char, etc).
User must describe how the voxels’s values will be translated into materials. This is done with the patient.voxel_materials parameter that is a simple array of intervals defined by 3 values. The 3 values define an interval to assign a given material, 1) the starting value (included) 2) the ending value (not included) and 3) the material name. For example in the previous code, every voxel value between -900 and -100 will be assigned to the material “Lung”. If there are voxel value outside all the intervals, the default material will be used as defined by patient.material. See for example the test t009.
There is a specific function that can help to automatically create such an array of intervals for conventional Hounsfield Unit of CT images:
gcm3 = gate.g4_units("g/cm3")
f1 = "Schneider2000MaterialsTable.txt"
f2 = "Schneider2000DensitiesTable.txt"
tol = 0.05 * gcm3
patient.voxel_materials, materials = gate.HounsfieldUnit_to_material(tol, f1, f2)
patient.dump_label_image = "labels.mhd"
In that case, the HounsfieldUnit_to_material function will create the array of intervals. It also creates a list of materials. The input parameters for this function are 1) the density tolerance (in g/cm3), 2) a list of reference material and 3) a list of reference densities. Example of such files can be found in opengate/tests/data folder. The option dump_label_image is a help and can be used to write the corresponding labeled image (every voxel value is replaced by the material label). See for example the test t009.
The coordinate system of such image is like for other Geant4’s volumes: by default, the center of the image is positioned at the origin. The embedded origin in the image (like in DICOM or mhd) is not considered here. This is the user responsibility to compute the needed translation/rotation.
Repeated and parameterized volumes¶
Sometimes, it can be convenient to duplicate a volume at different location. This is for example the case in a PET simulation where the crystal, or some parts of the detector, are repeated. This is done thanks to the following:
import opengate as gate
from scipy.spatial.transform import Rotation
cm = gate.g4_units("cm")
crystal = sim.add_volume("Box", "crystal")
crystal.size = [1 * cm, 1 * cm, 1 * cm]
crystal.translation = None
crystal.rotation = None
crystal.material = "LYSO"
m = Rotation.identity().as_matrix()
crystal.repeat = [
{"name": "crystal1", "translation": [1 * cm, 0 * cm, 0], "rotation": m},
{"name": "crystal2", "translation": [0.2 * cm, 2 * cm, 0], "rotation": m},
{"name": "crystal3", "translation": [-0.2 * cm, 4 * cm, 0], "rotation": m},
{"name": "crystal4", "translation": [0, 6 * cm, 0], "rotation": m},
]
In this example, the volume named crystal is duplicated into 4 elements. Each has the same shape (a box), size (1 cm3) and material (LYSO). The array set in crystal.repeat describes for each of the 4 copies, the name of the copy, the translation and the rotation. In this example, only the translation is modified, the rotation is set to the same (identity) matrix. Of course, any rotation matrix can be given to each copy. Note that is is important to explicitly set crystal.translation and crystal.rotation to None as this is only the translation/rotation in the repeat array that will be used. This is a convenient and generic way to declare some repeated objects, but be aware that is somewhat limited to a “not too large” number of repetitions: the Geant4 tracking engine can be slow for a large number of repetitions. In that case, it is better to use parameterised volumes (see below). This is not easy to define what is a “not too large” number ; it seems that few hundreds is ok, but it has to be checked. Note that, if the volume contains sub-volumes, everything will be repeated (in an optimized and efficient way).
There are functions that help to describe a set of repetitions. For example:
crystal.repeat = gate.repeat_array("crystal", [1, 4, 5], [0, 32.85 * mm, 32.85 * mm])
# or
crystal.repeat = gate.repeat_ring("crystal", 190, 18, [391.5 * mm, 0, 0], [0, 0, 1])
Here, the repeat_array function is a helper to generate a 3D grid repetition with the number of repetition along the x, y and z axis is given in the first array [1, 4, 5]: 1 single repetition along x, 4 along y and 5 along z. The offsets are given in the second array: [0, 32.85 * mm, 32.85 * mm], meaning that, e.g., the y repetitions will be separated by 32.85 mm. The output of this function will be a array of dic with name/translation/rotation, like in the generic crystal.repeat of the previous example. The names of the repetitions will be the word “crystal” concatenated with the copy number (such as “crystal_1”, “crystal_2”, etc).
The second helper function repeat_ring generates ring-link repetitions. The first parameter (190) is the starting angle, the second is the number of repetitions (18 here). The third is the initial translation of the first repetition. The fourth is the rotation axis (along Z here). This function will generate the correct array of dic to repeat the volume as a ring. It is for example useful for PET systems. You can look at the pet_philips_vereos.py example in the contrib folder.
In some situations, this repeater concept is not sufficient and can be inefficient when the number of repetitions is large. This is for example the case when describing a collimator for SPECT imaging. Thus, there is an alternative way to describe repetitions by using the so-called “parameterized” volume.
param = sim.add_volume("RepeatParametrised", f"my_param")
param.repeated_volume_name = "crystal"
param.translation = None
param.rotation = None
size = [183, 235, 1]
tr = [2.94449 * mm, 1.7 * mm, 0]
param.linear_repeat = size
param.translation = tr
param.start = [-(x - 1) * y / 2.0 for x, y in zip(size, tr)]
param.offset_nb = 1
param.offset = [0, 0, 0]
TODO
Boolean volumes¶
Examples of complex volumes: Linac, SPECT, PET.¶
See section contrib.