def assemble_ehpq(self, e=None, h=None, p=None, q=None, discr=None): if discr is None: def zero(): return 0 else: def zero(): return discr.volume_zeros() from grudge.tools import count_subset e_components = count_subset(self.get_eh_subset()[0:3]) h_components = count_subset(self.get_eh_subset()[3:6]) def default_fld(fld, comp): if fld is None: return [zero() for i in range(comp)] else: return fld e = default_fld(e, e_components) h = default_fld(h, h_components) p = default_fld(p, self.dimensions) q = default_fld(q, self.dimensions) from grudge.tools import join_fields return join_fields(e, h, p, q)
def sym_operator(self, w=None): """The full operator template - the high level description of the Maxwell operator. Combines the relevant operator templates for spatial derivatives, flux, boundary conditions etc. """ from grudge.tools import count_subset w = sym.make_sym_array("w", count_subset(self.get_eh_subset())) elec_components = count_subset(self.get_eh_subset()[0:3]) mag_components = count_subset(self.get_eh_subset()[3:6]) if self.fixed_material: # need to check this material_divisor = ([self.epsilon] * elec_components + [self.mu] * mag_components) tags_and_bcs = [ (self.pec_tag, self.pec_bc(w)), (self.pmc_tag, self.pmc_bc(w)), (self.absorb_tag, self.absorbing_bc(w)), (self.incident_tag, self.incident_bc(w)), ] def flux(pair): return sym.project(pair.dd, "all_faces")(self.flux(pair)) return (-self.local_derivatives(w) - sym.InverseMassOperator() (sym.FaceMassOperator()(flux(sym.int_tpair(w)) + sum( flux(sym.bv_tpair(tag, w, bc)) for tag, bc in tags_and_bcs)))) / material_divisor
def sym_operator(self, w=None): from grudge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) if w is None: from grudge.symbolic import make_sym_vector w = make_sym_vector("w", fld_cnt + 2 * self.dimensions) from grudge.tools import join_fields return join_fields(MaxwellOperator.sym_operator(self, w[:fld_cnt]), numpy.zeros((2 * self.dimensions, ), dtype=object)) + self.pml_local_op(w)
def __init__(self, dimensions, subset=None): self.dimensions = dimensions if subset is None: self.subset = dimensions * [ True, ] else: # chop off any extra dimensions self.subset = subset[:dimensions] from grudge.tools import count_subset self.arg_count = count_subset(self.subset)
def operator(self, t, w): """The full operator template - the high level description of the Maxwell operator. Combines the relevant operator templates for spatial derivatives, flux, boundary conditions etc. """ from grudge.tools import count_subset elec_components = count_subset(self.get_eh_subset()[0:3]) mag_components = count_subset(self.get_eh_subset()[3:6]) if self.fixed_material: # need to check this material_divisor = ([self.epsilon] * elec_components + [self.mu] * mag_components) tags_and_bcs = [ (self.pec_tag, self.pec_bc(w)), (self.pmc_tag, self.pmc_bc(w)), (self.absorb_tag, self.absorbing_bc(w)), (self.incident_tag, self.incident_bc(w)), ] dcoll = self.dcoll def flux(pair): return op.project(dcoll, pair.dd, "all_faces", self.flux(pair)) return (-self.local_derivatives(w) - op.inverse_mass( dcoll, op.face_mass( dcoll, sum( flux(tpair) for tpair in op.interior_trace_pairs(dcoll, w)) + sum( flux(op.bv_trace_pair(dcoll, tag, w, bc)) for tag, bc in tags_and_bcs)))) / material_divisor
def incident_bc(self, w): """Flux terms for incident boundary conditions""" # NOTE: Untested for inhomogeneous materials, but would usually be # physically meaningless anyway (are there exceptions to this?) e, h = self.split_eh(w) from grudge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from grudge.tools import is_zero incident_bc_data = self.incident_bc_data(self, e, h) if is_zero(incident_bc_data): return make_obj_array([0]*fld_cnt) else: return sym.cse(-incident_bc_data)