Exemple #1
0
        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"
Exemple #2
0
        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"
Exemple #3
0
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)
Exemple #4
0
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)
Exemple #5
0
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)
Exemple #6
0
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