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 hedge.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 xrange(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 hedge.tools import join_fields return join_fields(e, h, p, q)
def assemble_eh(self, e=None, h=None, discr=None): "Combines separate E and H vectors into a single array." if discr is None: def zero(): return 0 else: def zero(): return discr.volume_zeros() from hedge.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 xrange(comp)] else: return fld e = default_fld(e, e_components) h = default_fld(h, h_components) from hedge.tools import join_fields return join_fields(e, h)
def op_template(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 hedge.tools import join_fields w = self.field_placeholder(w) if self.fixed_material: flux_w = w else: epsilon = self.epsilon mu = self.mu flux_w = join_fields(epsilon, mu, w) from hedge.optemplate import BoundaryPair, \ InverseMassOperator, get_flux_operator flux_op = get_flux_operator(self.flux(self.flux_type)) bdry_flux_op = get_flux_operator(self.flux(self.bdry_flux_type)) from hedge.tools.indexing 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) else: material_divisor = join_fields([epsilon] * elec_components, [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 make_flux_bc_vector(tag, bc): if self.fixed_material: return bc else: from hedge.optemplate import BoundarizeOperator return join_fields(cse(BoundarizeOperator(tag)(epsilon)), cse(BoundarizeOperator(tag)(mu)), bc) return ( -self.local_derivatives(w) + InverseMassOperator()(flux_op(flux_w) + sum( bdry_flux_op( BoundaryPair(flux_w, make_flux_bc_vector(tag, bc), tag)) for tag, bc in tags_and_bcs))) / material_divisor
def split_ehphi(self, w): e, h = self.split_eh(w) from hedge.tools import count_subset eh_components = count_subset(self.maxwell_op.get_eh_subset()) phi = w[eh_components] return e, h, phi
def local_derivatives(self, w=None): """Template for the spatial derivatives of the relevant components of E and H""" e, h = self.split_eh(self.field_placeholder(w)) def e_curl(field): return self.space_cross_e(nabla, field) def h_curl(field): return self.space_cross_h(nabla, field) from hedge.optemplate import make_nabla from hedge.tools import join_fields, count_subset nabla = make_nabla(self.dimensions) if self.current is not None: from hedge.optemplate import make_vector_field j = make_vector_field("j", count_subset(self.get_eh_subset()[:3])) else: j = 0 # in conservation form: u_t + A u_x = 0 return join_fields( (j - h_curl(h)), e_curl(e) )
def field_placeholder(self, w=None): "A placeholder for E and H." from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) if w is None: from hedge.optemplate import make_sym_vector w = make_sym_vector("w", fld_cnt) return w
def __init__(self, maxwell_op, chi=1, phi_decay=0): self.maxwell_op = maxwell_op self.chi = chi self.phi_decay = phi_decay assert chi > 0 assert phi_decay >= 0 from hedge.tools import count_subset self.component_count = count_subset(maxwell_op.get_eh_subset())+1
def __init__(self, maxwell_op, chi=1, phi_decay=0): self.maxwell_op = maxwell_op self.chi = chi self.phi_decay = phi_decay assert chi > 0 assert phi_decay >= 0 from hedge.tools import count_subset self.component_count = count_subset(maxwell_op.get_eh_subset()) + 1
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 hedge.tools import count_subset self.arg_count = count_subset(self.subset)
def op_template(self, w=None): from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) if w is None: from hedge.optemplate import make_sym_vector w = make_sym_vector("w", fld_cnt + 2 * self.dimensions) from hedge.tools import join_fields return join_fields(MaxwellOperator.op_template(self, w[:fld_cnt]), numpy.zeros((2 * self.dimensions, ), dtype=object)) + self.pml_local_op(w)
def op_template(self, w=None): from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) if w is None: from hedge.optemplate import make_vector_field w = make_vector_field("w", fld_cnt+2*self.dimensions) from hedge.tools import join_fields return join_fields( MaxwellOperator.op_template(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 hedge.tools import count_subset self.arg_count = count_subset(self.subset)
def incident_bc(self, w=None): "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(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous" " background material, results may be unphysical") from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from hedge.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 cse(-incident_bc_data)
def incident_bc(self, w=None): "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(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous" " background material, results may be unphysical") from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from hedge.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 cse(-incident_bc_data)
def incident_bc(self, w=None): "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(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous"+ " background material, results may be unphysical") from hedge.tools import count_subset from hedge.tools import join_fields fld_cnt = count_subset(self.get_eh_subset()) if self.incident_bc_data is not None: from hedge.optemplate import make_vector_field inc_field = cse( -make_vector_field("incident_bc", fld_cnt)) else: inc_field = make_obj_array([0]*fld_cnt) return inc_field
def op_template(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 hedge.tools import join_fields w = self.field_placeholder(w) if self.fixed_material: flux_w = w else: epsilon = self.epsilon mu = self.mu flux_w = join_fields(epsilon, mu, w) from hedge.optemplate import BoundaryPair, \ InverseMassOperator, get_flux_operator flux_op = get_flux_operator(self.flux(self.flux_type)) bdry_flux_op = get_flux_operator(self.flux(self.bdry_flux_type)) from hedge.tools.indexing 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) else: material_divisor = join_fields( [epsilon]*elec_components, [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 make_flux_bc_vector(tag, bc): if self.fixed_material: return bc else: from hedge.optemplate import BoundarizeOperator return join_fields( cse(BoundarizeOperator(tag)(epsilon)), cse(BoundarizeOperator(tag)(mu)), bc) return ( - self.local_derivatives(w) + InverseMassOperator()( flux_op(flux_w) + sum( bdry_flux_op(BoundaryPair( flux_w, make_flux_bc_vector(tag, bc), tag)) for tag, bc in tags_and_bcs)) ) / material_divisor
def flux(self, flux_type): """The template for the numerical flux for variable coefficients. :param flux_type: can be in [0,1] for anything between central and upwind, or "lf" for Lax-Friedrichs. As per Hesthaven and Warburton page 433. """ from hedge.flux import (make_normal, FluxVectorPlaceholder, FluxConstantPlaceholder) from hedge.tools import join_fields normal = make_normal(self.dimensions) if self.fixed_material: from hedge.tools import count_subset w = FluxVectorPlaceholder(count_subset(self.get_eh_subset())) e, h = self.split_eh(w) epsilon = FluxConstantPlaceholder(self.epsilon) mu = FluxConstantPlaceholder(self.mu) else: from hedge.tools import count_subset w = FluxVectorPlaceholder(count_subset(self.get_eh_subset()) + 2) epsilon, mu, e, h = self.split_eps_mu_eh(w) Z_int = (mu.int / epsilon.int)**0.5 Y_int = 1 / Z_int Z_ext = (mu.ext / epsilon.ext)**0.5 Y_ext = 1 / Z_ext if flux_type == "lf": if self.fixed_material: max_c = (self.epsilon * self.mu)**(-0.5) else: from hedge.flux import Max c_int = (epsilon.int * mu.int)**(-0.5) c_ext = (epsilon.ext * mu.ext)**(-0.5) max_c = Max(c_int, c_ext) # noqa return join_fields( # flux e, 1 / 2 * ( -self.space_cross_h(normal, h.int - h.ext) # multiplication by epsilon undoes material divisor below #-max_c*(epsilon.int*e.int - epsilon.ext*e.ext) ), # flux h 1 / 2 * ( self.space_cross_e(normal, e.int - e.ext) # multiplication by mu undoes material divisor below #-max_c*(mu.int*h.int - mu.ext*h.ext) )) elif isinstance(flux_type, (int, float)): # see doc/maxima/maxwell.mac return join_fields( # flux e, (-1 / (Z_int + Z_ext) * self.space_cross_h( normal, Z_ext * (h.int - h.ext) - flux_type * self.space_cross_e(normal, e.int - e.ext))), # flux h (1 / (Y_int + Y_ext) * self.space_cross_e( normal, Y_ext * (e.int - e.ext) + flux_type * self.space_cross_h(normal, h.int - h.ext))), ) else: raise ValueError("maxwell: invalid flux_type (%s)" % self.flux_type)
def flux(self, flux_type): """The template for the numerical flux for variable coefficients. :param flux_type: can be in [0,1] for anything between central and upwind, or "lf" for Lax-Friedrichs. As per Hesthaven and Warburton page 433. """ from hedge.flux import (make_normal, FluxVectorPlaceholder, FluxConstantPlaceholder) from hedge.tools import join_fields normal = make_normal(self.dimensions) if self.fixed_material: from hedge.tools import count_subset w = FluxVectorPlaceholder(count_subset(self.get_eh_subset())) e, h = self.split_eh(w) epsilon = FluxConstantPlaceholder(self.epsilon) mu = FluxConstantPlaceholder(self.mu) else: from hedge.tools import count_subset w = FluxVectorPlaceholder(count_subset(self.get_eh_subset())+2) epsilon, mu, e, h = self.split_eps_mu_eh(w) Z_int = (mu.int/epsilon.int)**0.5 Y_int = 1/Z_int Z_ext = (mu.ext/epsilon.ext)**0.5 Y_ext = 1/Z_ext if flux_type == "lf": if self.fixed_material: max_c = (self.epsilon*self.mu)**(-0.5) else: from hedge.flux import Max c_int = (epsilon.int*mu.int)**(-0.5) c_ext = (epsilon.ext*mu.ext)**(-0.5) max_c = Max(c_int, c_ext) # noqa return join_fields( # flux e, 1/2*( -self.space_cross_h(normal, h.int-h.ext) # multiplication by epsilon undoes material divisor below #-max_c*(epsilon.int*e.int - epsilon.ext*e.ext) ), # flux h 1/2*( self.space_cross_e(normal, e.int-e.ext) # multiplication by mu undoes material divisor below #-max_c*(mu.int*h.int - mu.ext*h.ext) )) elif isinstance(flux_type, (int, float)): # see doc/maxima/maxwell.mac return join_fields( # flux e, ( -1/(Z_int+Z_ext)*self.space_cross_h(normal, Z_ext*(h.int-h.ext) - flux_type*self.space_cross_e(normal, e.int-e.ext)) ), # flux h ( 1/(Y_int + Y_ext)*self.space_cross_e(normal, Y_ext*(e.int-e.ext) + flux_type*self.space_cross_h(normal, h.int-h.ext)) ), ) else: raise ValueError("maxwell: invalid flux_type (%s)" % self.flux_type)