E.g. CTV high, CTV elective, CTV intermediate etc.
Hi,
Yes it is possible to work with multiple CTVs.
For example, to set up contours and optimization objectives with two CTVs, a possible way could be:
ctImagePath = r"/auto/globalscratch/users/b/r/brober/Arcpt/Patients/HAN_02_05"
dataList = readData(ctImagePath, maxDepth=0)
ct = dataList[-1]
contours = dataList[-2]
# 1st CTV
CTVp_7000 = contours.getContourByName('CTVp_7000')
CTVp_7000_Mask = CTVp_7000.getBinaryMask(origin=ct.origin, gridSize=ct.gridSize, spacing=ct.spacing)
# 2nd CTV
CTVn_5400 = contours.getContourByName('CTVn_5400')
CTVn_5400_Mask = CTVn_5400.getBinaryMask(origin=ct.origin, gridSize=ct.gridSize, spacing=ct.spacing)
CTV_all_Mask = CTVp_7000.getBinaryMask(origin=ct.origin, gridSize=ct.gridSize, spacing=ct.spacing)
CTV_all_Mask.imageArray=np.logical_or(CTV_all_Mask.imageArray, CTVn_5400_Mask.imageArray)
.
.
.
planDesign = PlanDesign()
planDesign.ct = ct
planDesign.targetMask = CTV_all_Mask
.
.
.
plan = planDesign.buildPlan() # Spot placement
#----
beamlets = mc2.computeBeamlets(ct, plan) # If computation needed
#----
plan.planDesign.beamlets = beamlets
#Optimization objectives
plan.planDesign.objectives = ObjectivesList()
plan.planDesign.objectives.setTarget(CTVp_7000.name, 70)
plan.planDesign.objectives.targetMask = plan.planDesign.targetMask
plan.planDesign.objectives.fidObjList = []
plan.planDesign.objectives.addFidObjective(CTVp_7000_Mask, FidObjective.Metrics.DMIN, 70, 100) #dose prescription: 70Gy
plan.planDesign.objectives.addFidObjective(CTVp_7000_Mask, FidObjective.Metrics.DMAX, 70, 100)
plan.planDesign.objectives.addFidObjective(CTVn_5400_Mask, FidObjective.Metrics.DMAX, 54.25, 100)
plan.planDesign.objectives.addFidObjective(CTVn_5400_Mask, FidObjective.Metrics.DMIN, 54.25, 100) #dose prescription: 54.25Gy
solver = IMPTPlanOptimizer(method='Scipy-LBFGS', plan=plan, maxit=500)
doseImage, ps = solver.optimize()
Tell us if you need any further details.
Best,
Benjamin
Thank you so much Benjamin
@Broberfroid. could you also explain/ include a snippet to demonstrate how you make sure that the dose deposition matrices are calculated also for a given set of robustness scenarios?
Sure,
when defining your planDesign you can specify your treatment uncertainties like this:
planDesign.robustness.setupSystematicError = [4.0, 4.0, 4.0] # mm
planDesign.robustness.setupRandomError = [0.0, 0.0, 0.0] # mm (sigma)
planDesign.robustness.rangeSystematicError = 2.6 # %
planDesign.robustness.selectionStrategy = planDesign.robustness.Strategies.ERRORSPACE_REGULAR
Then, you can compute your beamlets for the different robust scenarios like this:
nominal, scenarios = mc2.computeRobustScenarioBeamlets(ct, plan, roi=[roi], storePath=output_path) #dose will be cropped at roi, use it carefully to save disk space
plan.planDesign.beamlets = nominal
plan.planDesign.robustness.scenarios = scenarios
plan.planDesign.robustness.numScenarios = len(scenarios)
If you have already computed the different robust beamlets, don’t hesitate to use the loadBeamlets function to load them directly.
from opentps.core.io.serializedObjectIO import loadBeamlets
from glob import glob
scenarios=[]
scenarios_list=glob(os.path.join(output_path, "*Scenario_*"))
for i,j in enumerate(scenarios_list):
bl = loadBeamlets(j)
scenarios.append(bl)
plan.planDesign.robustness.scenarios = scenarios
plan.planDesign.robustness.numScenarios = 21
Then, for the optimization, you can use the “robust” argument to specify whether the objective should be robustly optimized.
plan.planDesign.objectives.addFidObjective(roi, FidObjective.Metrics.DMAX, 20.0, 1.0, robust=True)
plan.planDesign.objectives.addFidObjective(roi, FidObjective.Metrics.DMIN, 20.5, 1.0, robust=True)
Note that beamlets are currently computed and stored for each scenario, it is thus quite time-consuming. We are currently investigating methods to improve the whole robust optimization process.
Hi @Wens , code has been refactored so that one can use the following function planDesign.defineTargetMaskAndPrescription(target = [primaryTumor,secondaryTumor], targetPrescription = [50.,30.])
and define more than one CTV for the spot placement instead of doing it all manually. Objectives still have to be added for each CTV independently.