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)
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))
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)
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))
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)
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))
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)) # }}}