class WLDemo(WinstonLutzMixin, TestCase): num_images = 17 gantry_sag = 1 gantry_iso_size = 0.7 gantry_iso2bb_vector = Vector(0.2, 0.1, 0.4) collimator_iso_size = 0.5 collimator_iso2bb_vector = Vector(0.2, 0.4, 0) couch_iso_size = 1.2 couch_iso2bb_vector = Vector(-1, -0.4, 0) variable_axes = {0: 'Reference'} @classmethod def setUpClass(cls): cls.wl = WinstonLutz.from_demo_images()
class WLDemo(WinstonLutzMixin, TestCase): num_images = 17 gantry_iso_size = 1 gantry_iso2bb_vector = Vector(-0.4, 0.2, -0.5) collimator_iso_size = 1.2 collimator_iso2bb_vector = Vector(-0.15, 0.4, 0) couch_iso_size = 3.5 couch_iso2bb_vector = Vector(1.3, -0.7, 0) variable_axes = {0: 'Reference'} gantry_deviation = 0.9 @classmethod def setUpClass(cls): cls.wl = WinstonLutz.from_demo_images()
class WinstonLutzMixin(LocationMixin): dir_location = osp.join(TEST_BANK_DIR, 'Winston-Lutz') num_images = 0 zip = True gantry_iso_size = 0 collimator_iso_size = 0 couch_iso_size = 0 cax2bb_max_distance = 0 cax2bb_median_distance = 0 epid_deviation = None bb_shift_vector = Vector() # vector to place BB at iso axis_of_rotation = {0: 'Reference'} # fill with as many {image#: known_axis_of_rotation} pairs as desired print_results = False use_filenames = False @classmethod def setUpClass(cls): filename = cls.get_filename() if cls.zip: cls.wl = WinstonLutz.from_zip(filename, use_filenames=cls.use_filenames) else: cls.wl = WinstonLutz(filename, use_filenames=cls.use_filenames) if cls.print_results: print(cls.wl.results()) print(cls.wl.bb_shift_vector) def test_number_of_images(self): self.assertEqual(len(self.wl.images), self.num_images) def test_gantry_iso(self): # test iso size self.assertAlmostEqual(self.wl.gantry_iso_size, self.gantry_iso_size, delta=0.2) def test_collimator_iso(self): # test iso size if self.collimator_iso_size is not None: self.assertAlmostEqual(self.wl.collimator_iso_size, self.collimator_iso_size, delta=0.2) def test_couch_iso(self): # test iso size if self.couch_iso_size is not None: self.assertAlmostEqual(self.wl.couch_iso_size, self.couch_iso_size, delta=0.2) def test_epid_deviation(self): if self.epid_deviation is not None: self.assertAlmostEqual(max(self.wl.axis_rms_deviation(EPID)), self.epid_deviation, delta=0.2) def test_bb_max_distance(self): self.assertAlmostEqual(self.wl.cax2bb_distance(metric='max'), self.cax2bb_max_distance, delta=0.2) def test_bb_median_distance(self): self.assertAlmostEqual(self.wl.cax2bb_distance(metric='median'), self.cax2bb_median_distance, delta=0.2) def test_bb_shift_vector(self): self.assertTrue(vector_is_close(self.wl.bb_shift_vector, self.bb_shift_vector, delta=0.2), msg="The vector {} is not sufficiently close to vector {}".format(self.wl.bb_shift_vector, self.bb_shift_vector)) def test_known_axis_of_rotation(self): for idx, axis in self.axis_of_rotation.items(): self.assertEqual(axis, self.wl.images[idx].variable_axis)
class WLLateral3mm(WinstonLutzMixin, TestCase): # verified independently file_path = ['lat3mm.zip'] num_images = 4 gantry_iso_size = 0.5 cax2bb_max_distance = 3.8 cax2bb_median_distance = 2.3 bb_shift_vector = Vector(x=-3.6, y=0.5, z=0.6)
class WLDontUseFileNames(WinstonLutzMixin, TestCase): file_path = ['Naming.zip'] num_images = 4 gantry_iso_size = 0.3 cax2bb_max_distance = 0.9 cax2bb_median_distance = 0.8 bb_shift_vector = Vector(x=-0.4, y=0.6, z=0.6) axis_of_rotation = {0: Axis.REFERENCE, 1: Axis.GANTRY, 2: Axis.GANTRY, 3: Axis.GANTRY}
class WLLongitudinal3mm(WinstonLutzMixin, TestCase): # verified independently file_path = ['lng3mm.zip'] num_images = 4 gantry_iso_size = 0.5 cax2bb_max_distance = 3.9 cax2bb_median_distance = 3.7 bb_shift_vector = Vector(x=-0.63, y=3.6, z=0.6)
class WLVertical3mm(WinstonLutzMixin, TestCase): file_path = ['vrt3mm.zip'] num_images = 4 gantry_iso_size = 0.5 cax2bb_max_distance = 3.8 cax2bb_median_distance = 2.3 bb_shift_vector = Vector(x=-0.5, y=0.5, z=3.6) print_results = True
class WLLateral3mm(WinstonLutzMixin, TestCase): # verified independently dir_location = TEST_FILES_DIR file_path = ['Winston-Lutz', 'lat3mm.zip'] num_images = 4 gantry_iso_size = 0.5 cax2bb_max_distance = 3.8 cax2bb_median_distance = 2.3 bb_shift_vector = Vector(x=-3.7, y=0.6, z=-0.5)
class WLVertical3mm(WinstonLutzMixin, TestCase): dir_location = TEST_FILES_DIR file_path = ['Winston-Lutz', 'vrt3mm.zip'] num_images = 4 gantry_iso_size = 0.5 cax2bb_max_distance = 3.8 cax2bb_median_distance = 2.3 bb_shift_vector = Vector(x=-0.5, y=3.7, z=-0.5) print_results = True
class WLDontUseFileNames(WinstonLutzMixin, TestCase): dir_location = TEST_FILES_DIR file_path = ['Winston-Lutz', 'Naming.zip'] num_images = 4 gantry_iso_size = 0.3 cax2bb_max_distance = 0.9 cax2bb_median_distance = 0.8 bb_shift_vector = Vector(x=-0.4, y=0.6, z=0.6) axis_of_rotation = {0: REFERENCE, 1: GANTRY, 2: GANTRY, 3: GANTRY}
class WLUseFileNames(WinstonLutzMixin, TestCase): file_path = ['Naming.zip'] use_filenames = True num_images = 4 collimator_iso_size = 1.2 cax2bb_max_distance = 0.9 cax2bb_median_distance = 0.8 bb_shift_vector = Vector(y=0.6) axis_of_rotation = {0: Axis.COLLIMATOR, 1: Axis.COLLIMATOR, 2: Axis.COLLIMATOR, 3: Axis.COLLIMATOR}
class WLLongitudinal3mm(WinstonLutzMixin, TestCase): # verified independently dir_location = TEST_FILES_DIR file_path = ['Winston-Lutz', 'lng3mm.zip'] num_images = 4 gantry_iso_size = 0.5 cax2bb_max_distance = 3.9 cax2bb_median_distance = 3.7 bb_shift_vector = Vector(x=-0.7, y=0.6, z=-3.6) print_results = True
class WLNoisy30x5(WinstonLutzMixin, TestCase): """30x30mm field, 5mm BB. S&P noise added""" file_path = ['noisy_WL_30x5.zip'] num_images = 4 gantry_iso_size = 0.08 collimator_iso_size = 0 couch_iso_size = 0 cax2bb_max_distance = 0 cax2bb_median_distance = 0 epid_deviation = 0 bb_shift_vector = Vector()
class WLPerfect10x4(WinstonLutzMixin, TestCase): """10x10mm field, 4mm BB""" file_path = ['perfect_WL_10x4.zip'] num_images = 4 gantry_iso_size = 0 collimator_iso_size = 0 couch_iso_size = 0 cax2bb_max_distance = 0 cax2bb_median_distance = 0 epid_deviation = 0 bb_shift_vector = Vector()
class WLUseFileNames(WinstonLutzMixin, TestCase): dir_location = TEST_FILES_DIR file_path = ['Winston-Lutz', 'Naming.zip'] use_filenames = True num_images = 4 collimator_iso_size = 1.2 cax2bb_max_distance = 0.9 cax2bb_median_distance = 0.8 bb_shift_vector = Vector(y=np.nan, z=-0.6) axis_of_rotation = {0: COLLIMATOR, 1: COLLIMATOR, 2: COLLIMATOR, 3: COLLIMATOR} print_results = True
class WLDemo(WinstonLutzMixin, TestCase): num_images = 17 gantry_iso_size = 1 collimator_iso_size = 1.2 couch_iso_size = 1.1 cax2bb_max_distance = 1 cax2bb_median_distance = 0.7 axis_of_rotation = {0: 'Reference'} bb_shift_vector = Vector(y=-0.1, z=0.3) @classmethod def setUpClass(cls): cls.wl = WinstonLutz.from_demo_images()
class WLDemo(WinstonLutzMixin, TestCase): num_images = 17 gantry_iso_size = 1 collimator_iso_size = 1.2 couch_iso_size = 2.3 cax2bb_max_distance = 1.2 cax2bb_median_distance = 0.7 epid_deviation = 1.3 axis_of_rotation = {0: Axis.REFERENCE} bb_shift_vector = Vector(x=0.4, y=-0.4, z=-0.2) @classmethod def setUpClass(cls): cls.wl = WinstonLutz.from_demo_images() cls.wl.analyze()
def collimator_iso2bb_vector(self): """The 2D vector from the collimator isocenter to the BB (located at the origin).""" min_col = self._minimize_axis(COLLIMATOR) return Vector(min_col.x[0], min_col.x[1])
def cax2bb_vector(self): """The vector in mm from the CAX to the BB.""" dist = (self.field_cax - self.bb) / self.dpmm return Vector(dist.x, dist.y, dist.z)
def gantry_iso2bb_vector(self): """The 3D vector from the isocenter to the BB (located at the origin).""" min_fun = self._minimize_axis(GANTRY) return Vector(min_fun.x[0], min_fun.x[1], min_fun.x[2])
def couch_iso2bb_vector(self): """The 2D vector from the couch isocenter to the BB (located at the origin).""" min_col = self._minimize_axis(COUCH) return Vector(min_col.x[0], min_col.x[1])