示例#1
0
 def create_rois(self):
     # Delete pre-existing ROIs (except those which are manually contoured) in sorted order:
     group = self.grouped_rois()
     for key in sorted(iter(group)):
         for roi in group[key]:
             PMF.delete_matching_roi_except_manually_contoured(
                 self.pm, self.ss, roi)
     group = self.grouped_rois()
     # Create ROIs (in reverse sorted order):
     for key in reversed(sorted(iter(group))):
         for roi in group[key]:
             # Only create ROI if it doesn't already exist:
             if not PMF.has_roi(self.pm, roi.name):
                 if roi.__class__.__name__ == 'ROI':
                     if roi.model:
                         PMF.create_model_roi(self.pm, self.examination,
                                              roi)
                     else:
                         PMF.create_empty_roi(self.pm, roi)
                 elif roi.__class__.__name__ == 'ROIExpanded':
                     PMF.create_expanded_roi(self.pm, self.examination,
                                             self.ss, roi)
                 elif roi.__class__.__name__ == 'ROIAlgebra':
                     PMF.create_algebra_roi(self.pm, self.examination,
                                            self.ss, roi)
                 elif roi.__class__.__name__ == 'ROIWall':
                     PMF.create_wall_roi(self.pm, self.examination, self.ss,
                                         roi)
示例#2
0
def roi_overlap(pm, examination, ss, roi1, roi2, threshold):
    subtraction = ROI.ROIAlgebra(roi1.name + '-' + roi2.name,
                                 'Undefined',
                                 'Black',
                                 sourcesA=[roi1],
                                 sourcesB=[roi2],
                                 operator='Subtraction')
    # In the rare case that this ROI already exists, delete it (to avoid a crash):
    PMF.delete_roi(pm, subtraction.name)
    PMF.create_algebra_roi(pm, examination, ss, subtraction)
    # Is overlapping volume less than threshold?
    overlap = False
    if ss.RoiGeometries[roi1.name].GetRoiVolume() - ss.RoiGeometries[
            subtraction.name].GetRoiVolume() > threshold:
        overlap = True
    PMF.delete_roi(pm, subtraction.name)
    return overlap
def create_roi_subtraction(pm, examination, ss, roi1, roi2, subtraction_name,
                           threshold):
    overlap = False
    if has_named_roi_with_contours(
            ss, roi1.name) and has_named_roi_with_contours(ss, roi2.name):
        subtraction = ROI.ROIAlgebra(subtraction_name,
                                     'Undefined',
                                     'Black',
                                     sourcesA=[roi1],
                                     sourcesB=[roi2],
                                     operator='Subtraction')
        # In the rare case that this ROI already exists, delete it (to avoid a crash):
        PMF.delete_roi(pm, subtraction.name)
        PMF.create_algebra_roi(pm, examination, ss, subtraction)
        # Is overlapping volume less than threshold?
        if has_named_roi_with_contours(ss, subtraction.name):
            if ss.RoiGeometries[roi1.name].GetRoiVolume() - ss.RoiGeometries[
                    subtraction.name].GetRoiVolume() > threshold:
                overlap = True
    else:
        GUIF.handle_missing_roi_for_derived_rois(subtraction_name, roi2.name)
    return overlap
def create_expanded_and_intersected_volume(pm, examination, ss, source_roi,
                                           intersect_roi, expanded_roi_name,
                                           threshold_volume):
    # Volume of source roi
    volume1 = ss.RoiGeometries[source_roi.name].GetRoiVolume()
    # Estimated radius of source roi calculated from volume (assuming perfect sphere)
    radius1 = math.pow((volume1 * 3) / (4 * math.pi), 1.0 / 3.0)
    # Estimated radius of expanded roi calculated from thresgold volume (assuming perfect sphere)
    radius2 = math.pow((threshold_volume * 3) / (4 * math.pi), 1.0 / 3.0)
    # Expansion radius
    r = round(radius2 - radius1, 1)
    # Expanded roi object
    expanded_roi = ROI.ROIAlgebra(expanded_roi_name,
                                  'Undefined',
                                  'Black',
                                  sourcesA=[source_roi],
                                  sourcesB=[intersect_roi],
                                  operator='Intersection',
                                  marginsA=MARGIN.Expansion(r, r, r, r, r, r),
                                  marginsB=MARGINS.zero)
    # Deletes roi if it already exists in RayStation
    PMF.delete_roi(pm, expanded_roi.name)
    # Create ROI in RayStation
    PMF.create_algebra_roi(pm, examination, ss, expanded_roi)
示例#5
0
  PMF.create_posterior_half(pm, examination, ss, ROIS.rectum, ROIS.dorso_rectum)
if selected_oar_list.get(ROIS.cornea_l) and selected_oar_list.get(ROIS.retina_l):
  PMF.create_retina_and_cornea(pm, examination, ss, ROIS.lens_l, ROIS.box_l, ROIS.eye_l, ROIS.retina_l, ROIS.cornea_l)
elif selected_oar_list.get(ROIS.retina_l) and not selected_oar_list.get(ROIS.cornea_l):
  PMF.create_retina(pm, examination, ss, ROIS.lens_l, ROIS.box_l, ROIS.eye_l, ROIS.retina_l)
elif selected_oar_list.get(ROIS.cornea_l) and not selected_oar_list.get(ROIS.retina_l):
  PMF.create_cornea(pm, examination, ss, ROIS.lens_l, ROIS.box_l, ROIS.eye_l, ROIS.cornea_l)
if selected_oar_list.get(ROIS.cornea_r) and selected_oar_list.get(ROIS.retina_r):
  PMF.create_retina_and_cornea(pm, examination, ss, ROIS.lens_r, ROIS.box_r, ROIS.eye_r, ROIS.retina_r, ROIS.cornea_r)
elif selected_oar_list.get(ROIS.retina_r) and not selected_oar_list.get(ROIS.cornea_r):
  PMF.create_retina(pm, examination, ss, ROIS.lens_r, ROIS.box_r, ROIS.eye_r, ROIS.retina_r)
elif selected_oar_list.get(ROIS.cornea_r) and not selected_oar_list.get(ROIS.retina_r):
  PMF.create_cornea(pm, examination, ss, ROIS.lens_r, ROIS.box_r, ROIS.eye_r, ROIS.cornea_r)


# Create ROIs:
for roi in reversed(list(selected_oar_list)):
  # Only create ROI if it doesn't already exist:
  if not PMF.has_roi(pm, roi.name):
    if roi.__class__.__name__ == 'ROI':
      if roi.model:
        PMF.create_model_roi(pm, examination, roi)
      else:
        PMF.create_empty_roi(pm, roi)
    elif roi.__class__.__name__ == 'ROIExpanded':
      PMF.create_expanded_roi(pm, examination, ss, roi)
    elif roi.__class__.__name__ == 'ROIAlgebra':
      PMF.create_algebra_roi(pm, examination, ss, roi)
    elif roi.__class__.__name__ == 'ROIWall':
      PMF.create_wall_roi(pm, examination, ss, roi)
示例#6
0
def create_brain_objectives(pm, examination, ss, plan, total_dose,
                            nr_fractions):
    if nr_fractions in [1, 3]:  # Stereotactic brain
        nr_targets = SSF.determine_nr_of_indexed_ptvs(ss)
        for i in range(0, nr_targets):
            OF.max_eud(ss,
                       plan,
                       ROIS.brain_ptv.name,
                       0.08 * total_dose * 100,
                       1.3,
                       1,
                       beam_set_index=i)
            OF.max_eud(ss,
                       plan,
                       ROIS.brain_ptv.name,
                       0.06 * total_dose * 100,
                       1,
                       1,
                       beam_set_index=i)
            OF.fall_off(ss,
                        plan,
                        ROIS.body.name,
                        total_dose * 100,
                        total_dose * 100 / 2,
                        0.8,
                        25,
                        beam_set_index=i)
        if nr_targets == 1:  # one target
            OF.min_dose(ss,
                        plan,
                        ROIS.ptv.name,
                        total_dose * 100,
                        200,
                        beam_set_index=0)
            OF.fall_off(ss,
                        plan,
                        ROIS.z_ptv_wall.name,
                        total_dose * 100,
                        0.7 * total_dose * 100,
                        0.6,
                        25,
                        beam_set_index=0)
        else:
            for i in range(0, nr_targets):
                OF.min_dose(ss,
                            plan,
                            ROIS.ptv.name + str(i + 1),
                            total_dose * 100,
                            200,
                            beam_set_index=i)
                OF.fall_off(ss,
                            plan,
                            "zPTV" + str(i + 1) + "_Wall",
                            total_dose * 100,
                            0.7 * total_dose * 100,
                            0.6,
                            25,
                            beam_set_index=i)
    else:  # Partial brain
        OF.max_dose(ss, plan, ROIS.ptv.name, total_dose * 100 * 1.05, 80)
        OF.fall_off(ss, plan, ROIS.external.name, total_dose * 100,
                    total_dose * 100 / 2, 1.5, 30)
        OF.max_dose(ss, plan, ROIS.external.name, total_dose * 100 * 1.05, 30)
        # Objectives for prioritized OARs:
        OF.max_dose(
            ss, plan, ROIS.brainstem_surface.name,
            (TOL.brainstem_surface_v003_adx.equivalent(nr_fractions) * 100) -
            50, 60)
        OF.max_dose(
            ss, plan, ROIS.brainstem_core.name,
            (TOL.brainstem_core_v003_adx.equivalent(nr_fractions) * 100) - 50,
            80)
        OF.max_dose(
            ss, plan, ROIS.optic_chiasm.name,
            (TOL.optic_chiasm_v003_adx.equivalent(nr_fractions) * 100) - 50,
            40)
        OF.max_dose(ss, plan, ROIS.optic_nrv_l.name,
                    (TOL.optic_nrv_v003_adx.equivalent(nr_fractions) * 100) -
                    50, 20)
        OF.max_dose(ss, plan, ROIS.optic_nrv_r.name,
                    (TOL.optic_nrv_v003_adx.equivalent(nr_fractions) * 100) -
                    50, 20)

        prioritized_oars = [
            ROIS.brainstem_core, ROIS.brainstem_surface, ROIS.optic_chiasm,
            ROIS.optic_nrv_l, ROIS.optic_nrv_r
        ]
        tolerances = [
            TOL.brainstem_core_v003_adx, TOL.brainstem_surface_v003_adx,
            TOL.optic_chiasm_v003_adx, TOL.optic_nrv_v003_adx,
            TOL.optic_nrv_v003_adx
        ]
        conflict_oars = []
        for i in range(len(prioritized_oars)):
            if tolerances[i].equivalent(nr_fractions) < total_dose * 0.95:
                conflict_oars.append(prioritized_oars[i])
        # Setup of min and uniform doses depends on presence of critical overlaps or not:
        if len(conflict_oars) > 0:
            # Create subtraction and intersect ROIs for planning of conflicting sites:
            ctv_oars = ROI.ROIAlgebra(ROIS.ctv_oars.name,
                                      ROIS.ctv_oars.type,
                                      ROIS.ctv.color,
                                      sourcesA=[ROIS.ctv],
                                      sourcesB=conflict_oars,
                                      operator='Subtraction',
                                      marginsA=MARGINS.zero,
                                      marginsB=MARGINS.uniform_2mm_expansion)
            ptv_oars = ROI.ROIAlgebra(ROIS.ptv_oars.name,
                                      ROIS.ptv_oars.type,
                                      ROIS.ptv.color,
                                      sourcesA=[ROIS.ptv],
                                      sourcesB=conflict_oars,
                                      operator='Subtraction',
                                      marginsA=MARGINS.zero,
                                      marginsB=MARGINS.uniform_2mm_expansion)
            ptv_and_oars = ROI.ROIAlgebra(ROIS.ptv_and_oars.name,
                                          ROIS.ptv_and_oars.type,
                                          ROIS.other_ptv.color,
                                          sourcesA=[ROIS.ptv],
                                          sourcesB=conflict_oars,
                                          operator='Intersection')
            rois = [ctv_oars, ptv_oars, ptv_and_oars]
            PMF.delete_matching_rois(pm, rois)
            for i in range(len(rois)):
                PMF.create_algebra_roi(pm, examination, ss, rois[i])
                PMF.exclude_roi_from_export(pm, rois[i].name)
            # Create objectives for the subtraction/intersect ROIs:
            OF.uniform_dose(
                ss, plan, ROIS.ptv_and_oars.name,
                (tolerances[0].equivalent(nr_fractions) * 100 - 50), 5
            )  # (Note that this assumes our OARs have the same tolerance dose...)
            OF.uniform_dose(ss, plan, ROIS.ctv_oars.name, total_dose * 100, 30)
            OF.min_dose(ss, plan, ROIS.ptv_oars.name, total_dose * 100 * 0.95,
                        150)
        else:
            OF.uniform_dose(ss, plan, ROIS.ctv.name, total_dose * 100, 30)
            OF.min_dose(ss, plan, ROIS.ptv.name, total_dose * 100 * 0.95, 150)
        # Setup of objectives for less prioritized OARs:
        other_oars = [
            ROIS.cochlea_l, ROIS.cochlea_r, ROIS.hippocampus_l,
            ROIS.hippocampus_r, ROIS.lens_l, ROIS.lens_r, ROIS.lacrimal_l,
            ROIS.lacrimal_r, ROIS.retina_l, ROIS.retina_r, ROIS.cornea_r,
            ROIS.cornea_l, ROIS.pituitary
        ]
        tolerances = [
            TOL.cochlea_mean_tinnitus, TOL.cochlea_mean_tinnitus,
            TOL.hippocampus_v40, TOL.hippocampus_v40, TOL.lens_v003_adx,
            TOL.lens_v003_adx, TOL.lacrimal_mean, TOL.lacrimal_mean,
            TOL.retina_v003_adx, TOL.retina_v003_adx, TOL.cornea_v003_adx,
            TOL.cornea_v003_adx, TOL.pituitary_mean
        ]
        for i in range(len(other_oars)):
            if SSF.has_named_roi_with_contours(ss, other_oars[i].name):
                weight = None
                # Conflict with dose?
                if tolerances[i].equivalent(nr_fractions) < total_dose * 0.95:
                    # Conflict with dose:
                    if not SSF.roi_overlap(pm, examination, ss, ROIS.ptv,
                                           other_oars[i], 2):
                        if ROIF.roi_vicinity_approximate(
                                SSF.rg(ss, ROIS.ptv.name),
                                SSF.rg(ss, other_oars[i].name), 2):
                            # OAR is close, but not overlapping:
                            weight = 2
                        else:
                            weight = 20
                else:
                    # No conflict with dose:
                    weight = 20
                # Create objective if indicated:
                if weight:
                    if other_oars[i].name in [
                            ROIS.cochlea_r.name, ROIS.cochlea_l.name,
                            ROIS.lacrimal_l.name, ROIS.lacrimal_r.name,
                            ROIS.hippocampus_l.name, ROIS.hippocampus_r.name
                    ]:
                        OF.max_eud(
                            ss, plan, other_oars[i].name,
                            tolerances[i].equivalent(nr_fractions) * 100 - 50,
                            1, weight)
                    else:
                        OF.max_dose(
                            ss, plan, other_oars[i].name,
                            (tolerances[i].equivalent(nr_fractions) * 100) -
                            50, weight)
            else:
                GUIF.handle_missing_roi_for_objective(other_oars[i].name)