def beamset3selectionChanged(self, sender, args): #Set text windows to default values if beamset selection is cleared if self.beamset3combo.Text == "Choisissez beamset": self.dosebox3.Text = "----" self.fxbox3.Text = "----" self.Label35.Text = "Nom du PTV: " self.Label36.Text = "Contour isodose: " self.Label37.Text = "Nom final du beamset: " return try: beamset = plan.BeamSets[self.beamset3combo.Text] except: return self.Label32.Text = "Site: " + self.site1combo.Text #Copy directly from first beamset # Attempt to determine site and prescription if roi.roi_exists("PROSTATE"): dose_scale = 95.0 else: dose_scale = 100.0 try: self.dosebox3.Text = "%.2f" % ( (beamset.Prescription.PrimaryDosePrescription.DoseValue) / dose_scale) except: hello = True self.fxbox3.Text = str( beamset.FractionationPattern.NumberOfFractions) # Determine PTV and isodose contours if beamset.Prescription.PrimaryDosePrescription.PrescriptionType == 'DoseAtVolume': ptv_name = beamset.Prescription.PrimaryDosePrescription.OnStructure.Name new_beamset_name = ptv_name.split()[1] self.Label35.Text = "Nom du PTV: " + ptv_name if roi.roi_exists("isodose " + new_beamset_name): self.Label36.Text = "Contour isodose: isodose " + new_beamset_name else: self.Label36.Text = "Contour isodose: pas trouvé" self.Label37.Text = "Nom final du beamset: " + new_beamset_name else: self.Label35.Text = "Nom du PTV: Rx pas sur un ROI" self.Label37.Text = "Nom final du beamset: impossible de continuer"
def beamset1selectionChanged(self, sender, args): try: beamset = plan.BeamSets[self.beamset1combo.Text] except: return # Attempt to determine site and prescription dose_scale = 100.0 if roi.roi_exists("PROSTATE"): self.site1combo.Text = "Prostate" dose_scale = 95.0 elif roi.roi_exists("CAVITE ORALE"): self.site1combo.Text = "ORL" elif roi.roi_exists("CERVEAU"): self.site1combo.Text = "Crâne" elif roi.roi_exists("BR SOUCHE"): self.site1combo.Text = "Poumon" elif roi.roi_exists("FOIE EXPI-GTV"): self.site1combo.Text = "Foie" try: self.dosebox.Text = "%.2f" % ( (beamset.Prescription.PrimaryDosePrescription.DoseValue) / dose_scale) except: hello = True self.fxbox.Text = str( beamset.FractionationPattern.NumberOfFractions) # Determine PTV and isodose contours if beamset.Prescription.PrimaryDosePrescription.PrescriptionType == 'DoseAtVolume': ptv_name = beamset.Prescription.PrimaryDosePrescription.OnStructure.Name new_beamset_name = ptv_name.split()[1] self.Label5.Text = "Nom du PTV: " + ptv_name if roi.roi_exists("isodose " + new_beamset_name): self.Label6.Text = "Contour isodose: isodose " + new_beamset_name else: self.Label6.Text = "Contour isodose: pas trouvé" self.Label7.Text = "Nom final du beamset: " + new_beamset_name else: self.Label5.Text = "Nom du PTV: Rx pas sur un ROI" self.Label7.Text = "Nom final du beamset: impossible de continuer"
def add_opt_obj_orl(plan_data, yeux=False): plan = plan_data['patient'].TreatmentPlans[plan_data['plan_name']] patient = plan_data['patient'] rx_dose = plan_data['rx_dose'] ptv = plan_data['ptv'] nb_fx = plan_data['nb_fx'] nb_ptv = len(ptv) #change the dose from 60 to 59.4 if 33 fractions but just for the objectives and clinical goals if 'PTV60' in ptv and nb_fx == 33: rx_dose.append(5940) rx_dose.remove(6000) rx_dose.sort(reverse=True) if nb_ptv == 4: optim.add_mindose_objective('mod' + ptv[0], rx_dose[0], weight=500, plan=plan) optim.add_maxdose_objective('mod' + ptv[0], rx_dose[0] * 1.05, weight=50, plan=plan) optim.add_mindose_objective('mod' + ptv[1], rx_dose[1], weight=500, plan=plan) optim.add_maxdose_objective('OPT' + ptv[1], rx_dose[1] * 1.05, weight=50, plan=plan) optim.add_mindose_objective('mod' + ptv[2], rx_dose[2], weight=500, plan=plan) optim.add_maxdose_objective('OPT' + ptv[2], rx_dose[2] * 1.05, weight=50, plan=plan) optim.add_mindose_objective('mod' + ptv[3], rx_dose[3], weight=500, plan=plan) optim.add_maxdose_objective('OPT' + ptv[3], rx_dose[3] * 1.05, weight=50, plan=plan) elif nb_ptv == 3: optim.add_mindose_objective('mod' + ptv[0], rx_dose[0], weight=500, plan=plan) optim.add_maxdose_objective('mod' + ptv[0], rx_dose[0] * 1.05, weight=50, plan=plan) optim.add_mindose_objective('mod' + ptv[1], rx_dose[1], weight=500, plan=plan) optim.add_maxdose_objective('OPT' + ptv[1], rx_dose[1] * 1.05, weight=50, plan=plan) optim.add_mindose_objective('mod' + ptv[2], rx_dose[2], weight=500, plan=plan) optim.add_maxdose_objective('OPT' + ptv[2], rx_dose[2] * 1.05, weight=50, plan=plan) elif nb_ptv == 2: optim.add_mindose_objective('mod' + ptv[0], rx_dose[0], weight=500, plan=plan) optim.add_maxdose_objective('mod' + ptv[0], rx_dose[0] * 1.05, weight=50, plan=plan) optim.add_mindose_objective('mod' + ptv[1], rx_dose[1], weight=500, plan=plan) optim.add_maxdose_objective('OPT' + ptv[1], rx_dose[1] * 1.05, weight=50, plan=plan) elif nb_ptv == 1: optim.add_mindose_objective('mod' + ptv[0], rx_dose[0], weight=500, plan=plan) optim.add_maxdose_objective('mod' + ptv[0], rx_dose[0] * 1.05, weight=50, plan=plan) if rx_dose[0] < 4300: optim.add_maxdose_objective('MOELLE', rx_dose[0], plan=plan) optim.add_maxdose_objective('prv5mmMOELLE', rx_dose[0], plan=plan) optim.add_maxdose_objective('TR CEREBRAL', rx_dose[0], plan=plan) optim.add_maxdose_objective('prv5mmTR CEREBRAL', rx_dose[0], plan=plan) else: optim.add_maxdose_objective('MOELLE', 4300, weight=100, plan=plan) optim.add_maxdose_objective('prv5mmMOELLE', 4700, weight=100, plan=plan) optim.add_maxdose_objective('TR CEREBRAL', 4800, weight=100, plan=plan) optim.add_maxdose_objective('prv5mm TRONC', 5000, weight=100, plan=plan) optim.add_maxdose_objective('BLOC MOELLE', 4300, weight=1, plan=plan) try: optim.add_maxdose_objective('OREILLE DRT', 4800, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('OREILLE GCHE', 4800, weight=10, plan=plan) except: pass try: if rx_dose[0] > 5700: optim.add_maxdose_objective('OPT CERVEAU', 5700, weight=10, plan=plan) else: optim.add_maxdose_objective('OPT CERVEAU', rx_dose[0] * 1.02, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('MAND ds ' + ptv[0] + '+5mm', rx_dose[0] * 1.02, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('MAND-' + ptv[0] + '-5mm', rx_dose[0] * 0.97, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('PBD ds ' + ptv[0], rx_dose[0] * 1.02, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('PBG ds ' + ptv[0], rx_dose[0] * 1.02, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('PBD ds ' + ptv[1], rx_dose[1] * 1.05, weight=10, plan=plan) except: pass try: optim.add_maxdose_objective('PBG ds ' + ptv[1], rx_dose[1] * 1.05, weight=10, plan=plan) except: pass try: vol_paro_drt = patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['OPT PARO DRT'].GetRoiVolume( ) / patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['PARO DRT'].GetRoiVolume() if vol_paro_drt > 0.99: vol_paro_drt = 0.5 dose_paro_drt = round(vol_paro_drt * 30 * rx_dose[0] / (100), -1) optim.add_maxeud_objective('OPT PARO DRT', dose_paro_drt, param_a=1.0, weight=1.0, plan=plan, plan_opt=0) except: pass try: vol_paro_gche = patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['OPT PARO GCHE'].GetRoiVolume( ) / patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['PARO GCHE'].GetRoiVolume() if vol_paro_gche > 0.99: vol_paro_gche = 0.5 dose_paro_gche = round(vol_paro_gche * 30 * rx_dose[0] / (100), -1) optim.add_maxeud_objective('OPT PARO GCHE', dose_paro_gche, param_a=1.0, weight=1.0, plan=plan, plan_opt=0) except: pass try: vol_cavite = patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['OPT CAVITE ORALE'].GetRoiVolume( ) / patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['CAVITE ORALE'].GetRoiVolume() if vol_cavite > 0.98: vol_cavite = 1.6 dose_vol_cavite = round(((vol_cavite * (-26)) + 72) * rx_dose[0] / 100, -1) optim.add_maxeud_objective('OPT CAVITE ORALE', dose_vol_cavite, param_a=1.0, weight=1.0, plan=plan, plan_opt=0) except: pass if roi.roi_exists('OPT LARYNX'): optim.add_maxeud_objective('OPT LARYNX', round(0.54 * rx_dose[0], -1), param_a=1.0, weight=1.0, plan=plan, plan_opt=0) else: if roi.roi_exists('LARYNX'): optim.add_maxdose_objective('LARYNX', round(rx_dose[0] * 1.03, -1), weight=10, plan=plan) try: vol_oeso = patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['OPT OESOPHAGE'].GetRoiVolume( ) / patient.PatientModel.StructureSets[ plan_data['ct']].RoiGeometries['OESOPHAGE'].GetRoiVolume() if vol_oeso > 0.98: vol_oeso = 1 dose_vol_oeso = round(((vol_oeso * (-30)) + 58) * rx_dose[0] / (100), -1) optim.add_maxeud_objective('OPT OESOPHAGE', dose_vol_oeso, param_a=1.0, weight=1.0, plan=plan, plan_opt=0) except: if roi.roi_exists('OESOPHAGE'): optim.add_maxdose_objective('OESOPHAGE', round(rx_dose[0] * 1.03, -1), weight=10, plan=plan) optim.add_dosefalloff_objective('Ring', rx_dose[0], rx_dose[0] * 0.5, distance=3, weight=1, plan=plan, plan_opt=0, adapt_dose_level=True) optim.add_dosefalloff_objective('BodyRS+Table', rx_dose[0], rx_dose[0] * 0.85, distance=0.3, weight=1, plan=plan, plan_opt=0, adapt_dose_level=True) if yeux: optim.add_maxdose_objective('CHIASMA', 4900, weight=10, plan=plan) optim.add_maxdose_objective('prv5mmCHIASMA', 5500, weight=10, plan=plan) optim.add_maxdose_objective('OEIL DRT', 4400, weight=10, plan=plan) optim.add_maxdose_objective('OEIL GCHE', 4400, weight=10, plan=plan) optim.add_maxdose_objective('CRISTALLIN DRT', 600, weight=10, plan=plan) optim.add_maxdose_objective('CRISTALLIN GCHE', 600, weight=10, plan=plan) optim.add_maxdose_objective('N OPT DRT', 4400, weight=10, plan=plan) optim.add_maxdose_objective('N OPT GCHE', 4400, weight=10, plan=plan) optim.add_maxdose_objective('prv5mmNOD', 5300, weight=10, plan=plan) optim.add_maxdose_objective('prv5mmNOG', 5300, weight=10, plan=plan)
def add_opt_obj_prostate_A1(plan=None): """ Ajoute les objectifs d'optimisation pour les cas de prostate (plan A1). =================== ================ =========== ========= ========= ROI Type de critère Poids Valeur 1 Valeur 2 =================== ================ =========== ========= ========= PTV A1 ``mindose`` 100 76 Gy PTV A1 ``maxdose`` 10 83 Gy RECTUM ``maxdvh` ` 10 75 Gy 15 % RECTUM ``maxdvh` ` 10 70 Gy 25 % RECTUM ``maxdvh` ` 1 65 Gy 35 % RECTUM ``maxdvh` ` 1 60 Gy 50 % RECTUM ``maxdose`` 10 79.5 Gy VESSIE ``maxdose`` 1 82 Gy BodyRS ``dosefalloff`` 0 76-40 Gy 3 cm =================== ================ =========== ========= ========= .. seealso:: fonctions :py:func:`hmrlib.hmrlib.optim.add_mindose_objective`, :py:func:`hmrlib.hmrlib.optim.add_maxdose_objective` """ if plan is None: plan = lib.get_current_plan() nb_fx = plan.BeamSets[0].FractionationPattern.NumberOfFractions if nb_fx == 40: #Plan to 80Gy optim.add_mindose_objective('PTV A1', 7600, weight=100, plan=plan) optim.add_maxdose_objective('PTV A1', 8300, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 7500, 15, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 7000, 25, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 6500, 35, weight=1, plan=plan) optim.add_maxdvh_objective('RECTUM', 6000, 50, weight=1, plan=plan) optim.add_maxdose_objective('RECTUM+3mm', 7900, weight=10, plan=plan) optim.add_maxdose_objective('VESSIE', 8200, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 7600, 4000, 3, weight=0, plan=plan) elif nb_fx == 33: #Plan to 66 Gy optim.add_mindose_objective('PTV A1', 6270, weight=100, plan=plan) optim.add_maxdose_objective('PTV A1', 6850, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 6500, 35, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 6000, 50, weight=10, plan=plan) optim.add_maxdose_objective('RECTUM+3mm', 6800, weight=10, plan=plan) optim.add_maxdose_objective('VESSIE', 6900, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 6270, 3300, 3, weight=0, plan=plan) elif nb_fx == 22: #Plan to 66 Gy at 3Gy per fraction optim.add_mindose_objective('PTV A1', 6270, weight=100, plan=plan) optim.add_maxdose_objective('PTV A1', 6850, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 5420, 35, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 5000, 50, weight=10, plan=plan) optim.add_maxdose_objective('RECTUM+3mm', 6500, weight=10, plan=plan) optim.add_maxdose_objective('VESSIE', 6900, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 6270, 3300, 3, weight=0, plan=plan) elif nb_fx == 20 or nb_fx == 24: #Plan to 60 Gy at 3Gy per fraction (or PACE 62Gy in 20fx) if roi.roi_exists('PTV_6200'): optim.add_mindose_objective('PTV_6200', 5890, weight=100, plan=plan) optim.add_maxdose_objective('PTV_6200', 6450, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 6000, 5, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 5600, 25, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 5200, 30, weight=1, plan=plan) optim.add_maxdvh_objective('Rectum', 4800, 50, weight=1, plan=plan) optim.add_maxdose_objective('Rectum+3mm', 6100, weight=10, plan=plan) optim.add_maxdose_objective('Bladder', 6400, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 5890, 3100, 3, weight=0, plan=plan) else: optim.add_mindose_objective('PTV A1', 5700, weight=100, plan=plan) optim.add_maxdose_objective('PTV A1', 6225, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 5700, 15, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 5280, 30, weight=10, plan=plan) optim.add_maxdvh_objective('RECTUM', 4860, 50, weight=1, plan=plan) optim.add_maxdvh_objective('RECTUM', 3240, 70, weight=1, plan=plan) optim.add_maxdose_objective('RECTUM+3mm', 6000, weight=10, plan=plan) optim.add_maxdose_objective('VESSIE', 6300, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 5700, 3000, 3, weight=0, plan=plan) elif nb_fx == 39: #PACE 78Gy en 29fx optim.add_mindose_objective('PTV_7800', 7410, weight=100, plan=plan) optim.add_maxdose_objective('PTV_7800', 8100, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 7500, 5, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 7000, 25, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 6500, 30, weight=1, plan=plan) optim.add_maxdvh_objective('Rectum', 6000, 50, weight=1, plan=plan) optim.add_maxdose_objective('Rectum+3mm', 7700, weight=10, plan=plan) optim.add_maxdose_objective('Bladder', 8000, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 7410, 3900, 3, weight=0, plan=plan) elif nb_fx == 5: #PACE 36.25Gy en 5fx optim.add_mindose_objective('PTV_3625', 3444, weight=100, plan=plan) optim.add_maxdose_objective('PTV_3625', 3760, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 2500, 20, weight=10, plan=plan) optim.add_maxdvh_objective('Rectum', 1810, 50, weight=10, plan=plan) optim.add_maxdose_objective('Rectum+3mm', 3575, weight=10, plan=plan) optim.add_maxdose_objective('Bladder', 3700, weight=1, plan=plan) optim.add_dosefalloff_objective('BodyRS', 3444, 1813, 3, weight=0, plan=plan)
def finalize_beamset(original_beamset_name, rx_dose, nb_fx, site, ptv_name, color, skip_oars=False): #Note that I tried to pass the beamset and ptv objects directly into this function, but that seems to cause crashing, so now I pass strings instead. patient = lib.get_current_patient() plan = lib.get_current_plan() bs = plan.BeamSets[original_beamset_name] ptv = patient.PatientModel.RegionsOfInterest[ptv_name] beamset_name = ptv_name.split()[1] scan_name = "CT 1" if site == 'Crâne': try: #statistics.stereo_brain_statistics() crane.crane_kbp_write_final_results_to_file( rx_dose, nb_fx, ptv_name) except: #file_path = r'\\radonc.hmr\Departements\Physiciens\Clinique\IMRT\Statistiques\crane.txt' file_path = r'\\radonc.hmr\Departements\Physiciens\Clinique\IMRT\Statistiques\Crane KBP Plan Failure.txt' #Dump to a separate file in case exception was caused by main stats file being open elsewhere output = patient.PatientName + ',' + patient.PatientID + ',' + plan.Name + ',' + bs.DicomPlanLabel + ',' + 'Collecte de statistiques échouée' with open(file_path, 'a') as stat_file: stat_file.write(output + '\n') elif site == 'Poumon': try: statistics.stereo_lung_statistics() except: file_path = r'\\radonc.hmr\Departements\Physiciens\Clinique\IMRT\Statistiques\poumon.txt' output = patient.PatientName + ',' + patient.PatientID + ',' + plan.Name + ',' + bs.DicomPlanLabel + ',' + 'Collecte de statistiques échouée' with open(file_path, 'a') as stat_file: stat_file.write(output + '\n') #Check to see if PTV is drawn using contours (since prescription point placement will fail if the PTV is in voxel format) try: temp = patient.PatientModel.StructureSets[scan_name].RoiGeometries[ ptv_name].PrimaryShape.Contours[0] except: return "PTV en voxels" #Check to see if prescription dose exists in patient (otherwise it is impossible to place PT PRESC correctly) rx_dose_vol = bs.FractionDose.GetRelativeVolumeAtDoseValues( RoiName=ptv_name, DoseValues=[rx_dose * 100 / nb_fx]) if rx_dose_vol[ 0] == 0: #The volume in BodyRS that receives the prescription dose is 0 return "Impossible de placer PT PRESC pour beamset " + original_beamset_name + " car \ndose max inférieure à la dose de prescription" """ #WARNING: This script uses UI scripting. If the user switches focus to another piece of software during # execution, the UI commands will not be completed. The script will not give the desired results # and may crash. # Erase setup beams ui = lib.get_current("ui") #Select the beamset using the combobox on the top right of RayStation. Note that in plans with only one beamset, this combobox does not exist! So we have to use try. try: ui.SelectionBar.ComboBox_RadiationSets.ToggleButton.Click() ui.SelectionBar.ComboBox_RadiationSets.Popup.ComboBoxItem[original_beamset_name].Select() ui.SelectionBar.ComboBox_RadiationSets.ToggleButton.Click() except: no_big_deal = True ui.MenuItem[2].Button_PlanDesign.Click() #Select Plan Design tab try: ui.Workspace.TabControl['Beams'].TabItem['Setup Beams'].Select() for setup_beam in bs.PatientSetup.SetupBeams: ui.Workspace.TabControl['Beams'].Button_Delete.Click() except: no_big_deal = True """ if site == "Poumon": expi_scan = "CT 2" #Used for transfer of contours to expi scan for Mosaiq if not skip_oars: # Rename OAR contours for SuperBridge transfer roi_list = check_rois(site) if site == "Poumon": #Add ITV to transfer list and prepare to copy contours to expi scan itv_name = "I" + ptv_name[1:] roi_list.append(itv_name) for rois in patient.PatientModel.RegionsOfInterest: if rois.Name in roi_list: rois.Name += "*" if site == "Poumon": patient.PatientModel.CopyRoiGeometry( SourceExamination=patient.Examinations[scan_name], TargetExamination=patient.Examinations[expi_scan], RoiName=rois.Name) # Rename beamset bs.DicomPlanLabel = beamset_name # Rename isodose ROI and add * to it and PTV isodose_roi = patient.PatientModel.RegionsOfInterest["isodose " + beamset_name] if site == "Prostate" or site == "ORL": isodose_roi.Name = "ISO %s %.2fGy*" % (beamset_name, rx_dose * 0.95) else: isodose_roi.Name = "ISO %s %.2fGy*" % (beamset_name, rx_dose) isodose_roi.Name = isodose_roi.Name.replace('.00Gy', 'Gy') ptv.Name += '*' # Rename ISO MOELLE 48Gy (ORL only) if roi.roi_exists("isodose moelle"): patient.PatientModel.RegionsOfInterest[ 'isodose moelle'].Name = "ISO MOELLE 48Gy*" # Copy PTV and isodose ROIs to second beamset for patient positioning at treatment room (lung cases only) if site == "Poumon": patient.PatientModel.CopyRoiGeometry( SourceExamination=patient.Examinations[scan_name], TargetExamination=patient.Examinations[expi_scan], RoiName=ptv.Name) patient.PatientModel.CopyRoiGeometry( SourceExamination=patient.Examinations[scan_name], TargetExamination=patient.Examinations[expi_scan], RoiName=isodose_roi.Name) # Add comment for Superbridge transfer (except for prostate cases, since they are not measured with the ArcCheck) if site != "Prostate": bs.Prescription.Description = "VMAT" # Create DSP and PT PRESC poi_name = 'PT PRESC ' + beamset_name poi.create_poi({ 'x': 0, 'y': 0, 'z': 0 }, poi_name, color=color, examination=patient.Examinations[scan_name]) bs.CreateDoseSpecificationPoint(Name="DSP", Coordinates={ 'x': 0, 'y': 0, 'z': 0 }) # Move PT PRESC to a point that receives correct dose per fraction and prescribe poi.place_prescription_point(target_fraction_dose=rx_dose * 100 / nb_fx, ptv_name=ptv.Name, poi_name=poi_name, beamset=bs, exam=patient.Examinations[scan_name]) bs.AddDosePrescriptionToPoi(PoiName=poi_name, DoseValue=rx_dose * 100) # Move DSP to coordinates of PT PRESC and assign to all beams point = poi.get_poi_coordinates(poi_name) dsp = [x for x in bs.DoseSpecificationPoints][0] dsp.Name = "DSP " + beamset_name dsp.Coordinates = point.value for beam in bs.Beams: beam.SetDoseSpecificationPoint(Name=dsp.Name) bs.ComputeDose( ComputeBeamDoses=True, DoseAlgorithm="CCDose", ForceRecompute=True ) # Dose is recalculated to show beam dose at spec point (otherwise not displayed) return ("You just finalized the beamset named " + bs.DicomPlanLabel)
def test_MA(): #plan = lib.get_current_plan() #beamset = lib.get_current_beamset() exam = lib.get_current_examination() patient = lib.get_current_patient() #ui = get_current("ui") #uis.ui_statetree() #ui = get_current("ui") #if lib.check_version(4.7): # ui.MenuItem[2].Button_PlanDesign.Click() #Select Plan Design tab #elif lib.check_version(4.6): # ui.MenuItem[4].Button_PlanDesign.Click() #Select Plan Design tab #qa.preparation_qa() poi_name = "ISO GCHE" lung_dict = dict(x=-600,y=1600) exam.Series[0].LevelWindow = lung_dict if roi.roi_exists("verif_excentricite"): patient.PatientModel.RegionsOfInterest["verif_excentricite"].DeleteRoi() center = poi.get_poi_coordinates(poi_name,exam) patient.PatientModel.CreateRoi(Name="verif_ex_temp1", Color="Green", Type="Organ", TissueName=None, RoiMaterial=None) patient.PatientModel.RegionsOfInterest["verif_ex_temp1"].CreateCylinderGeometry(Radius=30, Axis={ 'x': 0, 'y': 0, 'z': 1 }, Length=50, Examination=exam, Center={ 'x': center.x, 'y': center.y, 'z': center.z }) patient.PatientModel.CreateRoi(Name="verif_ex_temp2", Color="Pink", Type="Organ", TissueName=None, RoiMaterial=None) patient.PatientModel.RegionsOfInterest["verif_ex_temp2"].SetMarginExpression(SourceRoiName="verif_ex_temp1", MarginSettings={'Type': "Expand", 'Superior': 0, 'Inferior': 0, 'Anterior': 5, 'Posterior': 5, 'Right': 5, 'Left': 5}) patient.PatientModel.RegionsOfInterest["verif_ex_temp2"].UpdateDerivedGeometry(Examination=exam) patient.PatientModel.CreateRoi(Name="verif_excentricite", Color="Red", Type="Organ", TissueName=None, RoiMaterial=None) patient.PatientModel.RegionsOfInterest["verif_excentricite"].SetMarginExpression(SourceRoiName="verif_ex_temp2", MarginSettings={'Type': "Expand", 'Superior': 0, 'Inferior': 0, 'Anterior': 5, 'Posterior': 5, 'Right': 5, 'Left': 5}) patient.PatientModel.RegionsOfInterest["verif_excentricite"].UpdateDerivedGeometry(Examination=exam) patient.PatientModel.RegionsOfInterest["verif_ex_temp1"].DeleteRoi() patient.PatientModel.RegionsOfInterest["verif_ex_temp2"].DeleteRoi() #message.message_window('Hi!') #statistics.auto_collect_crane_stats(startpoint=60,endpoint=999,min_vol=3.999) #statistics.batch_autoplan_crane(startpoint=1,endpoint=11,min_vol=1.0) #statistics.single_autoplan_crane() #Code for switching to a new machine and recalculating dose """ try: plan = patient.CopyPlan(PlanName="Pinnacle", NewPlanName="TestSyn") except: pass patient.Save() #Might not be necessary a second time, I'm not sure time.sleep(5) ui.SelectionBar.ComboBox_TreatmentPlanCollectionView.ToggleButton.Click() ui.SelectionBar.ComboBox_TreatmentPlanCollectionView.Popup.ComboBoxItem['TestSyn'].Select() ui.MenuItem[2].Button_PlanDesign.Click() #Select Plan Design tab ui.TabControl_Modules.TabItem['Plan Setup'].Select() for rois in patient.PatientModel.RegionsOfInterest: rois.SetRoiMaterial(Material=None) roi.generate_BodyRS_plus_Table() ui.TabControl_ToolBar.ToolBarGroup['DOSE GRID'].Button_SetDefaultGrid.Click() ui.MenuItem[2].Button_PlanDesign.Click() #Select Plan Design tab ui.TabControl_Modules.TabItem['Plan Setup'].Select() ui.TabControl_ToolBar.ToolBarGroup['PLAN PREPARATION'].Button_EditPlan.Click() ui.TabControl.TreatmentSetup.TreatmentSetup2.ComboBox_AvailableTreatmentUnits.ToggleButton.Click() ui.TabControl.TreatmentSetup.TreatmentSetup2.ComboBox_AvailableTreatmentUnits.Popup.ComboBoxItem["Synergy_Temp [31 Aug 2017, 11:23:51 (hr:min:sec)]"].Select() ui.TabControl.TreatmentSetup.TreatmentSetup2.ComboBox_AvailableTreatmentUnits.ToggleButton.Click() ui.Button_OK.Click() try: ui.MessageBoxWindowContent.Button['Yes'].Click() except: pass ui.TabControl_ToolBar.ToolBarGroup['FINAL DOSE'].Button_FinalDose.Click() time.sleep(6) """ #launcher.crane_launcher() #launcher.foie_calculer_ntcp() """
def addplanClicked(self, sender, args): self.status.ForeColor = Color.Black self.status.Text = "Compilation des données du plan" d,error_message = self.compile_plan_data() if error_message != "": #If an error is noticed, cancel script execution self.status.Text = error_message self.status.ForeColor = Color.Red return rx = d['rx'] ptv_names = d['ptv_names'] technique = d['technique'] site = d['site_name'] #Predict dose to brain (and generate ROIs) self.status.Text = "Estimation de la dose au cerveau" predicted_vol = crane.crane_stereo_kbp_predict_dose(plan_data = d) cerv_ptv_vol = patient.PatientModel.StructureSets[d['exam'].Name].RoiGeometries["CERVEAU-PTV_"+d['site_name']].GetRoiVolume() #Display predicted results self.message.Text = 'Volumes prédits dans le cerveau-PTV:\n V100%%: %.2fcc\n V90%%: %.2fcc\n V80%%: %.2fcc\n V70%%: %.2fcc\n V60%%: %.2fcc\n V50%%: %.2fcc\n V40%%: %.2fcc' % (predicted_vol[0],predicted_vol[1],predicted_vol[2],predicted_vol[3],predicted_vol[4],predicted_vol[5],predicted_vol[6]) v10 = crane.estimate_vx(predicted_vol=predicted_vol,rx_dose=max(rx),dose_level=1000) v12 = crane.estimate_vx(predicted_vol=predicted_vol,rx_dose=max(rx),dose_level=1200) self.message.Text += '\n\nV10 Cerveau-PTV estimé: %s\nV12 Cerveau-PTV estimé: %s' % (v10,v12) if max(rx) >= 2000: v20 = crane.estimate_vx(predicted_vol=predicted_vol,rx_dose=max(rx),dose_level=2000) self.message.Text += '\nV20 Cerveau-PTV estimé: %s' % (v20) self.status.Text = "Estimation de la dose max au tronc cerebral" tronc_max = crane.crane_stereo_kbp_predict_oar_dose(plan_data = d) #Check which steps of the script are to be performed if self.stepcombo.Text == "Rouler le script au complet": add_plan = True optimize_collimator_angles = True optimize_plan = True elif self.stepcombo.Text == "Multi-PTV: Arrêtez avant optimization collimateur": add_plan = True optimize_collimator_angles = False optimize_plan = False elif self.stepcombo.Text == "Multi-PTV: Reprendre après optimization collimateur": add_plan = False optimize_collimator_angles = False optimize_plan = True if add_plan: if patient.BodySite == '': patient.BodySite = 'Crâne' if self.isodosecombo.Text == "Créer": self.status.Text = "Ajout du dose color table" crane.crane_stereo_create_isodose_lines(plan_data = d) #Create/assign types to POIs and ROIs (only if this is the first plan for the patient) try: existing_plan = patient.TreatmentPlans[0] except: if d['iso_name'] == 'REF SCAN': #Need to skip this step if planner is intentionally using a different isocenter self.status.Text = "Création de l'isocentre à partir du REF SCAN" poi.create_iso() self.status.Text = "Gestion des POIs" poi.auto_assign_poi_types() self.status.Text = "Suppression des overrides de densité" for rois in patient.PatientModel.RegionsOfInterest: rois.SetRoiMaterial(Material=None) self.status.Text = "Création du contour externe" roi.generate_BodyRS_using_threshold() #Create TISSU SAINS à 1cm if not roi.roi_exists("TISSU SAIN 1cm "+site): patient.PatientModel.CreateRoi(Name="TISSU SAIN 1cm "+site, Color="Magenta", Type="Organ", TissueName=None, RoiMaterial=None) patient.PatientModel.RegionsOfInterest["TISSU SAIN 1cm "+site].SetAlgebraExpression(ExpressionA={'Operation': "Union", 'SourceRoiNames': ["BodyRS"], 'MarginSettings': {'Type': "Expand", 'Superior': 0, 'Inferior': 0, 'Anterior': 0, 'Posterior': 0, 'Right': 0, 'Left': 0}}, ExpressionB={'Operation': "Union", 'SourceRoiNames': ['sum_ptvs_'+site], 'MarginSettings': {'Type': "Expand", 'Superior': 1, 'Inferior': 1, 'Anterior': 1, 'Posterior': 1, 'Right': 1, 'Left': 1}}, ResultOperation="Subtraction", ResultMarginSettings={'Type': "Expand", 'Superior': 0, 'Inferior': 0, 'Anterior': 0, 'Posterior': 0, 'Right': 0, 'Left': 0}) patient.PatientModel.RegionsOfInterest["TISSU SAIN 1cm "+site].UpdateDerivedGeometry(Examination=exam) #Assign proper contour type to all PTVs self.status.Text = "Assignation du statut PTV" for ptv in ptv_names: try: roi.set_roi_type(ptv, 'Ptv', 'Target') except: pass #In a perfect world, I would copy the ROI, replace the PTV with the copy in ptv_names and then change its type #Add plan, beamset and beams self.status.Text = "Ajout du plan, beamset et faisceaux" if technique == 'VMAT': #Only case where we don't need a 3DC plan at all plan,beamset = crane.crane_stereo_kbp_add_VMAT_plan_and_beamset(plan_data = d) elif technique == 'IMRT' and len(ptv_names) == 1: plan,beamset = crane.crane_stereo_kbp_add_IMRT_plan_and_beamset(plan_data = d) elif technique == 'IMRT' and len(ptv_names) > 1: if optimize_collimator_angles: self.status.Text = "Ajout du plan, beamset et faisceaux (touchez pas à l'ordinateur SVP)" plan,beamset = crane.crane_stereo_kbp_add_3DC_plan(plan_data = d) self.status.Text = "Optimisation angles collimateur (touchez pas à l'ordinateur SVP)" crane.optimize_collimator_angles() self.status.Text = "Conversion du plan 3DC > IMRT (touchez pas à l'ordinateur SVP)" crane.crane_stereo_convert_3DC_IMRT(plan=plan,beamset=beamset) else: self.status.Text = "Ajout du plan, beamset et faisceaux" plan,beamset = crane.crane_stereo_kbp_add_IMRT_plan_and_beamset(plan_data = d) self.status.Text = "Prêt pour optimisation manuelle des angles de collimateur" self.status.ForeColor = Color.Green return elif technique == '3DC': self.status.Text = "Ajout du plan, beamset et faisceaux (touchez pas à l'ordinateur SVP)" plan,beamset = crane.crane_stereo_kbp_add_3DC_plan(plan_data = d) #if len(ptv_names)>1: if optimize_collimator_angles and len(ptv_names) > 1: self.status.Text = "Optimisation angles collimateur (touchez pas à l'ordinateur SVP)" crane.optimize_collimator_angles() elif not optimize_collimator_angles: self.status.Text = "Prêt pour optimisation manuelle des angles de collimateur" self.status.ForeColor = Color.Green return if add_plan == False: plan = lib.get_current_plan() beamset = lib.get_current_beamset() if optimize_plan: # Add clinical goals (conveniently the same for all types of plan) self.status.Text = "Ajout des clinical goals" clinical_goals.add_dictionary_cg('Crane Stereo', 15, 1, plan = plan) eval.add_clinical_goal("CERVEAU-PTV_"+d['site_name'], 1000, 'AtMost', 'AbsoluteVolumeAtDose', 10, plan=plan) eval.add_clinical_goal("CERVEAU-PTV_"+d['site_name'], 1200, 'AtMost', 'AbsoluteVolumeAtDose', 8, plan=plan) if max(rx) >= 2000: eval.add_clinical_goal("CERVEAU-PTV_"+d['site_name'], 2000, 'AtMost', 'AbsoluteVolumeAtDose', 20, plan=plan) for i,ptv in enumerate(ptv_names): eval.add_clinical_goal(ptv, rx[i], 'AtLeast', 'VolumeAtDose', 99, plan=plan) eval.add_clinical_goal(ptv, 1.5 * rx[i], 'AtMost', 'DoseAtAbsoluteVolume', 0.1, plan=plan) #if technique == '3DC': # optim.copy_clinical_goals(old_plan = plan,new_plan = patient.TreatmentPlans[d['site_name']+' 3DC optimised']) #Add objectives and optimize plan if technique == '3DC': self.status.Text = "Optimisation du plan 3DC (touchez pas à l'ordinateur SVP)" plan,beamset = crane.crane_stereo_kbp_optimize_3DC_plan(plan_data=d,plan=plan,beamset=beamset) obtained_vol,initial_ptv_cov = crane.crane_stereo_kbp_scale_dose(plan_data=d,beamset=beamset,reset_dose=False) else: self.status.Text = "Ajout des objectifs d'optimisation" crane.crane_stereo_kbp_initial_optimization_objectives(plan_data=d,plan=plan,predicted_vol=predicted_vol,tronc_max=tronc_max) #Make a copy of plan before optimizing for dosimetrists patient.CopyPlan(PlanName=plan.Name, NewPlanName=plan.Name + ' non-optimisé') self.status.Text = "Optimization du plan initial" plan.PlanOptimizations[beamset.Number-1].ResetOptimization() if len(ptv_names) == 1: optim.triple_optimization(plan=plan,beamset=beamset) elif len(ptv_names) > 1: optim.optimization_90_30(plan=plan,beamset=beamset) self.status.Text = "Modification du plan" if len(ptv_names) == 1: crane.crane_stereo_kbp_modify_plan_single_ptv(plan_data=d,plan=plan,beamset=beamset,predicted_vol=predicted_vol,tronc_max=tronc_max) self.status.Text = "Optimization du plan modifié" optim.triple_optimization(plan=plan,beamset=beamset) self.status.Text = "Scaling couverture à la prescription" obtained_vol,initial_ptv_cov = crane.crane_stereo_kbp_scale_dose(plan_data=d,beamset=beamset,reset_dose=False) elif len(ptv_names) > 1: obtained_vol,initial_ptv_cov = crane.crane_stereo_kbp_scale_dose(plan_data=d,beamset=beamset,reset_dose=True) self.message.Text += '\n\nV10 obtenu (plan initial): %.2fcc\nV12 obtenu (plan initial): %.2fcc' % (obtained_vol[0]*cerv_ptv_vol,obtained_vol[1]*cerv_ptv_vol) continue_optimization = True best_vol = 100000 for i in range(4): #i IS EQUAL TO THE NUMBER OF COMPLETED ITERATIONS! if continue_optimization: self.status.Text = "Modification du plan et réoptimisation (étape %d/4)" % (i+1) continue_optimization = crane.crane_stereo_kbp_modify_plan_multi_ptv(plan_data=d,plan=plan,beamset=beamset) #Evaluates PTV coverage, adjusts and reoptimizes if necessary obtained_vol,initial_ptv_cov = crane.crane_stereo_kbp_scale_dose(plan_data=d,beamset=beamset,reset_dose=True) if (obtained_vol[0] + obtained_vol[1]) < best_vol: best_vol = obtained_vol[0] + obtained_vol[1] best_iteration = i #if continue_optimization: #If crane_stereo_kbp_modify_plan_multi_ptv returns False, then the plan hasn't changed since last time and we don't need to print these values again self.message.Text += '\n\nV10 obtenu (après %d révision(s)): %.2fcc\nV12 obtenu (après %d révision(s)): %.2fcc' % (i+1,obtained_vol[0]*cerv_ptv_vol,i+1,obtained_vol[1]*cerv_ptv_vol) self.status.Text = "Scaling de la couverture à la prescription" obtained_vol,initial_ptv_cov = crane.crane_stereo_kbp_scale_dose(plan_data=d,beamset=beamset,reset_dose=False) #Now we have to check if the final plan is better than the previous plans. If not, we will reoptimize and stop and the correct point. self.status.Text = "Meilleur plan: plan initial avec %d itérations" % best_iteration #if (obtained_vol[0]+obtained_vol[1]*0.9) > best_vol: if (obtained_vol[0]+obtained_vol[1]) > best_vol: self.status.Text = "Retour vers le meilleur plan, veuillez patientez svp" optim.erase_objectives(plan,beamset) plan.PlanOptimizations[beamset.Number-1].ResetOptimization() crane.crane_stereo_kbp_initial_optimization_objectives(plan_data=d,plan=plan,predicted_vol=predicted_vol,tronc_max=tronc_max) optim.optimization_90_30(plan=plan,beamset=beamset) for i in range(best_iteration+1): self.status.Text = "Modification du plan et réoptimisation (étape %d/%d)" % (i+1,best_iteration+1) continue_optimization = crane.crane_stereo_kbp_modify_plan_multi_ptv(plan_data=d,plan=plan,beamset=beamset) self.status.Text = "Scaling de la couverture à la prescription" obtained_vol,initial_ptv_cov = crane.crane_stereo_kbp_scale_dose(plan_data=d,beamset=beamset,reset_dose=False) #Display results of plan self.message.Text += '\n\nV10 obtenu: %.2fcc\nV12 obtenu: %.2fcc' % (obtained_vol[0]*cerv_ptv_vol,obtained_vol[1]*cerv_ptv_vol) #Write results to file (this is put into a try because it will crash if someone has the destination file open when it tries to write to it) try: crane.crane_kbp_write_results_to_file(plan_data=d,plan=plan,beamset=beamset,predicted_vol=predicted_vol,initial_ptv_cov=initial_ptv_cov,obtained_vol=obtained_vol) except: pass #If the plan is VMAT or IMRT, copy it and set it up using the old technique for comparison if technique != '3DC': kbp_plan_name = site + ' ' + technique old_style_plan_name = site + ' ' + technique + ' RINGS' self.status.Text = "Ajout du plan RINGS" patient.CopyPlan(PlanName=kbp_plan_name, NewPlanName=old_style_plan_name) plan = patient.TreatmentPlans[old_style_plan_name] self.status.Text = "Nom du nouveau plan: " + plan.Name beamset = plan.BeamSets[old_style_plan_name] self.status.Text = "Préparation des ROIs et objectifs pour plan RINGS" crane.crane_add_old_plan(plan_data=d,plan=plan,beamset=beamset) #Create TISSU SAINS à 1cm (because sometimes I guess this wasn't happening for some reason) if not roi.roi_exists("TISSU SAIN 1cm "+site): patient.PatientModel.CreateRoi(Name="TISSU SAIN 1cm "+site, Color="Magenta", Type="Organ", TissueName=None, RoiMaterial=None) patient.PatientModel.RegionsOfInterest["TISSU SAIN 1cm "+site].SetAlgebraExpression(ExpressionA={'Operation': "Union", 'SourceRoiNames': ["BodyRS"], 'MarginSettings': {'Type': "Expand", 'Superior': 0, 'Inferior': 0, 'Anterior': 0, 'Posterior': 0, 'Right': 0, 'Left': 0}}, ExpressionB={'Operation': "Union", 'SourceRoiNames': ['sum_ptvs_'+site], 'MarginSettings': {'Type': "Expand", 'Superior': 1, 'Inferior': 1, 'Anterior': 1, 'Posterior': 1, 'Right': 1, 'Left': 1}}, ResultOperation="Subtraction", ResultMarginSettings={'Type': "Expand", 'Superior': 0, 'Inferior': 0, 'Anterior': 0, 'Posterior': 0, 'Right': 0, 'Left': 0}) patient.PatientModel.RegionsOfInterest["TISSU SAIN 1cm "+site].UpdateDerivedGeometry(Examination=exam) plan.PlanOptimizations[beamset.Number-1].ResetOptimization() self.status.Text = "Optimization du plan RINGS" optim.optimization_90_30(plan=plan,beamset=beamset) self.isodosecombo.Text = 'Ne pas créer' self.status.Text = "Terminé avec succès!" self.status.ForeColor = Color.Green
def compile_plan_data(self): self.status.Text = "Compilation des données du plan" ptv_names = [] rx = [] custom_max = [] error_message = "" if roi.roi_exists(self.PTV1combo.Text): ptv_names.append(self.PTV1combo.Text) try: rx.append(int(float(self.dose1_value.Text) * 100)) except: error_message = "Dose du PTV 1 illisible" if roi.roi_exists(self.PTV2combo.Text): ptv_names.append(self.PTV2combo.Text) try: rx.append(int(float(self.dose2_value.Text) * 100)) except: error_message = "Dose du PTV 2 illisible" if roi.roi_exists(self.PTV3combo.Text): ptv_names.append(self.PTV3combo.Text) try: rx.append(int(float(self.dose3_value.Text) * 100)) except: error_message = "Dose du PTV 3 illisible" if len(ptv_names) == 0: error_message = "Aucun PTV sélectionné" try: nb_fx = int(self.fxbox.Text) except: error_message = "Nb de fractions illisible" technique = self.techcombo.Text if self.isocombo.Text == '': error_message = "Choisissez un isocentre avant de continuer" if self.scancombo.Text == '': error_message = "Choisissez un scan avant de continuer" if self.couchcombo.Text == 'Ajouter': couch = True else: couch = False name = self.sitebox.Text + ' ' + technique if couch: name += ' Couch' if self.stepcombo.Text != "Multi-PTV: Reprendre après optimization collimateur": #We need to skip this step if completing a plan that was started earlier try: existing_plan = patient.TreatmentPlans[name] error_message = "Un plan avec le nom %s exist déjà, SVP le renommez avant de commencer" % name except: pass if self.stepcombo.Text == "Multi-PTV: Arrêtez avant optimization collimateur" or self.stepcombo.Text == "Multi-PTV: Reprendre après optimization collimateur": if technique == 'VMAT': error_message = "Le script partiel devrait seulement être utilisé pour les cas d'IMRT et 3DC" elif len(ptv_names) == 1: error_message = "Le script partiel devrait seulement être utilisé pour les cas avec plus qu'un PTV" if roi.roi_exists(self.OAR1combo.Text): try: custom_max.append((self.OAR1combo.Text,float(self.OAR1_value.Text))) #Yes, you need all those parentheses for this to work except: error_message = "Impossible de lire custom max dose 1" if roi.roi_exists(self.OAR2combo.Text): try: custom_max.append((self.OAR2combo.Text,float(self.OAR2_value.Text))) except: error_message = "Impossible de lire custom max dose 2" if roi.roi_exists(self.OAR3combo.Text): try: custom_max.append((self.OAR3combo.Text,float(self.OAR3_value.Text))) except: error_message = "Impossible de lire custom max dose 3" oar_list = crane.crane_stereo_kbp_identify_rois(patient) if oar_list[0] == 'ERROR': error_message = 'OAR essentiel pas trouvé: ' + oar_list[1] if error_message != '': #In case of any error, abort and send error message back d = [] return d,error_message #Compile plan data to send to scripts d = dict(patient = patient, site_name = self.sitebox.Text, exam = patient.Examinations[self.scancombo.Text], iso_name = self.isocombo.Text, machine = self.machinecombo.Text, nb_fx = nb_fx, rx = rx, rx_dose = max(rx), #Needed for isodose creation ptv_names = ptv_names, oar_list = oar_list, technique = technique, couch = couch, custom_max = custom_max) return d,error_message