conrad¶
convex optimization in radiation therapy
Contents:¶
Case¶
Case¶
Medicine¶
Dose Constraints¶
Prescription¶
Define Prescription and methods for parsing prescription data
from python objects as well as JSON- or YAML-formatted files.
Parsing methods expect the following formats.
YAML:
- name : PTV
label : 1
is_target: Yes
dose : 35.
constraints:
- "D90 >= 32.3Gy"
- "D1 <= 1.1rx"
- name : OAR1
label : 2
is_target: No
dose :
constraints:
- "D95 <= 20Gy"
- "V30 Gy <= 20%"
Python list of dict (JSON approximately the same):
[{
"name" : "PTV",
"label" : 1,
"is_target" : True,
"dose" : 35.,
"constraints" : ["D1 <= 1.1rx", "D90 >= 32.3Gy"]
}, {
"name" : "OAR1",
"label" : 2,
"is_target" : False,
"dose" : None,
"constraints" : ["D95 <= 20Gy"]
}]
- JSON verus Python syntax differences:
true/falseinstead ofTrue/Falsenullinstead ofNone
-
class
prescription.Prescription(prescription_data=None)[source]¶ Class for specifying structures with dose targets and constraints.
-
add_structure_to_dictionaries(structure)[source]¶ Add a new structure to internal representation of prescription.
Parameters: structure ( Structure) – Structure added toPrescription.structure_dict. An corresponding, empty constraint list is added toPrescription.constraint_dict.Returns: None Raises: TypeError– Ifstructurenot aStructure.
-
constraints_by_label¶ Dictionary of constraints in prescription, by structure label.
-
dict¶ Dictionary of structures in prescription, by label.
-
digest(prescription_data)[source]¶ Populate
Prescription‘s structures and dose constraints.Specifically, for each entry in
prescription_data, construct aStructureto capture structure data (e.g., name, label), as well as a corresponding but separateConstraintListobject to capture any dose constraints specified for the structure.Add each such structure to
Prescription.structure_dict, and each such constraint list toPrescription.constraint_dict. Build or copy a “list of dictionaries” representation of the prescription data, assign toPrescription.rx_list.Parameters: prescription_data – Input to be parsed for structure and dose constraint data. Accepted formats include strspecifying a valid path to a suitably-formatted JSON or YAML file, or a suitably-formattedlistofdictobjects.Returns: None Raises: TypeError– If input not of typelistor astrspecfying a valid path to file that can be loaded with thejson.load()oryaml.safe_load()methods.
-
list¶ List of structures in prescription
-
report(anatomy)[source]¶ Reports whether
anatomyfulfills all prescribed constraints.Parameters: anatomy ( Antomy) – Container of structures to compare against prescribed constraints.Returns: Dictionary keyed by structure label, with data on each dose constraint associated with that structure in this Prescription. Reported data includes the constraint, whether it was satisfied, and the actual dose achieved at the percentile/threshold specified by the constraint.Return type: dictRaises: TypeError– Ifanatomynot anAnatomy.
-
Anatomy¶
Define Anatomy, container for treatment planning structures.
-
class
anatomy.Anatomy(structures=None)[source]¶ Iterable container class for treatment planning structures.
Provides simple syntax via overloaded operators, including addition, retrieval, and removal of structures from anatomy:
anatomy = Anatomy() # target structure with label = 4 s1 = Structure(4, 'target', True) # non-target structure with label = 12 s2 = Structure(12, 'non-target', False) # non-target structure with label = 7 s3 = Structure(7, 'non-target 2', False) anatomy += s1 anatomy += s2 anatomy += s3 # remove structure s3 by name anatomy -= 'non-target 2' # remove structure s2 by label anatomy -= 12 # retrieve structure s1 by name anatomy[4] anatomy['target']
-
calculate_doses(beam_intensities)[source]¶ Calculate voxel doses to each structure in
Anatomy.Parameters: beam_intensities – Beam intensities to provide to each structure’s Structure.calculate_dose method. Returns: None
-
clear_constraints()[source]¶ Clear all constraints from all structures in
Anatomy.Parameters: None – Returns: None
-
dose_summary_data(percentiles=[2, 98])[source]¶ Collimate dose summaries from each structure in
Anatomy.Parameters: percentiles ( list) – List of percentiles to include in dose summary queries.Returns: Dictionary of dose summaries obtained by calling Structure.summary for each structure. Return type: dict
-
dose_summary_string¶ Collimate dose summary strings from each structure in
Anatomy.Parameters: None – Returns: Dictionary of dose summaries obtained by calling Structure.summary_string for each structure. Return type: dict
-
label_order¶ Ranked list of labels of structures in
Anatomy.Raises: ValueError– If input to setter contains labels for structures not contained in anatomy, or if the length of the input list does not match Anatomy.n_structures.
-
plannable¶ Trueif all structures plannable and at least one is a target.
-
plotting_data(constraints_only=False, maxlength=None)[source]¶ Dictionary of
matplotlib-compatible plotting data for all structures.Parameters: - constraints_only (
bool, optional) – IfTrue, return only the constraints associated with each structure. - maxlength (
int, optional) – If specified, re-sample each structure’s DVH plotting data to have a maximum series length ofmaxlength.
- constraints_only (
-
propagate_doses(voxel_doses)[source]¶ Assign pre-calculated voxel doses to each structure in
AnatomyParameters: voxel_doses ( dict) – Dictionary mapping structure labels to voxel dose subvectors.Returns: None
-
satisfies_prescription(constraint_dict)[source]¶ Check whether anatomy satisfies supplied constraints.
:param
dict: Dictionary ofConstraintListobjects :param keyed by structure labels.:Returns: True if each structure in Return type: int
-
structures¶ Dictionary of structures in anatomy, keyed by label.
Setter method accepts any iterable collection of
Structureobjects.Raises: TypeError– If input to setter is not iterable.ValueError– If input to setter contains elements of a type other thanStructure.
-
Define Structure, building block of Anatomy.
-
structure.W_UNDER_DEFAULT¶ float – Default objective weight for underdose penalty on target structures.
-
structure.W_OVER_DEFAULT¶ float – Default objective weight for underdose penalty on non-target structures.
-
structure.W_NONTARG_DEFAULT¶ float – Default objective weight for overdose penalty on non-target structures.
-
class
structure.Structure(label, name, is_target, size=None, **options)[source]¶ Structuremanages the dose information (including the dose influence matrix, dose calculations and dose volume histogram), as well as optimization objective information—including dose constraints—for a set of voxels (volume elements) in the patient volume to be treated as a logically homogeneous unit with respect to the optimization process.- There are usually three types of structures:
- Anatomical structures, such as a kidney or the spinal
- cord, termed organs-at-risk (OARs),
- Clinically delineated structures, such as a tumor or a target
- volume, and,
- Tissues grouped together by virtue of not being explicitly
- delineated by a clinician, typically lumped together under the catch-all category “body”.
Healthy tissue structures, including OARs and “body”, are treated as non-target, are prescribed zero dose, and only subject to an overdose penalty during optimization.
Target tissue structures are prescribed a non-zero dose, and subject to both an underdose and an overdose penalty.
-
label¶ (
intorstr): Label, applied to each voxel in the structure, usually generated during CT contouring step in the clinical workflow for treatment planning.
-
name¶ str– Clinical or anatomical name.
-
is_target¶ bool–Trueif structure is a target.
-
dvh¶ DVH– Dose volume histogram.
-
constraints¶ ConstraintList– Mutable collection of dose constraints to be applied to structure during optimization.
-
A¶ Alias for
Structure.A_full.
-
A_full¶ Full dose matrix (dimensions = voxels x beams).
- Setter method will perform two additional tasks:
- If
Structure.sizeis not set, set it based on - number of rows in
A_full.
- If
- Trigger
Structure.A_meanto be calculated from Structure.A_full.
- Trigger
Raises: TypeError– IfA_fullis not a matrix innp.ndarray,sp.csc_matrix, orsp.csr_matrixformats.ValueError– IfStructure.sizeis set, and the number of rows inA_fulldoes not matchStructure.size.
-
A_mean¶ Mean dose matrix (dimensions =
1xbeams).Setter expects a one dimensional
np.ndarrayrepresenting the mean dose matrix for the structure. If this optional argument is not provided, the method will attempt to calculate the mean dose fromStructure.A_full.Raises: TypeError– IfA_meanprovided and not of typenp.ndarray, or if mean dose matrix is to be calculated fromStructure.A_full, but full dose matrix is not aconrad-recognized matrix type.ValueError– IfA_meanis not dimensioned as a row or column vector, or number of beams implied byA_meanconflicts with number of beams implied byStructure.A_full.
-
assign_dose(y)[source]¶ Assign dose vector to structure.
Parameters: y – Vector-like input of voxel doses. Returns: None Raises: ValueError– if structure size is known and incompatible with length ofy.
-
boost¶ Adjustment factor from precription dose to optimization dose.
-
calc_y(x)[source]¶ Calculate voxel doses as: attr:Structure.y =
Structure.A*x.Parameters: x – Vector-like input of beam intensities. Returns: None
-
calculate_dose(beam_intensities)[source]¶ Alias for
Structure.calc_y().
-
collapsable¶ Trueif optimization can be performed with mean dose only.
-
constraints_string¶ String of structure header and constraints
-
dose¶ Dose level targeted in structure’s optimization objective.
The dose has two components: the precribed dose,
Structure.dose_rx, and a multiplicative adjustment factor,Structure.boost.Once the structure’s dose has been initialized, setting
Structure.dosewill change the adjustment factor. This is to distinguish (and allow for differences) between the dose level prescribed to a structure by a clinician and the dose level request to a numerical optimization algorithm that yields a desirable distribution, since the latter may require some offset relative to the former. To change the reference dose level, use theStructure.dose_rxsetter.Setter is no-op for non-target structures, since zero dose is prescribed always.
Raises: TypeError– If requested dose does not have units ofDeliveredDose.ValueError– If zero dose is requested to a target structure.
-
dose_rx¶ Prescribed dose level.
Setting this field sets
Structure.doseto the requested value andStructure.boostto1.
-
dose_unit¶ One times the
DeliveredDoseunit of the structure dose.
-
max_dose¶ Maximum dose to structure’s voxels.
-
mean_dose¶ Average dose to structure’s voxels.
-
min_dose¶ Minimum dose to structure’s voxels.
-
objective_string¶ String of structure header and objectives
-
plannable¶ True if structure’s attached data is sufficient for optimization.
- Minimum requirements:
- Structure size determined, and
- Dose matrix assigned, or
- Structure collapsable and mean dose matrix assigned.
-
plotting_data(constraints_only=False, maxlength=None)[source]¶ Dictionary of
matplotlib-compatible plotting data.Data includes DVH curve, constraints, and prescribed dose.
Parameters: - constraints_only (
bool, optional) – IfTrue, return only the constraints associated with the structure. - maxlength (
int, optional) – If specified, re-sample the structure’s DVH plotting data to have a maximum series length ofmaxlength.
- constraints_only (
-
satisfies(constraint)[source]¶ Test whether structure’s voxel doses satisfy
constraint.Parameters: constraint (
Constraint) – Dose constraint to test against structure’s voxel doses.Returns: Trueif structure’s voxel doses conform to the queried constraint.Return type: boolRaises: TypeError– Ifconstraintnot of typeConstraint.ValueError– IfStructure.dvhnot initialized or not populated with dose data.
-
set_constraint(constr_id, threshold=None, relop=None, dose=None)[source]¶ Modify threshold, relop, and dose of an existing constraint.
Parameters: - constr_id (
str) – Key to a constraint inStructure.constraints. - threshold (optional) – Percentile threshold to assign if
queried constraint is of type
PercentileConstraint, no-op otherwise. Must be compatible with the setter method forPercentileConstraint.percentile. - relop (optional) – Inequality constraint sense. Must be
compatible with the setter method for
Constraint.relop. - dose (optional) – Constraint dose. Must be compatible with
setter method for
Constraint.dose.
Returns: None
Raises: ValueError– Ifconstr_idis not the key to a constraint in theConstraintlistlocated atStructure.constraints.- constr_id (
-
size¶ Structure size (i.e., number of voxels in structure).
Raises: ValueError– Ifsizenot anint.
-
summary(percentiles=[2, 25, 75, 98])[source]¶ Dictionary summarizing dose statistics.
Parameters: percentiles ( list, optional) – Percentile levels at which to query the structure dose. If not provided, will query doses at default percentile levels of 2%, 25%, 75% and 98%.Returns: Dictionary of doses at requested percentiles, plus mean, minimum and maximum voxel doses. Return type: dict
-
summary_string¶ String of structure header and dose summary
-
voxel_weights¶ Voxel weights, or relative volumes of voxels.
The voxel weights are the
1vector if the structure volume is regularly discretized, and some other set of integer values if voxels are clustered.Raises: ValueError– IfStructure.voxel_weightssetter called beforeStructure.sizeis defined, or if length of input does not matchStructure.size, or if any of the provided weights are negative.
-
y¶ Vector of structure’s voxel doses.
-
y_mean¶ Value of structure’s mean voxel dose.
Physics¶
Define DoseFrame and Physics classes for treatment
planning.
-
class
physics.DoseFrame(voxels=None, beams=None, data=None, voxel_labels=None, beam_labels=None, voxel_weights=None, beam_weights=None, frame_name=None)[source]¶ Describe a reference frame (voxels x beams) for dosing physics.
A
DoseFrameprovides a description of the mathematical basis of the dosing physics, which usually consists of a matrix in \(\mathbf{R}^{\mbox{voxels} \times \mbox{beams}}\), mapping the space of beam intensities, \(\mathbf{R}^\mbox{beams}\) to the space of doses delivered to each voxel, \(\mathbf{R}^\mbox{voxels}\).For a given plan, we may require conversions between several related representations of the dose matrix. For instance, the beams may in fact be beamlets that can be coalesced into apertures, or—in order to accelerate the treatment plan optimization—may be clustered or sampled. Similarly, voxels may be clustered or sampled. For voxels, there is also a geometric frame, with
X*Y*Zvoxels, where the tuple (X,Y,Z) gives the dimensions of a regularly discretized grid, the so-called dose grid used in Monte Carlo simulations or ray tracing calculations. Since many of the voxels in this rectangular volume necessarily lie outside of the patient volume, there is only some number of voxelsm<X*Y*Zthat are actually relevant to treatment planning.Accordingly, each
DoseFrameis intended to capture one such configuration of beams and voxels, with corresponding data on labels and/or weights attached to the configuration. Voxel labels allow each voxel to be mapped to an anatomical or clinical structure used in planning. The concept of beam labels is defined to allow beams to be gathered in logical groups (e.g. beamlets in fluence maps, or apertures in arcs) that may be constrained jointly or treated as a unit in some other way in an optimization context. Voxel and beam weights are defined for accounting purposes: if aDoseFramerepresents a set of clustered voxels or beams, the associated weights give the number of unitary voxels or beams in each cluster, so that optimization objective terms can be weighted appropriately.-
beam_labels¶ Vector of labels mapping beams to beam groups.
Setter will also use dimension of input vector to set beam dimensions (
DoseFrame.beams) if not already assigned at call time.Raises: ValueError– If provided vector dimensions inconsistent with known frame dimensions.
-
beam_weights¶ Vector of weights assigned to each (meta-)beam.
Setter will also use dimension of input vector to set voxel dimensions (
DoseFrame.beams) if not already assigned at call time.Raises: ValueError– If provided vector dimensions inconsistent with known frame dimensions.
-
beams¶ Number of beams in dose frame.
If
DoseFrame.beam_weightshas not been assigned at call time, the setter will initialize it to the 1 vector.Raises: ValueError– IfDoseFrame.beamsalready determined. Beam dimension is a write-once property.
-
dose_matrix¶ Dose matrix.
Setter will also use dimensions of input matrix to set any dimensions (
DoseFrame.voxelsorDoseFrame.beams) that are not already assigned at call time.Raises: TypeError– If input to setter is not a sparse or dense matrix type recognized byconrad.ValueError– If provided matrix dimensions inconsistent with known frame dimensions.
-
static
indices_by_label(label_vector, label, vector_name)[source]¶ Retrieve indices of vector entries corresponding to a given value.
Parameters: - label_vector – Vector of values to search for entries corresponding
- label – Value to find.
- vector_name (
str) – Name of vector, for use in exception messages.
Returns: Vector of indices at which the entries of
label_vectorare equal tolabel.Return type: ndarrayRaises: ValueError– Iflabel_vectorisNone.KeyError– Iflabelnot found inlabel_vector.
-
plannable¶ True if both dose matrix and voxel label data loaded.
This can be achieved by having a contiguous matrix and a vector of voxel labels indicating the identity of each row of the matrix, or a dictionary of submatrices that map label keys to submatrix values.
-
shape¶ Frame dimensions, \(\{\mathbf{R}^\mbox{voxels} \times \mathbf{R}^\mbox{beams}\}\).
-
voxel_labels¶ Vector of labels mapping voxels to structures.
Setter will also use dimension of input vector to set voxel dimensions (
DoseFrame.voxels) if not already assigned at call time.Raises: ValueError– If provided vector dimensions inconsistent with known frame dimensions.
-
voxel_weights¶ Vector of weights assigned to each (meta-)voxel.
Setter will also use dimension of input vector to set voxel dimensions (
DoseFrame.voxels) if not already assigned at call time.Raises: ValueError– If provided vector dimensions inconsistent with known frame dimensions.
-
voxels¶ Number of voxels in dose frame.
If
DoseFrame.voxel_weightshas not been assigned at call time, the setter will initialize it to the 1 vector.Raises: ValueError– IfDoseFrame.voxelsalready determined. Voxel dimension is a write-once property.
-
-
class
physics.Physics(voxels=None, beams=None, dose_matrix=None, dose_grid=None, voxel_labels=None, **options)[source]¶ Class managing all dose-related information for treatment planning.
A
Physicsinstance includes one or moreDoseFrames, each with attached data including voxel dimensions, beam dimensions, a voxel-to-structure mapping, and a dose influence matrix. The class also provides an interface for adding and switching between frames, and extracting data from the active frame.A
Physicsinstance optionally has an associatedVoxelGridthat represents the dose grid used for dose matrix calculation, and that provides the necessary geometric information for reconstructing and rendering the 3-D dose distribution (or 2-D slices thereof).-
add_dose_frame(key, **frame_args)[source]¶ Add new
DoseFramerepresentation of a dosing configuration.Parameters: Returns: None
Raises: ValueError– Ifkeycorresponds to an existing key in thePhysicsobject’s dictionary of dose frames.
-
beams¶ Number of beams in current
Physics.frame.
-
data_loaded¶ Trueif a client has seen data from the current dose frame.
-
dose_grid¶ Three-dimensional grid.
-
dose_matrix¶ Dose influence matrix for current
Physics.frame.
-
dose_matrix_by_label(voxel_label=None, beam_label=None)[source]¶ Submatrix of dose matrix, filtered by voxel and beam labels.
Parameters: - voxel_label (optional) – Label for which to build/retrieve
submatrix of current
Physics.dose_matrixbased on row indices for whichvoxel_labelmatches the entries ofPhysics.voxel_labels. All rows returned if no label provided. - beam_label (optional) – Label for which to build/retrieve
submatrix of current
Physics.dose_matrixbased on column indices for whichbeam_labelmatches the entries ofPhysics.frame.beam_labels. All columns returned if no label provided.
Returns: Submatrix of dose matrix attached to current
Physics.frame, based on row indices for whichPhysics.frame.voxel_labelsmatches the queriedvoxel_label, and column indices for whichPhysics.frame.beam_labelsmatches the queriedbeam_label.- voxel_label (optional) – Label for which to build/retrieve
submatrix of current
-
plannable¶ True if current frame has both dose matrix and voxel label data
-
voxel_labels¶ Vector mapping voxels to structures in current
Physics.frame.
-
voxels¶ Number of voxels in current
Physics.frame.
-
Optimization¶
Treatment Planning as a Convex Problem¶
Define PlanningProblem, interface between Case
and solvers.
-
class
problem.PlanningProblem[source]¶ Interface between
Caseand convex solvers.Builds and solves specified treatment planning problem using fastest available solver, then extracts solution data and solver metadata (e.g., timing results) for use by clients of the
PlanningProblemobject (e.g., aCase).-
solver_cvxpy¶ SolverCVXPYorNoneType–cvxpy-baed solver, if available.
-
solver_pogs¶ SolverOptkitorNoneType– POGS solver, if available.
-
solve(structures, run_output, slack=True, exact_constraints=False, **options)[source]¶ Run treatment plan optimization.
Parameters: - structures – Iterable collection of
Structureobjects with attached objective, constraint, and dose matrix information. Build convex model of treatment planning problem using these data. - run_output (
RunOutput) – Container for saving solver results. - slack (
bool, optional) – IfTrue, build dose constraints with slack. - exact_constraints (
bool, optional) – IfTrueand at least one structure has a percentile-type dose constraint, execute the two-pass planning algorithm, using convex restrictions of the percentile constraints on the firstpass, and exact versions of the constraints on the second pass. - **options – Abitrary keyword arguments, passed through to
PlanningProblem.solver.init_problem()andPlanningProblem.solver.build().
Returns: Number of feasible solver runs performed:
0if first pass infeasible,1if first pass feasible,2if two-pass method requested and both passes feasible.Return type: intRaises: ValueError– If no solvers avaialable.- structures – Iterable collection of
-
solver¶ Get active solver (CVXPY or OPTKIT/POGS).
-
Convex Solvers¶
Define solver using the cvxpy module, if available.
For np.information on cvxpy, see:
http://www.cvxpy.org/en/latest/
If conrad.defs.module_installed() routine does not find the module
cvxpy, the variable SolverCVXPY is still defined in this
module’s namespace as a lambda returning None with the same method
signature as the initializer for SolverCVXPY. If cvxpy
is found, the class is defined normally.
-
solver_cvxpy.SOLVER_DEFAULT¶ str– Default solver, set to ‘SCS’ if modulescsis installed, otherwise set to ‘ECOS’.
Define POGS-based solver using optkit, if available.
For information on POGS, see: https://foges.github.io/pogs/
For infromation on optkit, see:
https://github.com/bungun/optkit
If conrad.defs.module_installed() does not find the optkit,
the variable SolverOptkit is still defined in the module
namespace as a lambda returning None with the same method signature
as the initializer for SolverOptkit. If optkit is found,
the class is defined normally.
# TODO: change backend switching syntax to check flag .precision_is_64bit instead of current .precision_is_32bit when optkit api updated
CVXPY solver interface¶
-
class
solver_cvxpy.SolverCVXPY(n_beams=None, **options)[source]¶ Interface between
conradandcvxpyoptimization library.SolverCVXPYinterpretsconradtreatment planning problems (based on structures with attached objectives, dose constraints, and dose matrices) to build equivalent convex optimization problems usingcvxpy‘s syntax.The class provides an interface to modify, run, and retrieve solutions from optimization problems that can be executed on a CPU (or GPU, if
scsinstalled with appropriate backend libraries).-
problem¶ cvxpy.Minimize– CVXPY representation of optimization problem.
-
constraint_dual_vars¶ dict– Dictionary, keyed by constraint ID, of dual variables associated with each dose constraint in the CVXPY problem representation. The dual variables’ values are stored here after each optimization run for access by clients of theSolverCVXPYobject.
-
build(structures, exact=False, **options)[source]¶ Update
cvxpyoptimization based on structure data.Extract dose matrix, target doses, and objective weights from structures.
Use doses and weights to add minimization terms to
SolverCVXPY.problem.objective. Use dose constraints to extendSolverCVXPY.problem.constraints.(When constraints include slack variables, a penalty on each slack variable is added to the objective.)
Parameters: structures – Iterable collection of Structureobjects.Returns: String documenting how data in structureswere parsed to form an optimization problem.Return type: str
-
clear()[source]¶ Reset
cvxpyproblem to minimal representation.- The minmal representation consists of:
- An empty objective (Minimize 0),
- A nonnegativity constraint on the vector of beam intensities (\(x \ge 0\)).
- Reset dictionaries of:
- Slack variables (all dose constraints),
- Dual variables (all dose constraints), and
- Slope variables for convex restrictions (percentile dose constraints).
-
get_dual_value(constr_id)[source]¶ Retrieve dual variable for queried constraint.
Parameters: constr_id ( str) – ID of queried constraint.Returns: Noneifconstr_iddoes not correspond to a registered dual variable. Value of dual variable otherwise.
-
get_dvh_slope(constr_id)[source]¶ Retrieve slope variable for queried constraint.
Parameters: constr_id ( str) – ID of queried constraint.Returns: Noneifconstr_iddoes not correspond to a registered slope variable. ‘NaN’ (asnumpy.np.nan) if constraint built as exact. Reciprocal of slope variable otherwise.
-
get_slack_value(constr_id)[source]¶ Retrieve slack variable for queried constraint.
Parameters: constr_id ( str) – ID of queried constraint.Returns: Noneifconstr_iddoes not correspond to a registered slack variable.0if corresponding constraint built without slack. Value of slack variable if constraint built with slack.
-
init_problem(n_beams, use_slack=True, use_2pass=False, **options)[source]¶ Initialize
cvxpyvariables and problem components.Create a
cvxpy.Variableof length-n_beamsto representthe beam intensities. InvokeSolverCVXPY.clear()to build minimal problem.Parameters: - n_beams (
int) – Number of candidate beams in plan. - use_slack (
bool, optional) – IfTrue, next invocation ofSolverCVXPY.build()will build dose constraints with slack variables. - use_2pass (
bool, optional) – IfTrue, next invocation ofSolverCVXPY.build()will build percentile-type dose constraints as exact constraints instead of convex restrictions thereof, assuming other requirements are met. - **options – Arbitrary keyword arguments.
Returns: None
- n_beams (
-
n_beams¶ Number of candidate beams in treatment plan.
-
objective_value¶ Objective value at end of solve.
-
solve(**options)[source]¶ Execute optimization of a previously built planning problem.
Parameters: **options – Keyword arguments specifying solver options, passed to cvxpy.Problem.solve().Returns: Trueifcvxpysolver converged.Return type: boolRaises: ValueError– If specified solver is neither ‘SCS’ nor ‘ECOS’.
-
solveiters¶ Number of solver iterations performed.
-
solvetime¶ Solver run time.
-
status¶ Solver status.
-
x¶ Vector variable of beam intensities, x.
-
x_dual¶ Dual variable corresponding to constraint x >= 0.
-
Define Case, the top level interface for treatment planning.
-
class
case.Case(anatomy=None, physics=None, prescription=None, suppress_rx_constraints=False)[source]¶ Top level interface for treatment planning.
A
Casehas four major components.Case.physicsis of typePhysics, and contains physical information for the case, including the number of voxels, beams, beam layout, voxel labels and dose influence matrix.Case.anatomyis of typeAntomy, and manages the structures in the patient anatomy, including optimization objectives and dose constraints applied to each structure.Case.prescriptionis of typePrescription, and specifies a clinical prescription for the case, including prescribed doses for target structures and prescribed dose constraints (e.g., RTOG recommendations).Case.problemis of typePlanningProblem, and is a tool that forms and manages the mathematical representation of treatment planning problem specified by case anatomy, physics and prescription; it serves as the interface to convex solvers that run the treatment plan optimization.-
A¶ Dose matrix from current planning frame of
Case.physics.
-
add_constraint(structure_label, constraint)[source]¶ Add
constraintto structure specified bystructure_label.Parameters: - structure_label – Must correspond to label or name of a
StructureinCase.anatomy. - constraint (
conrad.medicine.Constraint) – Dose constraint to add to constraint list of specified structure.
Returns: None
- structure_label – Must correspond to label or name of a
-
anatomy¶ Container for all planning structures.
-
calculate_doses(x)[source]¶ Calculate voxel doses for each structure in
Case.anatomy.Parameters: x – Vector-like np.array of beam intensities. Returns: None
-
change_constraint(constr_id, threshold=None, direction=None, dose=None)[source]¶ Modify constraint in
Case.If
constr_idis a valid key to a constraint in theConstraintListattached to one of the structures inCase.anatomy, that constraint will be modified according to the remaining arguments. Call is no-op if key does not exist.Parameters: - constr_id – Key to a constraint on one of the structures in
Case.anatomy. - threshold (optional) – If constraint in question is a
PercentileConstraint, percentile threshold set to this value. No effect otherwise. - direction (
str, optional) – Constraint direction set to this value. Should be one of: ‘<’ or ‘>’. - dose (
DeliveredDose, optional) – Constraint dose level set to this value.
Returns: None
- constr_id – Key to a constraint on one of the structures in
-
change_objective(label, **objective_parameters)[source]¶ Modify objective for structure in
Case.Parameters: - label – Label or name of a
StructureinCase.anatomy. - **options –
Returns: None
- label – Label or name of a
-
clear_constraints()[source]¶ Remove all constraints from all structures in
Case.Parameters: None – Returns: None
-
drop_constraint(constr_id)[source]¶ Remove constraint from case.
If
constr_idis a valid key to a constraint in theConstraintListattached to one of the structures inCase.anatomy, that constraint will be removed from the structure’s constraint list. Call is no-op if key does not exist.Parameters: constr_id – Key to a constraint on one of the structures in Case.anatomy.Returns: None
-
gather_physics_from_anatomy()[source]¶ Gather dose matrices from structures.
Parameters: None – Returns: None Raises: AttributeError– Ifcase.physics.dose_matrixis already set.
-
load_physics_to_anatomy(overwrite=False)[source]¶ Transfer data from physics to each structure.
The label associated with each structure in
Case.anatomyis used to retrieve the dose matrix data and voxel weights fromCase.physicsfor the voxels bearing that label.The method marks the
Case.physics.dose_matrixas seen, in order to prevent redundant data transfers.Parameters: overwrite ( bool, optional) – IfTrue, dose matrix data fromCase.physicswill overwrite dose matrices assigned to each structure inCase.anatomy.Returns: None Raises: ValueError– IfCase.anatomyhas assigned dose matrices,Case.physicsnot marked as having updated dose matrix data, and flagoverwriteset toFalse.
-
n_beams¶ Number of beams in current planning frame of
Case.physics.
-
n_structures¶ Number of structures in
Case.anatomy.
-
n_voxels¶ Number of voxels in current planning frame of
Case.physics.
-
physics¶ Patient anatomy, contains all dose physics information.
-
plan(use_slack=True, use_2pass=False, **options)[source]¶ Invoke numerical solver to optimize plan, given state of
Case.At call time, the objectives, dose constraints, dose matrix, and other relevant data associated with each structure in
Case.anatomyis passed toCase.problemto build and solve a convex optimization problem.Parameters: - use_slack (
bool, optional) – Allow slacks on each dose constraint. - use_2pass (
bool, optional) – Execute two-pass planing method to enforce exact versions, rather than convex restrictions of any percentile-type dose constraints included in the plan. - **options – Arbitrary keyword arguments. Passed through to
Case.problem.solve().
Returns: Tuple with
boolindicator of planning problem feasibility and aRunRecordwith data from the setup, execution and output of the planning run.Return type: tupleRaises: ValueError– If case not plannable due to missing information.- use_slack (
-
plannable¶ Trueif case meets minimum requirements forCase.plan()call.Parameters: None – Returns: Trueif anatomy has one or more target structures and dose matrices from the case physics.Return type: bool
-
plotting_data(x=None, constraints_only=False, maxlength=None)[source]¶ Dictionary of
matplotlib-compatible plotting data.Includes data for dose volume histograms, prescribed doses, and dose volume (percentile) constraints for each structure in
Case.anatomy.Parameters: - x (optional) – Vector of beam intensities from which to calculate structure doses prior to emitting plotting data.
- constraints_only (
bool, optional) – IfTrue, only include each structure’s constraint data in returned dictionary. - maxlength (
int, optional) – If specified, re-sample each structure’s DVH plotting data to have a maximum series length ofmaxlength.
Returns: Plotting data for each structure, keyed by structure label.
Return type: dict
-
prescription¶ Container for clinical goals and limits.
Structure list from prescription used to populate
Case.anatomyif anatomy is empty whenCase.prescriptionsetter is invoked.
-
problem¶ Object managing numerical optimization setup and results.
-
propagate_doses(y)[source]¶ Split voxel dose vector
yinto doses for each structure inCase.anatomy.Parameters: y – Vector-like np.array of voxel doses, or dictionary mapping structure labels to voxel dose subvectors,
-
structures¶ Dictionary of structures contained in
Case.anatomy.
-
transfer_rx_constraints_to_anatomy()[source]¶ Push constraints in prescription onto structures in anatomy.
Assume each structure label represented in
Case.prescriptionis represented inCase.anatomy. Any existing constraints on structures inCase.anatomyare preserved.Parameters: None – Returns: None
-
Treatment Planning Workflow¶
Treatment Planning Workflow¶
Planning History¶
Define classes used to record solver inputs/outputs and maintain a treatment planning history.
-
class
history.PlanningHistory[source]¶ Class for tracking treatment plans generated by a
Case.dict– Dictionary mapping tags of named plans to their respective indices inPlanningHistory.runs
-
last_feasible¶ Solver feasibility flag from most recent treatment plan.
-
last_info¶ Solver info from most recent treatment plan.
-
last_solvetime¶ Solver runtime from most recent treatment plan.
-
last_solvetime_exact¶ Second-pass solver runtime from most recent treatment plan.
-
last_x¶ Vector of beam intensities from most recent treatment plan.
-
last_x_exact¶ Second-pass beam intensities from most recent treatment plan.
-
no_run_check(property_name)[source]¶ Test whether history includes any treatment plans.
Helper method for property getter methods.
Parameters: property_name ( str) – Name to use in error message if exception raised.Returns: None Raises: ValueError– If no treatment plans exist in history, i.e.,PlanningHistory.runshas length zero.
-
tag_last(tag)[source]¶ Tag most recent treatment plan in history.
Parameters: tag – Name to apply to most recently added treatment plan. Plan can then be retrieved with slicing syntax:
# (history is a :class:`PlanningHistory` instance) history[tag]
Returns: None Raises: ValueError– If no treatment plans exist in history.
-
class
history.RunOutput[source]¶ Record of solver outputs associated with a treatment planning run.
-
optimal_variables¶ dict– Dictionary of optimal variables returned by solver. At a minimum, has entries for the beam intensity vectors for the first-pass and second-pass solver runs. May include entries for:- x (beam intensities),
- y (voxel doses),
- mu (dual variable for constraint x>= 0), and
- nu (dual variable for constraint Ax == y).
-
optimal_dvh_slopes¶ dict– Dictionary of optimal slopes associated with the convex restriction of each percentile-type dose constraint. Keyed by constraint ID.
-
solver_info¶ dict– Dictionary of solver information. At a minimum, has entries solver run time (first pass/restricted constraints, and second pass/exact constraints).
-
solvetime¶ Run time for first-pass solve (restricted dose constraints).
-
solvetime_exact¶ Run time for second-pass solve (exact dose constraints).
-
x¶ Optimal beam intensities from first-pass solve.
-
x_exact¶ Optimal beam intensities from second-pass solve.
-
-
class
history.RunProfile(structures=None, use_slack=True, use_2pass=False, gamma='default')[source]¶ Record of solver input associated with a treatment planning run.
-
use_slack¶ bool–Trueif solver allowed to construct convex problem with slack variables for each dose constraint.
-
use_2pass¶ bool–Trueif solver requested to construct and solve two problems, one incorporating convex restrictions of all percentile-type dose constraints, and a second problem formulating exact constraints based on the feasible output of the first solver run.
-
objectives¶ dict– Dictionary of objective data associated with each structure in plan, keyed by structure labels.
-
constraints¶ dict– Dictionary of constraint data for each dose constraint on each structure in plan, keyed by constraint ID.
-
gamma¶ Master scaling applied to slack penalty term in objective when dose constraint slacks allowed.
-
-
class
history.RunRecord(structures=None, use_slack=True, use_2pass=False, gamma='default')[source]¶ -
profile¶ RunProfile– Record of the objective weights, dose constraints, and relevant solver options passed to the convex solver prior to planning.
-
output¶ RunOutput– Output from the solver, including optimal beam intensities, i.e., the treatment plan.
-
plotting_data¶ dict– Dictionary of plotting data from case, with entries corresponding to the first (and potentially only) plan formed by the solver, as well as the exact-constraint version of the same plan, if the two-pass planning method was invoked.
-
feasible¶ Solver feasibility flag from solver output.
-
info¶ Solver information from solver output.
-
nonzero_beam_count¶ Number of active beams in first-pass solution.
-
nonzero_beam_count_exact¶ Number of active beams in second-pass solution.
-
solvetime¶ Run time for first-pass solve (restricted dose constraints).
-
solvetime_exact¶ Run time for second-pass solve (exact dose constraints).
-
x¶ Optimal beam intensitites from first-pass solution.
-
x_exact¶ Optimal beam intensitites from second-pass solution.
-
x_pass1¶ Alias for
RunRecord.x.
-
x_pass2¶ Alias for
RunRecord.x_exact.
-
Visualization¶
Dose volume histogram plotting utilities.
Provides CasePlotter for conveniently
plotting DVH curve data generated by calling Case.plan().
If matplotlib is available, plotting types such as
CasePlotter types are defined normally.
This switch allows conrad to install, load and operate without
Python plotting capabilities, and exempts matplotlib from being
a load-time requirement.