def create_cornea(pm, examination, ss, source_roi, box_roi, roi, subtraction_roi): if SSF.has_named_roi_with_contours(ss, source_roi.name): center_x = SSF.roi_center_x(ss, source_roi.name) center_z = SSF.roi_center_z(ss, source_roi.name) source_roi_box = ss.RoiGeometries[source_roi.name].GetBoundingBox() y_min = source_roi_box[1].y if y_min > 0: y_min = -source_roi_box[1].y delete_roi(pm, box_roi.name) box = pm.CreateRoi(Name=box_roi.name, Color=box_roi.color, Type=box_roi.type) pm.RegionsOfInterest[box_roi.name].CreateBoxGeometry( Size={ 'x': 5, 'y': 5, 'z': 4 }, Examination=examination, Center={ 'x': center_x, 'y': y_min + 2.5, 'z': center_z }) exclude_roi_from_export(pm, box_roi.name) if source_roi.name == ROIS.lens_l.name: wall_roi = ROIS.z_eye_l elif source_roi.name == ROIS.lens_r.name: wall_roi = ROIS.z_eye_r delete_roi(pm, wall_roi.name) create_wall_roi(pm, examination, ss, wall_roi) exclude_roi_from_export(pm, wall_roi.name) if not SSF.is_approved_roi_structure(ss, roi.name): if is_approved_roi_structure_in_one_of_all_structure_sets( pm, roi.name): intersection = ROI.ROIAlgebra(roi.name + "1", roi.type, roi.color, sourcesA=[source_roi], sourcesB=[box_roi], operator='Intersection') # In the rare case that this ROI already exists, delete it (to avoid a crash): delete_roi(pm, intersection.name) create_algebra_roi(pm, examination, ss, intersection) GUIF.handle_creation_of_new_roi_because_of_approved_structure_set( intersection.name) else: subtraction = ROI.ROIAlgebra(subtraction_roi.name, subtraction_roi.type, subtraction_roi.color, sourcesA=[wall_roi], sourcesB=[box_roi], operator='Subtraction') # In the rare case that this ROI already exists, delete it (to avoid a crash): delete_roi(pm, subtraction.name) create_algebra_roi(pm, examination, ss, subtraction) else: GUIF.handle_missing_roi_for_derived_rois(subtraction_roi.name, source_roi.name)
def __init__(self, pm, examination, ss, choices, site): site.add_oars(DEF.bladder_oars) ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv_low, sourcesA=[ROIS.gtv], sourcesB=[ROIS.bladder]) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA = [ctv], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.bladder_expansion, marginsB = MARGINS.uniform_5mm_contraction) site.add_targets([ROIS.gtv, ctv, ptv]) # Create all targets and OARs in RayStation: site.create_rois()
def create_bottom_part_x_cm(pm, examination, ss, source_roi, roi, distance): if SSF.has_named_roi_with_contours(ss, source_roi.name): center_x = SSF.roi_center_x(ss, source_roi.name) center_y = SSF.roi_center_y(ss, source_roi.name) center_z = SSF.roi_center_z(ss, source_roi.name) source_roi_box = ss.RoiGeometries[source_roi.name].GetBoundingBox() x_min = source_roi_box[0].x x_max = source_roi_box[1].x x = source_roi_box[1].x - source_roi_box[0].x y_min = source_roi_box[0].y y_max = source_roi_box[1].y y = source_roi_box[1].y - source_roi_box[0].y z_min = source_roi_box[0].z z = source_roi_box[1].z - source_roi_box[0].z z_cutoff = z_min + distance / 2 delete_roi(pm, ROIS.box.name) box = pm.CreateRoi(Name=ROIS.box.name, Color=ROIS.box.color, Type=ROIS.box.type) pm.RegionsOfInterest[ROIS.box.name].CreateBoxGeometry( Size={ 'x': x, 'y': y, 'z': distance }, Examination=examination, Center={ 'x': center_x, 'y': center_y, 'z': z_cutoff }) if not SSF.is_approved_roi_structure(ss, roi.name): if is_approved_roi_structure_in_one_of_all_structure_sets( pm, roi.name): intersection = ROI.ROIAlgebra(roi.name + "1", roi.type, roi.color, sourcesA=[source_roi], sourcesB=[ROIS.box], operator='Intersection') # In the rare case that this ROI already exists, delete it (to avoid a crash): delete_roi(pm, intersection.name) create_algebra_roi(pm, examination, ss, intersection) GUIF.handle_creation_of_new_roi_because_of_approved_structure_set( intersection.name) else: intersection = ROI.ROIAlgebra(roi.name, roi.type, roi.color, sourcesA=[source_roi], sourcesB=[ROIS.box], operator='Intersection') # In the rare case that this ROI already exists, delete it (to avoid a crash): delete_roi(pm, intersection.name) create_algebra_roi(pm, examination, ss, intersection) delete_roi(pm, ROIS.box.name) else: GUIF.handle_missing_roi_for_derived_rois(roi.name, source_roi.name)
def create_posterior_half_fast(pm, examination, ss, source_roi, roi): center_x = SSF.roi_center_x(ss, source_roi.name) center_y = SSF.roi_center_y(ss, source_roi.name) center_z = SSF.roi_center_z(ss, source_roi.name) source_roi_box = ss.RoiGeometries[source_roi.name].GetBoundingBox() x_min = source_roi_box[0].x x_max = source_roi_box[1].x x = source_roi_box[1].x - source_roi_box[0].x boxes = [] boxes2 = [] for [contour_index, contour] in enumerate( ss.RoiGeometries[source_roi.name].PrimaryShape.Contours): y_min = 9999 y_max = -9999 for coordinate in contour: if coordinate.y > y_max: y_max = coordinate.y elif coordinate.y < y_min: y_min = coordinate.y length = round((abs(y_max - y_min)), 1) center_y = y_max delete_roi(pm, ROIS.box.name + str(contour_index)) box = pm.CreateRoi(Name=ROIS.box.name + str(contour_index), Color=ROIS.box.color, Type=ROIS.box.type) i = 0 for i in range(0, contour_index): if i % 3 == 0: pm.RegionsOfInterest[ROIS.box.name + str(contour_index)].CreateBoxGeometry( Size={ 'x': x, 'y': length, 'z': 0.3 }, Examination=examination, Center={ 'x': center_x, 'y': center_y, 'z': coordinate.z }) boxes.append(box) boxes2.append( ROI.ROI(ROIS.box.name + str(contour_index), ROIS.box.type, ROIS.box.color)) subtraction = ROI.ROIAlgebra(roi.name, roi.type, roi.color, sourcesA=[source_roi], sourcesB=boxes2, operator='Intersection') # In the rare case that this ROI already exists, delete it (to avoid a crash): delete_roi(pm, subtraction.name) create_algebra_roi(pm, examination, ss, subtraction) for i in range(0, len(boxes)): delete_roi(pm, boxes[i].Name)
def create_grey_value_intersection_roi(pm, examination, ss, grey_level_roi, source_roi, intersection_roi, low_threshold, high_threshold): # If the grey level threshold ROI already exists, delete it and re-create an empty ROI: delete_roi(pm, grey_level_roi.name) pm.CreateRoi(Name=grey_level_roi.name, Type=grey_level_roi.type, Color=grey_level_roi.color) ss.RoiGeometries[grey_level_roi.name].OfRoi.GrayLevelThreshold( Examination=examination, LowThreshold=low_threshold, HighThreshold=high_threshold) # Create the intersection ROI: if not SSF.is_approved_roi_structure(ss, intersection_roi.name): if is_approved_roi_structure_in_one_of_all_structure_sets( pm, intersection_roi.name): intersection = ROI.ROIAlgebra(intersection_roi.name + "1", intersection_roi.type, intersection_roi.color, sourcesA=[source_roi], sourcesB=[grey_level_roi], operator='Intersection') create_algebra_roi(pm, examination, ss, intersection) else: delete_roi(pm, intersection_roi.name) intersection = ROI.ROIAlgebra(intersection_roi.name, intersection_roi.type, intersection_roi.color, sourcesA=[source_roi], sourcesB=[grey_level_roi], operator='Intersection') create_algebra_roi(pm, examination, ss, intersection) # Clean up: Delete the threshold ROI which was created: if ss.RoiGeometries[grey_level_roi.name]: delete_roi(pm, grey_level_roi.name) # In case of failure (no volume or volume < 0.1 cm^3), delete the intersection ROI: if ss.RoiGeometries[intersection_roi.name].HasContours(): if ss.RoiGeometries[intersection_roi.name].GetRoiVolume() < 0.1: delete_roi(pm, intersection_roi.name) else: delete_roi(pm, intersection_roi.name)
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)
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Local/Regional/Regional with IMN region = choices[1] # Choice 2: Side - Left or right? side = choices[2] if region == 'part': site.add_oars(DEF.breast_part_oars) if side == 'right': site.add_oars([ROIS.breast_r_draft]) breast_r = ROI.ROIAlgebra( ROIS.breast_r.name, ROIS.breast_r.type, ROIS.breast_r.color, sourcesA=[ROIS.breast_r_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_sb = ROI.ROIAlgebra( ROIS.ctv_sb.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.surgical_bed], sourcesB=[breast_r], operator='Intersection', marginsA=MARGINS.uniform_15mm_expansion, marginsB=MARGINS.zero) ptv_sbc = ROI.ROIAlgebra( ROIS.ptv_sbc.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv_sb], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_oars([breast_r, ctv_sb, ptv_sbc]) else: site.add_oars([ROIS.breast_l_draft]) breast_l = ROI.ROIAlgebra( ROIS.breast_l.name, ROIS.breast_l.type, ROIS.breast_l.color, sourcesA=[ROIS.breast_l_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_sb = ROI.ROIAlgebra( ROIS.ctv_sb.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.surgical_bed], sourcesB=[breast_l], operator='Intersection', marginsA=MARGINS.uniform_15mm_expansion, marginsB=MARGINS.zero) ptv_sbc = ROI.ROIAlgebra( ROIS.ptv_sbc.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv_sb], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_oars([breast_l, ctv_sb, ptv_sbc]) elif region == 'tang': # Breast with tangential fields site.add_oars(DEF.breast_tang_oars) if side == 'right': site.add_oars([ROIS.breast_r_draft]) ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.breast_r_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) else: site.add_oars([ROIS.breast_l_draft]) ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.breast_l_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv_c.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ctv, ptv]) # Choice 2: With our without boost? boost = choices[3] elif region in ['reg', 'imn']: # Breast where regional lymph nodes or IMN is included # Choice 3: Hypofractionation or not frac = choices[3] # Choice 4: With our without boost? boost = choices[4] site.add_oars(DEF.breast_reg_oars) # Hypofractionated if frac == 'hypo': if side == 'right': ctv_p = ROI.ROIAlgebra( ROIS.ctv_p.name, ROIS.ctv_p.type, ROIS.ctv.color, sourcesA=[ROIS.breast_r_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_n = ROI.ROIAlgebra(ROIS.ctv_n.name, ROIS.ctv_n.type, ROIS.ctv.color, sourcesA=[ ROIS.level_r, ROIS.level1_r, ROIS.level2_r, ROIS.level3_r, ROIS.level4_r ], sourcesB=[ctv_p], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_oars([ ROIS.breast_r_draft, ROIS.humeral_r, ROIS.breast_l, ROIS.level_r, ROIS.level1_r, ROIS.level2_r, ROIS.level3_r, ROIS.level4_r, ROIS.artery1_r, ROIS.artery2_r, ROIS.vein1_r, ROIS.vein2_r ]) else: # (left) ctv_p = ROI.ROIAlgebra( ROIS.ctv_p.name, ROIS.ctv_p.type, ROIS.ctv.color, sourcesA=[ROIS.breast_l_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_n = ROI.ROIAlgebra(ROIS.ctv_n.name, ROIS.ctv_n.type, ROIS.ctv.color, sourcesA=[ ROIS.level_l, ROIS.level1_l, ROIS.level2_l, ROIS.level3_l, ROIS.level4_l ], sourcesB=[ctv_p], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_oars([ ROIS.breast_l_draft, ROIS.humeral_l, ROIS.breast_r, ROIS.level_l, ROIS.level1_l, ROIS.level2_l, ROIS.level3_l, ROIS.level4_l, ROIS.artery1_l, ROIS.artery2_l, ROIS.vein1_l, ROIS.vein2_l ]) # Common for left and right: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ctv_n], sourcesB=[ctv_p], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_p = ROI.ROIAlgebra( ROIS.ptv_pc.name, ROIS.ptv_pc.type, ROIS.ptv.color, sourcesA=[ctv_p], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv_n = ROI.ROIAlgebra( ROIS.ptv_nc.name, ROIS.ptv_nc.type, ROIS.ptv.color, sourcesA=[ctv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv_c.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv_n], sourcesB=[ptv_p], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) else: if side == 'right': ctv = ROI.ROIAlgebra( ROIS.ctv_50.name, ROIS.ctv_50.type, ROIS.ctv.color, sourcesA=[ROIS.breast_r_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_47 = ROI.ROIAlgebra( ROIS.ctv_47.name, ROIS.ctv_50.type, ROIS.ctv.color, sourcesA=[ ROIS.level_r, ROIS.level1_r, ROIS.level2_r, ROIS.level3_r, ROIS.level4_r ], sourcesB=[ctv], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_expansion) site.add_oars([ ROIS.breast_r_draft, ROIS.humeral_r, ROIS.breast_l, ROIS.level_r, ROIS.level1_r, ROIS.level2_r, ROIS.level3_r, ROIS.level4_r, ROIS.artery1_r, ROIS.artery2_r, ROIS.vein1_r, ROIS.vein2_r ]) else: # (left) ctv = ROI.ROIAlgebra( ROIS.ctv_50.name, ROIS.ctv_50.type, ROIS.ctv.color, sourcesA=[ROIS.breast_l_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_47 = ROI.ROIAlgebra( ROIS.ctv_47.name, ROIS.ctv_47.type, ROIS.ctv.color, sourcesA=[ ROIS.level_l, ROIS.level1_l, ROIS.level2_l, ROIS.level3_l, ROIS.level4_l ], sourcesB=[ctv], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_expansion) site.add_oars([ ROIS.breast_l_draft, ROIS.humeral_l, ROIS.breast_r, ROIS.level_l, ROIS.level1_l, ROIS.level2_l, ROIS.level3_l, ROIS.level4_l, ROIS.artery1_l, ROIS.artery2_l, ROIS.vein1_l, ROIS.vein2_l ]) # Common for left and right: ctv_47_50 = ROI.ROIAlgebra(ROIS.ctv_47_50.name, ROIS.ctv_47_50.type, ROIS.ctv.color, sourcesA=[ctv_47], sourcesB=[ctv], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_50c = ROI.ROIAlgebra( ROIS.ptv_50c.name, ROIS.ptv_50.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv_47 = ROI.ROIAlgebra(ROIS.ptv_47.name, ROIS.ptv_47.type, ROIS.ptv.color, sourcesA=[ctv_47], sourcesB=[ptv_50c], operator='Subtraction', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.zero) ptv_47c = ROI.ROIAlgebra( ROIS.ptv_47c.name, ROIS.ptv_47.type, ROIS.ptv.color, sourcesA=[ptv_47], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv_c.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv_47c], sourcesB=[ptv_50c], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) # Only if IMN is included in target volume: if region == 'imn': site.add_oars([ROIS.imn]) if frac == 'hypo': ctv_n.sourcesA.extend([ROIS.imn]) else: ctv_47.sourcesA.extend([ROIS.imn]) # Common for all regional: if frac == 'hypo': site.add_targets([ctv_p, ctv_n, ctv, ptv_p, ptv_n, ptv]) else: site.add_targets( [ctv, ctv_47, ctv_47_50, ptv_50c, ptv_47, ptv_47c, ptv]) # Add volumes for boost (2Gy x 8) if selected: if not region == 'part': if boost == 'with': if side == 'right': ctv_sb = ROI.ROIAlgebra( ROIS.ctv_sb.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.surgical_bed], sourcesB=[ctv], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.zero) else: ctv_sb = ROI.ROIAlgebra( ROIS.ctv_sb.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.surgical_bed], sourcesB=[ctv], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.zero) ptv_sbc = ROI.ROIAlgebra( ROIS.ptv_sbc.name, ROIS.ptv_sb.type, ROIS.ptv.color, sourcesA=[ctv_sb], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ROIS.surgical_bed, ctv_sb, ptv_sbc]) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Stereotactic or not? stereotactic = choices[1] # Choice 2: Region region = choices[2] # Stereotactic: if stereotactic == 'yes': if region in ['col thorax', 'col pelvis']: if region == 'col thorax': site.add_oars(DEF.palliative_stereotactic_thorax_oars) elif region == 'col pelvis': site.add_oars(DEF.palliative_stereotactic_spine_pelvis_oars) ctv = ROI.ROIExpanded(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv_med, ROIS.gtv, margins = MARGINS.uniform_3mm_expansion) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.vb]) ptv_gtv = ROI.ROIAlgebra(ROIS.ptv_gtv.name, ROIS.ptv_gtv.type, COLORS.ptv_med, sourcesA = [ptv], sourcesB = [ROIS.gtv], operator='Subtraction') ptv_spinal = ROI.ROIAlgebra(ROIS.ptv_spinal.name, ROIS.ptv_spinal.type, COLORS.ptv_med, sourcesA = [ptv], sourcesB = [ROIS.spinal_cord_prv], operator='Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.uniform_1mm_expansion) wall_ptv = ROI.ROIWall(ROIS.wall_ptv.name, ROIS.wall_ptv.type, COLORS.wall, ptv, 1, 0) site.add_oars([ROIS.spinal_cord_prv, wall_ptv]) site.add_targets([ROIS.gtv, ROIS.vb, ptv_gtv, ptv_spinal, ctv, ptv]) else: site.add_oars(DEF.palliative_stereotactic_pelvis_oars) ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, ROIS.gtv, margins = MARGINS.uniform_3mm_expansion) wall_ptv = ROI.ROIWall(ROIS.wall_ptv.name, ROIS.wall_ptv.type, COLORS.wall, ptv, 1, 0) site.add_oars([wall_ptv]) site.add_targets([ROIS.gtv, ptv]) # Not stereotactic: else: # Region: if region == 'head': site.add_oars(DEF.palliative_head_oars) elif region == 'neck': site.add_oars(DEF.palliative_neck_oars) elif region == 'thorax': site.add_oars(DEF.palliative_thorax_oars) elif region == 'thorax_abdomen': site.add_oars(DEF.palliative_thorax_abdomen_oars) elif region == 'abdomen': site.add_oars(DEF.palliative_abdomen_oars) elif region == 'abdomen_pelvis': site.add_oars(DEF.palliative_abdomen_pelvis_oars) elif region == 'pelvis': site.add_oars(DEF.palliative_pelvis_oars) # Choice 3: Number of targets: nr_targets = choices[3] # Choice 4: GTV included? with_gtv = choices[4] # Nr of target volumes: if nr_targets == '1': if with_gtv == 'with': site.add_targets([ROIS.gtv, ROIS.ctv_ext]) else: site.add_targets([ROIS.ctv_underived]) if region == 'other': ROIS.ptv_ext.sourcesA = [ROIS.ctv_underived] site.add_targets([ROIS.ptv_ext_7]) else: ROIS.ptv_ext.sourcesA = [ROIS.ctv_underived] site.add_targets([ROIS.ptv_ext]) # 2 or 3 targets: else: # With GTV: if with_gtv=='with': ctv1 = ROI.ROIAlgebra(ROIS.ctv1.name, ROIS.ctv1.type, ROIS.ctv.color, sourcesA = [ROIS.gtv1], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ctv2 = ROI.ROIAlgebra(ROIS.ctv2.name, ROIS.ctv2.type, ROIS.ctv.color, sourcesA = [ROIS.gtv2], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ptv1 = ROI.ROIAlgebra(ROIS.ptv1.name, ROIS.ptv1.type, ROIS.ptv.color, sourcesA = [ROIS.ctv1], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ptv2 = ROI.ROIAlgebra(ROIS.ptv2.name, ROIS.ptv2.type, ROIS.ptv.color, sourcesA = [ROIS.ctv2], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) gtv = ROI.ROIAlgebra(ROIS.gtv.name, ROIS.gtv.type, ROIS.gtv.color, sourcesA=[ROIS.gtv1], sourcesB=[ROIS.gtv2]) ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ctv1], sourcesB=[ctv2]) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv1], sourcesB=[ptv2]) site.add_targets([ROIS.gtv1, ROIS.gtv2, gtv, ctv1, ctv2, ctv, ptv1, ptv2, ptv]) if nr_targets == '3': ctv3 = ROI.ROIAlgebra(ROIS.ctv3.name, ROIS.ctv3.type, ROIS.ctv.color, sourcesA = [ROIS.gtv3], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ptv3 = ROI.ROIAlgebra(ROIS.ptv3.name, ROIS.ptv3.type, ROIS.ptv.color, sourcesA = [ROIS.ctv3], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) gtv.sourcesB.extend([ROIS.gtv3]) ctv.sourcesB.extend([ctv3]) ptv.sourcesB.extend([ptv3]) site.add_targets([ROIS.gtv3, ctv3, ptv3]) # Without GTV: else: if region == 'other': ptv1 = ROI.ROIAlgebra(ROIS.ptv1.name, ROIS.ptv1.type, ROIS.ptv.color, sourcesA = [ROIS.ctv1], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_7mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ptv2 = ROI.ROIAlgebra(ROIS.ptv2.name, ROIS.ptv2.type, ROIS.ptv.color, sourcesA = [ROIS.ctv2], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_7mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) else: ptv1 = ROI.ROIAlgebra(ROIS.ptv1.name, ROIS.ptv1.type, ROIS.ptv.color, sourcesA = [ROIS.ctv1], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ptv2 = ROI.ROIAlgebra(ROIS.ptv2.name, ROIS.ptv2.type, ROIS.ptv.color, sourcesA = [ROIS.ctv2], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.ctv1], sourcesB=[ROIS.ctv2]) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv1], sourcesB=[ptv2]) site.add_targets([ROIS.ctv1, ROIS.ctv2, ctv, ptv1, ptv2, ptv]) if nr_targets == '3': if region == 'other': ptv3 = ROI.ROIAlgebra(ROIS.ptv3.name, ROIS.ptv3.type, ROIS.ptv.color, sourcesA = [ROIS.ctv3], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_7mm_contraction) else: ptv3 = ROI.ROIAlgebra(ROIS.ptv3.name, ROIS.ptv3.type, ROIS.ptv.color, sourcesA = [ROIS.ctv3], sourcesB = [ROIS.external], operator = 'Intersection', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.uniform_5mm_contraction) ctv.sourcesB.extend([ROIS.ctv3]) ptv.sourcesB.extend([ptv3]) site.add_targets([ROIS.ctv3, ptv3]) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Stereotactic or not? stereotactic = choices[1] # Choice 2: Region region = choices[2] if stereotactic == 'yes': # Stereotactic: if region in ['col thorax', 'col pelvis']: # Targets: ctv = ROI.ROIExpanded(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv_med, ROIS.gtv, margins=MARGINS.uniform_3mm_expansion) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.vb]) ptv_gtv = ROI.ROIAlgebra(ROIS.ptv_gtv.name, ROIS.ptv_gtv.type, COLORS.ptv_med, sourcesA=[ptv], sourcesB=[ROIS.gtv], operator='Subtraction') ptv_spinal = ROI.ROIAlgebra( ROIS.ptv_spinal.name, ROIS.ptv_spinal.type, COLORS.ptv_med, sourcesA=[ptv], sourcesB=[ROIS.spinal_cord_prv], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_1mm_expansion) site.add_targets( [ROIS.gtv, ROIS.vb, ptv_gtv, ptv_spinal, ctv, ptv]) # OARs: if region == 'col thorax': site.add_oars(DEF.palliative_stereotactic_thorax_oars) elif region == 'col pelvis': site.add_oars( DEF.palliative_stereotactic_spine_pelvis_oars) wall_ptv = ROI.ROIWall(ROIS.wall_ptv.name, ROIS.wall_ptv.type, COLORS.wall, ptv, 1, 0) site.add_oars([ROIS.spinal_cord_prv, wall_ptv]) else: # Non-columna SBRT (assumed pelvis): # Targets: ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, ROIS.gtv, margins=MARGINS.uniform_3mm_expansion) site.add_targets([ROIS.gtv, ptv]) # OARs: wall_ptv = ROI.ROIWall(ROIS.wall_ptv.name, ROIS.wall_ptv.type, COLORS.wall, ptv, 1, 0) site.add_oars(DEF.palliative_stereotactic_pelvis_oars + [wall_ptv]) else: # Non-stereotactic: # Region: if region == 'head': site.add_oars(DEF.palliative_head_oars) elif region == 'neck': site.add_oars(DEF.palliative_neck_oars) elif region == 'thorax': site.add_oars(DEF.palliative_thorax_oars) elif region == 'costa': site.add_oars(DEF.palliative_thorax_abdomen_oars) elif region == 'thorax_abdomen': site.add_oars(DEF.palliative_thorax_abdomen_oars) elif region == 'abdomen': site.add_oars(DEF.palliative_abdomen_oars) elif region == 'abdomen_pelvis': site.add_oars(DEF.palliative_abdomen_pelvis_oars) elif region == 'pelvis': site.add_oars(DEF.palliative_pelvis_oars) # Choice 3: Number of targets: nr_targets = int(choices[3]) # Choice 4: GTV included? with_gtv = choices[4] # Determine PTV margins: if with_gtv == 'with': # Soft tissue target: if region in ['head']: # Head: 3 mm ptv_margin = MARGINS.uniform_3mm_expansion elif region in ['neck']: # Neck: 3 mm (mask) or 5 mm (no mask) # Choice 5: Mask? mask = choices[5] if mask == 'mask': ptv_margin = MARGINS.uniform_3mm_expansion else: ptv_margin = MARGINS.uniform_5mm_expansion elif region in ['thorax_abdomen']: # Near lung (affected by breathing motion): ptv_margin = MARGINS.abdomen_near_lung_soft_tissue_expansion else: # All others: 7 mm ptv_margin = MARGINS.uniform_7mm_expansion else: # Bone target: if region in ['head']: # Head: 3 mm ptv_margin = MARGINS.uniform_3mm_expansion elif region in ['neck']: # Neck: 3 mm (mask) or 5 mm (no mask) # Choice 5: Mask? mask = choices[5] if mask == 'mask': ptv_margin = MARGINS.uniform_3mm_expansion else: ptv_margin = MARGINS.uniform_5mm_expansion elif region in ['costa', 'other']: # Costa/Extremities: 7 mm ptv_margin = MARGINS.uniform_7mm_expansion else: # Other torso: 5 mm ptv_margin = MARGINS.uniform_5mm_expansion # Set up target volumes: if nr_targets == 1: # A single target: if with_gtv == 'with': site.add_targets([ROIS.gtv, ROIS.ctv_ext]) else: site.add_targets([ROIS.ctv_underived]) site.add_targets([ ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ROIS.ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=ptv_margin, marginsB=MARGINS.uniform_5mm_contraction) ]) else: # Multiple targets (2 or 3): gtvs = [] ctvs = [] ptvs = [] if with_gtv == 'with': # With GTV: for i in range(0, nr_targets): gtvs.append( ROI.ROI('GTV' + str(i + 1), 'Gtv', COLORS.gtv)) ctvs.append( ROI.ROIAlgebra( ROIS.ctv.name + str(i + 1), ROIS.ctv1.type, ROIS.ctv.color, sourcesA=[gtvs[-1]], sourcesB=[ROIS.external], operator='Intersection', marginsA=ptv_margin, marginsB=MARGINS.uniform_5mm_contraction)) ptvs.append( ROI.ROIAlgebra( ROIS.ptv.name + str(i + 1), ROIS.ptv1.type, ROIS.ptv.color, sourcesA=[ctvs[-1]], sourcesB=[ROIS.external], operator='Intersection', marginsA=ptv_margin, marginsB=MARGINS.uniform_5mm_contraction)) # GTV union target volume: gtvs.append( ROI.ROIAlgebra(ROIS.gtv.name, ROIS.gtv.type, ROIS.gtv.color, sourcesA=[gtvs[0]], sourcesB=gtvs[1:])) site.add_targets(gtvs) else: # Without GTV: for i in range(0, nr_targets): ctvs.append( ROI.ROI('CTV' + str(i + 1), 'Ctv', COLORS.ctv)) ptvs.append( ROI.ROIAlgebra( ROIS.ptv.name + str(i + 1), ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctvs[-1]], sourcesB=[ROIS.external], operator='Intersection', marginsA=ptv_margin, marginsB=MARGINS.uniform_5mm_contraction)) # Union target volumes: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ctvs[0]], sourcesB=ctvs[1:]) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptvs[0]], sourcesB=ptvs[1:]) ctvs.append(ctv) ptvs.append(ptv) site.add_targets(ctvs + ptvs) # Create all targets and OARs in RayStation: site.create_rois()
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)
def __init__(self, pm, examination, ss, choices, site): site.add_oars(DEF.lung_oars) # Choice 1: Intent (curative or palliative) intent = choices[1] # Curative: if intent == 'curative': # Choice 2: Diagnosis diagnosis = choices[2] # Non small cell lung cancer (with 4DCT) or small cell lung cancer (with 4DCT): if diagnosis == '4dct': igtv = ROI.ROIAlgebra(ROIS.igtv.name, ROIS.igtv.type, ROIS.gtv.color, sourcesA=[ROIS.igtv_p], sourcesB=[ROIS.igtv_n]) ictv_p = ROI.ROIExpanded( ROIS.ictv_p.name, ROIS.ictv_p.type, COLORS.ctv_high, source=ROIS.igtv_p, margins=MARGINS.uniform_10mm_expansion) ictv_n = ROI.ROIExpanded(ROIS.ictv_n.name, ROIS.ictv_n.type, COLORS.ctv_high, source=ROIS.igtv_n, margins=MARGINS.uniform_5mm_expansion) ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ctv.color, sourcesA=[ictv_p, ictv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, sourcesA=[ictv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) lungs_igtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, ROIS.lungs_igtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[igtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[igtv], operator='Subtraction', operatorA='Intersection') site.add_targets([ ROIS.igtv_p, ROIS.igtv_n, igtv, ictv_p, ictv_n, ictv, ptv ]) site.add_oars([lungs_igtv, water]) # Small cell lung cancer (without 4DCT): elif diagnosis == 'sclc': ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.ctv_p, ROIS.ctv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv_p = ROI.ROIAlgebra( ROIS.ptv_p.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ROIS.ctv_p], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.lung_sclc_without_4dct, marginsB=MARGINS.uniform_5mm_contraction) ptv_n = ROI.ROIAlgebra( ROIS.ptv_n.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ROIS.ctv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv_p], sourcesB=[ptv_n]) water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ctv], operator='Subtraction', operatorA='Intersection') site.add_oars([water]) site.add_targets( [ROIS.ctv_p, ROIS.ctv_n, ctv, ptv_p, ptv_n, ptv]) # Pancoast tumor (with 4DCT): elif diagnosis == 'pancoast': igtv = ROI.ROI(ROIS.igtv.name, ROIS.igtv.type, COLORS.gtv) ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ctv.color, sourcesA=[igtv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ictv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) lungs_igtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, ROIS.lungs_igtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[igtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[igtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_igtv, water]) site.add_targets([igtv, ictv, ptv]) # Post operative treatment: elif diagnosis == 'postop': ctv = ROI.ROI(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ctv], operator='Subtraction', operatorA='Intersection') site.add_oars([water]) site.add_targets([ctv, ptv]) # Common for all curative cases: heart_ptv = ROI.ROIAlgebra(ROIS.z_heart.name, ROIS.z_heart.type, COLORS.heart, sourcesA=[ROIS.heart], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) esophagus_ptv = ROI.ROIAlgebra( ROIS.z_esophagus.name, ROIS.z_esophagus.type, COLORS.esophagus, sourcesA=[ROIS.esophagus], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) site.add_oars([heart_ptv, esophagus_ptv]) # Palliative: elif intent == 'palliative': # Choice 2: 4DCT - with or without? # With 4DCT: if choices[2]: ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ctv.color, sourcesA=[ROIS.igtv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ictv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) lungs_gtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, ROIS.lungs_igtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[ROIS.igtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ROIS.igtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_gtv, water]) site.add_targets([ROIS.igtv, ictv, ptv]) # Without 4DCT: else: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.gtv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) lungs_gtv = ROI.ROIAlgebra(ROIS.lungs_gtv.name, ROIS.lungs_gtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[ROIS.gtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ROIS.gtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_gtv, water]) site.add_targets([ROIS.gtv, ctv, ptv]) # Common for all palliative cases: heart_ptv = ROI.ROIAlgebra(ROIS.z_heart.name, ROIS.z_heart.type, COLORS.heart, sourcesA=[ROIS.heart], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) esophagus_ptv = ROI.ROIAlgebra( ROIS.z_esophagus.name, ROIS.z_esophagus.type, COLORS.esophagus, sourcesA=[ROIS.esophagus], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) site.add_oars([heart_ptv, esophagus_ptv]) # Stereotactic treatment: elif intent == 'stereotactic': # Choice 2: Side - left or right? side = choices[2] if side == 'right': site.add_oars([ROIS.rib_x_r, ROIS.rib_y_r, ROIS.ribs_r]) elif side == 'left': site.add_oars([ROIS.rib_x_l, ROIS.rib_y_l, ROIS.ribs_l]) nr_targets = choices[3] # Choice 3: Number of target volumes? if nr_targets == 'one': site.add_targets( [ROIS.igtv, ROIS.ictv, ROIS.iptv, ROIS.wall_ptv]) site.add_oars([ROIS.lungs_igtv]) elif nr_targets in ['two', 'three']: igtv = ROI.ROIAlgebra(ROIS.igtv.name, ROIS.igtv.type, ROIS.gtv.color, sourcesA=[ROIS.igtv1], sourcesB=[ROIS.igtv2]) site.add_targets([ ROIS.igtv1, ROIS.igtv2, igtv, ROIS.ictv1, ROIS.ictv2, ROIS.iptv1, ROIS.iptv2, ROIS.wall_ptv1, ROIS.wall_ptv2 ]) if nr_targets == 'three': igtv.sourcesB.extend([ROIS.igtv3]) site.add_targets( [ROIS.igtv3, ROIS.ictv3, ROIS.iptv3, ROIS.wall_ptv3]) lungs_igtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, 'Organ', COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[igtv], operator='Subtraction') site.add_oars([lungs_igtv]) site.add_oars(DEF.lung_stereotactic_oars) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Local/Regional/Regional with IMN region = choices[1] # Choice 2: Side - Left or right? side = choices[2] # Region: if region == 'partial': # Partial breast only: if side == 'right': # Right: breast_draft = ROIS.breast_r_draft breast = ROI.ROIAlgebra( ROIS.breast_r.name, ROIS.breast_r.type, ROIS.breast_r.color, sourcesA=[breast_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) else: # Left: breast_draft = ROIS.breast_l_draft breast = ROI.ROIAlgebra( ROIS.breast_l.name, ROIS.breast_l.type, ROIS.breast_l.color, sourcesA=[breast_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) # Targets: ctv_sb = ROI.ROIAlgebra(ROIS.ctv_sb.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.surgical_bed], sourcesB=[breast], operator='Intersection', marginsA=MARGINS.uniform_15mm_expansion, marginsB=MARGINS.zero) ptv_sbc = ROI.ROIAlgebra(ROIS.ptv_sbc.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv_sb], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ctv_sb, ptv_sbc]) # OARs: site.add_oars(DEF.breast_part_oars + [breast_draft, breast]) else: # Whole breast (with or without regional nodes): # Choice 3: With our without boost? boost = choices[3] if region == 'whole': # Whole breast: if side == 'right': breast_draft = ROIS.breast_r_draft # OARs: site.add_oars(DEF.breast_whole_oars + [ROIS.breast_r_draft]) else: breast_draft = ROIS.breast_l_draft # Left side: Use DL model: examination.RunOarSegmentation( ModelName="St. Olavs-Ålesund Breast CT", ExaminationsAndRegistrations={examination.Name: None}, RoisToInclude=[ "A_LAD", "BreastString_L", "Breast_L_Draft", "Clips_L", "Breast_R_Draft", "Esophagus", "Heart", "Lung_L", "Lung_R", "SpinalCanalFull", "Sternum", "SurgicalBed_L", "Trachea" ]) # Rename DL ROI(s): pm.RegionsOfInterest[ 'SpinalCanalFull'].Name = 'SpinalCanal' # Change type to 'Other' for selected ROIs: for roi_name in [ 'Clips_L', 'BreastString_L', 'Breast_L_Draft', 'Breast_R_Draft', 'SurgicalBed_L' ]: pm.RegionsOfInterest[ roi_name].OrganData.OrganType = "Other" # OARs: site.add_oars([ROIS.breast_r, ROIS.lungs]) # Targets: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[breast_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv_c.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) # Robustness evaluation volume: if side == 'right': ptv_robustness = ROI.ROIExpanded( 'PTV_robustness', ROIS.ptv.type, COLORS.ptv_high, ptv, margins=MARGINS.breast_right_robustness) else: ptv_robustness = ROI.ROIExpanded( 'PTV_robustness', ROIS.ptv.type, COLORS.ptv_high, ptv, margins=MARGINS.breast_left_robustness) # Targets for whole breast: site.add_targets([ctv, ptv, ptv_robustness]) elif region in ['regional', 'regional_imn']: # Regional breast (with or without IMN): # Side dependent OARs and support structures for regional treatment: if side == 'right': # Targets: ctv_p = ROI.ROIAlgebra( ROIS.ctv_p.name, ROIS.ctv_p.type, ROIS.ctv.color, sourcesA=[ROIS.breast_r_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_n = ROI.ROIAlgebra(ROIS.ctv_n.name, ROIS.ctv_n.type, ROIS.ctv.color, sourcesA=[ ROIS.level_r, ROIS.level1_r, ROIS.level2_r, ROIS.level3_r, ROIS.level4_r ], sourcesB=[ctv_p], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) if region == 'regional_imn': imn = ROIS.imn_r site.add_targets([imn]) # Others: site.add_oars([ ROIS.breast_r_draft, ROIS.breast_l, ROIS.level_r, ROIS.level1_r, ROIS.level2_r, ROIS.level3_r, ROIS.level4_r ]) # OARs: site.add_oars(DEF.breast_reg_oars + [ ROIS.humeral_r, ROIS.scalene_muscle_r, ROIS.artery1_r, ROIS.artery2_r, ROIS.artery3_r, ROIS.vein1_r, ROIS.vein2_r, ROIS.vein3_r, ROIS.liver ]) else: # Left side: Use DL model: examination.RunOarSegmentation( ModelName="St. Olavs-Ålesund Breast CT", ExaminationsAndRegistrations={examination.Name: None}, RoisToInclude=[ "A_Carotid_L", "A_LAD", "A_Subclavian_L+A_Axillary_L", "BreastString_L", "Breast_L_Draft", "Clips_L", "Breast_R_Draft", "Esophagus", "Heart", "HumeralHead_L", "LN_Ax_L1_L", "LN_Ax_L2_L", "LN_Ax_L3_L", "LN_Ax_L4_L", "LN_Ax_Pectoral_L", "LN_IMN_L", "Lung_L", "Lung_R", "ScaleneMusc_Ant_L", "SpinalCanalFull", "Sternum", "SurgicalBed_L", "ThyroidGland", "Trachea", "V_Brachioceph_L", "V_Jugular_L", "V_Subclavian_L+V_Axillary_L" ]) # Rename DL ROI(s): pm.RegionsOfInterest[ 'SpinalCanalFull'].Name = 'SpinalCanal' # Change type to 'Other' for selected ROIs: for roi_name in [ 'Clips_L', 'BreastString_L', 'Breast_L_Draft', 'LN_Ax_Pectoral_L', 'LN_Ax_L1_L', 'LN_Ax_L2_L', 'LN_Ax_L3_L', 'LN_Ax_L4_L', 'Breast_R_Draft', 'ScaleneMusc_Ant_L', 'A_Subclavian_L+A_Axillary_L', 'A_Carotid_L', 'V_Brachioceph_L', 'V_Subclavian_L+V_Axillary_L', 'V_Jugular_L', 'LN_IMN_L', 'SurgicalBed_L' ]: pm.RegionsOfInterest[ roi_name].OrganData.OrganType = "Other" # Targets: ctv_p = ROI.ROIAlgebra( ROIS.ctv_p.name, ROIS.ctv_p.type, ROIS.ctv.color, sourcesA=[ROIS.breast_l_draft], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ctv_n = ROI.ROIAlgebra(ROIS.ctv_n.name, ROIS.ctv_n.type, ROIS.ctv.color, sourcesA=[ ROIS.level_l, ROIS.level1_l, ROIS.level2_l, ROIS.level3_l, ROIS.level4_l ], sourcesB=[ctv_p], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) if region == 'regional_imn': imn = ROIS.imn_l # OARs: site.add_oars([ROIS.breast_r, ROIS.lungs]) # Common targets for left and right: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ctv_n], sourcesB=[ctv_p], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_p = ROI.ROIAlgebra( ROIS.ptv_pc.name, ROIS.ptv_pc.type, ROIS.ptv.color, sourcesA=[ctv_p], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv_n = ROI.ROIAlgebra( ROIS.ptv_nc.name, ROIS.ptv_nc.type, ROIS.ptv.color, sourcesA=[ctv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv_c.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv_n], sourcesB=[ptv_p], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) # IMN: if region == 'regional_imn': ctv_n.sourcesA.extend([imn]) # Robustness evaluation volume: if side == 'right': ptv_robustness = ROI.ROIExpanded( 'PTV_robustness', ROIS.ptv.type, COLORS.ptv_high, ptv_p, margins=MARGINS.breast_right_robustness) else: ptv_robustness = ROI.ROIExpanded( 'PTV_robustness', ROIS.ptv.type, COLORS.ptv_high, ptv_p, margins=MARGINS.breast_left_robustness) # Common targets for all regional: site.add_targets( [ctv_p, ctv_n, ctv, ptv_p, ptv_n, ptv, ptv_robustness]) # Add targets for boost (2 Gy x 8) if selected: if boost == 'with': if side == 'right': sb = ROIS.surgical_bed_r site.add_targets([sb]) else: sb = ROIS.surgical_bed_l ctv_sb = ROI.ROIAlgebra(ROIS.ctv_sb.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[sb], sourcesB=[ctv], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.zero) ptv_sbc = ROI.ROIAlgebra( ROIS.ptv_sbc.name, ROIS.ptv_sb.type, ROIS.ptv.color, sourcesA=[ctv_sb], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ctv_sb, ptv_sbc]) # Create all targets and OARs in RayStation: site.create_rois() if 'ptv_robustness' in locals(): # Change type of robustness volume to avoid problems with dose grid and dose calculation: pm.RegionsOfInterest['PTV_robustness'].Type = "Control" pm.RegionsOfInterest[ 'PTV_robustness'].OrganData.OrganType = "Other"
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Scope (whole brain, part or stereotactic). region = choices[1] # Region: if region == 'whole': # Whole brain: # Choice 2: Involvement of menignes. meninges = choices[2] if meninges == 'yes': brain_margin = MARGINS.uniform_1mm_expansion else: brain_margin = MARGINS.zero # Targets: ctv = ROI.ROIExpanded(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv, ROIS.brain, margins=brain_margin) ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv, ctv, margins=MARGINS.uniform_3mm_expansion) site.add_targets([ctv, ptv]) # OARs: site.add_oars(DEF.brain_whole_oars) elif region == 'part': # Partial Brain: # Targets: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv, sourcesA=[ROIS.gtv], sourcesB=[ROIS.brain], operator='Intersection', marginsA=MARGINS.uniform_20mm_expansion, marginsB=MARGINS.uniform_1mm_expansion) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv, sourcesA=[ctv], sourcesB=[ROIS.body], operator='Intersection', marginsA=MARGINS.uniform_3mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ROIS.gtv, ctv, ptv]) # OARs: brain_gtv = ROI.ROIAlgebra(ROIS.brain_gtv.name, ROIS.brain_gtv.type, ROIS.brain.color, sourcesA=[ROIS.brain], sourcesB=[ROIS.gtv], operator='Subtraction') brain_ptv = ROI.ROIAlgebra(ROIS.brain_ptv.name, ROIS.brain_ptv.type, ROIS.other_ptv.color, sourcesA=[ROIS.brain], sourcesB=[ptv], operator='Subtraction') site.add_oars(DEF.brain_partial_oars + [brain_gtv, brain_ptv]) elif region == 'stereotactic': # Stereotactic brain: # Choice 2: Nr of targets. nr_targets = int(choices[2]) gtvs = [] ptvs = [] walls = [] # How many targets? if nr_targets == 1: # Single target: gtv = ROI.ROI('GTV', 'Gtv', ROIS.gtv.color) ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv, gtv, margins=MARGINS.uniform_2mm_expansion) gtvs.append(gtv) ptvs.append(ptv) walls.append( ROI.ROIWall(ROIS.z_ptv_wall.name, ROIS.z_ptv_wall.type, COLORS.wall, ptvs[-1], 1, 0)) else: # Multiple targets (2, 3 or 4): for i in range(0, nr_targets): # Targets: gtvs.append( ROI.ROI('GTV' + str(i + 1), 'Gtv', ROIS.gtv.color)) ptvs.append( ROI.ROIExpanded(ROIS.ptv.name + str(i + 1), ROIS.ptv.type, COLORS.ptv, gtvs[-1], margins=MARGINS.uniform_2mm_expansion)) # OARs: walls.append( ROI.ROIWall("zPTV" + str(i + 1) + "_Wall", ROIS.z_ptv_wall.type, COLORS.wall, ptvs[-1], 1, 0)) # Union target volumes: gtv = ROI.ROIAlgebra(ROIS.gtv.name, ROIS.gtv.type, ROIS.gtv.color, sourcesA=[gtvs[0]], sourcesB=gtvs[1:]) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptvs[0]], sourcesB=ptvs[1:]) gtvs.append(gtv) ptvs.append(ptv) # Common for single or multiple SRT targets: # Brain with targets excluded: brain_gtv = ROI.ROIAlgebra(ROIS.brain_gtv.name, ROIS.brain_gtv.type, ROIS.brain.color, sourcesA=[ROIS.brain], sourcesB=[gtv], operator='Subtraction') brain_ptv = ROI.ROIAlgebra(ROIS.brain_ptv.name, ROIS.brain_ptv.type, ROIS.other_ptv.color, sourcesA=[ROIS.brain], sourcesB=[ptv], operator='Subtraction') # Add to site: site.add_targets(gtvs + ptvs) site.add_oars(DEF.brain_stereotactic_oars + [brain_gtv, brain_ptv] + walls) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Scope (whole brain, part or stereotactic). region = choices[1] # Region: # Whole brain: if region == 'whole': site.add_oars(DEF.brain_whole_oars) ctv = ROI.ROIExpanded(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv, ROIS.brain) ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv, ctv, margins=MARGINS.uniform_3mm_expansion) site.add_targets([ctv, ptv]) # Partial Brain: elif region == 'part': ctv = ROI.ROIExpanded(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv, ROIS.gtv, margins=MARGINS.uniform_20mm_expansion) brain_gtv = ROI.ROIAlgebra(ROIS.brain_gtv.name, ROIS.brain_gtv.type, ROIS.brain.color, sourcesA=[ROIS.brain], sourcesB=[ROIS.gtv], operator='Subtraction') site.add_oars([brain_gtv]) site.add_targets([ROIS.gtv, ctv]) # Common for all diagnoses of partial brain: site.add_oars(DEF.brain_partial_oars) ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv, ctv, margins=MARGINS.uniform_3mm_expansion) brain_ptv = ROI.ROIAlgebra(ROIS.brain_ptv.name, ROIS.brain_ptv.type, ROIS.other_ptv.color, sourcesA=[ROIS.brain], sourcesB=[ptv], operator='Subtraction') site.add_oars([brain_ptv]) site.add_targets([ptv]) # Stereotactic brain: elif region == 'stereotactic': site.add_oars(DEF.brain_stereotactic_oars) # Choice 2: Nr of targets. nr_targets = choices[2] # One target: if nr_targets == 'one': gtv = ROI.ROI('GTV', 'Gtv', ROIS.gtv.color) ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv, gtv, margins=MARGINS.uniform_2mm_expansion) wall_ptv = ROI.ROIWall(ROIS.z_ptv_wall.name, ROIS.z_ptv_wall.type, COLORS.wall, ptv, 1, 0) site.add_targets([wall_ptv]) # Multiple targets (2, 3 or 4): elif nr_targets in ['two', 'three', 'four']: gtv = ROI.ROIAlgebra(ROIS.gtv.name, ROIS.gtv.type, ROIS.gtv.color, sourcesA=[ROIS.gtv1], sourcesB=[ROIS.gtv2]) ptv1 = ROI.ROIExpanded(ROIS.ptv1.name, ROIS.ptv1.type, COLORS.ptv, ROIS.gtv1, margins=MARGINS.uniform_2mm_expansion) ptv2 = ROI.ROIExpanded(ROIS.ptv2.name, ROIS.ptv2.type, COLORS.ptv, ROIS.gtv2, margins=MARGINS.uniform_2mm_expansion) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv1], sourcesB=[ptv2]) wall_ptv1 = ROI.ROIWall(ROIS.z_ptv1_wall.name, ROIS.z_ptv1_wall.type, COLORS.wall, ptv1, 1, 0) wall_ptv2 = ROI.ROIWall(ROIS.z_ptv2_wall.name, ROIS.z_ptv2_wall.type, COLORS.wall, ptv2, 1, 0) site.add_targets([wall_ptv1, wall_ptv2]) site.add_targets([ROIS.gtv1, ROIS.gtv2, ptv1, ptv2]) # 3 or 4 targets: if nr_targets in ['three', 'four']: ptv3 = ROI.ROIExpanded( ROIS.ptv3.name, ROIS.ptv3.type, COLORS.ptv, ROIS.gtv3, margins=MARGINS.uniform_2mm_expansion) wall_ptv3 = ROI.ROIWall(ROIS.z_ptv3_wall.name, ROIS.z_ptv3_wall.type, COLORS.wall, ptv3, 1, 0) ptv.sourcesB.extend([ptv3]) gtv.sourcesB.extend([ROIS.gtv3]) site.add_targets([ROIS.gtv3, ptv3]) site.add_targets([wall_ptv3]) # 4 targets: if nr_targets in ['four']: ptv4 = ROI.ROIExpanded( ROIS.ptv4.name, ROIS.ptv4.type, COLORS.ptv, ROIS.gtv4, margins=MARGINS.uniform_2mm_expansion) wall_ptv4 = ROI.ROIWall(ROIS.z_ptv4_wall.name, ROIS.z_ptv4_wall.type, COLORS.wall, ptv4, 1, 0) ptv.sourcesB.extend([ptv4]) gtv.sourcesB.extend([ROIS.gtv4]) site.add_targets([ROIS.gtv4, ptv4]) site.add_targets([wall_ptv4]) # Common for stereotactic: brain_ptv = ROI.ROIAlgebra(ROIS.brain_ptv.name, ROIS.brain_ptv.type, ROIS.other_ptv.color, sourcesA=[ROIS.brain], sourcesB=[ptv], operator='Subtraction') brain_gtv = ROI.ROIAlgebra(ROIS.brain_gtv.name, ROIS.brain_gtv.type, ROIS.brain.color, sourcesA=[ROIS.brain], sourcesB=[gtv], operator='Subtraction') site.add_targets([gtv, ptv]) site.add_oars([brain_ptv, brain_gtv]) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Default OARs: site.add_oars(DEF.lung_oars) # Choice 1: Intent (curative or palliative) intent = choices[1] if intent == 'curative': # Curative: # Choice 2: Diagnosis diagnosis = choices[2] if diagnosis == '4dct': # Non small cell lung cancer (with 4DCT) or small cell lung cancer (with 4DCT): # Targets: igtv = ROI.ROIAlgebra(ROIS.igtv.name, ROIS.igtv.type, ROIS.gtv.color, sourcesA=[ROIS.igtv_p], sourcesB=[ROIS.igtv_n]) ictv_p = ROI.ROIExpanded( ROIS.ictv_p.name, ROIS.ictv_p.type, COLORS.ctv_high, source=ROIS.igtv_p, margins=MARGINS.uniform_10mm_expansion) ictv_n = ROI.ROIExpanded(ROIS.ictv_n.name, ROIS.ictv_n.type, COLORS.ctv_high, source=ROIS.igtv_n, margins=MARGINS.uniform_5mm_expansion) ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ctv.color, sourcesA=[ictv_p, ictv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, sourcesA=[ictv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ ROIS.igtv_p, ROIS.igtv_n, igtv, ictv_p, ictv_n, ictv, ptv ]) # OARs / others: lungs_igtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, ROIS.lungs_igtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[igtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[igtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_igtv, water]) elif diagnosis == 'sclc': # Small cell lung cancer (without 4DCT): # Targets: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.ctv_p, ROIS.ctv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.zero, marginsB=MARGINS.uniform_5mm_contraction) ptv_p = ROI.ROIAlgebra( ROIS.ptv_p.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ROIS.ctv_p], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.lung_sclc_without_4dct, marginsB=MARGINS.uniform_5mm_contraction) ptv_n = ROI.ROIAlgebra( ROIS.ptv_n.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ROIS.ctv_n], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptv_p], sourcesB=[ptv_n]) site.add_targets( [ROIS.ctv_p, ROIS.ctv_n, ctv, ptv_p, ptv_n, ptv]) # OARs / others: water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ctv], operator='Subtraction', operatorA='Intersection') site.add_oars([water]) elif diagnosis == 'pancoast': # Pancoast tumor (with 4DCT): # Targets: igtv = ROI.ROI(ROIS.igtv.name, ROIS.igtv.type, COLORS.gtv) ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ctv.color, sourcesA=[igtv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ictv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([igtv, ictv, ptv]) # OARs / others: lungs_igtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, ROIS.lungs_igtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[igtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[igtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_igtv, water]) elif diagnosis == 'postop': # Post operative treatment: # Targets: ctv = ROI.ROI(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ctv, ptv]) # OARs / others: water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ctv], operator='Subtraction', operatorA='Intersection') site.add_oars([water]) # Common structures for all curative cases: heart_ptv = ROI.ROIAlgebra(ROIS.z_heart.name, ROIS.z_heart.type, COLORS.heart, sourcesA=[ROIS.heart], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) esophagus_ptv = ROI.ROIAlgebra( ROIS.z_esophagus.name, ROIS.z_esophagus.type, COLORS.esophagus, sourcesA=[ROIS.esophagus], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) site.add_oars([heart_ptv, esophagus_ptv]) elif intent == 'palliative': # Palliative: # Choice 2: 4DCT - with or without? with_4dct = choices[2] if with_4dct == 'with': # 4DCT: # Targets: ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ctv.color, sourcesA=[ROIS.igtv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ictv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ROIS.igtv, ictv, ptv]) # OARs / others: lungs_gtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, ROIS.lungs_igtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[ROIS.igtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ROIS.igtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_gtv, water]) else: # Non-4DCT: # Targets: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, ROIS.ctv.color, sourcesA=[ROIS.gtv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ctv], sourcesB=[ROIS.external], operator='Intersection', marginsA=MARGINS.uniform_10mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) site.add_targets([ROIS.gtv, ctv, ptv]) # OARs / others: lungs_gtv = ROI.ROIAlgebra(ROIS.lungs_gtv.name, ROIS.lungs_gtv.type, COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[ROIS.gtv], operator='Subtraction') water = ROI.ROIAlgebra(ROIS.z_water.name, ROIS.z_water.type, COLORS.other_ptv, sourcesA=[ROIS.lungs, ptv], sourcesB=[ROIS.gtv], operator='Subtraction', operatorA='Intersection') site.add_oars([lungs_gtv, water]) # Common for all palliative cases: heart_ptv = ROI.ROIAlgebra(ROIS.z_heart.name, ROIS.z_heart.type, COLORS.heart, sourcesA=[ROIS.heart], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) esophagus_ptv = ROI.ROIAlgebra( ROIS.z_esophagus.name, ROIS.z_esophagus.type, COLORS.esophagus, sourcesA=[ROIS.esophagus], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) site.add_oars([heart_ptv, esophagus_ptv]) elif intent == 'stereotactic': # Stereotactic treatment: # Slice thickness quality control: DEFQC.test_slice_thickness(examination, 0.2, "Lunge SBRT") # Add a POI for breath hold measurement: PMF.create_poi(pm, examination, 'Pust', 'Marker', 'Magenta') # Choice 2: Side - left or right? side = choices[2] if side == 'right': site.add_oars([ROIS.rib_x_r, ROIS.rib_y_r, ROIS.ribs_r]) elif side == 'left': site.add_oars([ROIS.rib_x_l, ROIS.rib_y_l, ROIS.ribs_l]) # Choice 3: Number of target volumes? nr_targets = int(choices[3]) if nr_targets == 1: # Single target: site.add_targets( [ROIS.igtv, ROIS.ictv, ROIS.iptv, ROIS.wall_ptv]) site.add_oars([ROIS.lungs_igtv]) else: # Multiple targets: igtvs = [] ictvs = [] ptvs = [] walls = [] for i in range(0, nr_targets): # Targets: igtvs.append( ROI.ROI('IGTV' + str(i + 1), 'Gtv', ROIS.igtv.color)) ictvs.append( ROI.ROIExpanded(ROIS.ictv.name + str(i + 1), ROIS.ictv.type, COLORS.ctv, igtvs[-1], margins=MARGINS.uniform_5mm_expansion)) ptvs.append( ROI.ROIExpanded(ROIS.ptv.name + str(i + 1), ROIS.ptv.type, COLORS.ptv, ictvs[-1], margins=MARGINS.uniform_5mm_expansion)) # OARs / others: walls.append( ROI.ROIWall("zPTV" + str(i + 1) + "_Wall", ROIS.z_ptv_wall.type, COLORS.wall, ptvs[-1], 1, 0)) # Union target volumes: igtv = ROI.ROIAlgebra(ROIS.igtv.name, ROIS.igtv.type, ROIS.igtv.color, sourcesA=[igtvs[0]], sourcesB=igtvs[1:]) ictv = ROI.ROIAlgebra(ROIS.ictv.name, ROIS.ictv.type, ROIS.ictv.color, sourcesA=[ictvs[0]], sourcesB=ictvs[1:]) ptv = ROI.ROIAlgebra(ROIS.ptv.name, ROIS.ptv.type, ROIS.ptv.color, sourcesA=[ptvs[0]], sourcesB=ptvs[1:]) igtvs.append(igtv) ictvs.append(ictv) ptvs.append(ptv) # Targets: site.add_targets(igtvs + ictvs + ptvs) # OARs / others: lungs_igtv = ROI.ROIAlgebra(ROIS.lungs_igtv.name, 'Organ', COLORS.lungs, sourcesA=[ROIS.lungs], sourcesB=[igtv], operator='Subtraction') site.add_oars([lungs_igtv] + walls) # Common for single or multiple targets: site.add_oars(DEF.lung_stereotactic_oars) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Fractionation - normo or hypofractionated? frac = choices[1] site.add_oars(DEF.rectum_oars) # Conventionally fractionated (2 Gy x 25): if frac == 'normo': # Choice 2: Groin target volume - included or not? groin = choices[2] # Groin targets included: if groin == 'with': gtv = ROI.ROIAlgebra( ROIS.gtv.name, ROIS.gtv.type, ROIS.gtv.color, sourcesA=[ROIS.gtv_p], sourcesB=[ROIS.gtv_n1, ROIS.gtv_groin_l, ROIS.gtv_groin_r]) site.add_targets([ ROIS.gtv_p, ROIS.gtv_n1, ROIS.gtv_groin_l, ROIS.gtv_groin_r, gtv ]) # Without groin targets: else: gtv = ROI.ROIAlgebra(ROIS.gtv.name, ROIS.gtv.type, ROIS.gtv.color, sourcesA=[ROIS.gtv_p], sourcesB=[ROIS.gtv_n1]) site.add_targets([ROIS.gtv_p, ROIS.gtv_n1, gtv]) # Common for groin included or not: ctv_50 = ROI.ROIExpanded(ROIS.ctv_50.name, ROIS.ctv_50.type, COLORS.ctv_high, source=gtv, margins=MARGINS.uniform_10mm_expansion) ptv_50 = ROI.ROIExpanded(ROIS.ptv_50.name, ROIS.ptv_50.type, COLORS.ptv_high, source=ctv_50, margins=MARGINS.rectum_ptv_50_expansion) if groin == 'with': ctv_47 = ROI.ROIAlgebra( ROIS.ctv_47.name, ROIS.ctv_47.type, COLORS.ctv_low, sourcesA=[ROIS.ctv_e, ROIS.ctv_groin_l, ROIS.ctv_groin_r], sourcesB=[ptv_50], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_47_tot = ROI.ROIAlgebra( ROIS.ptv_47_tot.name, ROIS.ptv_47.type, COLORS.ptv_med, sourcesA=[ROIS.ctv_e], sourcesB=[ROIS.ctv_groin_l, ROIS.ctv_groin_r], operator='Union', marginsA=MARGINS.rectum_ctv_primary_risk_expansion, marginsB=MARGINS.uniform_5mm_expansion) ptv_47 = ROI.ROIAlgebra(ROIS.ptv_47.name, ROIS.ptv_47.type, COLORS.ptv_med, sourcesA=[ptv_47_tot], sourcesB=[ptv_50], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_targets([ ctv_47, ptv_47_tot, ptv_47, ROIS.ctv_groin_l, ROIS.ctv_groin_r, ctv_47, ptv_47_tot, ptv_47 ]) else: ctv_47 = ROI.ROIAlgebra(ROIS.ctv_47.name, ROIS.ctv_47.type, COLORS.ctv_low, sourcesA=[ROIS.ctv_e], sourcesB=[ptv_50], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_47 = ROI.ROIAlgebra( ROIS.ptv_47.name, ROIS.ptv_47.type, COLORS.ptv_med, sourcesA=[ctv_47], sourcesB=[ptv_50], operator='Subtraction', marginsA=MARGINS.rectum_ctv_primary_risk_expansion, marginsB=MARGINS.zero) site.add_targets([ctv_47, ptv_47]) ctv_47_50 = ROI.ROIAlgebra(ROIS.ctv_47_50.name, ROIS.ctv_47_50.type, COLORS.ctv_alt, sourcesA=[ctv_47], sourcesB=[ctv_50], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_47_50 = ROI.ROIAlgebra(ROIS.ptv_47_50.name, ROIS.ptv_47_50.type, COLORS.ptv_low, sourcesA=[ptv_47], sourcesB=[ptv_50], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv_47_50], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) bowel_ptv = ROI.ROIAlgebra(ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA=[ROIS.bowel_space], sourcesB=[ptv_47_50], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) wall_ptv_50 = ROI.ROIWall(ROIS.z_ptv_50_wall.name, ROIS.z_ptv_50_wall.type, COLORS.wall, ptv_50, 0.5, 0) site.add_oars([bladder_ptv, bowel_ptv, wall_ptv_50]) site.add_targets( [ROIS.ctv_e, ctv_50, ptv_50, ctv_47_50, ptv_47_50]) # Hypofractionated treatment (5 Gy x 5): else: ctv_p = ROI.ROIExpanded(ROIS.ctv_p.name, ROIS.ctv_p.type, COLORS.ctv_high, source=ROIS.gtv_p, margins=MARGINS.uniform_10mm_expansion) ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv_low, sourcesA=[ROIS.ctv_e], sourcesB=[ctv_p]) ptv = ROI.ROIAlgebra( ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_med, sourcesA=[ctv_p], sourcesB=[ROIS.ctv_e], marginsA=MARGINS.rectum_ptv_50_expansion, marginsB=MARGINS.rectum_ctv_primary_risk_expansion) bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) bowel_ptv = ROI.ROIAlgebra(ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA=[ROIS.bowel_space], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) site.add_oars([bladder_ptv, bowel_ptv]) site.add_targets([ROIS.gtv_p, ctv_p, ROIS.ctv_e, ctv, ptv]) # Create all targets and OARs in RayStation: site.create_rois()
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Region - prostate or bed? region = choices[1] # Prostate: if region == 'prostate': # Choice 2: Fractionation - normo or hypo? frac = choices[2] if frac == 'palliative': site.add_oars(DEF.prostate_palliative_oars) else: site.add_oars(DEF.prostate_oars) # Conventionally fractionated prostate with vesicles (2.2Gy x 35): if frac == 'normo': # Choice 3: Nodes - included or not? nodes = choices[3] ptv_77 = ROI.ROIExpanded(ROIS.ptv_77.name, ROIS.ptv_77.type, COLORS.ptv_high, source = ROIS.prostate, margins = MARGINS.prostate_seed_expansion) ctv_77 = ROI.ROIExpanded(ROIS.ctv_77.name, ROIS.ctv_77.type, COLORS.ctv_high, source = ROIS.prostate) bladder_ptv = ROI.ROIAlgebra(ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA = [ROIS.bladder], sourcesB = [ptv_77], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra(ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA = [ROIS.rectum], sourcesB = [ptv_77], operator='Subtraction', marginsB = MARGINS.uniform_2mm_expansion) wall_ptv_77 = ROI.ROIWall(ROIS.z_ptv_77_wall.name, ROIS.z_ptv_77_wall.type, COLORS.wall, ptv_77, 0.5, 0) # With nodes: if nodes == 'without': ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70_sib.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA = [ROIS.vesicles], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_70 = ROI.ROIAlgebra(ROIS.ptv_70_sib.name, ROIS.ptv_70.type, COLORS.ptv_med, sourcesA = [ROIS.vesicles], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.uniform_10mm_expansion, marginsB = MARGINS.zero) ptv_70_77 = ROI.ROIAlgebra(ROIS.ptv_70_77.name, ROIS.ptv_70_77.type, COLORS.ptv_low, sourcesA = [ROIS.prostate], sourcesB = [ROIS.vesicles], marginsA = MARGINS.prostate_seed_expansion, marginsB = MARGINS.uniform_10mm_expansion) bladder_ptv.sourcesB.extend([ptv_70]) rectum_ptv.sourcesB.extend([ptv_70]) site.add_targets([ptv_70_77]) elif nodes == 'with_node': ctv_n = ROI.ROIExpanded(ROIS.ctv_n.name, ROIS.ctv_n.type, COLORS.pelvic_nodes, source = ROIS.gtv_n, margins = MARGINS.uniform_5mm_expansion) ptv_n = ROI.ROIExpanded(ROIS.ptv_n.name, ROIS.ptv_n.type, ROIS.ptv_n.color, source = ctv_n, margins = MARGINS.prostate_lymph_nodes_seed_expansion) ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70_sib.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA = [ROIS.vesicles, ctv_n], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_semves = ROI.ROIAlgebra(ROIS.ptv_semves.name, ROIS.ptv_semves.type, COLORS.ptv_med, sourcesA = [ROIS.vesicles], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.uniform_10mm_expansion, marginsB = MARGINS.zero) ptv_70 = ROI.ROIAlgebra(ROIS.ptv_70_sib.name, ROIS.ptv_70_sib.type, ROIS.ptv_70_sib.color, sourcesA = [ptv_semves, ptv_n], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_70_77 = ROI.ROIAlgebra(ROIS.ptv_70_77.name, ROIS.ptv_70_77.type, COLORS.ptv_low, sourcesA = [ptv_70], sourcesB = [ptv_77], marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_56 = ROI.ROIAlgebra(ROIS.ptv_56.name, ROIS.ptv_56.type, COLORS.ptv_low, sourcesA = [ROIS.pelvic_nodes], sourcesB = [ptv_77, ptv_70], operator = 'Subtraction', marginsA = MARGINS.prostate_lymph_nodes_seed_expansion, marginsB = MARGINS.zero) ctv_56 = ROI.ROIAlgebra(ROIS.ctv_56.name, ROIS.ctv_56.type, COLORS.ctv_low, sourcesA = [ROIS.pelvic_nodes], sourcesB = [ptv_77, ptv_70], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_56_70_77 = ROI.ROIAlgebra(ROIS.ptv_56_70_77.name, ROIS.ptv_56_70_77.type, COLORS.ptv_low, sourcesA = [ptv_56, ptv_70], sourcesB = [ptv_77], marginsA = MARGINS.zero, marginsB = MARGINS.zero) bladder_ptv.sourcesB.extend([ptv_70, ptv_56]) rectum_ptv.sourcesB.extend([ptv_70, ptv_56]) bowel_ptv = ROI.ROIAlgebra(ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA = [ROIS.bowel_space], sourcesB = [ptv_77, ptv_70, ptv_56], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) wall_ptv_70_77 = ROI.ROIWall(ROIS.z_ptv_70_77_wall.name, ROIS.z_ptv_70_77_wall.type, COLORS.wall, ptv_70_77, 1, 0) site.add_oars([bowel_ptv, wall_ptv_70_77]) site.add_targets([ROIS.gtv_n, ctv_n, ptv_n, ptv_semves, ptv_56, ctv_56, ROIS.pelvic_nodes, ptv_70_77, ptv_56_70_77]) elif nodes == 'with': ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70_sib.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA = [ROIS.vesicles], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_70 = ROI.ROIAlgebra(ROIS.ptv_70_sib.name, ROIS.ptv_70.type, COLORS.ptv_med, sourcesA = [ROIS.vesicles], sourcesB = [ptv_77], operator = 'Subtraction', marginsA = MARGINS.uniform_10mm_expansion, marginsB = MARGINS.zero) ptv_70_77 = ROI.ROIAlgebra(ROIS.ptv_70_77.name, ROIS.ptv_70_77.type, COLORS.ptv_low, sourcesA = [ROIS.prostate], sourcesB = [ROIS.vesicles], marginsA = MARGINS.prostate_seed_expansion, marginsB = MARGINS.uniform_10mm_expansion) ptv_56 = ROI.ROIAlgebra(ROIS.ptv_56.name, ROIS.ptv_56.type, COLORS.ptv_low, sourcesA = [ROIS.pelvic_nodes], sourcesB = [ptv_77, ptv_70], operator = 'Subtraction', marginsA = MARGINS.prostate_lymph_nodes_seed_expansion, marginsB = MARGINS.zero) ctv_56 = ROI.ROIAlgebra(ROIS.ctv_56.name, ROIS.ctv_56.type, COLORS.ctv_low, sourcesA = [ROIS.pelvic_nodes], sourcesB = [ptv_77, ptv_70], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_56_70_77 = ROI.ROIAlgebra(ROIS.ptv_56_70_77.name, ROIS.ptv_56_70_77.type, COLORS.ptv_low, sourcesA = [ptv_56, ptv_70], sourcesB = [ptv_77], marginsA = MARGINS.zero, marginsB = MARGINS.zero) bladder_ptv.sourcesB.extend([ptv_70, ptv_56]) rectum_ptv.sourcesB.extend([ptv_70, ptv_56]) bowel_ptv = ROI.ROIAlgebra(ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA = [ROIS.bowel_space], sourcesB = [ptv_77, ptv_70, ptv_56], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) wall_ptv_70_77 = ROI.ROIWall(ROIS.z_ptv_70_77_wall.name, ROIS.z_ptv_70_77_wall.type, COLORS.wall, ptv_70_77, 1, 0) site.add_oars([bowel_ptv, wall_ptv_70_77]) site.add_targets([ptv_56, ctv_56, ROIS.pelvic_nodes, ptv_70_77, ptv_56_70_77]) # Common for conventional fractionation: site.add_oars([bladder_ptv, rectum_ptv, wall_ptv_77]) site.add_targets([ctv_77, ctv_70, ptv_77, ptv_70, ROIS.prostate, ROIS.vesicles]) # Hypofractionated prostate with vesicles (3 Gy x 20): elif frac == 'hypo_60': ptv_57_60 = ROI.ROIAlgebra(ROIS.ptv_57_60.name, ROIS.ptv_57_60.type, COLORS.ptv_low, sourcesA = [ROIS.prostate], sourcesB = [ROIS.vesicles], marginsA = MARGINS.prostate_seed_expansion, marginsB = MARGINS.uniform_10mm_expansion) ptv_60 = ROI.ROIExpanded(ROIS.ptv_60.name, ROIS.ptv_60.type, COLORS.ptv_high, source = ROIS.prostate, margins = MARGINS.prostate_seed_expansion) ptv_57 = ROI.ROIAlgebra(ROIS.ptv_57.name, ROIS.ptv_57.type, COLORS.ptv_med, sourcesA = [ptv_57_60], sourcesB = [ptv_60], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ctv_57_60 = ROI.ROIAlgebra(ROIS.ctv_57_60.name, ROIS.ctv_57_60.type, COLORS.ctv_low, sourcesA = [ROIS.prostate], sourcesB = [ROIS.vesicles], marginsA = MARGINS.zero, marginsB = MARGINS.zero) ctv_60 = ROI.ROIExpanded(ROIS.ctv_60.name, ROIS.ctv_60.type, COLORS.ctv_high, source = ROIS.prostate) ctv_57 = ROI.ROIAlgebra(ROIS.ctv_57.name, ROIS.ctv_57.type, COLORS.ctv_med, sourcesA = [ctv_57_60], sourcesB = [ptv_60], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) bladder_ptv = ROI.ROIAlgebra(ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA = [ROIS.bladder], sourcesB = [ptv_60, ptv_57], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra(ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA = [ROIS.rectum], sourcesB = [ptv_60, ptv_57], operator='Subtraction', marginsB = MARGINS.uniform_2mm_expansion) wall_ptv_60 = ROI.ROIWall(ROIS.z_ptv_60_wall.name, ROIS.z_ptv_60_wall.type, COLORS.wall, ptv_60, 0.5, 0) wall_ptv_57_60 = ROI.ROIWall(ROIS.z_ptv_57_60_wall.name, ROIS.z_ptv_57_60_wall.type, COLORS.wall, ptv_57_60, 1, 0) site.add_oars([bladder_ptv, rectum_ptv, wall_ptv_60, wall_ptv_57_60]) site.add_targets([ptv_57_60, ptv_60, ptv_57, ctv_60, ctv_57, ctv_57_60, ROIS.prostate, ROIS.vesicles]) elif frac in ['hypo_55','palliative']: ctv = ROI.ROIAlgebra(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv_low, sourcesA = [ROIS.prostate], sourcesB = [ROIS.vesicles], marginsA = MARGINS.zero, marginsB = MARGINS.zero) if frac == 'hypo_55': ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, source = ctv, margins = MARGINS.prostate_seed_expansion) elif frac == 'palliative': ptv = ROI.ROIExpanded(ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, source = ctv, margins = MARGINS.prostate_bone_match_expansion) bladder_ptv = ROI.ROIAlgebra(ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA = [ROIS.bladder], sourcesB = [ptv], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra(ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA = [ROIS.rectum], sourcesB = [ptv], operator='Subtraction', marginsB = MARGINS.uniform_2mm_expansion) wall_ptv_55 = ROI.ROIWall(ROIS.z_ptv_wall.name, ROIS.z_ptv_wall.type, COLORS.wall, ptv, 1, 0) site.add_oars([bladder_ptv, rectum_ptv, wall_ptv_55]) site.add_targets([ptv, ctv, ROIS.prostate, ROIS.vesicles]) # Prostate bed: else: # Choice 2: Nodes - included or not? frac = choices[2] site.add_oars(DEF.prostate_bed_oars) # With nodes: if frac == 'normo': nodes = choices[3] if nodes == 'without': ctv_70 = ROI.ROIExpanded(ROIS.ctv_70.name, ROIS.ctv_70.type, COLORS.ctv_high, source = ROIS.ctv_sb) ptv_70 = ROI.ROIExpanded(ROIS.ptv_70.name, ROIS.ptv_70.type, COLORS.ptv, source = ctv_70, margins = MARGINS.prostate_bone_match_expansion) bladder_ptv = ROI.ROIAlgebra(ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA = [ROIS.bladder], sourcesB = [ptv_70], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra(ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA = [ROIS.rectum], sourcesB = [ptv_70], operator='Subtraction', marginsB = MARGINS.uniform_2mm_expansion) else: if nodes == 'with': ctv_70 = ROI.ROIExpanded(ROIS.ctv_70.name, ROIS.ctv_70.type, COLORS.ctv_high, source = ROIS.ctv_sb) ptv_70 = ROI.ROIExpanded(ROIS.ptv_70.name, ROIS.ptv_70.type, COLORS.ptv, source = ctv_70, margins = MARGINS.prostate_bone_match_expansion) else: ctv_n = ROI.ROIExpanded(ROIS.ctv_n.name, ROIS.ctv_n.type, COLORS.pelvic_nodes, source = ROIS.gtv_n, margins = MARGINS.uniform_5mm_expansion) ptv_n = ROI.ROIExpanded(ROIS.ptv_n.name, ROIS.ptv_n.type, ROIS.ptv_n.color, source = ctv_n, margins = MARGINS.uniform_5mm_expansion) ptv_sb = ROI.ROIExpanded(ROIS.ptv_sb.name, ROIS.ptv_sb.type, ROIS.ptv_sb.color, source = ROIS.ctv_sb, margins = MARGINS.prostate_bone_match_expansion) ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA = [ROIS.ctv_sb], sourcesB = [ctv_n], operator = 'Union') ptv_70 = ROI.ROIAlgebra(ROIS.ptv_70.name, ROIS.ptv_70.type, COLORS.ptv, sourcesA = [ptv_sb], sourcesB = [ptv_n], operator = 'Union', marginsA = MARGINS.zero , marginsB = MARGINS.zero) site.add_targets([ROIS.gtv_n, ctv_n, ptv_n, ptv_sb]) ctv_56 = ROI.ROIAlgebra(ROIS.ctv_56.name, ROIS.ctv_56.type, COLORS.ctv_low, sourcesA = [ROIS.pelvic_nodes], sourcesB = [ptv_70], operator = 'Subtraction', marginsA = MARGINS.zero, marginsB = MARGINS.zero) ptv_56 = ROI.ROIAlgebra(ROIS.ptv_56.name, ROIS.ptv_56.type, COLORS.ptv_low, sourcesA = [ROIS.pelvic_nodes], sourcesB = [ptv_70], operator = 'Subtraction', marginsA = MARGINS.uniform_5mm_expansion, marginsB = MARGINS.zero) ptv_56_70 = ROI.ROIAlgebra(ROIS.ptv_56_70.name, ROIS.ptv_56_70.type, COLORS.ptv_low, sourcesA = [ptv_56], sourcesB = [ptv_70], marginsA = MARGINS.zero, marginsB = MARGINS.zero) bladder_ptv = ROI.ROIAlgebra(ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA = [ROIS.bladder], sourcesB = [ptv_70, ptv_56], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra(ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA = [ROIS.rectum], sourcesB = [ptv_70, ptv_56], operator='Subtraction', marginsB = MARGINS.uniform_2mm_expansion) bowel_ptv = ROI.ROIAlgebra(ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA = [ROIS.bowel_space], sourcesB = [ptv_70, ptv_56], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) wall_ptv_70 = ROI.ROIWall(ROIS.z_ptv_70_wall.name, ROIS.z_ptv_70_wall.type, COLORS.wall, ptv_70, 1, 0) wall_ptv_56_temp = ROI.ROIWall(ROIS.z_ptv_56_temp.name, ROIS.z_ptv_56_temp.type, COLORS.wall, ptv_56, 1, 0) wall_ptv_56 = ROI.ROIAlgebra(ROIS.z_ptv_56_wall.name, ROIS.z_ptv_56_wall.type, COLORS.wall, sourcesA = [wall_ptv_56_temp], sourcesB = [ptv_70, wall_ptv_70], operator='Subtraction', marginsB = MARGINS.zero) site.add_oars([bowel_ptv, ROIS.bowel_space, wall_ptv_70, wall_ptv_56_temp, wall_ptv_56]) site.add_targets([ctv_56, ptv_56, ROIS.pelvic_nodes, ptv_56_70]) # Common for bed (with or without nodes): site.add_oars([bladder_ptv, rectum_ptv]) site.add_targets([ctv_70, ptv_70, ROIS.ctv_sb]) else: ptv = ROI.ROIExpanded(ROIS.ptv_sb.name, ROIS.ptv_sb.type, COLORS.ptv_high, source = ROIS.ctv_sb, margins = MARGINS.prostate_bone_match_expansion) bladder_ptv = ROI.ROIAlgebra(ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA = [ROIS.bladder], sourcesB = [ptv], operator='Subtraction', marginsB = MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra(ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA = [ROIS.rectum], sourcesB = [ptv], operator='Subtraction', marginsB = MARGINS.uniform_2mm_expansion) wall_ptv = ROI.ROIWall(ROIS.z_ptv_wall.name, ROIS.z_ptv_wall.type, COLORS.wall, ptv, 1, 0) site.add_oars([bladder_ptv, rectum_ptv, wall_ptv]) site.add_targets([ptv, ROIS.ctv_sb]) # Create all targets and OARs in RayStation: site.create_rois()
# Target volumes: gtv = ROI.ROI('GTV', 'Gtv', COLORS.gtv) ctv = ROI.ROIExpanded('CTV', 'Ctv', COLORS.ctv, gtv, margins=MARGINS.uniform_5mm_expansion) ptv = ROI.ROIExpanded('PTV', 'Ptv', COLORS.ptv, ctv, margins=MARGINS.uniform_5mm_expansion) ctv_ext = ROI.ROIAlgebra('CTV', 'Ctv', COLORS.ctv, sourcesA=[gtv], sourcesB=[external], operator='Intersection', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.uniform_5mm_contraction) ctv_underived = ROI.ROI('CTV', 'Ctv', COLORS.ctv) igtv = ROI.ROI('IGTV', 'Gtv', COLORS.gtv) igtv1 = ROI.ROI('IGTV1', 'Gtv', COLORS.gtv) igtv2 = ROI.ROI('IGTV2', 'Gtv', COLORS.gtv) igtv3 = ROI.ROI('IGTV3', 'Gtv', COLORS.gtv) ictv = ROI.ROIExpanded('ICTV', 'Ctv', COLORS.ctv, igtv, margins=MARGINS.uniform_5mm_expansion) ictv1 = ROI.ROIExpanded('ICTV1', 'Ctv',
def __init__(self, pm, examination, ss, choices, site): # Choice 1: Region - prostate or bed? region = choices[1] if region == 'prostate': # Prostate: # Choice 2: Fractionation - normo or hypo? frac = choices[2] if frac == 'normo': # Conventionally fractionated prostate with vesicles (2.2Gy x 35): # Choice 3: Nodes - included or not? nodes = choices[3] # Targets: ctv_77 = ROI.ROIExpanded(ROIS.ctv_77.name, ROIS.ctv_77.type, COLORS.ctv_high, source=ROIS.prostate) ptv_77 = ROI.ROIExpanded( ROIS.ptv_77.name, ROIS.ptv_77.type, COLORS.ptv_high, source=ROIS.prostate, margins=MARGINS.prostate_seed_expansion) # OARs: bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv_77], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra( ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA=[ROIS.rectum], sourcesB=[ptv_77], operator='Subtraction', marginsB=MARGINS.uniform_2mm_expansion) wall_ptv_77 = ROI.ROIWall(ROIS.z_ptv_77_wall.name, ROIS.z_ptv_77_wall.type, COLORS.wall, ptv_77, 0.5, 0) if nodes == 'no': # Prostate only: # Targets: ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70_sib.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA=[ROIS.vesicles], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_70 = ROI.ROIAlgebra( ROIS.ptv_70_sib.name, ROIS.ptv_70.type, COLORS.ptv_med, sourcesA=[ROIS.vesicles], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.uniform_8mm_expansion, marginsB=MARGINS.zero) ptv_70_77 = ROI.ROIAlgebra( ROIS.ptv_70_77.name, ROIS.ptv_70_77.type, COLORS.ptv_low, sourcesA=[ROIS.prostate], sourcesB=[ROIS.vesicles], marginsA=MARGINS.prostate_seed_expansion, marginsB=MARGINS.uniform_8mm_expansion) site.add_targets([ptv_70_77]) # OARs: bladder_ptv.sourcesB.extend([ptv_70]) rectum_ptv.sourcesB.extend([ptv_70]) site.add_oars(DEF.prostate_oars + [bladder_ptv, rectum_ptv, wall_ptv_77]) elif nodes == 'with_node': # Elective nodes (with positive node): # Targets: ctv_n = ROI.ROIExpanded( ROIS.ctv_n.name, ROIS.ctv_n.type, COLORS.pelvic_nodes, source=ROIS.gtv_n, margins=MARGINS.uniform_5mm_expansion) ptv_n = ROI.ROIExpanded( ROIS.ptv_n.name, ROIS.ptv_n.type, ROIS.ptv_n.color, source=ctv_n, margins=MARGINS.prostate_lymph_nodes_seed_expansion) ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70_sib.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA=[ROIS.vesicles, ctv_n], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_semves = ROI.ROIAlgebra( ROIS.ptv_semves.name, ROIS.ptv_semves.type, COLORS.ptv_med, sourcesA=[ROIS.vesicles], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.uniform_8mm_expansion, marginsB=MARGINS.zero) ptv_70 = ROI.ROIAlgebra(ROIS.ptv_70_sib.name, ROIS.ptv_70_sib.type, ROIS.ptv_70_sib.color, sourcesA=[ptv_semves, ptv_n], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_70_77 = ROI.ROIAlgebra(ROIS.ptv_70_77.name, ROIS.ptv_70_77.type, COLORS.ptv_low, sourcesA=[ptv_70], sourcesB=[ptv_77], marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_56 = ROI.ROIAlgebra( ROIS.ptv_56.name, ROIS.ptv_56.type, COLORS.ptv_low, sourcesA=[ROIS.pelvic_nodes], sourcesB=[ptv_77, ptv_70], operator='Subtraction', marginsA=MARGINS.prostate_lymph_nodes_seed_expansion, marginsB=MARGINS.zero) ctv_56 = ROI.ROIAlgebra(ROIS.ctv_56.name, ROIS.ctv_56.type, COLORS.ctv_low, sourcesA=[ROIS.pelvic_nodes], sourcesB=[ptv_77, ptv_70], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_56_70_77 = ROI.ROIAlgebra(ROIS.ptv_56_70_77.name, ROIS.ptv_56_70_77.type, COLORS.ptv_low, sourcesA=[ptv_56, ptv_70], sourcesB=[ptv_77], marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_targets([ ROIS.gtv_n, ROIS.pelvic_nodes, ctv_n, ctv_56, ptv_n, ptv_semves, ptv_56, ptv_70_77, ptv_56_70_77 ]) # OARs: bladder_ptv.sourcesB.extend([ptv_70, ptv_56]) rectum_ptv.sourcesB.extend([ptv_70, ptv_56]) bowel_ptv = ROI.ROIAlgebra( ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA=[ROIS.bowel_space], sourcesB=[ptv_77, ptv_70, ptv_56], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) wall_ptv_70_77 = ROI.ROIWall(ROIS.z_ptv_70_77_wall.name, ROIS.z_ptv_70_77_wall.type, COLORS.wall, ptv_70_77, 1, 0) site.add_oars(DEF.prostate_nodes_oars + [bladder_ptv, rectum_ptv, wall_ptv_77] + [bowel_ptv, wall_ptv_70_77]) elif nodes == 'with': # Elective nodes: # Targets: ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70_sib.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA=[ROIS.vesicles], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_70 = ROI.ROIAlgebra( ROIS.ptv_70_sib.name, ROIS.ptv_70.type, COLORS.ptv_med, sourcesA=[ROIS.vesicles], sourcesB=[ptv_77], operator='Subtraction', marginsA=MARGINS.uniform_8mm_expansion, marginsB=MARGINS.zero) ptv_70_77 = ROI.ROIAlgebra( ROIS.ptv_70_77.name, ROIS.ptv_70_77.type, COLORS.ptv_low, sourcesA=[ROIS.prostate], sourcesB=[ROIS.vesicles], marginsA=MARGINS.prostate_seed_expansion, marginsB=MARGINS.uniform_8mm_expansion) ptv_56 = ROI.ROIAlgebra( ROIS.ptv_56.name, ROIS.ptv_56.type, COLORS.ptv_low, sourcesA=[ROIS.pelvic_nodes], sourcesB=[ptv_77, ptv_70], operator='Subtraction', marginsA=MARGINS.prostate_lymph_nodes_seed_expansion, marginsB=MARGINS.zero) ctv_56 = ROI.ROIAlgebra(ROIS.ctv_56.name, ROIS.ctv_56.type, COLORS.ctv_low, sourcesA=[ROIS.pelvic_nodes], sourcesB=[ptv_77, ptv_70], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_56_70_77 = ROI.ROIAlgebra(ROIS.ptv_56_70_77.name, ROIS.ptv_56_70_77.type, COLORS.ptv_low, sourcesA=[ptv_56, ptv_70], sourcesB=[ptv_77], marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_targets([ ROIS.pelvic_nodes, ctv_56, ptv_56, ptv_70_77, ptv_56_70_77 ]) # OARs: bladder_ptv.sourcesB.extend([ptv_70, ptv_56]) rectum_ptv.sourcesB.extend([ptv_70, ptv_56]) bowel_ptv = ROI.ROIAlgebra( ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA=[ROIS.bowel_space], sourcesB=[ptv_77, ptv_70, ptv_56], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) wall_ptv_70_77 = ROI.ROIWall(ROIS.z_ptv_70_77_wall.name, ROIS.z_ptv_70_77_wall.type, COLORS.wall, ptv_70_77, 1, 0) site.add_oars(DEF.prostate_nodes_oars + [bladder_ptv, rectum_ptv, wall_ptv_77] + [bowel_ptv, wall_ptv_70_77]) # Common ROIs for all conventional fractionation: site.add_targets([ ROIS.prostate, ROIS.vesicles, ctv_77, ctv_70, ptv_77, ptv_70 ]) elif frac == 'hypo_60': # Hypofractionated prostate with vesicles (3 Gy x 20): # Targets: ptv_57_60 = ROI.ROIAlgebra( ROIS.ptv_57_60.name, ROIS.ptv_57_60.type, COLORS.ptv_low, sourcesA=[ROIS.prostate], sourcesB=[ROIS.vesicles], marginsA=MARGINS.prostate_seed_expansion, marginsB=MARGINS.uniform_8mm_expansion) ptv_60 = ROI.ROIExpanded( ROIS.ptv_60.name, ROIS.ptv_60.type, COLORS.ptv_high, source=ROIS.prostate, margins=MARGINS.prostate_seed_expansion) ptv_57 = ROI.ROIAlgebra(ROIS.ptv_57.name, ROIS.ptv_57.type, COLORS.ptv_med, sourcesA=[ptv_57_60], sourcesB=[ptv_60], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ctv_57_60 = ROI.ROIAlgebra(ROIS.ctv_57_60.name, ROIS.ctv_57_60.type, COLORS.ctv_low, sourcesA=[ROIS.prostate], sourcesB=[ROIS.vesicles], marginsA=MARGINS.zero, marginsB=MARGINS.zero) ctv_60 = ROI.ROIExpanded(ROIS.ctv_60.name, ROIS.ctv_60.type, COLORS.ctv_high, source=ROIS.prostate) ctv_57 = ROI.ROIAlgebra(ROIS.ctv_57.name, ROIS.ctv_57.type, COLORS.ctv_med, sourcesA=[ctv_57_60], sourcesB=[ptv_60], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_targets([ ROIS.prostate, ROIS.vesicles, ctv_60, ctv_57, ctv_57_60, ptv_57_60, ptv_60, ptv_57 ]) # OARs: bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv_60, ptv_57], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra( ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA=[ROIS.rectum], sourcesB=[ptv_60, ptv_57], operator='Subtraction', marginsB=MARGINS.uniform_2mm_expansion) wall_ptv_60 = ROI.ROIWall(ROIS.z_ptv_60_wall.name, ROIS.z_ptv_60_wall.type, COLORS.wall, ptv_60, 0.5, 0) wall_ptv_57_60 = ROI.ROIWall(ROIS.z_ptv_57_60_wall.name, ROIS.z_ptv_57_60_wall.type, COLORS.wall, ptv_57_60, 1, 0) site.add_oars( DEF.prostate_oars + [bladder_ptv, rectum_ptv, wall_ptv_60, wall_ptv_57_60]) elif frac in ['hypo_55', 'palliative']: # STAMPEDE (2.75 Gy x 20) or palliative prostate (e.q. 3 Gy x 13): # Targets: ctv = ROI.ROIExpanded(ROIS.ctv.name, ROIS.ctv.type, COLORS.ctv_low, source=ROIS.prostate, margins=MARGINS.zero) if frac == 'hypo_55': # Choice 3: Seed match or bone match? match = choices[3] if match == 'seeds': # Seed match: ptv = ROI.ROIExpanded( ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, source=ctv, margins=MARGINS.prostate_seed_expansion) else: # Bone match: ptv = ROI.ROIExpanded( ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, source=ctv, margins=MARGINS.prostate_bone_match_expansion) elif frac == 'palliative': # Assuming no markers: ptv = ROI.ROIExpanded( ROIS.ptv.name, ROIS.ptv.type, COLORS.ptv_high, source=ctv, margins=MARGINS.prostate_bone_match_expansion) site.add_targets([ROIS.prostate, ctv, ptv]) # OARs: bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra( ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA=[ROIS.rectum], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_2mm_expansion) wall_ptv_55 = ROI.ROIWall(ROIS.z_ptv_wall.name, ROIS.z_ptv_wall.type, COLORS.wall, ptv, 1, 0) site.add_oars(DEF.prostate_palliative_oars + [bladder_ptv, rectum_ptv, wall_ptv_55]) else: # Prostate bed: # Choice 2: Fractionation - normo or hypo? frac = choices[2] # Fractionation: if frac == 'normo': # Conventional fractionation (2 Gy): # Choice 3: Nodes - included or not? nodes = choices[3] if nodes == 'no': # Prostate bed only: # Targets: ctv_70 = ROI.ROIExpanded(ROIS.ctv_70.name, ROIS.ctv_70.type, COLORS.ctv_high, source=ROIS.ctv_sb) ptv_70 = ROI.ROIExpanded( ROIS.ptv_70.name, ROIS.ptv_70.type, COLORS.ptv, source=ctv_70, margins=MARGINS.prostate_bone_match_expansion) # OARs: bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv_70], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra( ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA=[ROIS.rectum], sourcesB=[ptv_70], operator='Subtraction', marginsB=MARGINS.uniform_2mm_expansion) site.add_oars(DEF.prostate_bed_oars + [bladder_ptv, rectum_ptv]) else: # Elective nodes: if nodes == 'with': # Targets: ctv_70 = ROI.ROIExpanded(ROIS.ctv_70.name, ROIS.ctv_70.type, COLORS.ctv_high, source=ROIS.ctv_sb) ptv_70 = ROI.ROIExpanded( ROIS.ptv_70.name, ROIS.ptv_70.type, COLORS.ptv, source=ctv_70, margins=MARGINS.prostate_bone_match_expansion) else: # Elective nodes (with positive node): # Targets: ctv_n = ROI.ROIExpanded( ROIS.ctv_n.name, ROIS.ctv_n.type, COLORS.pelvic_nodes, source=ROIS.gtv_n, margins=MARGINS.uniform_5mm_expansion) ptv_n = ROI.ROIExpanded( ROIS.ptv_n.name, ROIS.ptv_n.type, ROIS.ptv_n.color, source=ctv_n, margins=MARGINS.uniform_5mm_expansion) ptv_sb = ROI.ROIExpanded( ROIS.ptv_sb.name, ROIS.ptv_sb.type, ROIS.ptv_sb.color, source=ROIS.ctv_sb, margins=MARGINS.prostate_bone_match_expansion) ctv_70 = ROI.ROIAlgebra(ROIS.ctv_70.name, ROIS.ctv_70.type, COLORS.ctv_med, sourcesA=[ROIS.ctv_sb], sourcesB=[ctv_n], operator='Union') ptv_70 = ROI.ROIAlgebra(ROIS.ptv_70.name, ROIS.ptv_70.type, COLORS.ptv, sourcesA=[ptv_sb], sourcesB=[ptv_n], operator='Union', marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_targets([ROIS.gtv_n, ctv_n, ptv_n, ptv_sb]) # Common for elective nodes (with or without positive node): # Targets: ctv_56 = ROI.ROIAlgebra(ROIS.ctv_56.name, ROIS.ctv_56.type, COLORS.ctv_low, sourcesA=[ROIS.pelvic_nodes], sourcesB=[ptv_70], operator='Subtraction', marginsA=MARGINS.zero, marginsB=MARGINS.zero) ptv_56 = ROI.ROIAlgebra( ROIS.ptv_56.name, ROIS.ptv_56.type, COLORS.ptv_low, sourcesA=[ROIS.pelvic_nodes], sourcesB=[ptv_70], operator='Subtraction', marginsA=MARGINS.uniform_5mm_expansion, marginsB=MARGINS.zero) ptv_56_70 = ROI.ROIAlgebra(ROIS.ptv_56_70.name, ROIS.ptv_56_70.type, COLORS.ptv_low, sourcesA=[ptv_56], sourcesB=[ptv_70], marginsA=MARGINS.zero, marginsB=MARGINS.zero) site.add_targets( [ROIS.pelvic_nodes, ctv_56, ptv_56, ptv_56_70]) # OARs: bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv_70, ptv_56], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra( ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA=[ROIS.rectum], sourcesB=[ptv_70, ptv_56], operator='Subtraction', marginsB=MARGINS.uniform_2mm_expansion) bowel_ptv = ROI.ROIAlgebra( ROIS.z_spc_bowel.name, ROIS.z_spc_bowel.type, COLORS.bowel_space, sourcesA=[ROIS.bowel_space], sourcesB=[ptv_70, ptv_56], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) wall_ptv_70 = ROI.ROIWall(ROIS.z_ptv_70_wall.name, ROIS.z_ptv_70_wall.type, COLORS.wall, ptv_70, 1, 0) wall_ptv_56_temp = ROI.ROIWall(ROIS.z_ptv_56_temp.name, ROIS.z_ptv_56_temp.type, COLORS.wall, ptv_56, 1, 0) wall_ptv_56 = ROI.ROIAlgebra( ROIS.z_ptv_56_wall.name, ROIS.z_ptv_56_wall.type, COLORS.wall, sourcesA=[wall_ptv_56_temp], sourcesB=[ptv_70, wall_ptv_70], operator='Subtraction', marginsB=MARGINS.zero) site.add_oars(DEF.prostate_bed_nodes_oars + [bladder_ptv, rectum_ptv] + [ bowel_ptv, ROIS.bowel_space, wall_ptv_70, wall_ptv_56_temp, wall_ptv_56 ]) # Common for all prostate bed (with or without nodes): site.add_targets([ROIS.ctv_sb, ctv_70, ptv_70]) else: # Hypofractionated (palliative): # Targets: ptv = ROI.ROIExpanded( ROIS.ptv_sb.name, ROIS.ptv_sb.type, COLORS.ptv_high, source=ROIS.ctv_sb, margins=MARGINS.prostate_bone_match_expansion) site.add_targets([ROIS.ctv_sb, ptv]) # OARs: bladder_ptv = ROI.ROIAlgebra( ROIS.z_bladder.name, ROIS.z_bladder.type, COLORS.bladder, sourcesA=[ROIS.bladder], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_3mm_expansion) rectum_ptv = ROI.ROIAlgebra( ROIS.z_rectum.name, ROIS.z_rectum.type, COLORS.rectum, sourcesA=[ROIS.rectum], sourcesB=[ptv], operator='Subtraction', marginsB=MARGINS.uniform_2mm_expansion) wall_ptv = ROI.ROIWall(ROIS.z_ptv_wall.name, ROIS.z_ptv_wall.type, COLORS.wall, ptv, 1, 0) site.add_oars([bladder_ptv, rectum_ptv, wall_ptv]) # Create all targets and OARs in RayStation: site.create_rois()