cerr.imrtp package
IMRT planning (IMRTP): beamlet/influence-matrix dose calculation and a PyQt5
planning GUI that displays the optimized dose and beam geometry through the
cerr.viewer.pycerr_gui desktop viewer.
Subpackages
- cerr.imrtp.dosecalc package
- Submodules
- cerr.imrtp.dosecalc.influence module
- cerr.imrtp.dosecalc.montecarlo module
- montecarlo
MC_SOLVER_DPMMCRecompParamsMCRecompParams.leakMCRecompParams.spectrum_FileMCRecompParams.nhistMCRecompParams.batchMCRecompParams.OutputErrorMCRecompParams.PBMaxWidthMCRecompParams.gradsenseMCRecompParams.MCsolverMCRecompParams.saveIMMCRecompParams.sourceModelMCRecompParams.doseToWaterMCRecompParams.fillWaterMCRecompParams.useWedgeMCRecompParams.inputPBMCRecompParams.inputIMMCRecompParams.SofteningMCRecompParams.UseFlatFilterMCRecompParams.MLCMCRecompParams.TongueGrooveMCRecompParams.interactiveModeMCRecompParams.LS_flagMCRecompParams.KMCRecompParams.scatterThreshold
beam2MCdose()calcDoseByBeamMeterset()dpmEngine()vmcEngine()
- cerr.imrtp.dosecalc.qib module
- cerr.imrtp.dosecalc.qib_data module
- cerr.imrtp.dosecalc.raytrace module
- cerr.imrtp.dosecalc.recalc module
- cerr.imrtp.dosecalc.rtplan module
- Module contents
- cerr.imrtp.dosecalc
QIBDataSloadPBData()getQIBDose()getPBConsts()applyIMRTCompression()rtogVectors2Gantry()gantry2RTOGVectors()ScanGridgetTargetSurfacePoints()getPBRays()getPBRayData()setBeamRayData()CTTracegenerateQIBInfluence()getIMDose()MCRecompParamsMCRecompParams.leakMCRecompParams.spectrum_FileMCRecompParams.nhistMCRecompParams.batchMCRecompParams.OutputErrorMCRecompParams.PBMaxWidthMCRecompParams.gradsenseMCRecompParams.MCsolverMCRecompParams.saveIMMCRecompParams.sourceModelMCRecompParams.doseToWaterMCRecompParams.fillWaterMCRecompParams.useWedgeMCRecompParams.inputPBMCRecompParams.inputIMMCRecompParams.SofteningMCRecompParams.UseFlatFilterMCRecompParams.MLCMCRecompParams.TongueGrooveMCRecompParams.interactiveModeMCRecompParams.LS_flagMCRecompParams.KMCRecompParams.scatterThreshold
beam2MCdose()calcDoseByBeamMeterset()recalcDose()structDoseMetric()qibEngine()imFromRTPlan()beamsFromRTPlan()dcmIsocenterToCerr()
Submodules
cerr.imrtp.imrtp module
imrtp
Driver for IMRT beamlet/dose computation in pyCERR; the role played by
IMRTP.m + dose2CERR.m in Matlab CERR.
Matlab CERR shipped three dose engines (QIB, VMC++, DPM) that rely on large external data files / executables and have not been ported to Python. This module therefore exposes a small engine registry: any callable with the signature
doseArray = engine(im, planC, statusCallback)
can be registered under a name and selected through the GUI’s
IM Parameters > algorithm field. A simple, self-contained
'PB-Demo' divergent pencil-beam engine is provided so that the GUI is
testable end-to-end; it is for geometry/QA demonstration only and is not
dosimetrically validated.
This file is part of pyCERR and is distributed under the terms of the Lesser GNU Public License (same terms as CERR).
- cerr.imrtp.imrtp.registerEngine(name: str, fn: Callable)[source]
Register a dose engine:
fn(im, planC, statusCallback) -> dose3M.dose3Mmust be a numpy array on the associated scan grid (rows x cols x slices), in Gy or arbitrary units.
- cerr.imrtp.imrtp.availableEngines()[source]
Names of registered dose engines (analog of VMCPresent/QIBPresent).
- cerr.imrtp.imrtp.runIMRTP(im: IMRTProblem, planC, statusCallback: Callable[[str, float], None] | None = None)[source]
Compute dose for all beams of
imusing the selected engine (port ofIMRTP.m’s top-level flow).- Returns:
total dose on the scan grid (rows x cols x slices).
- Return type:
np.ndarray
- cerr.imrtp.imrtp.doseToPlanC(dose3M: ndarray, im: IMRTProblem, planC, fractionGroupID: str | None = None) int[source]
Insert a computed dose into planC (port of
dose2CERR.m).Returns the new dose index.
cerr.imrtp.imrtp_gui module
imrtp_gui
pyCERR IMRTP GUI - a Qt port of Matlab CERR’s IMRTP/IMRTPGui.m.
Create a GUI to set up IM (intensity-modulated) beam/structure problems and calculate beamlet dose.
- Usage:
>>> from cerr import plan_container as pc >>> from cerr.imrtp import imrtp_gui >>> planC = pc.loadDcmDir(r'path/to/dicom') >>> imrtp_gui.IMRTPGui(planC) # blocks until window closed
or, inside an existing Qt event loop (e.g. napari console): >>> gui = imrtp_gui.IMRTPGui(planC, block=False)
- Panels (mirroring IMRTPGui.m):
Beams beam list, BEV check, New / Equispaced / Delete Geometry Preview axial CT at isocenter with draggable gantry lines Select Scan associated-scan picker Structures goal list: isTarg / marg / sampRate / remove Beam Parameters per-beam fields with auto-calculation checkboxes IM Parameters dose-engine parameters (algorithm, DoseTerm, …) VMC Parameters Monte-Carlo parameters IM Dosimetry set browse / delete / rename stored IM sets File Recompute/Copy/Overwrite/Revert actions, Go/Show/Exit Status status text + progress bar
Original Matlab author: JRA 4/30/04; JJW 07/05/06; APA 10/16/06. This file is part of pyCERR and is distributed under the terms of the Lesser GNU Public License (same terms as CERR).
- class cerr.imrtp.imrtp_gui.GeometryPreview(*args: Any, **kwargs: Any)[source]
Bases:
FigureCanvasQTAggAxial CT thumbnail with a 100 cm gantry circle and draggable beam lines; dragging the mouse sets the current beam’s gantry angle.
- angleChanged
int = …, arguments: Sequence = …) -> PYQT_SIGNAL
types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.
- Type:
pyqtSignal(*types, name
- Type:
str = …, revision
- dragFinished
int = …, arguments: Sequence = …) -> PYQT_SIGNAL
types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.
- Type:
pyqtSignal(*types, name
- Type:
str = …, revision
- cerr.imrtp.imrtp_gui.beamGeometry(beam, im, planC)[source]
Compute a beam’s display geometry in world coords (cm, pyCERR virtual):
polylines- the divergent field pyramid edges, the iso/exit field rectangles and the central axis (used for the 3D view);apexandcorners- the pyramid source point and 4 far field corners (used to compute the per-slice beam cross-section in the 2D views).Mirrors Matlab CERR’s beam’s-eye-view geometry: gantry in the axial plane (couch 0), source at SAD from the isocenter.
- cerr.imrtp.imrtp_gui.beamPolylines(beam, im, planC)[source]
Backward-compatible: just the polylines of
beamGeometry().
- class cerr.imrtp.imrtp_gui.IMRTPGuiWindow(planC, im=None, saveIndex=None, parent=None, viewer=None)[source]
Bases:
QMainWindow
- cerr.imrtp.imrtp_gui.IMRTPGui(planC, im=None, saveIndex=None, block=True, viewer=None)[source]
Open the IMRTP GUI for
planC.- Parameters:
planC – pyCERR plan container with at least one scan loaded.
im – optional existing
IMRTProblemto edit (analog ofIMRTPGui('init', IM, index)in Matlab).saveIndex – index of
imwithinplanC.imwhen editing a stored set.block – when True (script usage) run the Qt event loop until the window is closed; when False (napari / IPython with an active event loop) just show the window and return it.
viewer – optional
PyCerrViewerto show the computed dose and the beam’s-eye-view overlays in (instead of opening napari).
- Returns:
the window instance.
- Return type:
cerr.imrtp.imrtp_problem module
imrtp_problem
Python port of CERR’s IMRTP/initIMRTProblem.m data structures for pyCERR.
Defines the IMRT problem container (IMRTProblem) together with its
beam (IMBeam), goal (IMGoal), solution and parameter
sub-structures, mirroring the Matlab IM struct used by IMRTPGui.m.
Coordinates are in pyCERR’s virtual coordinate system (cm), consistent with
planC.scan[scanNum].getScanXYZVals().
- Based on:
https://github.com/cerr/CERR/blob/master/IMRTP/initIMRTProblem.m https://github.com/cerr/CERR/blob/master/IMRTP/IMRTPGui.m
This file is part of pyCERR and is distributed under the terms of the Lesser GNU Public License (same terms as CERR).
- cerr.imrtp.imrtp_problem.BEAM_FIELD_NAMES = [('beamNum',), ('beamModality',), ('beamEnergy',), ('isocenter', 'x'), ('isocenter', 'y'), ('isocenter', 'z'), ('isodistance',), ('arcAngle',), ('couchAngle',), ('collimatorAngle',), ('gantryAngle',), ('beamDescription',), ('beamletDelta_x',), ('beamletDelta_y',), ('dateOfCreation',), ('beamType',), ('zRel',), ('xRel',), ('yRel',), ('sigma_100',)]
Beam-parameter fields shown in the “Beam Parameters” panel. Nested fields (isocenter.x etc.) are expressed as tuples.
- cerr.imrtp.imrtp_problem.BEAM_FIELD_EDITABLE = [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1]
1 -> user editable, 0 -> auto-computed (checkbox toggles auto calculation)
- cerr.imrtp.imrtp_problem.PARAM_NAMES = [('algorithm',), ('DoseTerm',), ('ScatterMethod',), ('Scatter', 'Threshold'), ('Scatter', 'RandomStep'), ('xyDownsampleIndex',), ('numCTSamplePts',), ('cutoffDistance',)]
QIB / DPM pencil-beam dose-calculation parameters
- cerr.imrtp.imrtp_problem.MC_PARAM_NAMES = [('NumParticles',), ('NumBatches',), ('scoreDoseToWater',), ('includeError',), ('monoEnergy',), ('spectrum',), ('repeatHistory',), ('splitPhotons',), ('photonSplitFactor',), ('base',), ('dimension',), ('skip',)]
VMC++ Monte-Carlo parameters
- cerr.imrtp.imrtp_problem.GOAL_FIELDS = ['structNum', 'strUID', 'structName', 'isTarget', 'PBMargin', 'xySampleRate']
Goal (structure) fields
- class cerr.imrtp.imrtp_problem.Isocenter(x: float | str = 'COM', y: float | str = 'COM', z: float | str = 'COM')[source]
Bases:
objectBeam isocenter. Any coordinate may be the string
'COM'meaning “auto-compute from the center-of-mass of the target structures”.- x: float | str = 'COM'
- y: float | str = 'COM'
- z: float | str = 'COM'
- class cerr.imrtp.imrtp_problem.Beamlet(structureName: str = '', format: str = 'uint8', influence: ndarray | None = None, beamNum: int = 0, fullLength: int = 0, indexV: ndarray | None = None, maxInfluenceVal: float = 0.0, lowDosePoints: ndarray | None = None, sampleRate: int = 1, strUID: str = '')[source]
Bases:
objectSparse per-structure beamlet influence record.
One Beamlet instance corresponds to (structure i, pencil-beam j) and holds the non-zero dose contributions of that pencil beam to that structure, in the compressed format used by Matlab CERR.
- structureName: str = ''
- format: str = 'uint8'
- influence: ndarray | None = None
- beamNum: int = 0
- fullLength: int = 0
- indexV: ndarray | None = None
- maxInfluenceVal: float = 0.0
- lowDosePoints: ndarray | None = None
- sampleRate: int = 1
- strUID: str = ''
- class cerr.imrtp.imrtp_problem.IMBeam(beamNum: int = 1, beamModality: str = 'photons', beamEnergy: float = 18, isocenter: Isocenter = <factory>, isodistance: float = 100.0, arcAngle: float = 0.0, couchAngle: float = 0.0, collimatorAngle: float = 0.0, gantryAngle: float = 0.0, beamDescription: str = 'IMRT beam', beamletDelta_x: float = 1.0, beamletDelta_y: float = 1.0, dateOfCreation: str = <factory>, beamType: str = 'IM', zRel: float = 0.0, xRel: float = 0.0, yRel: float = 0.0, sigma_100: float = 0.4, beamUID: str = <factory>, beamlets: list = <factory>, RTOGPBVectorsM: ndarray | None = None, xPBPosV: ndarray | None = None, yPBPosV: ndarray | None = None)[source]
Bases:
objectOne IMRT beam; port of
IM.beamsin initIMRTProblem.m.- beamNum: int = 1
- beamModality: str = 'photons'
- beamEnergy: float = 18
- isodistance: float = 100.0
- arcAngle: float = 0.0
- couchAngle: float = 0.0
- collimatorAngle: float = 0.0
- gantryAngle: float = 0.0
- beamDescription: str = 'IMRT beam'
- beamletDelta_x: float = 1.0
- beamletDelta_y: float = 1.0
- dateOfCreation: str
- beamType: str = 'IM'
- zRel: float = 0.0
- xRel: float = 0.0
- yRel: float = 0.0
- sigma_100: float = 0.4
- beamUID: str
- beamlets: list
- RTOGPBVectorsM: ndarray | None = None
- xPBPosV: ndarray | None = None
- yPBPosV: ndarray | None = None
- class cerr.imrtp.imrtp_problem.IMGoal(structNum: int = 1, strUID: str = '', structName: str = '', isTarget: str = 'no', PBMargin: float = 0.0, xySampleRate: int = 2)[source]
Bases:
objectOne structure entry (“goal”); port of
IM.goals.- structNum: int = 1
- strUID: str = ''
- structName: str = ''
- isTarget: str = 'no'
- PBMargin: float = 0.0
- xySampleRate: int = 2
- class cerr.imrtp.imrtp_problem.ScatterParams(Threshold: 'float' = 0.01, RandomStep: 'float' = 30)[source]
Bases:
object- Threshold: float = 0.01
- RandomStep: float = 30
- class cerr.imrtp.imrtp_problem.VMCParams(NumParticles: 'int' = 50000, NumBatches: 'int' = 10, scoreDoseToWater: 'str' = 'Yes', includeError: 'str' = 'No', monoEnergy: 'Optional[float]' = None, spectrum: 'str' = '', repeatHistory: 'float' = 0.251, splitPhotons: 'str' = 'Yes', photonSplitFactor: 'int' = -40, base: 'int' = 2, dimension: 'int' = 60, skip: 'int' = 1)[source]
Bases:
object- NumParticles: int = 50000
- NumBatches: int = 10
- scoreDoseToWater: str = 'Yes'
- includeError: str = 'No'
- monoEnergy: float | None = None
- spectrum: str = ''
- repeatHistory: float = 0.251
- splitPhotons: str = 'Yes'
- photonSplitFactor: int = -40
- base: int = 2
- dimension: int = 60
- skip: int = 1
- class cerr.imrtp.imrtp_problem.IMParams(algorithm: str = 'QIB', DoseTerm: str = 'GaussPrimary+scatter', ScatterMethod: str = 'exponential', Scatter: ScatterParams = <factory>, xyDownsampleIndex: int = 1, numCTSamplePts: int = 300, cutoffDistance: float = 4, VMC: VMCParams = <factory>)[source]
Bases:
objectDose-calculation parameters; port of
IM.params.- algorithm: str = 'QIB'
- DoseTerm: str = 'GaussPrimary+scatter'
- ScatterMethod: str = 'exponential'
- Scatter: ScatterParams
- xyDownsampleIndex: int = 1
- numCTSamplePts: int = 300
- cutoffDistance: float = 4
- class cerr.imrtp.imrtp_problem.IMSolution(beamletWeights: ndarray | None = None, doseScale: float = 1.0, doseArray: ndarray | None = None, solutionDescription: str = '')[source]
Bases:
objectOptimization output placeholder; port of
IM.solutions.- beamletWeights: ndarray | None = None
- doseScale: float = 1.0
- doseArray: ndarray | None = None
- solutionDescription: str = ''
- class cerr.imrtp.imrtp_problem.IMRTProblem(name: str = 'IM doseSet 1', beams: List[IMBeam] = <factory>, goals: List[IMGoal] = <factory>, params: IMParams = <factory>, solutions: List[IMSolution] = <factory>, assocScanUID: str = '', isFresh: bool = True, IMUID: str = <factory>)[source]
Bases:
objectThe IM problem container; port of the Matlab
IMstruct.- name: str = 'IM doseSet 1'
- solutions: List[IMSolution]
- assocScanUID: str = ''
- isFresh: bool = True
- IMUID: str
- cerr.imrtp.imrtp_problem.initIMRTProblem(planC=None) IMRTProblem[source]
Create a fresh, empty IMRT problem (port of
initIMRTProblem.m).- Parameters:
planC – optional pyCERR plan container. When given, the problem is associated with the first scan and named
IM doseSet n+1.
- cerr.imrtp.imrtp_problem.createDefaultBeam(beamNum: int, planC=None, scanNum: int = 0) IMBeam[source]
Create a beam populated with GUI defaults (port of createDefaultBeam).
- cerr.imrtp.imrtp_problem.resolveIsocenter(beam: IMBeam, im: IMRTProblem, planC) Isocenter[source]
Resolve ‘COM’ isocenter coordinates from the targets’ center of mass.
- cerr.imrtp.imrtp_problem.conditionBeam(beam: IMBeam, im: IMRTProblem, planC, autoFields=None) IMBeam[source]
Fill in auto-computed beam fields (port of
conditionBeam).Auto fields (when enabled): beamNum is left as set by the caller, isocenter is resolved from target COM, dateOfCreation refreshed, and the relative source position is derived from the gantry angle:
xRel = isodistance * sin(gantry) yRel = isodistance * cos(gantry) zRel = 0
- cerr.imrtp.imrtp_problem.addEquispacedBeams(im: IMRTProblem, numBeams: int, startAngle: float, planC=None, templateBeam: IMBeam | None = None)[source]
Add
numBeamsequispaced beams starting atstartAngledegrees (port of the ‘NEWEQUISPACED’ GUI command).
- cerr.imrtp.imrtp_problem.addGoal(im: IMRTProblem, relStrNum: int, planC) IMGoal[source]
Append a goal for the relStrNum-th structure (0-based, relative to the structures associated with
im.assocScanUID); port of ‘ADDGOAL’.
- cerr.imrtp.imrtp_problem.getIMList(planC) list[source]
Return the list of IM problems stored on the plan container, creating it if necessary (pyCERR’s PlanC has no native
imattribute yet).
- cerr.imrtp.imrtp_problem.saveIMToPlan(im: IMRTProblem, planC, index: int | None = None) int[source]
Store
imon planC; append when index is None, else overwrite.Returns the (0-based) index at which the problem was stored.
- cerr.imrtp.imrtp_problem.asDict(im: IMRTProblem) dict[source]
JSON/pickle-friendly representation of the problem.
Module contents
cerr.imrtp
IMRT planning (IMRTP) module for pyCERR - Python port of Matlab CERR’s
IMRTP directory (IMRTPGui.m, initIMRTProblem.m et al.).
Quick start:
from cerr import plan_container as pc
from cerr.imrtp import IMRTPGui
planC = pc.loadDcmDir(r'C:/data/myPlan')
IMRTPGui(planC)
After pressing Go with a Recompute action selected, the resulting dose
is appended to planC.dose and the IM problem is stored on planC.im.
Dose engines: the QIB photon pencil-beam algorithm is ported in
cerr.imrtp.dosecalc (with DPM / VMC++ Monte-Carlo placeholders) and
registered automatically. Register additional engines with
cerr.imrtp.imrtp.registerEngine(); a self-contained 'PB-Demo'
engine is included for end-to-end testing.