def get_contrast_map(epsilon_r=None, sigma=None, epsilon_rb=None, sigma_b=None, omega=None): """Compute the contrast function for a given image. Parameters ---------- epsilon_r : `:class:numpy.ndarray` A matrix with the relative permittivity map. sigma : `:class:numpy.ndarray` A matrix with the conductivity map [S/m]. epsilon_rb : float Background relative permittivity of the medium. sigma_b : float Background conductivity of the medium [S/m]. frequency : float Linear frequency of operation [Hz]. """ if epsilon_r is None and sigma is None: raise error.MissingInputError('get_contrast_map', 'epsilon_r or sigma') if epsilon_r is not None and epsilon_rb is None: raise error.MissingInputError('get_contrast_map', 'epsilon_rb') if sigma is not None and sigma_b is None: raise error.MissingInputError('get_contrast_map', 'sigma_b') if sigma is not None and omega is None: raise error.MissingInputError('get_contrast_map', 'omega') if sigma is None: return (epsilon_r / epsilon_rb - 1) + 0j elif epsilon_r is None: return -1j * (sigma - sigma_b) / (omega * epsilon_rb * ct.epsilon_0) else: return (epsilon_r / epsilon_rb - 1 - 1j * (sigma - sigma_b) / (omega * epsilon_rb * ct.epsilon_0))
def __init__(self, configuration, linear_solver, parameter): r"""Create the object. Parameters ---------- configuration : :class:`configuration.Configuration` The container with the problem configuration variables. linear_solver : {'tikhonov', 'landweber', 'cg', 'lstsq'} The name of the chosen linear system solver. parameter The parameter to configure the linear solver. It may be defined in different ways: * `linear_solver='tikhonov'`: in this case, `parameter` will depend on different strategies of determining it. There are three different choice strategies: * Fixed: when you want to define an arbitrary value. The argument must be `parameter=('fixed', float())` or `parameter=float()`. * SVD-based: a strategy according to [1]_, which is based on Singular Value Decomposition and the definition of a Relative Residual Error. In this case, `parameter='lavarello'. * The Discrepancy Principle of Mozorov: a traditional principle for defining the regularization parameter of Tikhonov regularization [2]_. In this case, `parameter='mozorov'`. * L-curve: the parameter value is chosen according to the curve which relates error and solution norm. * `linear_solver='landweber'`: the method depend on two parameters: the regularization coefficient and the number of iterations. Therefore, `parameter=(float(), int())` for defining the regularization coefficient and the number of iterations, respectively; or `parameter=float()`, which will define the regularization coefficient and the number of iterations will be defined as 1000. The regularization parameter is defined as a proportion constant to: .. math:: \frac{1}{||A||^2} * `linear_solver='cg'`: The Conjugated-Gradient method depends on a parameter which means the noise level of the data. Therefore, `parameter=float()`. * `linear_solver='lstsq'`: The Least Squares Method depend on a parameter called `rcond` which means the truncation level of singular values of `A`. Therefore, singular values under this threshold will be truncated to zero. The argument is `parameter=float()`. Default: `1e-3`. References ---------- .. [1] Lavarello, Roberto, and Michael Oelze. "A study on the reconstruction of moderate contrast targets using the distorted Born iterative method." IEEE transactions on ultrasonics, ferroelectrics, and frequency control 55.1 (2008): 112-124. .. [2] Kirsch, Andreas. An introduction to the mathematical theory of inverse problems. Vol. 120. Springer Science & Business Media, 2011. """ super().__init__(configuration) self.name = "Method of Weighted Residuals" self.alias_name = 'mwr' self.discretization_method_alias = '' self.discretization_method_name = '' if linear_solver == TIKHONOV_METHOD: self.linsolver = linear_solver if isinstance(parameter, str): if (parameter == MOZOROV_CHOICE or parameter == LAVARELLO_CHOICE): self._choice_strategy = parameter self.parameter = None elif parameter == LCURVE_CHOICE: self._choice_strategy = parameter self._bounds = None self._number_terms = None elif parameter == FIXED_CHOICE: raise error.MissingInputError( 'MethodOfWeightedResiduals.__init__', 'parameter_value') else: raise error.WrongValueInput( 'MethodOfWeightedResiduals.__init__', 'parameter', "{'mozorov', 'lavarello', 'fixed'}", parameter) elif isinstance(parameter, float): self.parameter = parameter self._choice_strategy = FIXED_CHOICE elif isinstance(parameter, tuple) or isinstance(parameter, list): if parameter[0] == FIXED_CHOICE: if isinstance(parameter[1], float): self._choice_strategy = parameter[0] self.parameter = parameter[1] else: raise error.WrongTypeInput( 'MethodOfWeightedResiduals.__init__', "('fixed', parameter_value)", 'float', type(parameter[1])) elif (parameter[0] == LAVARELLO_CHOICE or parameter[0] == MOZOROV_CHOICE): self._choice_strategy = parameter[0] self.parameter = parameter[1] elif parameter[0] == LCURVE_CHOICE: self._choice_strategy = parameter[0] if len(parameter) == 2: self._number_terms = parameter[1] self._bounds = None elif len(parameter) == 3: self._number_terms = parameter[1] self._bounds = (parameter[2], 0) elif len(parameter) == 4: self._number_terms = parameter[1] self._bounds = (parameter[2], parameter[3]) else: raise error.WrongValueInput( 'MethodOfWeightedResiduals', 'parameter', "'lcurve' or ('lcurve', number_terms) " + "or ('lcurve', number_terms, lower_bound) " + "or ('lcurve', number_terms, lower_bound, " + " upper_bound)", "len(parameter) > 4") else: raise error.WrongValueInput( 'MethodOfWeightedResiduals.__init__', '(choice_strategy,...)', "{'mozorov', 'lavarello', 'fixed', 'exhaustive'," + " 'lcurve'}", parameter[0]) if self._choice_strategy == LAVARELLO_CHOICE: self._beta_approximation = None elif linear_solver == LANDWEBER_METHOD: self.linsolver = linear_solver if isinstance(parameter, tuple): self.parameter = parameter else: self.parameter = (parameter, 1000) elif linear_solver == CONJUGATED_GRADIENT_METHOD: self.linsolver = linear_solver if isinstance(parameter, float): self.parameter = parameter else: raise error.WrongTypeInput( 'MethodOfWeightedResiduals.__init__', 'parameter', 'float', type(parameter)) elif linear_solver == LEAST_SQUARES_METHOD: self.linsolver = linear_solver if isinstance(parameter, float): self.parameter = parameter elif parameter is None: self.parameter = 1e-3 else: raise error.WrongTypeInput( 'MethodOfWeightedResiduals.__init__', 'parameter', 'float', ) else: raise error.WrongValueInput( 'MethodOfWeightedResiduals.__init__', 'linear_solver', "{'tikhonov', 'landweber', 'cg'," + "'lstsq'}", linear_solver)
def get_coordinates_ddomain(configuration=None, resolution=None, dx=None, dy=None, xmin=None, xmax=None, ymin=None, ymax=None): """Return the meshgrid of the image domain. Examples -------- The function must be called in only one of the two different ways: >>> get_coordinates_ddomain(configuration=Configuration() resolution=(100, 100)) >>> get_coordinates_ddomain(dx=.1, dy=.1, xmin=-1., xmax=1., ymin=-1., ymax=1.) Parameters ---------- configuration : :class:`Configuration` A configuration object. resolution : 2-tuple Discretization size in y- and x-coordinates (this order). dx, dy : float Cell size. xmin, xmax : float Limits of the interval in x-axis. ymin, ymax : float Limits of the interval in y-axis. Notes ----- The D-domain are such that (x,y) in [xmin,xmax] times [ymin, ymax]. The coordinates are positioned at the center of the cells. """ function_name = 'get_coordinates_ddomain' if configuration is not None and resolution is None: raise error.MissingInputError(function_name, 'resolution') elif configuration is None and resolution is not None: raise error.MissingInputError(function_name, 'configuration') elif configuration is None and (dx is None or dy is None or xmin is None or xmax is None or ymin is None or ymax is None): inputs = [] if dx is None: inputs.append('dx') if dy is None: inputs.append('dy') if xmin is None: inputs.append('xmin') if xmax is None: inputs.append('xmax') if ymin is None: inputs.append('ymin') if ymax is None: inputs.append('ymax') raise error.MissingInputError(function_name, inputs) if configuration is not None: NY, NX = resolution xmin, xmax = get_bounds(configuration.Lx) ymin, ymax = get_bounds(configuration.Ly) dx, dy = configuration.Lx / NX, configuration.Ly / NY return np.meshgrid(np.arange(xmin + .5 * dx, xmax, dx), np.arange(ymin + .5 * dy, ymax, dy))
def __init__(self, name=None, number_measurements=10, number_sources=10, observation_radius=None, frequency=None, wavelength=None, background_permittivity=1., background_conductivity=.0, image_size=[1., 1.], wavelength_unit=True, magnitude=1., perfect_dielectric=False, good_conductor=False, import_filename=None, import_filepath='', path=''): """Build or import a configuration object. You may either give the parameters or import information from a save object. In addition, you must give either the frequency of operation or the wavelength. Parameters ---------- name : string A string naming the problem configuration. number_measurements : int, default: 10 Receivers in S-domain. number_sources : int, default: 10 Sources in S-domain observation_radius : float, default: 1.1*sqrt(2)*max([Lx,Ly]) Radius for circular array of sources and receivers at S-domain [m] frequency : float Linear frequency of operation [Hz] wavelength : float Background wavelength [m] background_permittivity : float, default: 1. Relative permittivity. background_conductivity : float, default: .0 [S/m] image_size : 2-tuple of int, default: (1., 1.) Side length of the image domain (D-domain). It may be given in meters or in wavelengths. wavelength_unit : boolean, default: True If `True`, the variable image_size will be interpreted as given in wavelegnths. Otherwise, it will be interpreted in meters. magnitude : float, default: 1.0 Magnitude of the incident field. perfect_dielectric : boolean, default: False If `True`, it indicates the assumption of only perfect dielectric objects. Then, only the relative permittivity map will be recovered. good_conductor : boolean, default: False If `True`, it indicates the assumption of only good conductors objects. Then, only the conductivity map will be recovered. import_filename : string, default: None A string with the name of the pickle file containing the information of a previous Configuration object. import_filepath : string, default: '' A string containing the path to the object to be imported. """ if import_filename is not None: self.importdata(import_filename, import_filepath) else: if name is None: raise error.MissingInputError('Configuration.__init__()', 'name') if wavelength is None and frequency is None: raise error.MissingInputError('Configuration.__init__()', 'frequency or wavelength') elif wavelength is not None and frequency is not None: raise error.ExcessiveInputsError('Configuration.__init__()', ['frequency', 'wavelength']) if perfect_dielectric and good_conductor: raise error.ExcessiveInputsError( 'Configuration.__init__()', ['perfect_dielectric', 'good_conductor']) self.name = name self.NM = number_measurements self.NS = number_sources self.epsilon_rb = background_permittivity self.sigma_b = background_conductivity self.perfect_dielectric = perfect_dielectric self.good_conductor = good_conductor self.E0 = magnitude self.path = path if frequency is not None: self.f = frequency self.lambda_b = compute_wavelength(frequency, self.epsilon_rb, sigma=self.sigma_b) else: self.lambda_b = wavelength self.f = compute_frequency(self.lambda_b, self.epsilon_rb) self.kb = compute_wavenumber(self.f, epsilon_r=self.epsilon_rb, sigma=self.sigma_b) if wavelength_unit: self.Lx = image_size[1] * self.lambda_b self.Ly = image_size[0] * self.lambda_b else: self.Lx = image_size[1] self.Ly = image_size[0] if observation_radius is None: self.Ro = 1.1 * np.sqrt(2) * max([self.Lx, self.Ly]) else: if wavelength_unit: self.Ro = observation_radius * self.lambda_b else: self.Ro = observation_radius
def __init__(self, name=None, configuration_filename=None, resolution=None, scattered_field=None, total_field=None, incident_field=None, relative_permittivity_map=None, conductivity_map=None, noise=None, import_filename=None, import_filepath='', homogeneous_objects=True, compute_residual_error=True, compute_map_error=False, compute_totalfield_error=False, path=''): r"""Build or import an object. You must give either the import file name and path or the required variables. Call signatures:: InputData(import_filename='my_file', import_filepath='./data/') InputData(name='instance00', configuration_filename='setup00', ...) Parameters ---------- name : string The name of the instance. `configuration_filename` : string A string with the name of the problem configuration file. resolution : 2-tuple The size, in pixels, of the image to be recovered. Y-X ordered. scattered_field : :class:`numpy.ndarray` A matrix containing the scattered field information at S-domain. total_field : :class:`numpy.ndarray` A matrix containing the total field information at D-domain. incident_field : :class:`numpy.ndarray` A matrix containing the incident field information at D-domain. relative_permittivity_map : :class:`numpy.ndarray` A matrix with the discretized image of the relative permittivity map. conductivity_map : :class:`numpy.ndarray` A matrix with the discretized image of the conductivity map. noise : float Noise level of scattered field data. homogeneous_objects : bool A flag to indicate if the instance only contains homogeneous objects. compute_residual_error : bool A flag to indicate the measurement of the residual error throughout or at the end of the solver executation. compute_map_error : bool A flag to indicate the measurement of the error in predicting the dielectric properties of the image. compute_totalfield_error : bool A flag to indicate the measurement of the estimation error of the total field throughout or at the end of the solver executation. import_filename : string A string with the name of the saved file. import_filepath : string A string with the path to the saved file. """ if import_filename is not None: self.importdata(import_filename, import_filepath) else: if name is None: raise error.MissingInputError('InputData.__init__()', 'name') if configuration_filename is None: raise error.MissingInputError('InputData.__init__()', 'configuration_filename') if (resolution is None and relative_permittivity_map is None and conductivity_map is None): raise error.MissingInputError('InputData.__init__()', 'resolution') self.name = name self.path = path self.configuration_filename = configuration_filename self.homogeneous_objects = homogeneous_objects self.compute_residual_error = compute_residual_error self.compute_map_error = compute_map_error self.compute_totalfield_error = compute_totalfield_error self.total_field_resolution = None if resolution is not None: self.resolution = resolution else: self.resolution = None if scattered_field is not None: self.es = np.copy(scattered_field) else: self.es = None if total_field is not None: self.et = np.copy(total_field) else: self.et = None if incident_field is not None: self.ei = np.copy(incident_field) else: self.ei = None if relative_permittivity_map is not None: self.epsilon_r = relative_permittivity_map if resolution is None: self.resolution = relative_permittivity_map.shape else: self.epsilon_r = None if conductivity_map is not None: self.sigma = conductivity_map if resolution is None: self.resolution = conductivity_map.shape else: self.sigma = None if noise is not None: self.noise = noise else: self.noise = None
def draw(self, figure_title=None, file_path='', file_format='eps', show=False): """Draw the relative permittivity/conductivity map. Parameters ---------- figure_title : str, optional A title that you want to give to the figure. show : boolean, default: False If `True`, a window will be raised to show the image. If `False`, the image will be saved. file_path : str, default: '' A path where you want to save the figure. file_format : str, default: 'eps' The file format. It must be one of the available ones by `matplotlib.pyplot.savefig()`. """ if self.epsilon_r is not None and self.sigma is None: plt.imshow(self.epsilon_r, origin='lower') plt.xlabel('x [Pixels]') plt.ylabel('y [Pixels]') if figure_title is None: plt.title('Relative Permittivity Map') else: plt.title(figure_title) cbar = plt.colorbar() cbar.set_label(r'$\epsilon_r$') elif self.epsilon_r is None and self.sigma is not None: plt.imshow(self.sigma, origin='lower') plt.xlabel('x [Pixels]') plt.ylabel('y [Pixels]') if figure_title is None: plt.title('Conductivity Map') else: plt.title(figure_title) cbar = plt.colorbar() cbar.set_label(r'$\sigma$ [S/m]') elif self.epsilon_r is not None and self.sigma is not None: fig = plt.figure(figsize=(10, 4)) fig.subplots_adjust(left=.125, bottom=.1, right=.9, top=.9, wspace=.5, hspace=.2) if type(figure_title) is str: fig.suptitle(figure_title, fontsize=16) elif figure_title is None: fig.suptitle(self.name, fontsize=16) ax = fig.add_subplot(1, 2, 1) im1 = ax.imshow(self.epsilon_r, origin='lower') ax.set_xlabel('x [Pixels]') ax.set_ylabel('y [Pixels]') cbar = fig.colorbar(im1, fraction=0.046, pad=0.04) cbar.set_label(r'$\epsilon_r$') ax.set_title('Relative Permittivity') ax = fig.add_subplot(1, 2, 2) im2 = ax.imshow(self.sigma, origin='lower') ax.set_xlabel('x [Pixels]') ax.set_ylabel('y [Pixels]') cbar = fig.colorbar(im2, fraction=0.046, pad=0.04) cbar.set_label(r'$\sigma$') ax.set_title('Conductivity') else: raise error.MissingInputError( 'InputData.draw()', 'relative_permittivity or ' + 'conductivity') if self.epsilon_r is not None or self.sigma is not None: if show: plt.show() else: plt.savefig(file_path + self.name + '.' + file_format, format=file_format) plt.close()