def step(self, model, step_num): alpha = self.get_alpha(model, step_num) # multiplication det_num = model.detector_signal.shape[0] for i in range(self.n_slices): # get slice # ############## may be speeded up if all slices are calc. once out of for cycle i1 = int(i * np.ceil(det_num / self.n_slices)) i2 = int(min((i + 1) * np.ceil(det_num / self.n_slices), det_num)) w_slice = model.detector_geometry[i1:i2] wi_slice = self.wi[i1:i2] y_slice = model.detector_signal[i1:i2] # calculating correction p = signal.get_signal(model.solution, w_slice) dp = y_slice - p a = np.divide(dp, wi_slice, out=np.zeros_like(dp), where=wi_slice != 0) if self.iter_type == 1: # SMART a = np.divide(a, np.abs(y_slice), out=np.zeros_like(a), where=y_slice > 1E-20) correction = alpha / (i2 - i1) * np.sum( np.multiply(np.moveaxis(w_slice, 0, -1), a), axis=-1) model.solution = model.solution + correction
def step(self, model, step_num): # expected signal y_expected = signal.get_signal(model.solution, model.detector_geometry) # multiplication mult = np.sum(np.divide(self.w_det, y_expected, out=np.zeros_like(self.w_det), where=y_expected != 0), axis=-1) mult = mult / self.wi # find delta model.solution = model.solution * mult
def step(self, model, solution, real_solution, *args, **kwargs): """Residual norm at current step. Args: model(tomomak.Model): used model. real_solution(ndarray): known solution. *args, **kwargs: not used, but needed to be here in order to work with Solver properly. Returns: float: residual norm """ norm = model.detector_signal - signal.get_signal( model.solution, model.detector_geometry) norm = np.square(norm) res = np.sqrt(np.sum(norm)) self.data.append(res) return res
mod.solution = None # Next step is to provide information about the detectors. # Let's create 15 fans with 22 detectors around the investigated object. # Each line will have 1 cm width and 0.2 Rad divergence. # Note that number of detectors = 330 < solution cells = 600, so it's impossible to get perfect solution. det = detectors2d.fan_detector_array(mesh=mesh, focus_point=(5, 5), radius=11, fan_num=15, line_num=22, width=1, divergence=0.2) # Now we can calculate signal of each detector. # Of course in the real experiment you measure detector signals so you don't need this function. det_signal = signal.get_signal(real_solution, det) mod.detector_signal = det_signal mod.detector_geometry = det # Let's take a look at the detectors geometry: mod.plot2d(data_type='detector_geometry') # It's also possible to get short model summary by converting the model object to string. print(mod) # The next step is optional. You can perform transformation with existing geometry, # e.g. switch to another coordinate system or to basic function space. # Convenient way to do this is to use pipeline. Once pipeline is created, # you can do transformations using forward() method. # And if you wish to perform backward transformation later, you can use backward() method. # let's rescale our model to 20x20 cells. Rescale class performs transformation to the # keeps axes types but changes number of segments. If the axis is irregular, rescaling take it into account. pipe = pipeline.Pipeline(mod)
# You should see a discrete circle. Now let's pretend that solution is unknown. mod.solution = None # We will start with the ideal case: no signal noise and number of detectors > number of cells. # Let's create 30 fan detectors around the target. 40 detectors in each fan. det = detectors2d.fan_detector_array(mesh=mesh, focus_point=(5, 5), radius=11, fan_num=30, line_num=40, width=0.5, divergence=0.05) mod.detector_geometry = det # Next step is to simulate each detector signal. det_signal = signal.get_signal(real_solution, det) mod.detector_signal = det_signal # Now let's create solver which will use ART with step = 0.1 in order to find the solution. solver = solver.Solver() solver.iterator = algebraic.ART() solver.iterator.alpha = 0.1 # When you are using ART, often a good idea is to suggest that all values are positive. c1 = tomomak.constraints.basic.Positive() solver.constraints = [c1] # Finally we want some quantitative parameters in order to evaluate reconstruction results. # Let's count residual mean square and residual norm. solver.statistics = [statistics.RMS(), statistics.RN()] # In order to get RMS real solution should be defined. solver.real_solution = real_solution
end = time.time() print("Parallel calculation took {} s ".format(end - start)) # This calculation went faster. Note, that parallelization is effective only for the long calculation. # We can visualize new geometry and see that it is the same. mod.detector_geometry = det mod.plot2d(data_type='detector_geometry') # The next step is inverse problem solution. Here you can use GPU acceleration. It requires CuPy to be installed. # To turn it on run script with environmental variable TM_GPU set to any nonzero value. # Or just write in your script: # import os # os.environ["TM_GPU"] = "1" # Let's create synthetic object and find the solution using CPU. real_solution = objects2d.ellipse(mesh, (5, 5), (3, 3)) mod.detector_signal = signal.get_signal(real_solution, det) solver = Solver() solver.iterator = ml.ML() steps = 3000 solver.solve(mod, steps=steps) # Now we let's switch to GPU. os.environ["TM_GPU"] = "1" mod.solution = None # Since you enabled GPU in the middle of the execution, you need to recreate solver. # The syntax doesn't change. solver.iterator = ml.ML() solver.solve(mod, steps=steps) # Let's see the result. mod.plot2d()
radius=45, theta_num=20, phi_num=20) mod.plot3d(axes=True, style=3, data_type='detector_geometry', cartesian_coordinates=True) # You can add other detectors - just uncomment the line and append the result using mod.add_detector(det) # det = [detectors3d.aperture_detector(mesh, [(4, -5, 4), (6, -5, 4), (4, -5, 6), (6, -5, 6)], # [(4, 0, 4), (6, 0, 4), (4, 0, 6), (6, 0, 6)])] # det = [detectors3d.aperture_detector(mesh, [(4, -5, 4), (6, -5, 4), (4, -5, 6), (6, -5, 6)], # [(4, 0, 4), (6, 0, 4), (4, 0, 6), (6, 0, 6)])] # ver = np.array([[0, 0, 0], [0, 0, 10], [0, 10, 0], [10, 0, 0]]) # det = [detectors3d.custom_detector(mesh, ver, radius_dependence=False)] # det = [detectors3d.line_detector(mesh, (5, 5, 12), (10, 2, 0), 1, calc_volume=True)] # det = [detectors3d.cone_detector(mesh, (5, 5, 20), (5, 5, 0), 0.3)] # det = [detectors3d.line_detector(mesh, (5, 5, 12), (10, 2, 0), None, calc_volume=False)] # det = detectors3d.fan_detector(mesh, (-5, 5, 5), [[5, 2, 6], [5, 7, 6], [5, 2, 4], [5, 7, 4]], # number=[4, 4], divergence=0.3) det_signal = signal.get_signal(real_solution, mod.detector_geometry) mod.detector_signal = det_signal # Now let's find the solution solver = Solver() solver.statistics = [statistics.RN(), statistics.RMS()] solver.real_solution = real_solution solver.iterator = ml.ML() steps = 1500 solver.solve(mod, steps=steps) mod.save("tor.tmm") # Now we can see the solution. mod.plot3d(axes=True, style=3, cartesian_coordinates=True) mod.plot2d(index=(1,2), cartesian_coordinates=True) solver.plot_statistics() # Of course, the result we got is not ideal due to limitations of our synthetic experiment.