Examples

Code snippets demonstrating PyTRiP capabilities.

Example 00 - Cube arithmetic

This example demonstrates simple arithmetic on dose- and LET-cubes. Two dose cubes from two fields are summed to generate a new total dose cube.

The two LET-cubes from the two fields are combined to calculate the total dose-averaged LET in the resulting treatment plan. All data are saved to disk.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""
Simple example of how to do arithmetic on Cube objects in PyTRiP.
"""
import pytrip as pt

# sum two dose cubes, write result:
print("Two half boxes: out.dos")
d1 = pt.DosCube()
d2 = pt.DosCube()
d1.read("box052000.dos")
d2.read("box053000.dos")
d = (d1 + d2)
d.write("out.dos")

# print minium and maximum value found in cubes
print(d1.cube.min(), d1.cube.max())
print(d2.cube.min(), d2.cube.max())

# calculate new dose average LET cube
l1 = pt.LETCube()
l2 = pt.LETCube()
l1.read("box052000.dosemlet.dos")
l2.read("box053000.dosemlet.dos")

let = ((d1 * l1) + (d2 * l2)) / (d1 + d2)
let.write("out.dosemlet.dos")

Example 01 - Handling structures

This example shows how one can select a region inside a CTX data cube using a VDX file, and perform some manipulation of it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""
This example shows how to use contours to select volume of interests inside a CTX cube. The VOI is then manipulated.
"""

import logging
import pytrip as pt

# by default logging in PyTRiP98 is disabled, here we enable it to see it with basic INFO level
logging.basicConfig(level=logging.DEBUG)

# first define some paths and other important parameters
ctx_path = "/home/bassler/Projects/CTdata/TST000/TST000000.ctx"
vdx_path = "/home/bassler/Projects/CTdata/TST000/TST000000.vdx"
my_target_voi = "GTV"

# load CT cube
my_ctx = pt.CtxCube()
my_ctx.read(ctx_path)

# load VOIs
my_vdx = pt.VdxCube(my_ctx)  # my_vdx is the object which will hold all volumes of interest and the meta information
my_vdx.read(vdx_path)  # load the .vdx file
print(my_vdx.voi_names())  # show us all VOIs found in the .vdx file

# Select the requested VOI from the VdxCube object
target_voi = my_vdx.get_voi_by_name(my_target_voi)

# get_voi_cube() returns a DosCube() object, where all voxels inside the VOI holds the value 1000, and 0 elsewhere.
voi_cube = target_voi.get_voi_cube()

# Based on the retrieved DosCube() we calculate a three dimensional mask object,
# which assigns True to all voxels inside the Voi, and False elsewhere.
mask = (voi_cube.cube == 1000)

# "The mask object and the CTX cube have same dimensions (they are infact inherited from the same top level class).
# Therefore we can apply the mask cube to the ctx cube and work with the values.
# For instance we can set all HUs to zero within the Voi:
my_ctx.cube[mask] = 0
# or add 100 to all HUs of the voxels inside the mask:
# my_ctx.cube[mask] += 100

# save masked CT to the file in current directory
masked_ctx = "masked.ctx"
my_ctx.write(masked_ctx)

Working with dose cubes is fully analogous to the CTX cubes.

Example 02 - TRiP execution

In this example, we demonstrate how to actually perform a treatment plan using TRiP98. Most of the lines concern with the setup of TRiP.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
"""
This example demonstrates how to load a CT cube in Voxelplan format, and the associated contours.
Then a plan is prepared and optimized using TRiP98.
"""
import os
import logging

import pytrip as pt
import pytrip.tripexecuter as pte

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)  # give some output on what is going on.

# Please adjust these paths according to location of the patient data (CT and contouring) and TRiP98 installation.
# Fist we specify the directory where all our files are:
wdir = "/home/user/workspace"  # working dir must exist.
patient_dir = "/home/user/data/yoda"
trip_path = "/home/user/usr/trip98"

# In TRiP, the patient "TST000" would typically carry the filename "TST000000"
patient_name = "TST000000"

# so we can construc the paths to the CTX and VDX files like this:
ctx_path = os.path.join(patient_dir, patient_name + ".ctx")
vdx_path = os.path.join(patient_dir, patient_name + ".vdx")

# Next we load the CT cube:
c = pt.CtxCube()
c.read(ctx_path)

# And load the contours
v = pt.VdxCube(c)
v.read(vdx_path)

# we may print all contours found in the Vdx file, if we want to
print(v.voi_names())

# We need to specify where the kernel files can be found. The location may depend on the ion we
# want to treat with. This example sets up a kernel model for C-12 ions with a 3 mm Ripple Filter.
mykernel = pte.KernelModel()
mykernel.projectile = pte.Projectile("C", a=12)
mykernel.ddd_path = trip_path + "/DATA/DDD/12C/RF3MM/*"
mykernel.spc_path = trip_path + "/DATA/SPC/12C/RF3MM/*"
mykernel.sis_path = trip_path + "/DATA/SIS/19981218.sis"
mykernel.rifi_thickness = 3.0  # 3 mm ripple filter. (Only for documentaiton, will not affect dose optimization.)
mykernel.rifi_name = "GSI_1D_3mm"  # Additional free text for documentation.
mykernel.comment = "Carbon-12 ions with 3 mm 1D Ripple Filter"

# Ok, we have the Contours, the CT cube and dose kernels ready. Next we must prepare a plan.
# We may choose any basename for the patient. All output files will be named using
# this basename.
plan = pte.Plan(basename=patient_name, default_kernel=mykernel)

# Plan specific data:
plan.hlut_path = trip_path + "/DATA/HLUT/19990218.hlut"  # Hounsfield lookup table location
plan.dedx_path = trip_path + "/DATA/DEDX/20000830.dedx"  # Stopping power tables
plan.working_dir = wdir

# Set the plan target to the voi called "CTV"
plan.voi_target = v.get_voi_by_name('CTV')

# some optional plan specific parameters (if not set, they will all be zero by default)
plan.bolus = 0.0  # No bolus is applied here. Set this to some value, if you are to optimize very shallow tumours.
plan.offh2o = 1.873  # Some offset mimicing the monitoring ionization chambers and exit window of the beam nozzle.

# Next we need to specify at least one field, and add that field to the plan.
field = pte.Field(kernel=mykernel)  # The ion speicies is selected by passing the corresponding kernel to the field.
field.basename = patient_name  # This name will be used for output filenames, if any field specific output is saved.
field.gantry = 10.0  # degrees
field.couch = 90.0  # degrees
field.fwhm = 4.0  # spot size in [mm]

print(field)  # We can print all parameters of this field, for checking.
plan.fields.append(field)  # attach field to plan. You may attach multiple fields.

# Next, set the flags for what output should be generated, when the plan has completed.
plan.want_phys_dose = True  # We want a physical dose cube, "TST000000.dos"
plan.want_bio_dose = False  # No biological cube (Dose * RBE)
plan.want_dlet = True  # We want to have the dose-averaged LET cube
plan.want_rst = False  # Print the raster scan files (.rst) for all fields.

# print(plan)  # this will print all plan parameters

te = pte.Execute(c, v)  # get the executer object, based on the given Ctx and Vdx cube.

# in the case that TRiP98 is not installed locally, you may have to enable remote execution:
# te.remote = True
# te.servername = "titan.phys.au.dk"
# te.username = "bassler"
# te.password = "xxxxxxxx"  # you can set a password, but this is strongly discouraged. Better to exchange SSH keys!
# te.remote_base_dir = "/home/bassler/test"
#
# Depending on the remote .bashrc_profile setup, it may be needed to specify the full path
# for the remote TRiP installation. On some systems the $PATH is set, so this line can be omitted,
# or shortened to just "TRiP98" :
# te.trip_bin_path = trip_path + "/bin/TRiP98"

te.execute(plan)  # this will run TRiP
# te.execute(plan, False)  # set to False, if TRiP98 should not be executed. Good for testing.

# requested results can be found in
# plan.dosecubes[]
# and
# plan.letcubes[]
# and they are also saved to working_dir