CT and Structure Set#
Patient data in pyRadPlan is represented by two objects: the CT image (ct) and the
structure set (cst). Both are pydantic models that enforce data integrity and expose a
to_matrad() method for interoperability.
Loading patient data#
The most common entry point is load_patient(), which reads a matRad-format
*.mat file and returns a validated (CT, StructureSet) pair:
from importlib import resources
from pyRadPlan import load_patient
tg119_path = resources.files("pyRadPlan.data.phantoms").joinpath("TG119.mat")
ct, cst = load_patient(tg119_path)
The CT object#
CT stores the CT image together with its spatial metadata.
Internally the image is held as a SimpleITK image, which
provides sub-millimetre-accurate coordinate transforms and easy resampling.
Attribute |
Description |
|---|---|
|
|
|
Voxel spacing as |
|
Grid dimensions |
|
World coordinates of the image origin in mm (LPS convention). |
|
Direction cosines matrix (3×3) describing the image axes in world space. |
import numpy as np
print(ct.resolution) # {'x': 3.0, 'y': 3.0, 'z': 3.0}
print(ct.size) # (nx, ny, nz)
hu_array = sitk.GetArrayFromImage(ct.cube_hu) # (nz, ny, nx) NumPy array
The StructureSet object#
StructureSet holds a list of
VOI (Volume of Interest) objects and keeps a reference to the
associated CT image so that spatial queries always use consistent coordinates.
print(len(cst.vois)) # number of structures
for voi in cst.vois:
print(voi.name, voi.voi_type)
Volumes of Interest (VOI)#
Each VOI carries:
Attribute |
Description |
|---|---|
|
Structure name (e.g. |
|
One of |
|
Boolean |
|
Flattened voxel indices (Fortran/column-major order) for efficient sparse lookups. |
|
Linear-quadratic α parameter (Gy⁻¹, default 0.1). Used for biological modelling. |
|
Linear-quadratic β parameter (Gy⁻², default 0.05). |
|
Determines which VOI “wins” in overlapping regions (lower = higher priority). |
|
List of optimization objectives attached to this structure (see Optimization). |
Attaching optimization objectives#
Objectives are stored directly on each VOI and are automatically picked up during optimization. They can be added programmatically:
from pyRadPlan.optimization.objectives import SquaredDeviation, MaxDVH
# Add a squared-deviation objective to the PTV
ptv = next(v for v in cst.vois if v.voi_type == "TARGET")
ptv.objectives.append(
SquaredDeviation(priority=1000, d_ref=60.0, quantity="physical_dose")
)
# Penalize dose above 45 Gy in more than 2% of the spinal cord volume
cord = next(v for v in cst.vois if v.name == "Spinal_Cord")
cord.objectives.append(
MaxDVH(priority=100, d=45.0, v_max=2.0)
)
matRad interoperability#
matrad_ct = ct.to_matrad() # dict with 'cubeHU', 'resolution', etc.
matrad_cst = cst.to_matrad() # cell array compatible with matRad's cst