Example #1
0
    def operator(self, unk):
        u = self.split_unknown(unk)

        Jxyz = cse(tangential_to_xyz(u.jt), "Jxyz")
        Mxyz = cse(tangential_to_xyz(u.mt), "Mxyz")

        omega = self.omega
        mu0, mu1 = self.mus
        eps0, eps1 = self.epss
        k0, k1 = self.ks

        S = partial(sym.S, self.kernel, qbx_forced_limit="avg")

        def curl_S(dens, k):
            return sym.curl(sym.S(self.kernel, dens, qbx_forced_limit="avg", k=k))

        grad = partial(sym.grad, 3)

        E0 = sym.cse(1j*omega*mu0*eps0*S(Jxyz, k=k0)
            + mu0*curl_S(Mxyz, k=k0) - grad(S(u.rho_e, k=k0)), "E0")
        H0 = sym.cse(-1j*omega*mu0*eps0*S(Mxyz, k=k0)
            + eps0*curl_S(Jxyz, k=k0) + grad(S(u.rho_m, k=k0)), "H0")
        E1 = sym.cse(1j*omega*mu1*eps1*S(Jxyz, k=k1)
            + mu1*curl_S(Mxyz, k=k1) - grad(S(u.rho_e, k=k1)), "E1")
        H1 = sym.cse(-1j*omega*mu1*eps1*S(Mxyz, k=k1)
            + eps1*curl_S(Jxyz, k=k1) + grad(S(u.rho_m, k=k1)), "H1")

        F1 = (xyz_to_tangential(sym.n_cross(H1-H0) + 0.5*(eps0+eps1)*Jxyz))
        F2 = (sym.n_dot(eps1*E1-eps0*E0) + 0.5*(eps1+eps0)*u.rho_e)
        F3 = (xyz_to_tangential(sym.n_cross(E1-E0) + 0.5*(mu0+mu1)*Mxyz))

        # sign flip included
        F4 = -sym.n_dot(mu1*H1-mu0*H0) + 0.5*(mu1+mu0)*u.rho_m  # noqa pylint:disable=invalid-unary-operand-type

        return sym.flat_obj_array(F1, F2, F3, F4)
Example #2
0
    def rhs(self, Einc_xyz, Hinc_xyz):
        mu1 = self.mus[1]
        eps1 = self.epss[1]

        return sym.flat_obj_array(xyz_to_tangential(sym.n_cross(Hinc_xyz)),
                                  sym.n_dot(eps1 * Einc_xyz),
                                  xyz_to_tangential(sym.n_cross(Einc_xyz)),
                                  sym.n_dot(-mu1 * Hinc_xyz))
Example #3
0
    def scattered_volume_field(self, Jt, rho, qbx_forced_limit=None):
        """
        This will return an object array of six entries, the first three of which
        represent the electric, and the second three of which represent the
        magnetic field. This satisfies the time-domain Maxwell's equations
        as verified by :func:`sumpy.point_calculus.frequency_domain_maxwell`.
        """
        Jxyz = sym.cse(sym.tangential_to_xyz(Jt), "Jxyz")

        A = sym.S(self.kernel, Jxyz, k=self.k, qbx_forced_limit=qbx_forced_limit)
        phi = sym.S(self.kernel, rho, k=self.k, qbx_forced_limit=qbx_forced_limit)

        E_scat = 1j*self.k*A - sym.grad(3, phi)
        H_scat = sym.curl(A)

        return sym.flat_obj_array(E_scat, H_scat)
Example #4
0
def get_sym_maxwell_plane_wave(amplitude_vec,
                               v,
                               omega,
                               epsilon=1,
                               mu=1,
                               dofdesc=None):
    r"""Return a symbolic expression that, when bound to a
    :class:`pytential.source.PointPotentialSource` will yield
    a field satisfying Maxwell's equations.

    :arg amplitude_vec: should be orthogonal to *v*. If it is not,
        it will be orthogonalized.
    :arg v: a three-vector representing the phase velocity of the wave
        (may be an object array of variables or a vector of concrete numbers)
        While *v* may mathematically be complex-valued, this function
        is for now only tested for real values.
    :arg omega: Accepts the "Helmholtz k" to be compatible with other parts
        of this module.

    Uses the sign convention :math:`\exp(-1 \omega t)` for the time dependency.

    This will return an object of six entries, the first three of which
    represent the electric, and the second three of which represent the
    magnetic field. This satisfies the time-domain Maxwell's equations
    as verified by :func:`sumpy.point_calculus.frequency_domain_maxwell`.
    """

    # See section 7.1 of Jackson, third ed. for derivation.

    # NOTE: for complex, need to ensure real(n).dot(imag(n)) = 0  (7.15)

    x = sym.nodes(3, dofdesc=dofdesc).as_vector()

    v_mag_squared = sym.cse(np.dot(v, v), "v_mag_squared")
    n = v / sym.sqrt(v_mag_squared)

    amplitude_vec = amplitude_vec - np.dot(amplitude_vec, n) * n

    c_inv = np.sqrt(mu * epsilon)

    e = amplitude_vec * sym.exp(1j * np.dot(n * omega, x))

    return sym.flat_obj_array(e, c_inv * sym.cross(n, e))
Example #5
0
    def representation(self, i, sol):
        u = self.split_unknown(sol)
        Jxyz = sym.cse(sym.tangential_to_xyz(u.jt), "Jxyz")
        Mxyz = sym.cse(sym.tangential_to_xyz(u.mt), "Mxyz")

        # omega = self.omega
        mu = self.mus[i]
        eps = self.epss[i]
        k = self.ks[i]

        S = partial(sym.S, self.kernel, qbx_forced_limit=None, k=k)

        def curl_S(dens):
            return sym.curl(sym.S(self.kernel, dens, qbx_forced_limit=None, k=k))

        grad = partial(sym.grad, 3)

        E0 = 1j*k*eps*S(Jxyz) + mu*curl_S(Mxyz) - grad(S(u.rho_e))
        H0 = -1j*k*mu*S(Mxyz) + eps*curl_S(Jxyz) + grad(S(u.rho_m))

        return sym.flat_obj_array(E0, H0)
Example #6
0
def get_sym_maxwell_point_source(kernel, jxyz, k):
    r"""Return a symbolic expression that, when bound to a
    :class:`pytential.source.PointPotentialSource` will yield
    a field satisfying Maxwell's equations.

    Uses the sign convention :math:`\exp(-i \omega t)` for the time dependency.

    This will return an object of six entries, the first three of which
    represent the electric, and the second three of which represent the
    magnetic field. This satisfies the time-domain Maxwell's equations
    as verified by :func:`sumpy.point_calculus.frequency_domain_maxwell`.
    """
    # This ensures div A = 0, which is simply a consequence of div curl S=0.
    # This means we use the Coulomb gauge to generate this field.

    A = sym.curl(sym.S(kernel, jxyz, k=k, qbx_forced_limit=None))

    # https://en.wikipedia.org/w/index.php?title=Maxwell%27s_equations&oldid=798940325#Alternative_formulations
    # (Vector calculus/Potentials/Any Gauge)
    # assumed time dependence exp(-1j*omega*t)
    return sym.flat_obj_array(1j * k * A, sym.curl(A))
Example #7
0
        print("Maxwell residuals:", maxwell_residuals)

        eoc_rec_repr_maxwell.add_data_point(h_max, max(maxwell_residuals))

        # }}}

        # {{{ check PEC BC on total field

        bc_repr = EHField(
            mfie.scattered_volume_field(jt_sym,
                                        rho_sym,
                                        qbx_forced_limit=loc_sign))
        pec_bc_e = sym.n_cross(bc_repr.e + inc_xyz_sym.e)
        pec_bc_h = sym.normal(3).as_vector().dot(bc_repr.h + inc_xyz_sym.h)

        eh_bc_values = bind(places, sym.flat_obj_array(pec_bc_e, pec_bc_h))(
            actx, jt=jt, rho=rho, inc_fld=inc_field_scat.field, **knl_kwargs)

        def scat_norm(f):
            return norm(density_discr, f, p=np.inf)

        e_bc_residual = scat_norm(eh_bc_values[:3]) / scat_norm(
            inc_field_scat.e)
        h_bc_residual = scat_norm(eh_bc_values[3]) / scat_norm(
            inc_field_scat.h)

        print("E/H PEC BC residuals:", h_max, e_bc_residual, h_bc_residual)

        eoc_pec_bc.add_data_point(h_max, max(e_bc_residual, h_bc_residual))

        # }}}