Example #1
0
    def _set_meshes(self, inputdata):
        """Set elements meshgrid data.

        Parameters
        ----------
            inputdata : :class:`inputdata.InputData`
                An instance of problem with resolution information.
        """
        # S-domain resolution
        NM, NS = self.configuration.NM, self.configuration.NS

        # Elements resolution
        NQ, NP = self.discretization

        # Image resolution
        NY, NX = inputdata.resolution
        dx = self.configuration.Lx / NX
        dy = self.configuration.Ly / NY

        # S-domain mesh
        xm, ym = cfg.get_coordinates_sdomain(self.configuration.Ro,
                                             self.configuration.NM)
        xms, yms = (np.reshape(np.tile(xm.reshape((-1, 1)), (1, NS)), (-1)),
                    np.reshape(np.tile(ym.reshape((-1, 1)), (1, NS)), (-1)))

        # Image mesh at D-domain
        x, y = cfg.get_coordinates_ddomain(configuration=self.configuration,
                                           resolution=inputdata.resolution)
        self._u, self._v = x.reshape(-1), y.reshape(-1)
        self._du, self._dv = dx, dy

        # Elements meshgrid
        self._xpq, self._ypq = get_elements_mesh(NX, NY, dx, dy, NP, NQ)

        # Radius matrix
        self._R = np.zeros((NM * NS, self._u.size))
        for i in range(NM * NS):
            self._R[i, :] = np.sqrt((xms[i] - self._u)**2 +
                                    (yms[i] - self._v)**2)

        # Bilinear trial function does not depend on field information
        if self.trial_function == TRIAL_BILINEAR:
            self._fij = bilinear(self._u.reshape((NY, NX)),
                                 self._v.reshape((NY, NX)),
                                 self._xpq.reshape((NQ, NP)),
                                 self._ypq.reshape((NQ, NP)))
Example #2
0
 def _compute_green_function(self, resolution):
     """Summarize method."""
     NM = self.configuration.NM
     NY, NX = resolution
     N = NX * NY
     kb = self.configuration.kb
     xm, ym = cfg.get_coordinates_sdomain(self.configuration.Ro, NM)
     x, y = cfg.get_coordinates_ddomain(configuration=self.configuration,
                                        resolution=resolution)
     dx, dy = x[0, 1] - x[0, 0], y[1, 0] - y[0, 0]
     xm = np.tile(xm.reshape((-1, 1)), (1, N))
     ym = np.tile(ym.reshape((-1, 1)), (1, N))
     R = np.sqrt((xm - np.tile(np.reshape(x, (N, 1)).T, (NM, 1)))**2 +
                 (ym - np.tile(np.reshape(y, (N, 1)).T, (NM, 1)))**2)
     an = np.sqrt(dx * dy / np.pi)
     self._GS = -1j * np.pi * kb * an / 2 * jv(1, kb * an) * hankel2(
         0, kb * R)
Example #3
0
    def incident_field(self, resolution):
        """Compute the incident field matrix.

        Given the configuration information stored in the object, it
        computes the incident field matrix considering plane waves in
        different from different angles.

        Parameters
        ----------
            resolution : 2-tuple
                The image size of D-domain in pixels (y and x).

        Returns
        -------
            ei : :class:`numpy.ndarray`
                Incident field matrix. The rows correspond to the points
                in the image following `C`-order and the columns
                corresponds to the sources.
        """
        NY, NX = resolution
        phi = cfg.get_angles(self.configuration.NS)
        x, y = cfg.get_coordinates_ddomain(configuration=self.configuration,
                                           resolution=resolution)
        kb = self.configuration.kb
        E0 = self.configuration.E0
        if isinstance(kb, float) or isinstance(kb, complex):
            ei = E0*np.exp(-1j*kb*(x.reshape((-1, 1))
                                   @ np.cos(phi.reshape((1, -1)))
                                   + y.reshape((-1, 1))
                                   @ np.sin(phi.reshape((1, -1)))))
        else:
            ei = np.zeros((NX*NY, self.configuration.NS, kb.size),
                          dtype=complex)
            for f in range(kb.size):
                ei[:, :, f] = E0*np.exp(-1j*kb[f]*(x.reshape((-1, 1))
                                                   @ np.cos(phi.reshape((1,
                                                                         -1)))
                                                   + y.reshape((-1, 1))
                                                   @ np.sin(phi.reshape((1,
                                                                         -1))))
                                        )
        return ei
Example #4
0
    def solve(self, scenario, noise=None, PRINT_INFO=False,
              COMPUTE_SCATTERED_FIELD=True, SAVE_INTERN_FIELD=True):
        """Solve the forward problem.

        Parameters
        ----------
            scenario : :class:`inputdata:InputData`
                An object describing the dielectric property map.

            PRINT_INFO : boolean, default: False
                Print iteration information.

            COMPUTE_INTERN_FIELD : boolean, default: True
                Compute the total field in D-domain.

        Return
        ------
            es, et, ei : :class:`numpy:ndarray`
                Matrices with the scattered, total and incident field
                information.

        Examples
        --------
        >>> solver = MoM_CG_FFT(configuration)
        >>> es, et, ei = solver.solve(scenario)
        >>> es, ei = solver.solve(scenario, COMPUTE_INTERN_FIELD=False)
        """
        epsilon_r, sigma = super().solve(scenario)
        # Quick access for configuration variables
        NM = self.configuration.NM
        NS = self.configuration.NS
        Ro = self.configuration.Ro
        epsilon_rb = self.configuration.epsilon_rb
        sigma_b = self.configuration.sigma_b
        f = self.configuration.f
        omega = 2*np.pi*f
        kb = self.configuration.kb
        Lx, Ly = self.configuration.Lx, self.configuration.Ly
        NY, NX = scenario.resolution
        N = NX*NY
        xmin, xmax = cfg.get_bounds(Lx)
        ymin, ymax = cfg.get_bounds(Ly)
        dx, dy = Lx/NX, Ly/NY
        xm, ym = cfg.get_coordinates_sdomain(Ro, NM)
        x, y = cfg.get_coordinates_ddomain(dx=dx, dy=dy, xmin=xmin, xmax=xmax,
                                           ymin=ymin, ymax=ymax)
        ei = self.incident_field(scenario.resolution)
        scenario.ei = np.copy(ei)
        ei = np.conj(ei)

        if isinstance(f, float):
            MONO_FREQUENCY = True
        else:
            MONO_FREQUENCY = False
            NF = f.size

        deltasn = dx*dy  # area of the cell
        an = np.sqrt(deltasn/np.pi)  # radius of the equivalent circle
        Xr = get_contrast_map(epsilon_r, sigma, epsilon_rb, sigma_b, omega)

        # Using circular convolution [extended domain (2N-1)x(2N-1)]
        [xe, ye] = np.meshgrid(np.arange(xmin-(NX/2-1)*dx, xmax+NY/2*dx, dx),
                               np.arange(ymin-(NY/2-1)*dy, ymax+NY/2*dy, dy))
        Rmn = np.sqrt(xe**2 + ye**2)  # distance between the cells
        G = self.__get_extended_matrix(Rmn, kb, an, NX, NY)
        b = np.copy(ei)

        if MONO_FREQUENCY:
            tic = time.time()
            et = np.zeros((N, NS), dtype=complex)
            niter = np.zeros(NS)
            error = np.zeros((self.MAX_IT, NS))
            num_cores = multiprocessing.cpu_count()

            results = (Parallel(n_jobs=num_cores)(delayed(self.CG_FFT)
                                                  (G,
                                                   b[:, ns].reshape((-1, 1)),
                                                   NX, NY, 1,
                                                   Xr,
                                                   self.MAX_IT, self.TOL,
                                                   False)
                                                  for ns in range(NS)))

            for ns in range(NS):
                et[:, ns] = results[ns][0].flatten()
                niter[ns] = results[ns][1]
                error[:, ns] = results[ns][2].flatten()

            time_cg_fft = time.time()-tic
            if PRINT_INFO:
                print('Execution time: %.2f' % time_cg_fft + ' [sec]')

        else:
            et = np.zeros((N, NS, NF), dtype=complex)
            niter = np.zeros(NF)
            error = np.zeros((self.MAX_IT, NF))
            num_cores = multiprocessing.cpu_count()

            results = (Parallel(n_jobs=num_cores)(delayed(self.CG_FFT)
                                                  (np.squeeze(G[:, :, nf]),
                                                   np.squeeze(b[:, :, nf]),
                                                   NX, NY, NS,
                                                   np.squeeze(Xr[:, :, nf]),
                                                   self.MAX_IT, self.TOL,
                                                   False)
                                                  for nf in range(NF)))

            for nf in range(NF):
                et[:, :, nf] = results[nf][0]
                niter[nf] = results[nf][1]
                error[:, nf] = results[nf][2]
                print('Frequency: %.3f ' % (f[nf]/1e9) + '[GHz] - '
                      + 'Number of iterations: %d - ' % (niter[nf]+1)
                      + 'Error: %.3e' % error[int(niter[nf]), nf])

        if SAVE_INTERN_FIELD:
            scenario.et = np.conj(et)

        if COMPUTE_SCATTERED_FIELD:
            GS = get_greenfunction(xm, ym, x, y, kb)

            if MONO_FREQUENCY:
                es = GS @ spr.dia_matrix((Xr.flatten(), 0), shape=(N, N)) @ et

            else:
                es = np.zeros((NM, NS, NF), dtype=complex)
                for nf in range(NF):
                    aux = spr.dia_matrix((Xr[:, :, nf].flatten(), 0),
                                         shape=(N, N))
                    es[:, :, nf] = GS[:, :, nf] @ aux @ et[:, :, nf]

            if noise is not None and noise > 0:
                es = fwr.add_noise(es, noise)
            scenario.es = np.conj(es)

            return np.conj(et), np.conj(ei), np.conj(es)

        else:
            return np.conj(et), np.conj(ei)
Example #5
0
    def _set_meshes(self, inputdata):
        """Set elements meshgrid data.

        Parameters
        ----------
            inputdata : :class:`inputdata.InputData`
                An instance of problem with resolution information.
        """
        # Number of measurements and sources
        NM, NS = self.configuration.NM, self.configuration.NS

        # Discretization in S-domain
        NW, NZ = self.discretization[0], self.discretization[1]

        # Discretization in D-domain
        NP, NQ = self.discretization[3], self.discretization[2]

        # Image resolution
        NY, NX = inputdata.resolution
        dx, dy = self.configuration.Lx / NX, self.configuration.Ly / NY

        x, y = cfg.get_coordinates_ddomain(configuration=self.configuration,
                                           resolution=inputdata.resolution)
        self._u, self._v = x.reshape(-1), y.reshape(-1)
        self._du, self._dv = dx, dy

        # Interpolation condition: if S-space discretization is greater
        # than the number of measurements and sources.
        # If the discretization is smaller, than S-space is integrated
        # in the points of the original data.
        # Otherwise, the original data is interpolated in order to have
        # more integration points than elements.
        self._FLAG_INTERPOLATION = NW > NM or NZ > NS

        # If the original data have more information than discretization
        if not self._FLAG_INTERPOLATION:
            xm, ym = cfg.get_coordinates_sdomain(self.configuration.Ro,
                                                 self.configuration.NM)
            self._xms = np.reshape(np.tile(xm.reshape((-1, 1)), (1, NS)), (-1))
            self._yms = np.reshape(np.tile(ym.reshape((-1, 1)), (1, NS)), (-1))
            self._phi_ms, self._theta_ms = np.meshgrid(cfg.get_angles(NS),
                                                       cfg.get_angles(NM))

        # If the original data have less information than discretization
        else:
            new_NM = self.constant_interpolation * NW
            new_NS = self.constant_interpolation * NZ
            xm, ym = cfg.get_coordinates_sdomain(self.configuration.Ro, new_NM)
            self._xms = np.reshape(np.tile(xm.reshape((-1, 1)), (1, new_NS)),
                                   (-1))
            self._yms = np.reshape(np.tile(ym.reshape((-1, 1)), (1, new_NS)),
                                   (-1))
            self._phi_ms, self._theta_ms = np.meshgrid(cfg.get_angles(new_NS),
                                                       cfg.get_angles(new_NM))

        self._phi_wz, self._theta_wz = np.meshgrid(cfg.get_angles(NZ),
                                                   cfg.get_angles(NW))
        self._dtheta = self._theta_ms[1, 0] - self._theta_ms[0, 0]
        self._dphi = self._phi_ms[0, 1] - self._phi_ms[0, 0]
        self._R = np.zeros((self._theta_ms.size, self._u.size))
        for i in range(self._R.shape[0]):
            self._R[i, :] = np.sqrt((self._xms[i] - self._u)**2 +
                                    (self._yms[i] - self._v)**2)

        # Coordinates of D-domain elements
        self._xpq, self._ypq = clc.get_elements_mesh(NX, NY, dx, dy, NP, NQ)

        if self.basis_function == BASIS_BILINEAR:
            self._fij = clc.bilinear(self._u.reshape((NY, NX)),
                                     self._v.reshape((NY, NX)),
                                     self._xpq.reshape((NQ, NP)),
                                     self._ypq.reshape((NQ, NP)))
            self._gij = clc.bilinear(self._phi_ms, self._theta_ms,
                                     self._phi_wz, self._theta_wz)

        elif self.basis_function == BASIS_LEGENDRE:
            xmin, xmax = cfg.get_bounds(self.configuration.Lx)
            ymin, ymax = cfg.get_bounds(self.configuration.Ly)
            self._fij = legendre(self._u.reshape((NY, NX)),
                                 self._v.reshape((NY, NX)), NQ, NP, xmin, xmax,
                                 ymin, ymax)
            self._gij = legendre(self._phi_ms, self._theta_ms, NW, NZ, 0,
                                 2 * np.pi, 0, 2 * np.pi)
Example #6
0
    def conductor_cylinder(self,
                           scenario,
                           radius_proportion=0.5,
                           SAVE_INTERN_FIELD=True,
                           SAVE_MAP=False):
        """Solve the forward problem.

        Parameters
        ----------
            scenario : :class:`inputdata:InputData`
                An object describing the dielectric property map.

            PRINT_INFO : boolean, default: False
                Print iteration information.

            COMPUTE_INTERN_FIELD : boolean, default: True
                Compute the total field in D-domain.

        Return
        ------
            es, et, ei : :class:`numpy:ndarray`
                Matrices with the scattered, total and incident field
                information.

        Examples
        --------
        >>> solver = MoM_CG_FFT(configuration)
        >>> es, et, ei = solver.solve(scenario)
        >>> es, ei = solver.solve(scenario, COMPUTE_INTERN_FIELD=False)
        """
        # Main constants
        omega = 2 * pi * self.configuration.f  # Angular frequency [rad/s]
        kb = self.configuration.kb  # Wavenumber of background [rad/m]
        a = radius_proportion * self.configuration.lambda_b  # Sphere's radius
        thetal = cfg.get_angles(self.configuration.NS)
        thetam = cfg.get_angles(self.configuration.NM)

        # Summing coefficients
        n = np.arange(-self.NT, self.NT + 1)
        an = -jv(n, kb * a) / hankel2(n, kb * a)
        cn = np.zeros(n.size)

        # Mesh parameters
        x, y = cfg.get_coordinates_ddomain(configuration=self.configuration,
                                           resolution=scenario.resolution)

        # Incident field
        ei = self.incident_field(scenario.resolution)

        # Total field array
        et = compute_total_field(x, y, a, an, cn, self.NT, kb, 1.,
                                 self.configuration.E0, thetal)

        # Map of parameters
        sigma = np.zeros(x.shape)
        sigma[x**2 + y**2 <= a**2] = 1e10

        # Scatered field
        rho = self.configuration.Ro
        xm, ym = rho * np.cos(thetam), rho * np.sin(thetam)
        es = compute_scattered_field(xm, ym, an, kb, thetal,
                                     self.configuration.E0)

        if scenario.noise > 0:
            es = fwr.add_noise(es, scenario.noise)

        scenario.es = np.copy(es)
        scenario.ei = np.copy(ei)
        if SAVE_INTERN_FIELD:
            scenario.et = np.copy(et)
        if SAVE_MAP:
            scenario.sigma = np.copy(sigma)
        self.et = et
        self.ei = ei
        self.es = es
        self.epsilon_r = None
        self.sigma = sigma
        self.radius_proportion = radius_proportion
        self.problem = PERFECT_DIELECTRIC_PROBLEM
Example #7
0
    def dielectric_cylinder(self,
                            scenario,
                            radius_proportion=0.5,
                            contrast=2.,
                            SAVE_INTERN_FIELD=True,
                            SAVE_MAP=False):
        """Solve the forward problem.

        Parameters
        ----------
            scenario : :class:`inputdata:InputData`
                An object describing the dielectric property map.

            PRINT_INFO : boolean, default: False
                Print iteration information.

            COMPUTE_INTERN_FIELD : boolean, default: True
                Compute the total field in D-domain.

        Return
        ------
            es, et, ei : :class:`numpy:ndarray`
                Matrices with the scattered, total and incident field
                information.

        Examples
        --------
        >>> solver = MoM_CG_FFT(configuration)
        >>> es, et, ei = solver.solve(scenario)
        >>> es, ei = solver.solve(scenario, COMPUTE_INTERN_FIELD=False)
        """
        # Main constants
        omega = 2 * pi * self.configuration.f  # Angular frequency [rad/s]
        epsilon_rd = cfg.get_relative_permittivity(
            contrast, self.configuration.epsilon_rb)
        epsd = epsilon_rd * epsilon_0  # Cylinder's permittivity [F/m]
        epsb = self.configuration.epsilon_rb * epsilon_0
        mud = mu_0  # Cylinder's permeability [H/m]
        kb = self.configuration.kb  # Wavenumber of background [rad/m]
        kd = omega * np.sqrt(mud * epsd)  # Wavenumber of cylinder [rad/m]
        lambdab = 2 * pi / kb  # Wavelength of background [m]
        a = radius_proportion * lambdab  # Sphere's radius [m]
        thetal = cfg.get_angles(self.configuration.NS)
        thetam = cfg.get_angles(self.configuration.NM)

        # Summing coefficients
        an, cn = get_coefficients(self.NT, kb, kd, a, epsd, epsb)

        # Mesh parameters
        x, y = cfg.get_coordinates_ddomain(configuration=self.configuration,
                                           resolution=scenario.resolution)

        # Incident field
        ei = self.incident_field(scenario.resolution)

        # Total field array
        et = compute_total_field(x, y, a, an, cn, self.NT, kb, kd,
                                 self.configuration.E0, thetal)

        # Map of parameters
        epsilon_r, _ = get_map(x, y, a, self.configuration.epsilon_rb,
                               epsilon_rd)

        # Scatered field
        rho = self.configuration.Ro
        xm, ym = rho * np.cos(thetam), rho * np.sin(thetam)
        es = compute_scattered_field(xm, ym, an, kb, thetal,
                                     self.configuration.E0)

        if scenario.noise > 0:
            es = fwr.add_noise(es, scenario.noise)

        scenario.es = np.copy(es)
        scenario.ei = np.copy(ei)
        if SAVE_INTERN_FIELD:
            scenario.et = np.copy(et)
        if SAVE_MAP:
            scenario.epsilon_r = np.copy(epsilon_r)
        self.et = et
        self.ei = ei
        self.es = es
        self.epsilon_r = epsilon_r
        self.sigma = None
        self.radius_proportion = radius_proportion
        self.contrast = contrast
        self.problem = PERFECT_DIELECTRIC_PROBLEM