def flux(self): from hedge.flux import FluxVectorPlaceholder, make_normal dim = self.dimensions w = FluxVectorPlaceholder(2 + dim) c = w[0] u = w[1] v = w[2:] normal = make_normal(dim) from hedge.tools import join_fields flux = self.time_sign * 1 / 2 * join_fields( c.ext * numpy.dot(v.ext, normal) - c.int * numpy.dot( v.int, normal), normal * (c.ext * u.ext - c.int * u.int)) if self.flux_type == "central": pass elif self.flux_type == "upwind": flux += join_fields( c.ext * u.ext - c.int * u.int, c.ext * normal * numpy.dot(normal, v.ext) - c.int * normal * numpy.dot(normal, v.int)) else: raise ValueError("invalid flux type '%s'" % self.flux_type) return flux
def flux(self): from hedge.flux import FluxVectorPlaceholder, make_normal dim = self.dimensions w = FluxVectorPlaceholder(1+dim) u = w[0] v = w[1:] normal = make_normal(dim) from hedge.tools import join_fields flux_weak = join_fields( np.dot(v.avg, normal), u.avg * normal) if self.flux_type == "central": pass elif self.flux_type == "upwind": # see doc/notes/hedge-notes.tm flux_weak -= self.sign*join_fields( 0.5*(u.int-u.ext), 0.5*(normal * np.dot(normal, v.int-v.ext))) else: raise ValueError("invalid flux type '%s'" % self.flux_type) flux_strong = join_fields( np.dot(v.int, normal), u.int * normal) - flux_weak return -self.c*flux_strong
def flux(self): from hedge.flux import FluxVectorPlaceholder, make_normal dim = self.dimensions w = FluxVectorPlaceholder(1 + dim) u = w[0] v = w[1:] normal = make_normal(dim) from hedge.tools import join_fields flux_weak = join_fields(numpy.dot(v.avg, normal), u.avg * normal) if self.flux_type == "central": pass elif self.flux_type == "upwind": # see doc/notes/hedge-notes.tm flux_weak -= self.sign * join_fields( 0.5 * (u.int - u.ext), 0.5 * (normal * numpy.dot(normal, v.int - v.ext))) else: raise ValueError("invalid flux type '%s'" % self.flux_type) flux_strong = join_fields(numpy.dot(v.int, normal), u.int * normal) - flux_weak return -self.c * flux_strong
def flux(self): from hedge.flux import FluxVectorPlaceholder, make_normal dim = self.dimensions w = FluxVectorPlaceholder(2+dim) c = w[0] u = w[1] v = w[2:] normal = make_normal(dim) from hedge.tools import join_fields flux = self.time_sign*1/2*join_fields( c.ext * np.dot(v.ext, normal) - c.int * np.dot(v.int, normal), normal*(c.ext*u.ext - c.int*u.int)) if self.flux_type == "central": pass elif self.flux_type == "upwind": flux += join_fields( c.ext*u.ext - c.int*u.int, c.ext*normal*np.dot(normal, v.ext) - c.int*normal*np.dot(normal, v.int) ) else: raise ValueError("invalid flux type '%s'" % self.flux_type) return flux
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 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 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 assemble_vars(self, u=None, v=None,F=None, discr=None): "Combines separate U and V vectors into a single array." if discr is None: def zero(): return 0 else: def zero(): return discr.volume_zeros() dim = self.dimensions def default_fld(fld, comp): if fld is None: return [zero() for i in xrange(comp)] else: return fld if self.init_velocity is None or discr is None: v = default_fld(v, dim) else: v = self.init_velocity.volume_interpolant(discr) if self.init_displacement is None or discr is None: u = default_fld(u, dim) else: u = self.init_displacement.volume_interpolant(discr) from hedge.tools import join_fields return join_fields(u, v)
def local_derivatives(self, w=None): """Template for the volume terms of the time derivatives for U and V. dU/dt = V, and dV/dt = div P. Body forces not yet implemented""" u, v, F = self.split_grad_vars(w) dim = self.dimensions from hedge.optemplate import make_stiffness_t, make_vector_field from hedge.tools import join_fields P = self.material.stress(F, self.dimensions) stiffness = make_stiffness_t(dim) Dv = [0,]*3 for i in range(dim): for j in range(dim): Dv[i] = Dv[i] - stiffness[j](P[3*j+i]) # in conservation form: u_t + A u_x = 0 return join_fields( # time derivative of u is v v[0], v[1], v[2], # time derivative of v is div P Dv[0], Dv[1], Dv[2] )
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 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)
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)
def __call__(self, t, x_vec): # JSH/TW Nodal DG Methods, p.326 rho = numpy.ones_like(x_vec[0]) rho_u = x_vec[1] * x_vec[1] rho_v = numpy.zeros_like(x_vec[0]) e = (2 * self.mu * x_vec[0] + 10) / (self.gamma - 1) + x_vec[1]**4 / 2 from hedge.tools import join_fields return join_fields(rho, e, rho_u, rho_v)
def pmc_bc(self, w=None): "Construct part of the flux operator template for PMC boundary conditions" e, h = self.split_eh(self.field_placeholder(w)) from hedge.tools import join_fields from hedge.optemplate import BoundarizeOperator pmc_e = BoundarizeOperator(self.pmc_tag)(e) pmc_h = BoundarizeOperator(self.pmc_tag)(h) return join_fields(pmc_e, -pmc_h)
def flux(self): from hedge.flux import make_normal, FluxVectorPlaceholder normal = make_normal(self.maxwell_op.dimensions) from hedge.tools import join_fields w = FluxVectorPlaceholder(self.component_count) e, h, phi = self.split_ehphi(w) # see hedge/doc/maxima/eclean.mac for derivation strong_flux = 0.5 * self.c * self.chi * join_fields( # flux e normal * (phi.int - phi.ext - numpy.dot(normal, e.int - e.ext)), # flux h len(h) * [0], # flux phi numpy.dot(e.int - e.ext, normal) - (phi.int - phi.ext)) return strong_flux + join_fields(self.maxwell_op.flux(1), 0)
def __call__(self, t, x_vec): rho = 2 + numpy.sin(x_vec[0] + x_vec[1] + x_vec[2] - 2 * t) velocity = numpy.array([1, 1, 0]) p = 1 e = p/(self.gamma-1) + rho/2 * numpy.dot(velocity, velocity) rho_u = rho * velocity[0] rho_v = rho * velocity[1] rho_w = rho * velocity[2] from hedge.tools import join_fields return join_fields(rho, e, rho_u, rho_v, rho_w)
def __call__(self, t, x_vec): rho = 2 + numpy.sin(x_vec[0] + x_vec[1] + x_vec[2] - 2 * t) velocity = numpy.array([1, 1, 0]) p = 1 e = p / (self.gamma - 1) + rho / 2 * numpy.dot(velocity, velocity) rho_u = rho * velocity[0] rho_v = rho * velocity[1] rho_w = rho * velocity[2] from hedge.tools import join_fields return join_fields(rho, e, rho_u, rho_v, rho_w)
def flux(self): from hedge.flux import make_normal, FluxVectorPlaceholder normal = make_normal(self.maxwell_op.dimensions) from hedge.tools import join_fields w = FluxVectorPlaceholder(self.component_count) e, h, phi = self.split_ehphi(w) # see hedge/doc/maxima/eclean.mac for derivation strong_flux = 0.5*self.c*self.chi*join_fields( # flux e normal*(phi.int-phi.ext - numpy.dot(normal, e.int-e.ext)), # flux h len(h)*[0], # flux phi numpy.dot(e.int-e.ext, normal)-(phi.int-phi.ext) ) return strong_flux + join_fields(self.maxwell_op.flux(1), 0)
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 some_vector(discr): x = discr.nodes.T.astype(discr.default_scalar_type) from hedge.tools import join_fields u1 = discr.interpolate_volume_function(lambda x, el: sin(pi * x[0])) u2 = discr.interpolate_volume_function(lambda x, el: sin(pi * x[1])) u3 = discr.interpolate_volume_function(lambda x, el: sin(pi * x[0] + pi * x[1])) u4 = discr.interpolate_volume_function(lambda x, el: cos(pi * x[0])) return join_fields(u1, u2, u3, u4)
def some_vector(discr): # x = discr.nodes.T.astype(discr.default_scalar_type) from hedge.tools import join_fields u1 = discr.interpolate_volume_function(lambda x, el: sin(pi * x[0])) u2 = discr.interpolate_volume_function(lambda x, el: sin(pi * x[1])) u3 = discr.interpolate_volume_function( lambda x, el: sin(pi * x[0] + pi * x[1])) u4 = discr.interpolate_volume_function(lambda x, el: cos(pi * x[0])) return join_fields(u1, u2, u3, u4)
def flux(self, beta, is_dirich): """The template for the numerical flux for variable coefficients. From Noels, Radovitzky 2007 """ from hedge.flux import (make_normal, FluxVectorPlaceholder, FluxConstantPlaceholder) from hedge.tools import join_fields dim = self.dimensions normal = make_normal(self.dimensions) w = FluxVectorPlaceholder(dim*2+9) # u is displacement field, v is its time derivative (velocity) u, v, F = self.split_grad_vars(w) P_int = self.material.stress(F.int, self.dimensions) C_int = self.material.tangent_moduli(F.int, self.dimensions, self.dimensions) # constitutive update for exterior face if is_dirich: P_ext = [0]*9 #[-3*p for p in P_int] C_ext = [0]*81 #C_int else: P_ext = self.material.stress(F.ext, self.dimensions) C_ext = self.material.tangent_moduli(F.ext, self.dimensions, self.dimensions) P_avg = [(P_int[i] + P_ext[i])/2 for i in range(dim*dim)] # 'force' flux v_flux = [0,]*self.dimensions for i in range(self.dimensions): for j in range(self.dimensions): v_flux[i] = v_flux[i] + P_avg[3*i+j]*normal[j] from hedge.flux import make_penalty_term stab_factor = beta * make_penalty_term() C_avg = [stab_factor * (C_int[i] + C_ext[i]) / 2 for i in range(dim*dim*dim*dim)] # stabilization term u_jump = u.ext - u.int for i in range(self.dimensions): for j in range(self.dimensions): for k in range(self.dimensions): for l in range(self.dimensions): v_flux[i] = v_flux[i] - normal[j]* \ C_avg[27*i+9*j+3*k+l]* \ u_jump[k]* \ normal[l] return join_fields( # u needs no flux term 0,0,0, # flux for v v_flux[0], v_flux[1], v_flux[2] )
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 make_vector_field(name, components): """Return an object array of *components* subscripted :class:`Field` instances. :param components: The number of components in the vector. """ if isinstance(components, int): components = range(components) from hedge.tools import join_fields vfld = pymbolic.primitives.Variable(name) return join_fields(*[vfld[i] for i in components])
def assemble_fields(self, e=None, h=None, phi=None, discr=None): if discr is None: def zero(): return 0 else: def zero(): return discr.volume_zeros() if phi is None: phi = zero() from hedge.tools import join_fields return join_fields( self.maxwell_op.assemble_fields(e, h), phi)
def __call__(self,t,x_vec,q): vortex_loc = self.center + t*self.velocity # coordinates relative to vortex center x_rel = x_vec[0] - vortex_loc[0] y_rel = x_vec[1] - vortex_loc[1] # sources written in terms of A=1.0 solution # (standard isentropic vortex) from math import pi r = numpy.sqrt(x_rel**2+y_rel**2) expterm = self.beta*numpy.exp(1-r**2) u = self.velocity[0] - expterm*y_rel/(2*pi) v = self.velocity[1] + expterm*x_rel/(2*pi) rho = (1-(self.gamma-1)/(16*self.gamma*pi**2)*expterm**2)**(1/(self.gamma-1)) p = rho**self.gamma #computed necessary derivatives expterm_t = 2*expterm*x_rel expterm_x = -2*expterm*x_rel expterm_y = -2*expterm*y_rel u_x = -expterm*y_rel/(2*pi)*(-2*x_rel) v_y = expterm*x_rel/(2*pi)*(-2*y_rel) #derivatives for rho (A=1) facG=self.gamma-1 rho_t = (1/facG)*(1-(facG)/(16*self.gamma*pi**2)*expterm**2)**(1/facG-1)* \ (-facG/(16*self.gamma*pi**2)*2*expterm*expterm_t) rho_x = (1/facG)*(1-(facG)/(16*self.gamma*pi**2)*expterm**2)**(1/facG-1)* \ (-facG/(16*self.gamma*pi**2)*2*expterm*expterm_x) rho_y = (1/facG)*(1-(facG)/(16*self.gamma*pi**2)*expterm**2)**(1/facG-1)* \ (-facG/(16*self.gamma*pi**2)*2*expterm*expterm_y) #derivatives for rho (A=1) to the power of gamma rho_gamma_t = self.gamma*rho**(self.gamma-1)*rho_t rho_gamma_x = self.gamma*rho**(self.gamma-1)*rho_x rho_gamma_y = self.gamma*rho**(self.gamma-1)*rho_y factorA=self.densityA**self.gamma-self.densityA #construct source terms source_rho = x_vec[0]-x_vec[0] source_e = (factorA/(self.gamma-1))*(rho_gamma_t + self.gamma*(u_x*rho**self.gamma+u*rho_gamma_x)+ \ self.gamma*(v_y*rho**self.gamma+v*rho_gamma_y)) source_rhou = factorA*rho_gamma_x source_rhov = factorA*rho_gamma_y from hedge.tools import join_fields return join_fields(source_rho, source_e, source_rhou, source_rhov, x_vec[0]-x_vec[0])
def assemble_fields(self, e=None, h=None, phi=None, discr=None): if discr is None: def zero(): return 0 else: def zero(): return discr.volume_zeros() if phi is None: phi = zero() from hedge.tools import join_fields return join_fields(self.maxwell_op.assemble_fields(e, h), phi)
def dirichlet_bc(self, w=None): """ Flux term for dirichlet (displacement) boundary conditions """ u, v = self.split_vars(self.field_placeholder(w)) if self.dirichlet_bc_data is not None: from hedge.optemplate import make_vector_field dir_field = cse( -make_vector_field("dirichlet_bc", 3)) else: dir_field = make_obj_array([0,]*3) from hedge.tools import join_fields return join_fields(dir_field, [0]*3, [0,]*9)
def op_template(self, w=None): """The full operator template - the high level description of the nonlinear mechanics operator. Combines the relevant operator templates for spatial derivatives, flux, boundary conditions etc. NOTE: Only boundary conditions allowed currently are homogenous dirichlet and neumann, and I'm not sure dirichlet is done properly """ from hedge.optemplate import InverseMassOperator, Field, \ make_vector_field from hedge.tools import join_fields w = self.field_placeholder(w) u,v = self.split_vars(w) from hedge.optemplate import make_nabla nabla = make_nabla(self.dimensions) ij = 0 F = [0,]*9 for i in range(self.dimensions): for j in range(self.dimensions): F[ij] = nabla[j](u[i]) if i == j: F[ij] = F[ij] + 1 ij = ij + 1 w = join_fields(u,v,F) flux_w = w from hedge.optemplate import BoundaryPair, get_flux_operator flux_op = get_flux_operator(self.flux(self.beta, is_dirich=False)) d_flux_op = get_flux_operator(self.flux(self.beta, is_dirich=True)) from hedge.optemplate import make_normal, BoundarizeOperator dir_normal = make_normal(self.dirichlet_tag, self.dimensions) dir_bc = self.dirichlet_bc(w) return self.local_derivatives(w) \ - (flux_op(flux_w) + d_flux_op(BoundaryPair(flux_w, dir_bc, self.dirichlet_tag)) )
def __call__(self, t, x_vec): ones = numpy.ones_like(x_vec[0]) rho_field = ones*self.rho if self.gaussian_pulse_at is not None: rel_to_pulse = [x_vec[i] - self.gaussian_pulse_at[i] for i in range(len(x_vec))] rho_field += self.pulse_magnitude * self.rho * numpy.exp( - sum(rtp_i**2 for rtp_i in rel_to_pulse)/2) direction = self.direction_vector(x_vec.shape[0]) from hedge.tools import make_obj_array u_field = make_obj_array([ones*self.velocity*dir_i for dir_i in direction]) from hedge.tools import join_fields return join_fields(rho_field, self.e*ones, self.rho*u_field)
def __call__(self, t, x_vec): ones = numpy.ones_like(x_vec[0]) rho_field = ones * self.rho if self.gaussian_pulse_at is not None: rel_to_pulse = [ x_vec[i] - self.gaussian_pulse_at[i] for i in range(len(x_vec)) ] rho_field += self.pulse_magnitude * self.rho * numpy.exp( -sum(rtp_i**2 for rtp_i in rel_to_pulse) / 2) direction = self.direction_vector(x_vec.shape[0]) from hedge.tools import make_obj_array u_field = make_obj_array( [ones * self.velocity * dir_i for dir_i in direction]) from hedge.tools import join_fields return join_fields(rho_field, self.e * ones, self.rho * u_field)
def local_derivatives(self, w=None): """Template for the spatial derivatives of the relevant components of :math:`E` and :math:`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 nabla = make_nabla(self.dimensions) # in conservation form: u_t + A u_x = 0 return join_fields((self.current - h_curl(h)), e_curl(e))
def __call__(self, t, x_vec): from hedge.tools import heaviside from hedge.tools import heaviside_a x_rel = x_vec[0] y_rel = x_vec[1] from math import pi r = numpy.sqrt(x_rel**2 + y_rel**2) r_shift = r - 3.0 u = 0.0 v = 0.0 from numpy import sign rho = heaviside(-r_shift) + .125 * heaviside_a(r_shift, 1.0) e = (1.0 / (self.gamma - 1.0)) * (heaviside(-r_shift) + .1 * heaviside_a(r_shift, 1.0)) p = (self.gamma - 1.0) * e from hedge.tools import join_fields return join_fields(rho, e, rho * u, rho * v)
def __call__(self, t, x_vec): vortex_loc = self.center + t*self.velocity # coordinates relative to vortex center x_rel = x_vec[0] - vortex_loc[0] y_rel = x_vec[1] - vortex_loc[1] # Y.C. Zhou, G.W. Wei / Journal of Computational Physics 189 (2003) 159 # also JSH/TW Nodal DG Methods, p. 209 from math import pi r = numpy.sqrt(x_rel**2+y_rel**2) expterm = self.beta*numpy.exp(1-r**2) u = self.velocity[0] - expterm*y_rel/(2*pi) v = self.velocity[1] + expterm*x_rel/(2*pi) rho = self.densityA*(1-(self.gamma-1)/(16*self.gamma*pi**2)*expterm**2)**(1/(self.gamma-1)) p = rho**self.gamma e = p/(self.gamma-1) + rho/2*(u**2+v**2) from hedge.tools import join_fields return join_fields(rho, e, rho*u, rho*v)
def absorbing_bc(self, w=None): """Construct part of the flux operator template for 1st order absorbing boundary conditions. """ from hedge.optemplate import normal absorb_normal = normal(self.absorb_tag, self.dimensions) from hedge.optemplate import BoundarizeOperator, Field from hedge.tools import join_fields e, h = self.split_eh(self.field_placeholder(w)) if self.fixed_material: epsilon = self.epsilon mu = self.mu else: epsilon = cse( BoundarizeOperator(self.absorb_tag)(Field("epsilon"))) mu = cse(BoundarizeOperator(self.absorb_tag)(Field("mu"))) absorb_Z = (mu / epsilon)**0.5 absorb_Y = 1 / absorb_Z absorb_e = BoundarizeOperator(self.absorb_tag)(e) absorb_h = BoundarizeOperator(self.absorb_tag)(h) bc = join_fields( absorb_e + 1 / 2 * (self.space_cross_h(absorb_normal, self.space_cross_e(absorb_normal, absorb_e)) - absorb_Z * self.space_cross_h(absorb_normal, absorb_h)), absorb_h + 1 / 2 * (self.space_cross_e(absorb_normal, self.space_cross_h(absorb_normal, absorb_h)) + absorb_Y * self.space_cross_e(absorb_normal, absorb_e))) return bc
def absorbing_bc(self, w=None): """Construct part of the flux operator template for 1st order absorbing boundary conditions. """ from hedge.optemplate import normal absorb_normal = normal(self.absorb_tag, self.dimensions) from hedge.optemplate import BoundarizeOperator, Field from hedge.tools import join_fields e, h = self.split_eh(self.field_placeholder(w)) if self.fixed_material: epsilon = self.epsilon mu = self.mu else: epsilon = cse( BoundarizeOperator(self.absorb_tag)(Field("epsilon"))) mu = cse( BoundarizeOperator(self.absorb_tag)(Field("mu"))) absorb_Z = (mu/epsilon)**0.5 absorb_Y = 1/absorb_Z absorb_e = BoundarizeOperator(self.absorb_tag)(e) absorb_h = BoundarizeOperator(self.absorb_tag)(h) bc = join_fields( absorb_e + 1/2*(self.space_cross_h(absorb_normal, self.space_cross_e( absorb_normal, absorb_e)) - absorb_Z*self.space_cross_h(absorb_normal, absorb_h)), absorb_h + 1/2*( self.space_cross_e(absorb_normal, self.space_cross_h( absorb_normal, absorb_h)) + absorb_Y*self.space_cross_e(absorb_normal, absorb_e))) return bc
def __call__(self, t, x_vec): from hedge.tools import heaviside from hedge.tools import heaviside_a x_rel = x_vec[0] y_rel = x_vec[1] from math import pi r = numpy.sqrt(x_rel ** 2 + y_rel ** 2) r_shift = r - 3.0 u = 0.0 v = 0.0 from numpy import sign rho = heaviside(-r_shift) + 0.125 * heaviside_a(r_shift, 1.0) e = (1.0 / (self.gamma - 1.0)) * (heaviside(-r_shift) + 0.1 * heaviside_a(r_shift, 1.0)) p = (self.gamma - 1.0) * e from hedge.tools import join_fields return join_fields(rho, e, rho * u, rho * v)
def local_derivatives(self, w=None): """Template for the spatial derivatives of the relevant components of :math:`E` and :math:`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 nabla = make_nabla(self.dimensions) # in conservation form: u_t + A u_x = 0 return join_fields( (self.current - h_curl(h)), e_curl(e) )
def test_efield_vs_gauss_law(): from hedge.mesh.generator import \ make_box_mesh, \ make_cylinder_mesh from math import sqrt, pi from pytools.arithmetic_container import \ ArithmeticList, join_fields from random import seed from pytools.stopwatch import Job from pyrticle.units import SIUnitsWithNaturalConstants units = SIUnitsWithNaturalConstants() seed(0) nparticles = 10000 beam_radius = 2.5 * units.MM emittance = 5 * units.MM * units.MRAD final_time = 0.1 * units.M / units.VACUUM_LIGHT_SPEED() field_dump_interval = 1 tube_length = 20 * units.MM # discretization setup ---------------------------------------------------- from pyrticle.geometry import make_cylinder_with_fine_core mesh = make_cylinder_with_fine_core( r=10 * beam_radius, inner_r=1 * beam_radius, min_z=0, max_z=tube_length, max_volume_inner=10 * units.MM**3, max_volume_outer=100 * units.MM**3, radial_subdiv=10, ) from hedge.backends import guess_run_context rcon = guess_run_context([]) discr = rcon.make_discretization(mesh, order=3) from hedge.models.em import MaxwellOperator max_op = MaxwellOperator(epsilon=units.EPSILON0, mu=units.MU0, flux_type=1) from hedge.models.nd_calculus import DivergenceOperator div_op = DivergenceOperator(discr.dimensions) # particles setup --------------------------------------------------------- from pyrticle.cloud import PicMethod from pyrticle.deposition.shape import ShapeFunctionDepositor from pyrticle.pusher import MonomialParticlePusher method = PicMethod(discr, units, ShapeFunctionDepositor(), MonomialParticlePusher(), 3, 3) # particle ic --------------------------------------------------------- cloud_charge = -1e-9 * units.C electrons_per_particle = abs(cloud_charge / nparticles / units.EL_CHARGE) el_energy = 10 * units.EL_REST_ENERGY() el_lorentz_gamma = el_energy / units.EL_REST_ENERGY() beta = (1 - 1 / el_lorentz_gamma**2)**0.5 gamma = 1 / sqrt(1 - beta**2) from pyrticle.distribution import KVZIntervalBeam beam = KVZIntervalBeam(units, total_charge=cloud_charge, p_charge=cloud_charge / nparticles, p_mass=electrons_per_particle * units.EL_MASS, radii=2 * [beam_radius], emittances=2 * [5 * units.MM * units.MRAD], z_length=tube_length, z_pos=tube_length / 2, beta=beta) state = method.make_state() method.add_particles(state, beam.generate_particles(), nparticles) # field ic ---------------------------------------------------------------- from pyrticle.cloud import guess_shape_bandwidth guess_shape_bandwidth(method, state, 2) from pyrticle.cloud import compute_initial_condition from hedge.data import ConstantGivenFunction fields = compute_initial_condition(rcon, discr, method, state, maxwell_op=max_op, potential_bc=ConstantGivenFunction()) # check against theory ---------------------------------------------------- q_per_unit_z = cloud_charge / beam.z_length class TheoreticalEField: shape = (3, ) def __call__(self, x, el): r = la.norm(x[:2]) if r >= max(beam.radii): xy_unit = x / r xy_unit[2] = 0 return xy_unit * ((q_per_unit_z) / (2 * pi * r * max_op.epsilon)) else: return numpy.zeros((3, )) def theory_indicator(x, el): r = la.norm(x[:2]) if r >= max(beam.radii): return 1 else: return 0 from hedge.tools import join_fields, to_obj_array e_theory = to_obj_array( discr.interpolate_volume_function(TheoreticalEField())) theory_ind = discr.interpolate_volume_function(theory_indicator) e_field, h_field = max_op.split_eh(fields) restricted_e = join_fields(*[e_i * theory_ind for e_i in e_field]) def l2_error(field, true): return discr.norm(field - true) / discr.norm(true) outer_l2 = l2_error(restricted_e, e_theory) assert outer_l2 < 0.08 if False: visf = vis.make_file("e_comparison") mesh_scalars, mesh_vectors = \ method.add_to_vis(vis, visf) vis.add_data(visf, [ ("e", restricted_e), ("e_theory", e_theory), ] + mesh_vectors + mesh_scalars) visf.close()
def rhs(t, y): return join_fields([ vel, 0 * vel, 0, # drecon ])
def op_template(self, with_sensor=False): from hedge.optemplate import \ Field, \ make_vector_field, \ BoundaryPair, \ get_flux_operator, \ make_nabla, \ InverseMassOperator, \ BoundarizeOperator d = self.dimensions w = make_vector_field("w", d + 1) u = w[0] v = w[1:] from hedge.tools import join_fields c = Field("c") flux_w = join_fields(c, w) # {{{ boundary conditions from hedge.flux import make_normal normal = make_normal(d) from hedge.tools import join_fields # Dirichlet dir_c = BoundarizeOperator(self.dirichlet_tag) * c dir_u = BoundarizeOperator(self.dirichlet_tag) * u dir_v = BoundarizeOperator(self.dirichlet_tag) * v dir_bc = join_fields(dir_c, -dir_u, dir_v) # Neumann neu_c = BoundarizeOperator(self.neumann_tag) * c neu_u = BoundarizeOperator(self.neumann_tag) * u neu_v = BoundarizeOperator(self.neumann_tag) * v neu_bc = join_fields(neu_c, neu_u, -neu_v) # Radiation from hedge.optemplate import make_normal rad_normal = make_normal(self.radiation_tag, d) rad_c = BoundarizeOperator(self.radiation_tag) * c rad_u = BoundarizeOperator(self.radiation_tag) * u rad_v = BoundarizeOperator(self.radiation_tag) * v rad_bc = join_fields( rad_c, 0.5 * (rad_u - self.time_sign * numpy.dot(rad_normal, rad_v)), 0.5 * rad_normal * (numpy.dot(rad_normal, rad_v) - self.time_sign * rad_u)) # }}} # {{{ diffusion ------------------------------------------------------- from pytools.obj_array import with_object_array_or_scalar def make_diffusion(arg): if with_sensor or (self.diffusion_coeff is not None and self.diffusion_coeff != 0): if self.diffusion_coeff is None: diffusion_coeff = 0 else: diffusion_coeff = self.diffusion_coeff if with_sensor: diffusion_coeff += Field("sensor") from hedge.second_order import SecondDerivativeTarget # strong_form here allows the reuse the value of grad u. grad_tgt = SecondDerivativeTarget( self.dimensions, strong_form=True, operand=arg) self.diffusion_scheme.grad( grad_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) div_tgt = SecondDerivativeTarget( self.dimensions, strong_form=False, operand=diffusion_coeff * grad_tgt.minv_all) self.diffusion_scheme.div( div_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) return div_tgt.minv_all else: return 0 # }}} # entire operator ----------------------------------------------------- nabla = make_nabla(d) flux_op = get_flux_operator(self.flux()) return ( -join_fields( -self.time_sign * c * numpy.dot(nabla, v) - make_diffusion(u), -self.time_sign * c * (nabla * u) - with_object_array_or_scalar(make_diffusion, v)) + InverseMassOperator() * (flux_op(flux_w) + flux_op( BoundaryPair(flux_w, dir_bc, self.dirichlet_tag)) + flux_op( BoundaryPair(flux_w, neu_bc, self.neumann_tag)) + flux_op( BoundaryPair(flux_w, rad_bc, self.radiation_tag))))
def op_template(self): from hedge.optemplate import \ make_vector_field, \ BoundaryPair, \ get_flux_operator, \ make_nabla, \ InverseMassOperator, \ BoundarizeOperator d = self.dimensions w = make_vector_field("w", d + 1) u = w[0] v = w[1:] # boundary conditions ------------------------------------------------- from hedge.tools import join_fields # dirichlet BCs ------------------------------------------------------- from hedge.optemplate import make_normal, Field dir_normal = make_normal(self.dirichlet_tag, d) dir_u = BoundarizeOperator(self.dirichlet_tag) * u dir_v = BoundarizeOperator(self.dirichlet_tag) * v if self.dirichlet_bc_f: # FIXME from warnings import warn warn("Inhomogeneous Dirichlet conditions on the wave equation " "are still having issues.") dir_g = Field("dir_bc_u") dir_bc = join_fields(2 * dir_g - dir_u, dir_v) else: dir_bc = join_fields(-dir_u, dir_v) # neumann BCs --------------------------------------------------------- neu_u = BoundarizeOperator(self.neumann_tag) * u neu_v = BoundarizeOperator(self.neumann_tag) * v neu_bc = join_fields(neu_u, -neu_v) # radiation BCs ------------------------------------------------------- from hedge.optemplate import make_normal rad_normal = make_normal(self.radiation_tag, d) rad_u = BoundarizeOperator(self.radiation_tag) * u rad_v = BoundarizeOperator(self.radiation_tag) * v rad_bc = join_fields( 0.5 * (rad_u - self.sign * numpy.dot(rad_normal, rad_v)), 0.5 * rad_normal * (numpy.dot(rad_normal, rad_v) - self.sign * rad_u)) # entire operator ----------------------------------------------------- nabla = make_nabla(d) flux_op = get_flux_operator(self.flux()) from hedge.tools import join_fields result = ( -join_fields(-self.c * numpy.dot(nabla, v), -self.c * (nabla * u)) + InverseMassOperator() * (flux_op(w) + flux_op(BoundaryPair(w, dir_bc, self.dirichlet_tag)) + flux_op(BoundaryPair(w, neu_bc, self.neumann_tag)) + flux_op( BoundaryPair(w, rad_bc, self.radiation_tag)))) if self.source_f is not None: result[0] += Field("source_u") return result
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 op_template(self): from hedge.tools import join_fields from hedge.optemplate import Field, make_vector_field, BoundaryPair, \ BoundarizeOperator, make_normal, get_flux_operator, \ make_nabla, InverseMassOperator w = make_vector_field("w", self.component_count) e, h, phi = self.split_ehphi(w) rho = Field("rho") # local part ---------------------------------------------------------- nabla = make_nabla(self.maxwell_op.dimensions) # in conservation form: u_t + A u_x = 0 # we're describing the A u_x part, the sign gets reversed # below. max_local_op = join_fields(self.maxwell_op.local_derivatives(w), 0) c = self.maxwell_op.c chi = self.chi hyp_local_operator = max_local_op + join_fields( c * chi * (nabla * phi), 0 * h, c * chi * numpy.dot(nabla, e) - c * chi * rho / self.maxwell_op.epsilon # sign gets reversed below, so this is actually # the decay it advertises to be. + self.phi_decay * phi) # BCs ----------------------------------------------------------------- pec_tag = self.maxwell_op.pec_tag pec_e = BoundarizeOperator(pec_tag)(e) pec_h = BoundarizeOperator(pec_tag)(h) pec_phi = BoundarizeOperator(pec_tag)(phi) pec_n = make_normal(pec_tag, self.maxwell_op.dimensions) bc = "prev" print "HYP CLEAN BC", bc if bc == "char": # see hedge/doc/maxima/eclean.mac for derivation pec_bc = join_fields( -pec_e + 3 / 2 * pec_n * numpy.dot(pec_n, pec_e) + 1 / 2 * pec_phi * pec_n, pec_h, 1 / 2 * (pec_phi + numpy.dot(pec_n, pec_e))) elif bc == "invent": # see hedge/doc/maxima/eclean.mac for derivation pec_bc = join_fields(-pec_e + 2 * pec_n * numpy.dot(pec_n, pec_e), pec_h, pec_phi) elif bc == "munz": # Munz et al pec_bc = join_fields(-pec_e, pec_h, pec_phi - numpy.dot(pec_n, pec_e)) elif bc == "prev": # previous condition pec_bc = join_fields(-pec_e + 2 * pec_n * numpy.dot(pec_n, pec_e), pec_h, -pec_phi) # assemble operator --------------------------------------------------- flux_op = get_flux_operator(self.flux()) return -hyp_local_operator + InverseMassOperator()( flux_op(w) + flux_op(BoundaryPair(w, pec_bc, pec_tag)))
def op_template(self, with_sensor=False): # {{{ operator preliminaries ------------------------------------------ from hedge.optemplate import (Field, BoundaryPair, get_flux_operator, make_stiffness_t, InverseMassOperator, make_sym_vector, ElementwiseMaxOperator, BoundarizeOperator) from hedge.optemplate.primitives import make_common_subexpression as cse from hedge.optemplate.operators import ( QuadratureGridUpsampler, QuadratureInteriorFacesGridUpsampler) to_quad = QuadratureGridUpsampler("quad") to_if_quad = QuadratureInteriorFacesGridUpsampler("quad") from hedge.tools import join_fields, \ ptwise_dot u = Field("u") v = make_sym_vector("v", self.dimensions) c = ElementwiseMaxOperator()(ptwise_dot(1, 1, v, v)) quad_u = cse(to_quad(u)) quad_v = cse(to_quad(v)) w = join_fields(u, v, c) quad_face_w = to_if_quad(w) # }}} # {{{ boundary conditions --------------------------------------------- from hedge.mesh import TAG_ALL bc_c = to_quad(BoundarizeOperator(TAG_ALL)(c)) bc_u = to_quad(Field("bc_u")) bc_v = to_quad(BoundarizeOperator(TAG_ALL)(v)) if self.bc_u_f is "None": bc_w = join_fields(0, bc_v, bc_c) else: bc_w = join_fields(bc_u, bc_v, bc_c) minv_st = make_stiffness_t(self.dimensions) m_inv = InverseMassOperator() flux_op = get_flux_operator(self.flux()) # }}} # {{{ diffusion ------------------------------------------------------- if with_sensor or (self.diffusion_coeff is not None and self.diffusion_coeff != 0): if self.diffusion_coeff is None: diffusion_coeff = 0 else: diffusion_coeff = self.diffusion_coeff if with_sensor: diffusion_coeff += Field("sensor") from hedge.second_order import SecondDerivativeTarget # strong_form here allows IPDG to reuse the value of grad u. grad_tgt = SecondDerivativeTarget(self.dimensions, strong_form=True, operand=u) self.diffusion_scheme.grad(grad_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) div_tgt = SecondDerivativeTarget(self.dimensions, strong_form=False, operand=diffusion_coeff * grad_tgt.minv_all) self.diffusion_scheme.div(div_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) diffusion_part = div_tgt.minv_all else: diffusion_part = 0 # }}} to_quad = QuadratureGridUpsampler("quad") quad_u = cse(to_quad(u)) quad_v = cse(to_quad(v)) return m_inv(numpy.dot(minv_st, cse(quad_v*quad_u)) - (flux_op(quad_face_w) + flux_op(BoundaryPair(quad_face_w, bc_w, TAG_ALL)))) \ + diffusion_part
def op_template(self, with_sensor=False): # {{{ operator preliminaries ------------------------------------------ from hedge.optemplate import (Field, BoundaryPair, get_flux_operator, make_stiffness_t, InverseMassOperator, make_sym_vector, ElementwiseMaxOperator, BoundarizeOperator) from hedge.optemplate.primitives import make_common_subexpression as cse from hedge.optemplate.operators import ( QuadratureGridUpsampler, QuadratureInteriorFacesGridUpsampler) to_quad = QuadratureGridUpsampler("quad") to_if_quad = QuadratureInteriorFacesGridUpsampler("quad") from hedge.tools import join_fields, \ ptwise_dot u = Field("u") v = make_sym_vector("v", self.dimensions) c = ElementwiseMaxOperator()(ptwise_dot(1, 1, v, v)) quad_u = cse(to_quad(u)) quad_v = cse(to_quad(v)) w = join_fields(u, v, c) quad_face_w = to_if_quad(w) # }}} # {{{ boundary conditions --------------------------------------------- from hedge.mesh import TAG_ALL bc_c = to_quad(BoundarizeOperator(TAG_ALL)(c)) bc_u = to_quad(Field("bc_u")) bc_v = to_quad(BoundarizeOperator(TAG_ALL)(v)) if self.bc_u_f is "None": bc_w = join_fields(0, bc_v, bc_c) else: bc_w = join_fields(bc_u, bc_v, bc_c) minv_st = make_stiffness_t(self.dimensions) m_inv = InverseMassOperator() flux_op = get_flux_operator(self.flux()) # }}} # {{{ diffusion ------------------------------------------------------- if with_sensor or ( self.diffusion_coeff is not None and self.diffusion_coeff != 0): if self.diffusion_coeff is None: diffusion_coeff = 0 else: diffusion_coeff = self.diffusion_coeff if with_sensor: diffusion_coeff += Field("sensor") from hedge.second_order import SecondDerivativeTarget # strong_form here allows IPDG to reuse the value of grad u. grad_tgt = SecondDerivativeTarget( self.dimensions, strong_form=True, operand=u) self.diffusion_scheme.grad(grad_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) div_tgt = SecondDerivativeTarget( self.dimensions, strong_form=False, operand=diffusion_coeff*grad_tgt.minv_all) self.diffusion_scheme.div(div_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) diffusion_part = div_tgt.minv_all else: diffusion_part = 0 # }}} to_quad = QuadratureGridUpsampler("quad") quad_u = cse(to_quad(u)) quad_v = cse(to_quad(v)) return m_inv(numpy.dot(minv_st, cse(quad_v*quad_u)) - (flux_op(quad_face_w) + flux_op(BoundaryPair(quad_face_w, bc_w, TAG_ALL)))) \ + diffusion_part
def main(write_output=True, flux_type_arg="upwind", dtype=np.float64, debug=[]): from math import sin, cos, pi, exp, sqrt # noqa from hedge.backends import guess_run_context rcon = guess_run_context() if rcon.is_head_rank: from hedge.mesh.reader.gmsh import generate_gmsh mesh = generate_gmsh(GEOMETRY, 2, allow_internal_boundaries=True, force_dimension=2) print "%d elements" % len(mesh.elements) mesh_data = rcon.distribute_mesh(mesh) else: mesh_data = rcon.receive_mesh() discr = rcon.make_discretization(mesh_data, order=4, debug=debug, default_scalar_type=dtype) from hedge.timestep.runge_kutta import LSRK4TimeStepper stepper = LSRK4TimeStepper(dtype=dtype) from hedge.visualization import VtkVisualizer if write_output: vis = VtkVisualizer(discr, rcon, "fld") source_center = 0 source_width = 0.05 source_omega = 3 import hedge.optemplate as sym sym_x = sym.nodes(2) sym_source_center_dist = sym_x - source_center from hedge.models.wave import StrongWaveOperator op = StrongWaveOperator( -1, discr.dimensions, source_f=sym.CFunction("sin")( source_omega * sym.ScalarParameter("t")) * sym.CFunction("exp")( -np.dot(sym_source_center_dist, sym_source_center_dist) / source_width**2), dirichlet_tag="boundary", neumann_tag=TAG_NONE, radiation_tag=TAG_NONE, flux_type=flux_type_arg) from hedge.tools import join_fields fields = join_fields( discr.volume_zeros(dtype=dtype), [discr.volume_zeros(dtype=dtype) for i in range(discr.dimensions)]) # diagnostics setup ------------------------------------------------------- from pytools.log import LogManager, \ add_general_quantities, \ add_simulation_quantities, \ add_run_info if write_output: log_file_name = "wiggly.dat" else: log_file_name = None logmgr = LogManager(log_file_name, "w", rcon.communicator) add_run_info(logmgr) add_general_quantities(logmgr) add_simulation_quantities(logmgr) discr.add_instrumentation(logmgr) stepper.add_instrumentation(logmgr) logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"]) # timestep loop ----------------------------------------------------------- rhs = op.bind(discr) try: from hedge.timestep import times_and_steps step_it = times_and_steps( final_time=4, logmgr=logmgr, max_dt_getter=lambda t: op.estimate_timestep( discr, stepper=stepper, t=t, fields=fields)) for step, t, dt in step_it: if step % 10 == 0 and write_output: visf = vis.make_file("fld-%04d" % step) vis.add_data(visf, [ ("u", fields[0]), ("v", fields[1:]), ], time=t, step=step) visf.close() fields = stepper(fields, t, dt, rhs) assert discr.norm(fields) < 1 assert fields[0].dtype == dtype finally: if write_output: vis.close() logmgr.close() discr.close()
def main(write_output=True): from math import sin, exp, sqrt # noqa from hedge.mesh.generator import make_rect_mesh mesh = make_rect_mesh(a=(-0.5, -0.5), b=(0.5, 0.5), max_area=0.008) from hedge.backends.jit import Discretization discr = Discretization(mesh, order=4) from hedge.visualization import VtkVisualizer vis = VtkVisualizer(discr, None, "fld") source_center = np.array([0.1, 0.22]) source_width = 0.05 source_omega = 3 import hedge.optemplate as sym sym_x = sym.nodes(2) sym_source_center_dist = sym_x - source_center from hedge.models.wave import StrongWaveOperator from hedge.mesh import TAG_ALL, TAG_NONE op = StrongWaveOperator( -0.1, discr.dimensions, source_f=sym.CFunction("sin")( source_omega * sym.ScalarParameter("t")) * sym.CFunction("exp")( -np.dot(sym_source_center_dist, sym_source_center_dist) / source_width**2), dirichlet_tag=TAG_NONE, neumann_tag=TAG_NONE, radiation_tag=TAG_ALL, flux_type="upwind") from hedge.tools import join_fields fields = join_fields( discr.volume_zeros(), [discr.volume_zeros() for i in range(discr.dimensions)]) from hedge.timestep.runge_kutta import LSRK4TimeStepper stepper = LSRK4TimeStepper() dt = op.estimate_timestep(discr, stepper=stepper, fields=fields) nsteps = int(10 / dt) print "dt=%g nsteps=%d" % (dt, nsteps) rhs = op.bind(discr) for step in range(nsteps): t = step * dt if step % 10 == 0 and write_output: print step, t, discr.norm(fields[0]) visf = vis.make_file("fld-%04d" % step) vis.add_data(visf, [ ("u", fields[0]), ("v", fields[1:]), ], time=t, step=step) visf.close() fields = stepper(fields, t, dt, rhs) vis.close()
def op_template(self, with_sensor=False): from hedge.optemplate import \ Field, \ make_sym_vector, \ BoundaryPair, \ get_flux_operator, \ make_nabla, \ InverseMassOperator, \ BoundarizeOperator d = self.dimensions w = make_sym_vector("w", d+1) u = w[0] v = w[1:] from hedge.tools import join_fields flux_w = join_fields(self.c, w) # {{{ boundary conditions from hedge.tools import join_fields # Dirichlet dir_c = BoundarizeOperator(self.dirichlet_tag) * self.c dir_u = BoundarizeOperator(self.dirichlet_tag) * u dir_v = BoundarizeOperator(self.dirichlet_tag) * v dir_bc = join_fields(dir_c, -dir_u, dir_v) # Neumann neu_c = BoundarizeOperator(self.neumann_tag) * self.c neu_u = BoundarizeOperator(self.neumann_tag) * u neu_v = BoundarizeOperator(self.neumann_tag) * v neu_bc = join_fields(neu_c, neu_u, -neu_v) # Radiation from hedge.optemplate import make_normal rad_normal = make_normal(self.radiation_tag, d) rad_c = BoundarizeOperator(self.radiation_tag) * self.c rad_u = BoundarizeOperator(self.radiation_tag) * u rad_v = BoundarizeOperator(self.radiation_tag) * v rad_bc = join_fields( rad_c, 0.5*(rad_u - self.time_sign*np.dot(rad_normal, rad_v)), 0.5*rad_normal*(np.dot(rad_normal, rad_v) - self.time_sign*rad_u) ) # }}} # {{{ diffusion ------------------------------------------------------- from pytools.obj_array import with_object_array_or_scalar def make_diffusion(arg): if with_sensor or ( self.diffusion_coeff is not None and self.diffusion_coeff != 0): if self.diffusion_coeff is None: diffusion_coeff = 0 else: diffusion_coeff = self.diffusion_coeff if with_sensor: diffusion_coeff += Field("sensor") from hedge.second_order import SecondDerivativeTarget # strong_form here allows the reuse the value of grad u. grad_tgt = SecondDerivativeTarget( self.dimensions, strong_form=True, operand=arg) self.diffusion_scheme.grad(grad_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) div_tgt = SecondDerivativeTarget( self.dimensions, strong_form=False, operand=diffusion_coeff*grad_tgt.minv_all) self.diffusion_scheme.div(div_tgt, bc_getter=None, dirichlet_tags=[], neumann_tags=[]) return div_tgt.minv_all else: return 0 # }}} # entire operator ----------------------------------------------------- nabla = make_nabla(d) flux_op = get_flux_operator(self.flux()) return ( - join_fields( - self.time_sign*self.c*np.dot(nabla, v) - make_diffusion(u) + self.source, -self.time_sign*self.c*(nabla*u) - with_object_array_or_scalar( make_diffusion, v) ) + InverseMassOperator() * ( flux_op(flux_w) + flux_op(BoundaryPair(flux_w, dir_bc, self.dirichlet_tag)) + flux_op(BoundaryPair(flux_w, neu_bc, self.neumann_tag)) + flux_op(BoundaryPair(flux_w, rad_bc, self.radiation_tag)) ))
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 op_template(self): from hedge.optemplate import \ make_sym_vector, \ BoundaryPair, \ get_flux_operator, \ make_nabla, \ InverseMassOperator, \ BoundarizeOperator d = self.dimensions w = make_sym_vector("w", d+1) u = w[0] v = w[1:] # boundary conditions ------------------------------------------------- from hedge.tools import join_fields # dirichlet BCs ------------------------------------------------------- from hedge.optemplate import normal, Field dir_u = BoundarizeOperator(self.dirichlet_tag) * u dir_v = BoundarizeOperator(self.dirichlet_tag) * v if self.dirichlet_bc_f: # FIXME from warnings import warn warn("Inhomogeneous Dirichlet conditions on the wave equation " "are still having issues.") dir_g = Field("dir_bc_u") dir_bc = join_fields(2*dir_g - dir_u, dir_v) else: dir_bc = join_fields(-dir_u, dir_v) # neumann BCs --------------------------------------------------------- neu_u = BoundarizeOperator(self.neumann_tag) * u neu_v = BoundarizeOperator(self.neumann_tag) * v neu_bc = join_fields(neu_u, -neu_v) # radiation BCs ------------------------------------------------------- rad_normal = normal(self.radiation_tag, d) rad_u = BoundarizeOperator(self.radiation_tag) * u rad_v = BoundarizeOperator(self.radiation_tag) * v rad_bc = join_fields( 0.5*(rad_u - self.sign*np.dot(rad_normal, rad_v)), 0.5*rad_normal*(np.dot(rad_normal, rad_v) - self.sign*rad_u) ) # entire operator ----------------------------------------------------- nabla = make_nabla(d) flux_op = get_flux_operator(self.flux()) from hedge.tools import join_fields result = ( - join_fields( -self.c*np.dot(nabla, v), -self.c*(nabla*u) ) + InverseMassOperator() * ( flux_op(w) + flux_op(BoundaryPair(w, dir_bc, self.dirichlet_tag)) + flux_op(BoundaryPair(w, neu_bc, self.neumann_tag)) + flux_op(BoundaryPair(w, rad_bc, self.radiation_tag)) )) result[0] += self.source_f return result
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 main(write_output=True, dir_tag=TAG_NONE, neu_tag=TAG_NONE, rad_tag=TAG_ALL, flux_type_arg="upwind"): from math import sin, cos, pi, exp, sqrt # noqa from hedge.backends import guess_run_context rcon = guess_run_context() dim = 2 if dim == 1: if rcon.is_head_rank: from hedge.mesh.generator import make_uniform_1d_mesh mesh = make_uniform_1d_mesh(-10, 10, 500) elif dim == 2: from hedge.mesh.generator import make_rect_mesh if rcon.is_head_rank: mesh = make_rect_mesh(a=(-1, -1), b=(1, 1), max_area=0.003) elif dim == 3: if rcon.is_head_rank: from hedge.mesh.generator import make_ball_mesh mesh = make_ball_mesh(max_volume=0.0005) else: raise RuntimeError("bad number of dimensions") if rcon.is_head_rank: print "%d elements" % len(mesh.elements) mesh_data = rcon.distribute_mesh(mesh) else: mesh_data = rcon.receive_mesh() discr = rcon.make_discretization(mesh_data, order=4) from hedge.timestep.runge_kutta import LSRK4TimeStepper stepper = LSRK4TimeStepper() from hedge.visualization import VtkVisualizer if write_output: vis = VtkVisualizer(discr, rcon, "fld") source_center = np.array([0.7, 0.4]) source_width = 1 / 16 source_omega = 3 import hedge.optemplate as sym sym_x = sym.nodes(2) sym_source_center_dist = sym_x - source_center from hedge.models.wave import VariableVelocityStrongWaveOperator op = VariableVelocityStrongWaveOperator( c=sym.If(sym.Comparison(np.dot(sym_x, sym_x), "<", 0.4**2), 1, 0.5), dimensions=discr.dimensions, source=sym.CFunction("sin")(source_omega * sym.ScalarParameter("t")) * sym.CFunction("exp")( -np.dot(sym_source_center_dist, sym_source_center_dist) / source_width**2), dirichlet_tag=dir_tag, neumann_tag=neu_tag, radiation_tag=rad_tag, flux_type=flux_type_arg) from hedge.tools import join_fields fields = join_fields( discr.volume_zeros(), [discr.volume_zeros() for i in range(discr.dimensions)]) # {{{ diagnostics setup from pytools.log import LogManager, \ add_general_quantities, \ add_simulation_quantities, \ add_run_info if write_output: log_file_name = "wave.dat" else: log_file_name = None logmgr = LogManager(log_file_name, "w", rcon.communicator) add_run_info(logmgr) add_general_quantities(logmgr) add_simulation_quantities(logmgr) discr.add_instrumentation(logmgr) from pytools.log import IntervalTimer vis_timer = IntervalTimer("t_vis", "Time spent visualizing") logmgr.add_quantity(vis_timer) stepper.add_instrumentation(logmgr) from hedge.log import LpNorm u_getter = lambda: fields[0] logmgr.add_quantity(LpNorm(u_getter, discr, 1, name="l1_u")) logmgr.add_quantity(LpNorm(u_getter, discr, name="l2_u")) logmgr.add_watches(["step.max", "t_sim.max", "l2_u", "t_step.max"]) # }}} # {{{ timestep loop rhs = op.bind(discr) try: from hedge.timestep.stability import \ approximate_rk4_relative_imag_stability_region max_dt = (1 / discr.compile(op.max_eigenvalue_expr())() * discr.dt_non_geometric_factor() * discr.dt_geometric_factor() * approximate_rk4_relative_imag_stability_region(stepper)) if flux_type_arg == "central": max_dt *= 0.25 from hedge.timestep import times_and_steps step_it = times_and_steps(final_time=3, logmgr=logmgr, max_dt_getter=lambda t: max_dt) for step, t, dt in step_it: if step % 10 == 0 and write_output: visf = vis.make_file("fld-%04d" % step) vis.add_data(visf, [ ("u", fields[0]), ("v", fields[1:]), ], time=t, step=step) visf.close() fields = stepper(fields, t, dt, rhs) assert discr.norm(fields) < 1 finally: if write_output: vis.close() logmgr.close() discr.close()
def main(write_output=True, dir_tag=TAG_NONE, neu_tag=TAG_NONE, rad_tag=TAG_ALL, flux_type_arg="upwind", dtype=np.float64, debug=[]): from math import sin, cos, pi, exp, sqrt # noqa from hedge.backends import guess_run_context rcon = guess_run_context() dim = 2 if dim == 1: if rcon.is_head_rank: from hedge.mesh.generator import make_uniform_1d_mesh mesh = make_uniform_1d_mesh(-10, 10, 500) elif dim == 2: from hedge.mesh.generator import make_rect_mesh if rcon.is_head_rank: mesh = make_rect_mesh(a=(-0.5, -0.5), b=(0.5, 0.5), max_area=0.008) elif dim == 3: if rcon.is_head_rank: from hedge.mesh.generator import make_ball_mesh mesh = make_ball_mesh(max_volume=0.0005) else: raise RuntimeError("bad number of dimensions") if rcon.is_head_rank: print "%d elements" % len(mesh.elements) mesh_data = rcon.distribute_mesh(mesh) else: mesh_data = rcon.receive_mesh() from hedge.timestep.runge_kutta import LSRK4TimeStepper stepper = LSRK4TimeStepper(dtype=dtype) from hedge.models.wave import StrongWaveOperator from hedge.mesh import TAG_ALL, TAG_NONE # noqa source_center = np.array([0.1, 0.22]) source_width = 0.05 source_omega = 3 import hedge.optemplate as sym sym_x = sym.nodes(2) sym_source_center_dist = sym_x - source_center op = StrongWaveOperator( -1, dim, source_f=sym.CFunction("sin")( source_omega * sym.ScalarParameter("t")) * sym.CFunction("exp")( -np.dot(sym_source_center_dist, sym_source_center_dist) / source_width**2), dirichlet_tag=dir_tag, neumann_tag=neu_tag, radiation_tag=rad_tag, flux_type=flux_type_arg) discr = rcon.make_discretization(mesh_data, order=4, debug=debug, default_scalar_type=dtype, tune_for=op.op_template()) from hedge.visualization import VtkVisualizer if write_output: vis = VtkVisualizer(discr, rcon, "fld") from hedge.tools import join_fields fields = join_fields( discr.volume_zeros(dtype=dtype), [discr.volume_zeros(dtype=dtype) for i in range(discr.dimensions)]) # {{{ diagnostics setup from pytools.log import LogManager, \ add_general_quantities, \ add_simulation_quantities, \ add_run_info if write_output: log_file_name = "wave.dat" else: log_file_name = None logmgr = LogManager(log_file_name, "w", rcon.communicator) add_run_info(logmgr) add_general_quantities(logmgr) add_simulation_quantities(logmgr) discr.add_instrumentation(logmgr) from pytools.log import IntervalTimer vis_timer = IntervalTimer("t_vis", "Time spent visualizing") logmgr.add_quantity(vis_timer) stepper.add_instrumentation(logmgr) from hedge.log import LpNorm u_getter = lambda: fields[0] logmgr.add_quantity(LpNorm(u_getter, discr, 1, name="l1_u")) logmgr.add_quantity(LpNorm(u_getter, discr, name="l2_u")) logmgr.add_watches(["step.max", "t_sim.max", "l2_u", "t_step.max"]) # }}} # {{{ timestep loop rhs = op.bind(discr) try: from hedge.timestep import times_and_steps step_it = times_and_steps( final_time=4, logmgr=logmgr, max_dt_getter=lambda t: op.estimate_timestep( discr, stepper=stepper, t=t, fields=fields)) for step, t, dt in step_it: if step % 10 == 0 and write_output: visf = vis.make_file("fld-%04d" % step) vis.add_data(visf, [ ("u", discr.convert_volume(fields[0], kind="numpy")), ("v", discr.convert_volume(fields[1:], kind="numpy")), ], time=t, step=step) visf.close() fields = stepper(fields, t, dt, rhs) assert discr.norm(fields) < 1 assert fields[0].dtype == dtype finally: if write_output: vis.close() logmgr.close() discr.close()