示例#1
0
 def test_global_to_beam_G270_C270(self):
     """ Test at G270, C270 """
     source = Source("varian_clinac_6MV")
     source.gantry(270)
     source.collimator(270)
     global_coords = np.array([.1, .2, .3])
     beam_coords = global_to_beam(global_coords, source.position,
                                  source.rotation)
     correct = np.array([-.2, .3, -100.1])
     np.testing.assert_array_almost_equal(correct, beam_coords, decimal=5)
示例#2
0
 def test_global_to_beam_G0_C90(self):
     """ Test at G0, C90 """
     source = Source("varian_clinac_6MV")
     source.gantry(0)
     source.collimator(90)
     global_coords = np.array([.1, .2, .3])
     beam_coords = global_to_beam(global_coords, source.position,
                                  source.rotation)
     correct = np.array([.2, -.1, -99.7])
     np.testing.assert_array_almost_equal(correct, beam_coords, decimal=5)
示例#3
0
    def calculate(self, source, block, phantom, settings):

        # Transform phantom to beam coords
        print("Transforming phantom to beam coords...")
        phantom_beam = np.zeros_like(phantom.positions)
        _, xlen, ylen, zlen = phantom_beam.shape
        for x in tqdm(range(xlen)):
            for y in range(ylen):
                for z in range(zlen):
                    phantom_beam[:, x, y, z] = global_to_beam(
                        phantom.positions[:, x, y, z], source.position,
                        source.rotation)

        print("Interpolating phantom densities...")
        phantom_densities_interp = RegularGridInterpolator(
            (phantom_beam[0, :, 0, 0], phantom_beam[1, 0, :, 0],
             phantom_beam[2, 0, 0, :]),
            phantom.densities,
            method='nearest',
            bounds_error=False,
            fill_value=0)

        # Create dose grid (just the same size as the phantom for now)
        self.dose_grid_positions = np.copy(phantom_beam)

        # Perform hit testing to find which dose grid voxels are in the beam
        print("Performing hit-testing of dose grid voxels...")
        _, xlen, ylen, zlen = self.dose_grid_positions.shape
        dose_grid_blocked = np.zeros((xlen, ylen, zlen))
        dose_grid_OAD = np.zeros((xlen, ylen, zlen))
        for x in tqdm(range(xlen)):
            for y in range(ylen):
                for z in range(zlen):
                    voxel = self.dose_grid_positions[:, x, y, z]
                    psi = line_block_plane_collision(voxel)
                    dose_grid_blocked[x, y, z] = (block.block_values_interp(
                        [psi[0], psi[1]]))
                    # Save off-axis distance (at iso plane) for later
                    dose_grid_OAD[x, y,
                                  z] = (euclidean(np.array([0, 0, source.SAD]),
                                                  psi))

        # Calculate effective depths of dose grid voxels
        print("Calculating effective depths of dose grid voxels...")
        dose_grid_d_eff = np.zeros_like(dose_grid_blocked)
        xlen, ylen, zlen = dose_grid_d_eff.shape
        for x in tqdm(range(xlen)):
            for y in range(ylen):
                for z in range(zlen):
                    voxel = self.dose_grid_positions[:, x, y, z]
                    psi = line_calc_limit_plane_collision(voxel)
                    dist = np.sqrt(np.sum(np.power(voxel - psi, 2)))
                    num_steps = np.floor(dist / settings['stepSize'])
                    xcoords = np.linspace(voxel[0], psi[0], num_steps)
                    ycoords = np.linspace(voxel[1], psi[1], num_steps)
                    zcoords = np.linspace(voxel[2], psi[2], num_steps)
                    dose_grid_d_eff[x, y, z] = np.sum(
                        phantom_densities_interp(
                            np.dstack((xcoords, ycoords, zcoords))) *
                        settings['stepSize'])

        # Calculate photon fluence at dose grid voxels
        print("Calculating fluence...")
        self.dose_grid_fluence = np.zeros_like(dose_grid_blocked)
        xlen, ylen, zlen = self.dose_grid_fluence.shape
        self.dose_grid_fluence = (settings['sPri'] * -source.SAD /
                                  self.dose_grid_positions[2, :, :, :] *
                                  dose_grid_blocked)

        # Calculate beam softening factor for dose grid voxels
        print("Calculating beam softening factor...")
        f_soften = np.ones_like(dose_grid_OAD)
        f_soften[dose_grid_OAD < settings['softLimit']] = 1 / (
            1 - settings['softRatio'] *
            dose_grid_OAD[dose_grid_OAD < settings['softLimit']])

        # Calculate TERMA of dose grid voxels
        print("Calculating TERMA...")
        E = np.linspace(settings['eLow'], settings['eHigh'], settings['eNum'])
        spectrum_weights = source.weights(E)
        mu_water = conehead.nist.mu_water(E)
        self.dose_grid_terma = np.zeros_like(dose_grid_blocked)
        xlen, ylen, zlen = self.dose_grid_terma.shape
        for x in tqdm(range(xlen)):
            for y in range(ylen):
                for z in range(zlen):
                    self.dose_grid_terma[x, y, z] = (np.sum(
                        spectrum_weights * self.dose_grid_fluence[x, y, z] *
                        np.exp(-mu_water * f_soften[x, y, z] *
                               dose_grid_d_eff[x, y, z]) * E * mu_water))