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, 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 flux_num(self, q, fluxes, bdry_tag_state_flux): n = self.len_q d = len(fluxes) fvph = FluxVectorPlaceholder(n*(d+1)+1) speed_ph = fvph[0] state_ph = fvph[1:n+1] fluxes_ph = [fvph[i*n+1:(i+1)*n+1] for i in range(1,d+1)] normal = make_normal(d) flux_strong = 0.5*sum(n_i*(f_i.ext-f_i.int) for n_i, f_i in zip(normal, fluxes_ph)) if self.flux_type == "central": pass elif self.flux_type == "lf": penalty = flux_max(speed_ph.int,speed_ph.ext)*(state_ph.ext-state_ph.int) flux_strong = 0.5 * penalty + flux_strong else: raise ValueError("Invalid flux type '%s'" % self.flux_type) flux_op = get_flux_operator(flux_strong) int_operand = join_fields(self.wave_speed(q), q, *fluxes) return (flux_op(int_operand) +sum(flux_op(BoundaryPair(int_operand, join_fields(0, bdry_state, *bdry_fluxes), tag)) for tag, bdry_state, bdry_fluxes in bdry_tag_state_flux))
def make_lax_friedrichs_flux(wave_speed, state, fluxes, bdry_tags_states_and_fluxes, strong): from pytools.obj_array import join_fields from hedge.flux import make_normal, FluxVectorPlaceholder, flux_max n = len(state) d = len(fluxes) normal = make_normal(d) fvph = FluxVectorPlaceholder(len(state)*(1+d)+1) wave_speed_ph = fvph[0] state_ph = fvph[1:1+n] fluxes_ph = [fvph[1+i*n:1+(i+1)*n] for i in range(1, d+1)] penalty = flux_max(wave_speed_ph.int,wave_speed_ph.ext)*(state_ph.ext-state_ph.int) if not strong: num_flux = 0.5*(sum(n_i*(f_i.int+f_i.ext) for n_i, f_i in zip(normal, fluxes_ph)) - penalty) else: num_flux = 0.5*(sum(n_i*(f_i.int-f_i.ext) for n_i, f_i in zip(normal, fluxes_ph)) + penalty) from hedge.optemplate import get_flux_operator flux_op = get_flux_operator(num_flux) int_operand = join_fields(wave_speed, state, *fluxes) from hedge.optemplate import BoundaryPair return (flux_op(int_operand) + sum( flux_op(BoundaryPair(int_operand, join_fields(0, bdry_state, *bdry_fluxes), tag)) for tag, bdry_state, bdry_fluxes in bdry_tags_states_and_fluxes))
def op_template(self): from hedge.optemplate import (Field, BoundaryPair, get_flux_operator, make_stiffness_t, InverseMassOperator, BoundarizeOperator, QuadratureGridUpsampler, QuadratureInteriorFacesGridUpsampler) u = Field("u") to_quad = QuadratureGridUpsampler("quad") to_int_face_quad = QuadratureInteriorFacesGridUpsampler("quad") # boundary conditions ------------------------------------------------- bc_in = Field("bc_in") bc_out = BoundarizeOperator(self.outflow_tag) * u stiff_t = make_stiffness_t(self.dimensions) m_inv = InverseMassOperator() flux_op = get_flux_operator(self.flux()) return m_inv( numpy.dot(self.v, stiff_t * u) - (flux_op(u) + flux_op(BoundaryPair(u, bc_in, self.inflow_tag)) + flux_op(BoundaryPair(u, bc_out, self.outflow_tag))))
def op_template(self): from hedge.optemplate import ( Field, BoundaryPair, get_flux_operator, make_stiffness_t, InverseMassOperator, BoundarizeOperator, QuadratureGridUpsampler, QuadratureInteriorFacesGridUpsampler) u = Field("u") to_quad = QuadratureGridUpsampler("quad") to_int_face_quad = QuadratureInteriorFacesGridUpsampler("quad") # boundary conditions ------------------------------------------------- bc_in = Field("bc_in") bc_out = BoundarizeOperator(self.outflow_tag)*u stiff_t = make_stiffness_t(self.dimensions) m_inv = InverseMassOperator() flux_op = get_flux_operator(self.flux()) return m_inv(numpy.dot(self.v, stiff_t*u) - ( flux_op(u) + flux_op(BoundaryPair(u, bc_in, self.inflow_tag)) + flux_op(BoundaryPair(u, bc_out, self.outflow_tag)) ))
def get_advection_op(self, q, velocity): from hedge.optemplate import (BoundaryPair, get_flux_operator, make_stiffness_t, InverseMassOperator) stiff_t = make_stiffness_t(self.method.dimensions) flux_op = get_flux_operator(self.get_advection_flux(velocity)) return InverseMassOperator()(np.dot(velocity, stiff_t * q) - flux_op(q))
def get_advection_op(self, q, velocity): from hedge.optemplate import ( BoundaryPair, get_flux_operator, make_stiffness_t, InverseMassOperator) stiff_t = make_stiffness_t(self.method.dimensions) flux_op = get_flux_operator(self.get_advection_flux(velocity)) return InverseMassOperator()( np.dot(velocity, stiff_t*q) - flux_op(q))
def op_template(self): from hedge.mesh import TAG_ALL from hedge.optemplate import Field, BoundaryPair, \ make_nabla, InverseMassOperator, get_flux_operator u = Field("u") bc = Field("bc") nabla = make_nabla(self.dimensions) flux_op = get_flux_operator(self.flux()) return nabla * u - InverseMassOperator()( flux_op(u) + flux_op(BoundaryPair(u, bc, TAG_ALL)))
def op_template(self): from hedge.mesh import TAG_ALL from hedge.optemplate import Field, BoundaryPair, \ make_nabla, InverseMassOperator, get_flux_operator u = Field("u") bc = Field("bc") nabla = make_nabla(self.dimensions) flux_op = get_flux_operator(self.flux()) return nabla*u - InverseMassOperator()( flux_op(u) + flux_op(BoundaryPair(u, bc, TAG_ALL)))
def op_template(self): from hedge.optemplate import Field, BoundaryPair, \ get_flux_operator, make_nabla, InverseMassOperator u = Field("u") bc_in = Field("bc_in") nabla = make_nabla(self.dimensions) m_inv = InverseMassOperator() flux_op = get_flux_operator(self.flux()) return (-numpy.dot(self.v, nabla * u) + m_inv( flux_op(u) + flux_op(BoundaryPair(u, bc_in, self.inflow_tag))))
def op_template(self): from hedge.optemplate import Field, BoundaryPair, \ get_flux_operator, make_nabla, InverseMassOperator u = Field("u") bc_in = Field("bc_in") nabla = make_nabla(self.dimensions) m_inv = InverseMassOperator() flux_op = get_flux_operator(self.flux()) return ( -numpy.dot(self.v, nabla*u) + m_inv( flux_op(u) + flux_op(BoundaryPair(u, bc_in, self.inflow_tag))))
def op_template(self): from hedge.mesh import TAG_ALL from hedge.optemplate import make_sym_vector, BoundaryPair, \ get_flux_operator, make_nabla, InverseMassOperator nabla = make_nabla(self.dimensions) m_inv = InverseMassOperator() v = make_sym_vector("v", self.arg_count) bc = make_sym_vector("bc", self.arg_count) local_op_result = 0 idx = 0 for i, i_enabled in enumerate(self.subset): if i_enabled and i < self.dimensions: local_op_result += nabla[i] * v[idx] idx += 1 flux_op = get_flux_operator(self.flux()) return local_op_result - m_inv( flux_op(v) + flux_op(BoundaryPair(v, bc, TAG_ALL)))
def op_template(self): from hedge.mesh import TAG_ALL from hedge.optemplate import make_vector_field, BoundaryPair, \ get_flux_operator, make_nabla, InverseMassOperator nabla = make_nabla(self.dimensions) m_inv = InverseMassOperator() v = make_vector_field("v", self.arg_count) bc = make_vector_field("bc", self.arg_count) local_op_result = 0 idx = 0 for i, i_enabled in enumerate(self.subset): if i_enabled and i < self.dimensions: local_op_result += nabla[i]*v[idx] idx += 1 flux_op = get_flux_operator(self.flux()) return local_op_result - m_inv( flux_op(v) + flux_op(BoundaryPair(v, bc, TAG_ALL)))
def make_lax_friedrichs_flux(wave_speed, state, fluxes, bdry_tags_states_and_fluxes, strong): from pytools.obj_array import join_fields from hedge.flux import make_normal, FluxVectorPlaceholder, flux_max n = len(state) d = len(fluxes) normal = make_normal(d) fvph = FluxVectorPlaceholder(len(state) * (1 + d) + 1) wave_speed_ph = fvph[0] state_ph = fvph[1:1 + n] fluxes_ph = [fvph[1 + i * n:1 + (i + 1) * n] for i in range(1, d + 1)] penalty = flux_max(wave_speed_ph.int, wave_speed_ph.ext) * (state_ph.ext - state_ph.int) if not strong: num_flux = 0.5 * (sum(n_i * (f_i.int + f_i.ext) for n_i, f_i in zip(normal, fluxes_ph)) - penalty) else: num_flux = 0.5 * (sum(n_i * (f_i.int - f_i.ext) for n_i, f_i in zip(normal, fluxes_ph)) + penalty) from hedge.optemplate import get_flux_operator flux_op = get_flux_operator(num_flux) int_operand = join_fields(wave_speed, state, *fluxes) from hedge.optemplate import BoundaryPair return (flux_op(int_operand) + sum( flux_op( BoundaryPair(int_operand, join_fields(0, bdry_state, *bdry_fluxes), tag)) for tag, bdry_state, bdry_fluxes in bdry_tags_states_and_fluxes))
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 test_interior_fluxes_tri(): """Check triangle surface integrals computed using interior fluxes against their known values. """ from math import pi, sin, cos def round_trip_connect(start, end): for i in range(start, end): yield i, i + 1 yield end, start a = -pi b = pi points = [(a, 0), (b, 0), (a, -1), (b, -1), (a, 1), (b, 1)] import meshpy.triangle as triangle mesh_info = triangle.MeshInfo() mesh_info.set_points(points) mesh_info.set_facets([(0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5), (1, 5)]) mesh_info.regions.resize(2) mesh_info.regions[0] = [0, -0.5, 1, 0.1] # coordinate # lower element tag # max area mesh_info.regions[1] = [0, 0.5, 2, 0.01] # coordinate # upper element tag # max area generated_mesh = triangle.build(mesh_info, attributes=True, volume_constraints=True) # triangle.write_gnuplot_mesh("mesh.dat", generated_mesh) def element_tagger(el): if generated_mesh.element_attributes[el.id] == 1: return ["upper"] else: return ["lower"] from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TriangleDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1]) else: return 0 u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_u + u_u # discr.visualize_vtk("dual.vtk", [("u", u)]) from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile(get_flux_operator((fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) err = abs(numpy.dot(res, ones)) # print err assert err < 5e-14
def add_boundary_flux(self, flux, volume_expr, bdry_expr, tag): from hedge.optemplate import BoundaryPair, get_flux_operator self.boundary_fluxes = self.boundary_fluxes + \ get_flux_operator(self.strong_neg*flux)(BoundaryPair( volume_expr, bdry_expr, tag))
def test_interior_fluxes_tri(): """Check triangle surface integrals computed using interior fluxes against their known values. """ from math import pi, sin, cos def round_trip_connect(start, end): for i in range(start, end): yield i, i + 1 yield end, start a = -pi b = pi points = [(a, 0), (b, 0), (a, -1), (b, -1), (a, 1), (b, 1)] import meshpy.triangle as triangle mesh_info = triangle.MeshInfo() mesh_info.set_points(points) mesh_info.set_facets([(0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5), (1, 5)]) mesh_info.regions.resize(2) mesh_info.regions[0] = [ 0, -0.5, # coordinate 1, # lower element tag 0.1, # max area ] mesh_info.regions[1] = [ 0, 0.5, # coordinate 2, # upper element tag 0.01, # max area ] generated_mesh = triangle.build(mesh_info, attributes=True, volume_constraints=True) #triangle.write_gnuplot_mesh("mesh.dat", generated_mesh) def element_tagger(el): if generated_mesh.element_attributes[el.id] == 1: return ["upper"] else: return ["lower"] from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TriangleDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1]) else: return 0 # u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_u + u_u #discr.visualize_vtk("dual.vtk", [("u", u)]) from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile( get_flux_operator( (fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) ones = ones_on_volume(discr) err = abs(numpy.dot(res, ones)) #print err assert err < 5e-14
def test_2d_gauss_theorem(): """Verify Gauss's theorem explicitly on a mesh""" from hedge.mesh.generator import make_disk_mesh from math import sin, cos, sqrt, exp, pi from numpy import dot mesh = make_disk_mesh() order = 2 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags()) ref_discr = discr_class(mesh, order=order) from hedge.flux import make_normal, FluxScalarPlaceholder normal = make_normal(discr.dimensions) flux_f_ph = FluxScalarPlaceholder(0) one_sided_x = flux_f_ph.int * normal[0] one_sided_y = flux_f_ph.int * normal[1] def f1(x, el): return sin(3 * x[0]) + cos(3 * x[1]) def f2(x, el): return sin(2 * x[0]) + cos(x[1]) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) f1_v = discr.interpolate_volume_function(f1) f2_v = discr.interpolate_volume_function(f2) from hedge.optemplate import BoundaryPair, Field, make_nabla, get_flux_operator nabla = make_nabla(discr.dimensions) diff_optp = nabla[0] * Field("f1") + nabla[1] * Field("f2") divergence = nabla[0].apply(discr, f1_v) + nabla[1].apply(discr, f2_v) int_div = discr.integral(divergence) flux_optp = get_flux_operator(one_sided_x)(BoundaryPair(Field("f1"), Field("fz"))) + get_flux_operator(one_sided_y)( BoundaryPair(Field("f2"), Field("fz")) ) from hedge.mesh import TAG_ALL bdry_val = discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) ref_bdry_val = ref_discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) boundary_int = dot(bdry_val, ones) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") from hedge.tools import make_obj_array from hedge.mesh import TAG_ALL vis.add_data( visf, [ ("bdry", bdry_val), ("ref_bdry", ref_bdry_val), ("div", divergence), ("f", make_obj_array([f1_v, f2_v])), ("n", discr.volumize_boundary_field(discr.boundary_normals(TAG_ALL), TAG_ALL)), ], expressions=[("bdiff", "bdry-ref_bdry")], ) # print abs(boundary_int-int_div) assert abs(boundary_int - int_div) < 5e-15
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 test_interior_fluxes_tet(): """Check tetrahedron surface integrals computed using interior fluxes against their known values. """ import meshpy.tet as tet from math import pi, sin, cos mesh_info = tet.MeshInfo() # construct a two-box extrusion of this base base = [(-pi, -pi, 0), (pi, -pi, 0), (pi, pi, 0), (-pi, pi, 0)] # first, the nodes mesh_info.set_points(base + [(x, y, z + pi) for x, y, z in base] + [(x, y, z + pi + 1) for x, y, z in base]) # next, the facets # vertex indices for a box missing the -z face box_without_minus_z = [[4, 5, 6, 7], [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [3, 7, 4, 0]] def add_to_all_vertex_indices(facets, increment): return [[pt + increment for pt in facet] for facet in facets] mesh_info.set_facets( [[0, 1, 2, 3]] # base + box_without_minus_z # first box + add_to_all_vertex_indices(box_without_minus_z, 4) # second box ) # set the volume properties -- this is where the tet size constraints are mesh_info.regions.resize(2) mesh_info.regions[0] = [ 0, 0, pi / 2, # point in volume -> first box 0, # region tag (user-defined number) 0.5, # max tet volume in region ] mesh_info.regions[1] = [ 0, 0, pi + 0.5, # point in volume -> second box 1, # region tag (user-defined number, arbitrary) 0.1, # max tet volume in region ] generated_mesh = tet.build(mesh_info, attributes=True, volume_constraints=True) from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TetrahedronDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TetrahedronDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1] + x[2]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1] + x[2]) else: return 0 u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_l + u_u # visualize the produced field # from hedge.visualization import SiloVisualizer # vis = SiloVisualizer(discr) # visf = vis.make_file("sandwich") # vis.add_data(visf, # [("u_l", u_l), ("u_u", u_u)], # expressions=[("u", "u_l+u_u")]) # make sure the surface integral of the difference # between top and bottom is zero from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile(get_flux_operator((fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) assert abs(numpy.dot(res, ones)) < 5e-14
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 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 test_interior_fluxes_tet(): """Check tetrahedron surface integrals computed using interior fluxes against their known values. """ import meshpy.tet as tet from math import pi, sin, cos mesh_info = tet.MeshInfo() # construct a two-box extrusion of this base base = [(-pi, -pi, 0), (pi, -pi, 0), (pi, pi, 0), (-pi, pi, 0)] # first, the nodes mesh_info.set_points(base + [(x, y, z + pi) for x, y, z in base] + [(x, y, z + pi + 1) for x, y, z in base]) # next, the facets # vertex indices for a box missing the -z face box_without_minus_z = [ [4, 5, 6, 7], [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [3, 7, 4, 0], ] def add_to_all_vertex_indices(facets, increment): return [[pt + increment for pt in facet] for facet in facets] mesh_info.set_facets( [[0, 1, 2, 3]] # base + box_without_minus_z # first box + add_to_all_vertex_indices(box_without_minus_z, 4) # second box ) # set the volume properties -- this is where the tet size constraints are mesh_info.regions.resize(2) mesh_info.regions[0] = [ 0, 0, pi / 2, # point in volume -> first box 0, # region tag (user-defined number) 0.5, # max tet volume in region ] mesh_info.regions[1] = [ 0, 0, pi + 0.5, # point in volume -> second box 1, # region tag (user-defined number, arbitrary) 0.1, # max tet volume in region ] generated_mesh = tet.build(mesh_info, attributes=True, volume_constraints=True) from hedge.mesh import make_conformal_mesh mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements) from hedge.discretization.local import TetrahedronDiscretization from hedge.discretization import ones_on_volume discr = discr_class(mesh, TetrahedronDiscretization(4), debug=discr_class.noninteractive_debug_flags()) def f_u(x, el): if generated_mesh.element_attributes[el.id] == 1: return cos(x[0] - x[1] + x[2]) else: return 0 def f_l(x, el): if generated_mesh.element_attributes[el.id] == 0: return sin(x[0] - x[1] + x[2]) else: return 0 u_l = discr.interpolate_volume_function(f_l) u_u = discr.interpolate_volume_function(f_u) u = u_l + u_u # visualize the produced field #from hedge.visualization import SiloVisualizer #vis = SiloVisualizer(discr) #visf = vis.make_file("sandwich") #vis.add_data(visf, #[("u_l", u_l), ("u_u", u_u)], #expressions=[("u", "u_l+u_u")]) # make sure the surface integral of the difference # between top and bottom is zero from hedge.flux import make_normal, FluxScalarPlaceholder from hedge.optemplate import Field, get_flux_operator fluxu = FluxScalarPlaceholder() res = discr.compile( get_flux_operator( (fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u) ones = ones_on_volume(discr) assert abs(numpy.dot(res, ones)) < 5e-14
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, 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 add_inner_fluxes(self, flux, expr): from hedge.optemplate import get_flux_operator self.inner_fluxes = self.inner_fluxes \ + get_flux_operator(self.strong_neg*flux)(expr)
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 test_2d_gauss_theorem(): """Verify Gauss's theorem explicitly on a mesh""" from hedge.mesh.generator import make_disk_mesh from math import sin, cos from numpy import dot mesh = make_disk_mesh() order = 2 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags()) ref_discr = discr_class(mesh, order=order) from hedge.flux import make_normal, FluxScalarPlaceholder normal = make_normal(discr.dimensions) flux_f_ph = FluxScalarPlaceholder(0) one_sided_x = flux_f_ph.int * normal[0] one_sided_y = flux_f_ph.int * normal[1] def f1(x, el): return sin(3 * x[0]) + cos(3 * x[1]) def f2(x, el): return sin(2 * x[0]) + cos(x[1]) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) f1_v = discr.interpolate_volume_function(f1) f2_v = discr.interpolate_volume_function(f2) from hedge.optemplate import BoundaryPair, Field, make_nabla, \ get_flux_operator nabla = make_nabla(discr.dimensions) divergence = nabla[0].apply(discr, f1_v) + nabla[1].apply(discr, f2_v) int_div = discr.integral(divergence) flux_optp = ( get_flux_operator(one_sided_x)(BoundaryPair(Field("f1"), Field("fz"))) + get_flux_operator(one_sided_y)(BoundaryPair(Field("f2"), Field("fz")))) from hedge.mesh import TAG_ALL bdry_val = discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) ref_bdry_val = ref_discr.compile(flux_optp)( f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) boundary_int = dot(bdry_val, ones) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") from hedge.tools import make_obj_array from hedge.mesh import TAG_ALL vis.add_data(visf, [ ("bdry", bdry_val), ("ref_bdry", ref_bdry_val), ("div", divergence), ("f", make_obj_array([f1_v, f2_v])), ("n", discr.volumize_boundary_field(discr.boundary_normals(TAG_ALL), TAG_ALL)), ], expressions=[("bdiff", "bdry-ref_bdry")]) #print abs(boundary_int-int_div) assert abs(boundary_int - int_div) < 5e-15
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_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