def op_template_struct(self, u=None): from hedge.optemplate import Field if u is None: u = Field("u") result = DecayFitDiscontinuitySensorBase\ .op_template_struct(self, u) from pymbolic.primitives import IfPositive from hedge.optemplate.primitives import ( CFunction, ScalarParameter) from math import pi from hedge.optemplate.primitives import make_common_subexpression as cse if self.correct_for_fit_error: decay_expt = cse(result.decay_expt_corrected, "decay_expt") else: decay_expt = cse(result.decay_expt, "decay_expt") def flat_end_sin(x): return IfPositive(-pi/2-x, -1, IfPositive(x-pi/2, 1, sin(x))) sin = CFunction("sin") isnan = CFunction("isnan") c_abs = CFunction("abs") visc_scale = Field("viscosity_scaling") result.sensor = IfPositive(c_abs(isnan(visc_scale)), ScalarParameter("max_viscosity_scaling"), 0.5*visc_scale * (1+flat_end_sin((decay_expt+2)*pi/2))) return result
def get_mu(self, q, to_quad_op): """ :param to_quad_op: If not *None*, represents an operator which transforms nodal values onto a quadrature grid on which the returned :math:`\mu` needs to be represented. In that case, *q* is assumed to already be on the same quadrature grid. """ if to_quad_op is None: def to_quad_op(x): return x if self.mu == "sutherland": # Sutherland's law: !!!not tested!!! t_s = 110.4 mu_inf = 1.735e-5 result = cse( mu_inf * self.cse_temperature(q)**1.5 * (1 + t_s) / (self.cse_temperature(q) + t_s), "sutherland_mu") else: result = self.mu if self.artificial_viscosity_mode == "cns": mapped_sensor = self.sensor() else: mapped_sensor = None if mapped_sensor is not None: result = result + cse(to_quad_op(mapped_sensor), "quad_sensor") return cse(result, "mu")
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 get_mu(self, q, to_quad_op): """ :param to_quad_op: If not *None*, represents an operator which transforms nodal values onto a quadrature grid on which the returned :math:`\mu` needs to be represented. In that case, *q* is assumed to already be on the same quadrature grid. """ if to_quad_op is None: def to_quad_op(x): return x if self.mu == "sutherland": # Sutherland's law: !!!not tested!!! t_s = 110.4 mu_inf = 1.735e-5 result = cse( mu_inf * self.cse_temperature(q) ** 1.5 * (1 + t_s) / (self.cse_temperature(q) + t_s), "sutherland_mu") else: result = self.mu if self.artificial_viscosity_mode == "cns": mapped_sensor = self.sensor() else: mapped_sensor = None if mapped_sensor is not None: result = result + cse(to_quad_op(mapped_sensor), "quad_sensor") return cse(result, "mu")
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 collision_update(self, f_bar): from hedge.optemplate.primitives import make_common_subexpression as cse rho = cse(self.rho(f_bar), "rho") rho_u = self.rho_u(f_bar) u = cse(rho_u / rho, "u") f_eq_func = self.method.f_equilibrium f_eq = make_obj_array( [f_eq_func(rho, alpha, u) for alpha in range(len(self.method))]) return f_bar - 1 / (self.tau + 1 / 2) * (f_bar - f_eq)
def collision_update(self, f_bar): from hedge.optemplate.primitives import make_common_subexpression as cse rho = cse(self.rho(f_bar), "rho") rho_u = self.rho_u(f_bar) u = cse(rho_u/rho, "u") f_eq_func = self.method.f_equilibrium f_eq = make_obj_array([ f_eq_func(rho, alpha, u) for alpha in range(len(self.method))]) return f_bar - 1/(self.tau+1/2)*(f_bar - f_eq)
def characteristic_velocity_optemplate(self, state): from hedge.optemplate.operators import ElementwiseMaxOperator from hedge.optemplate.primitives import CFunction sqrt = CFunction("sqrt") sound_speed = cse( sqrt(self.equation_of_state.gamma * self.cse_p(state) / self.cse_rho(state)), "sound_speed") u = self.cse_u(state) speed = cse(sqrt(numpy.dot(u, u)), "norm_u") + sound_speed return ElementwiseMaxOperator()(speed)
def characteristic_velocity_optemplate(self, state): from hedge.optemplate.operators import ElementwiseMaxOperator from hedge.optemplate.primitives import CFunction sqrt = CFunction("sqrt") sound_speed = cse(sqrt( self.equation_of_state.gamma*self.cse_p(state)/self.cse_rho(state)), "sound_speed") u = self.cse_u(state) speed = cse(sqrt(numpy.dot(u, u)), "norm_u") + sound_speed return ElementwiseMaxOperator()(speed)
def inflow_state_inner(self, normal, bc, name): # see hedge/doc/maxima/euler.mac return join_fields( # bc rho cse(bc.rho0 + numpy.dot(normal, bc.dumvec)*bc.rho0/(2*bc.c0) + bc.dpm/(2*bc.c0*bc.c0), "bc_rho_"+name), # bc p cse(bc.p0 + bc.c0*bc.rho0*numpy.dot(normal, bc.dumvec)/2 + bc.dpm/2, "bc_p_"+name), # bc u cse(bc.u0 + normal*numpy.dot(normal, bc.dumvec)/2 + bc.dpm*normal/(2*bc.c0*bc.rho0), "bc_u_"+name))
def primitive_to_conservative(self, prims, use_cses=True): if not use_cses: from hedge.optemplate.primitives import make_common_subexpression as cse else: def cse(x, name): return x rho = prims[0] p = prims[1] u = prims[2:] e = self.equation_of_state.p_to_e(p, rho, u) return join_fields(rho, cse(e, "e"), cse(rho * u, "rho_u"))
def primitive_to_conservative(self, prims, use_cses=True): if not use_cses: from hedge.optemplate.primitives import make_common_subexpression as cse else: def cse(x, name): return x rho = prims[0] p = prims[1] u = prims[2:] e = self.equation_of_state.p_to_e(p, rho, u) return join_fields( rho, cse(e, "e"), cse(rho * u, "rho_u"))
def ic_expr(t, x, fields): from hedge.optemplate import CFunction from pymbolic.primitives import IfPositive from pytools.obj_array import make_obj_array tanh = CFunction("tanh") sin = CFunction("sin") rho = 1 u0 = 0.05 w = 0.05 delta = 0.05 from hedge.optemplate.primitives import make_common_subexpression as cse u = cse( make_obj_array([ IfPositive(x[1] - 1 / 2, u0 * tanh(4 * (3 / 4 - x[1]) / w), u0 * tanh(4 * (x[1] - 1 / 4) / w)), u0 * delta * sin(2 * np.pi * (x[0] + 1 / 4)) ]), "u") return make_obj_array([ op.method.f_equilibrium(rho, alpha, u) for alpha in range(len(op.method)) ])
def ic_expr(t, x, fields): from hedge.optemplate import CFunction from pymbolic.primitives import IfPositive from pytools.obj_array import make_obj_array tanh = CFunction("tanh") sin = CFunction("sin") rho = 1 u0 = 0.05 w = 0.05 delta = 0.05 from hedge.optemplate.primitives import make_common_subexpression as cse u = cse(make_obj_array([ IfPositive(x[1]-1/2, u0*tanh(4*(3/4-x[1])/w), u0*tanh(4*(x[1]-1/4)/w)), u0*delta*sin(2*np.pi*(x[0]+1/4))]), "u") return make_obj_array([ op.method.f_equilibrium(rho, alpha, u) for alpha in range(len(op.method)) ])
def grad_interior_flux(self, tgt, u): from hedge.optemplate.primitives import make_common_subexpression as cse n_times = tgt.normal_times_flux v_times = tgt.vec_times return n_times( cse(u.avg, "u_avg") - v_times(self.beta(tgt), n_times(u.int-u.ext)))
def inflow_state_inner(self, normal, bc, name): # see hedge/doc/maxima/euler.mac return join_fields( # bc rho cse( bc.rho0 + numpy.dot(normal, bc.dumvec) * bc.rho0 / (2 * bc.c0) + bc.dpm / (2 * bc.c0 * bc.c0), "bc_rho_" + name), # bc p cse( bc.p0 + bc.c0 * bc.rho0 * numpy.dot(normal, bc.dumvec) / 2 + bc.dpm / 2, "bc_p_" + name), # bc u cse( bc.u0 + normal * numpy.dot(normal, bc.dumvec) / 2 + bc.dpm * normal / (2 * bc.c0 * bc.rho0), "bc_u_" + name))
def grad_interior_flux(self, tgt, u): from hedge.optemplate.primitives import make_common_subexpression as cse n_times = tgt.normal_times_flux v_times = tgt.vec_times return n_times( cse(u.avg, "u_avg") - v_times(self.beta(tgt), n_times(u.int - u.ext)))
def make_bc_info(self, bc_name, tag, state, state0=None): """ :param state0: The boundary 'free-stream' state around which the BC is linearized. """ if state0 is None: state0 = make_sym_vector(bc_name, self.dimensions+2) state0 = cse(to_bdry_quad(state0)) rho0 = self.rho(state0) p0 = self.cse_p(state0) u0 = self.cse_u(state0) c0 = (self.equation_of_state.gamma * p0 / rho0)**0.5 from hedge.optemplate import BoundarizeOperator bdrize_op = BoundarizeOperator(tag) class SingleBCInfo(Record): pass return SingleBCInfo( rho0=rho0, p0=p0, u0=u0, c0=c0, # notation: suffix "m" for "minus", i.e. "interior" drhom=cse(self.rho(cse(to_bdry_quad(bdrize_op(state)))) - rho0, "drhom"), dumvec=cse(self.cse_u(cse(to_bdry_quad(bdrize_op(state)))) - u0, "dumvec"), dpm=cse(self.cse_p(cse(to_bdry_quad(bdrize_op(state)))) - p0, "dpm"))
def flux(self, q): from pytools import delta return [ # one entry for each flux direction cse(join_fields( # flux rho self.rho_u(q)[i], # flux E cse(self.e(q)+self.cse_p(q))*self.cse_u(q)[i], # flux rho_u make_obj_array([ self.rho_u(q)[i]*self.cse_u(q)[j] + delta(i,j) * self.cse_p(q) for j in range(self.dimensions) ]) ), "%s_flux" % AXES[i]) for i in range(self.dimensions)]
def div(self, tgt, bc_getter, dirichlet_tags, neumann_tags): """ :param bc_getter: a function (tag, volume_expr) -> boundary expr. *volume_expr* will be None to query the Neumann condition. """ from hedge.optemplate.primitives import make_common_subexpression as cse from hedge.flux import FluxVectorPlaceholder, PenaltyTerm n_times = tgt.normal_times_flux if tgt.strong_form: def adjust_flux(f): return n_times(flux_v.int) - f else: def adjust_flux(f): return f dim = tgt.dimensions flux_w = FluxVectorPlaceholder(2 * tgt.dimensions) flux_v = flux_w[:dim] pure_diff_v = flux_w[dim:] flux_args = (list(tgt.int_flux_operand) + list(IPDGDerivativeGenerator()(tgt.int_flux_operand))) stab_term_generator = StabilizationTermGenerator(flux_args) stab_term = (self.stab_coefficient * PenaltyTerm() * stab_term_generator(tgt.int_flux_operand)) flux = n_times(pure_diff_v.avg - stab_term) from pytools.obj_array import make_obj_array flux_arg_int = cse(make_obj_array(stab_term_generator.flux_args)) tgt.add_derivative(cse(tgt.operand)) tgt.add_inner_fluxes(adjust_flux(flux), flux_arg_int) self.add_div_bcs(tgt, bc_getter, dirichlet_tags, neumann_tags, stab_term, adjust_flux, flux_v, flux_arg_int, 2 * tgt.dimensions)
def outflow_state(self, state): from hedge.optemplate import make_normal normal = make_normal(self.outflow_tag, self.dimensions) bc = self.make_bc_info("bc_q_out", self.outflow_tag, state) # see hedge/doc/maxima/euler.mac return join_fields( # bc rho cse(bc.rho0 + bc.drhom + numpy.dot(normal, bc.dumvec)*bc.rho0/(2*bc.c0) - bc.dpm/(2*bc.c0*bc.c0), "bc_rho_outflow"), # bc p cse(bc.p0 + bc.c0*bc.rho0*numpy.dot(normal, bc.dumvec)/2 + bc.dpm/2, "bc_p_outflow"), # bc u cse(bc.u0 + bc.dumvec - normal*numpy.dot(normal, bc.dumvec)/2 + bc.dpm*normal/(2*bc.c0*bc.rho0), "bc_u_outflow"))
def flux(self, q): from pytools import delta return [ # one entry for each flux direction cse( join_fields( # flux rho self.rho_u(q)[i], # flux E cse(self.e(q) + self.cse_p(q)) * self.cse_u(q)[i], # flux rho_u make_obj_array([ self.rho_u(q)[i] * self.cse_u(q)[j] + delta(i, j) * self.cse_p(q) for j in range(self.dimensions) ])), "%s_flux" % AXES[i]) for i in range(self.dimensions) ]
def subst_func(expr): from pymbolic.primitives import Subscript, Variable if isinstance(expr, Subscript): assert (isinstance(expr.aggregate, Variable) and expr.aggregate.name == "q") return cbstate[expr.index] elif isinstance(expr, Variable) and expr.name == "sensor": from hedge.optemplate import BoundarizeOperator result = BoundarizeOperator(tag)(self.sensor()) return cse(to_bdry_quad(result), "bdry_sensor")
def subst_func(expr): from pymbolic.primitives import Subscript, Variable if isinstance(expr, Subscript): assert (isinstance(expr.aggregate, Variable) and expr.aggregate.name == "q") return cbstate[expr.index] elif isinstance(expr, Variable) and expr.name =="sensor": from hedge.optemplate import BoundarizeOperator result = BoundarizeOperator(tag)(self.sensor()) return cse(to_bdry_quad(result), "bdry_sensor")
def outflow_state(self, state): from hedge.optemplate import make_normal normal = make_normal(self.outflow_tag, self.dimensions) bc = self.make_bc_info("bc_q_out", self.outflow_tag, state) # see hedge/doc/maxima/euler.mac return join_fields( # bc rho cse( bc.rho0 + bc.drhom + numpy.dot(normal, bc.dumvec) * bc.rho0 / (2 * bc.c0) - bc.dpm / (2 * bc.c0 * bc.c0), "bc_rho_outflow"), # bc p cse( bc.p0 + bc.c0 * bc.rho0 * numpy.dot(normal, bc.dumvec) / 2 + bc.dpm / 2, "bc_p_outflow"), # bc u cse( bc.u0 + bc.dumvec - normal * numpy.dot(normal, bc.dumvec) / 2 + bc.dpm * normal / (2 * bc.c0 * bc.rho0), "bc_u_outflow"))
def tau(self, to_quad_op, state, mu=None): faceq_state = self.faceq_state() dimensions = self.dimensions # {{{ compute gradient of u --------------------------------------- # Use the product rule to compute the gradient of # u from the gradient of (rho u). This ensures we don't # compute the derivatives twice. from pytools.obj_array import with_object_array_or_scalar dq = with_object_array_or_scalar(to_quad_op, self.grad_of_state()) q = cse(to_quad_op(state)) du = numpy.zeros((dimensions, dimensions), dtype=object) for i in range(dimensions): for j in range(dimensions): du[i, j] = cse( (dq[i + 2, j] - self.cse_u(q)[i] * dq[0, j]) / self.rho(q), "du%d_d%s" % (i, AXES[j])) # }}} # {{{ put together viscous stress tau ----------------------------- from pytools import delta if mu is None: mu = self.get_mu(q, to_quad_op) tau = numpy.zeros((dimensions, dimensions), dtype=object) for i in range(dimensions): for j in range(dimensions): tau[i, j] = cse( mu * cse(du[i, j] + du[j, i] - 2 / self.dimensions * delta(i, j) * numpy.trace(du)), "tau_%d%d" % (i, j)) return tau
def div(self, tgt, bc_getter, dirichlet_tags, neumann_tags): """ :param bc_getter: a function (tag, volume_expr) -> boundary expr. *volume_expr* will be None to query the Neumann condition. """ from hedge.optemplate.primitives import make_common_subexpression as cse from hedge.flux import FluxVectorPlaceholder, PenaltyTerm n_times = tgt.normal_times_flux if tgt.strong_form: def adjust_flux(f): return n_times(flux_v.int) - f else: def adjust_flux(f): return f dim = tgt.dimensions flux_w = FluxVectorPlaceholder(2*tgt.dimensions) flux_v = flux_w[:dim] pure_diff_v = flux_w[dim:] flux_args = ( list(tgt.int_flux_operand) + list(IPDGDerivativeGenerator()(tgt.int_flux_operand))) stab_term_generator = StabilizationTermGenerator(flux_args) stab_term = (self.stab_coefficient * PenaltyTerm() * stab_term_generator(tgt.int_flux_operand)) flux = n_times(pure_diff_v.avg - stab_term) from pytools.obj_array import make_obj_array flux_arg_int = cse(make_obj_array(stab_term_generator.flux_args)) tgt.add_derivative(cse(tgt.operand)) tgt.add_inner_fluxes(adjust_flux(flux), flux_arg_int) self.add_div_bcs(tgt, bc_getter, dirichlet_tags, neumann_tags, stab_term, adjust_flux, flux_v, flux_arg_int, 2*tgt.dimensions)
def tau(self, to_quad_op, state, mu=None): faceq_state = self.faceq_state() dimensions = self.dimensions # {{{ compute gradient of u --------------------------------------- # Use the product rule to compute the gradient of # u from the gradient of (rho u). This ensures we don't # compute the derivatives twice. from pytools.obj_array import with_object_array_or_scalar dq = with_object_array_or_scalar( to_quad_op, self.grad_of_state()) q = cse(to_quad_op(state)) du = numpy.zeros((dimensions, dimensions), dtype=object) for i in range(dimensions): for j in range(dimensions): du[i,j] = cse( (dq[i+2,j] - self.cse_u(q)[i] * dq[0,j]) / self.rho(q), "du%d_d%s" % (i, AXES[j])) # }}} # {{{ put together viscous stress tau ----------------------------- from pytools import delta if mu is None: mu = self.get_mu(q, to_quad_op) tau = numpy.zeros((dimensions, dimensions), dtype=object) for i in range(dimensions): for j in range(dimensions): tau[i,j] = cse(mu * cse(du[i,j] + du[j,i] - 2/self.dimensions * delta(i,j) * numpy.trace(du)), "tau_%d%d" % (i, j)) return tau
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 op_template(self, u=None): from pymbolic.primitives import IfPositive, Variable from hedge.optemplate.primitives import Field, ScalarParameter from hedge.optemplate.primitives import make_common_subexpression as cse from math import pi if u is None: u = Field("u") from hedge.optemplate.operators import ( MassOperator, FilterOperator, OnesOperator) mode_truncator = FilterOperator( persson_peraire_filter_response_function) truncated_u = mode_truncator(u) diff = u - truncated_u el_norm_squared_mass_diff_u = OnesOperator()(MassOperator()(diff)*diff) el_norm_squared_mass_u = OnesOperator()(MassOperator()(u)*u) capital_s_e = cse(el_norm_squared_mass_diff_u / el_norm_squared_mass_u, "S_e") sin = Variable("sin") log10 = Variable("log10") s_e = cse(log10(capital_s_e), "s_e") kappa = ScalarParameter("kappa") eps0 = ScalarParameter("eps0") s_0 = ScalarParameter("s_0") return IfPositive(s_0-self.kappa-s_e, 0, IfPositive(s_e-self.kappa-s_0, eps0, eps0/2*(1+sin(pi*(s_e-s_0)/self.kappa))))
def test_quadrature_tri_mass_mat_monomial(): """Check that quadrature integration on triangles is exact as designed.""" from hedge.mesh.generator import make_square_mesh mesh = make_square_mesh(a=-1, b=1, max_area=4 * 1 / 8 + 0.001) order = 4 discr = discr_class( mesh, order=order, debug=discr_class.noninteractive_debug_flags(), quad_min_degrees={"quad": 3 * order} ) m, n = 2, 1 f = Monomial((m, n)) f_vec = discr.interpolate_volume_function(lambda x, el: f(x)) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") vis.add_data(visf, [("f", f_vec * f_vec)]) visf.close() from hedge.optemplate import MassOperator, Field, QuadratureGridUpsampler f_fld = Field("f") mass_op = discr.compile(MassOperator()(f_fld * f_fld)) from hedge.optemplate.primitives import make_common_subexpression as cse f_upsamp = cse(QuadratureGridUpsampler("quad")(f_fld)) quad_mass_op = discr.compile(MassOperator()(f_upsamp * f_upsamp)) num_integral_1 = numpy.dot(ones, mass_op(f=f_vec)) num_integral_2 = numpy.dot(ones, quad_mass_op(f=f_vec)) true_integral = 4 / ((2 * m + 1) * (2 * n + 1)) err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) print num_integral_1, num_integral_2, true_integral print err_1, err_2 assert err_1 > 1e-8 assert err_2 < 1e-14
def test_quadrature_tri_mass_mat_monomial(): """Check that quadrature integration on triangles is exact as designed.""" from hedge.mesh.generator import make_square_mesh mesh = make_square_mesh(a=-1, b=1, max_area=4 * 1 / 8 + 0.001) order = 4 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags(), quad_min_degrees={"quad": 3 * order}) m, n = 2, 1 f = Monomial((m, n)) f_vec = discr.interpolate_volume_function(lambda x, el: f(x)) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") vis.add_data(visf, [("f", f_vec * f_vec)]) visf.close() from hedge.optemplate import (MassOperator, Field, QuadratureGridUpsampler) f_fld = Field("f") mass_op = discr.compile(MassOperator()(f_fld * f_fld)) from hedge.optemplate.primitives import make_common_subexpression as cse f_upsamp = cse(QuadratureGridUpsampler("quad")(f_fld)) quad_mass_op = discr.compile(MassOperator()(f_upsamp * f_upsamp)) num_integral_1 = numpy.dot(ones, mass_op(f=f_vec)) num_integral_2 = numpy.dot(ones, quad_mass_op(f=f_vec)) true_integral = 4 / ((2 * m + 1) * (2 * n + 1)) err_1 = abs(num_integral_1 - true_integral) err_2 = abs(num_integral_2 - true_integral) print num_integral_1, num_integral_2, true_integral print err_1, err_2 assert err_1 > 1e-8 assert err_2 < 1e-14
def incident_bc(self, w=None): "Flux terms for incident boundary conditions" # NOTE: Untested for inhomogeneous materials, but would usually be # physically meaningless anyway (are there exceptions to this?) e, h = self.split_eh(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous" " background material, results may be unphysical") from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from hedge.tools import is_zero incident_bc_data = self.incident_bc_data(self, e, h) if is_zero(incident_bc_data): return make_obj_array([0] * fld_cnt) else: return cse(-incident_bc_data)
def incident_bc(self, w=None): "Flux terms for incident boundary conditions" # NOTE: Untested for inhomogeneous materials, but would usually be # physically meaningless anyway (are there exceptions to this?) e, h = self.split_eh(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous" " background material, results may be unphysical") from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from hedge.tools import is_zero incident_bc_data = self.incident_bc_data(self, e, h) if is_zero(incident_bc_data): return make_obj_array([0]*fld_cnt) else: return cse(-incident_bc_data)
def make_bc_info(self, bc_name, tag, state, state0=None): """ :param state0: The boundary 'free-stream' state around which the BC is linearized. """ if state0 is None: state0 = make_sym_vector(bc_name, self.dimensions + 2) state0 = cse(to_bdry_quad(state0)) rho0 = self.rho(state0) p0 = self.cse_p(state0) u0 = self.cse_u(state0) c0 = (self.equation_of_state.gamma * p0 / rho0)**0.5 from hedge.optemplate import BoundarizeOperator bdrize_op = BoundarizeOperator(tag) class SingleBCInfo(Record): pass return SingleBCInfo( rho0=rho0, p0=p0, u0=u0, c0=c0, # notation: suffix "m" for "minus", i.e. "interior" drhom=cse( self.rho(cse(to_bdry_quad(bdrize_op(state)))) - rho0, "drhom"), dumvec=cse( self.cse_u(cse(to_bdry_quad(bdrize_op(state)))) - u0, "dumvec"), dpm=cse( self.cse_p(cse(to_bdry_quad(bdrize_op(state)))) - p0, "dpm"))
def grad_of_state_func(self, func, of_what_descr): return cse( self.grad_of(func(self.volq_state()), func(self.faceq_state())), "grad_" + of_what_descr)
def op_template(self, sensor_scaling=None, viscosity_only=False): u = self.cse_u rho = self.cse_rho rho_u = self.rho_u p = self.p e = self.e # {{{ artificial diffusion def make_artificial_diffusion(): if self.artificial_viscosity_mode not in ["diffusion"]: return 0 dq = self.grad_of_state() return make_obj_array([ self.div( to_vol_quad(self.sensor()) * to_vol_quad(dq[i]), to_int_face_quad(self.sensor()) * to_int_face_quad(dq[i])) for i in range(dq.shape[0]) ]) # }}} # {{{ state setup volq_flux = self.flux(self.volq_state()) faceq_flux = self.flux(self.faceq_state()) from hedge.optemplate.primitives import CFunction sqrt = CFunction("sqrt") speed = self.characteristic_velocity_optemplate(self.state()) has_viscosity = not is_zero(self.get_mu(self.state(), to_quad_op=None)) # }}} # {{{ operator assembly ----------------------------------------------- from hedge.flux.tools import make_lax_friedrichs_flux from hedge.optemplate.operators import InverseMassOperator from hedge.optemplate.tools import make_stiffness_t primitive_bcs_as_quad_conservative = dict( (tag, self.primitive_to_conservative(to_bdry_quad(bc))) for tag, bc in self.get_primitive_boundary_conditions().iteritems()) def get_bc_tuple(tag): state = self.state() bc = make_obj_array( [self.get_boundary_condition_for(tag, s_i) for s_i in state]) return tag, bc, self.flux(bc) first_order_part = InverseMassOperator()( numpy.dot(make_stiffness_t(self.dimensions), volq_flux) - make_lax_friedrichs_flux( wave_speed=cse(to_int_face_quad(speed), "emax_c"), state=self.faceq_state(), fluxes=faceq_flux, bdry_tags_states_and_fluxes=[ get_bc_tuple(tag) for tag in self.get_boundary_tags() ], strong=False)) if viscosity_only: first_order_part = 0 * first_order_part result = join_fields( first_order_part + self.make_second_order_part() + make_artificial_diffusion() + self.make_extra_terms(), speed) if self.source is not None: result = result + join_fields( make_sym_vector("source_vect", len(self.state())), # extra field for speed 0) return result
def __init__(self, **kwargs): from hedge.optemplate.primitives import make_common_subexpression as cse Record.__init__(self, dict((name, cse(expr, name)) for name, expr in kwargs.iteritems()))
def grad_of_state_func(self, func, of_what_descr): return cse(self.grad_of( func(self.volq_state()), func(self.faceq_state())), "grad_"+of_what_descr)
def faceq_state(self): return cse(to_int_face_quad(self.state()), "face_quad_state")
def op_template(self, sensor_scaling=None, viscosity_only=False): u = self.cse_u rho = self.cse_rho rho_u = self.rho_u p = self.p e = self.e # {{{ artificial diffusion def make_artificial_diffusion(): if self.artificial_viscosity_mode not in ["diffusion"]: return 0 dq = self.grad_of_state() return make_obj_array([ self.div( to_vol_quad(self.sensor())*to_vol_quad(dq[i]), to_int_face_quad(self.sensor())*to_int_face_quad(dq[i])) for i in range(dq.shape[0])]) # }}} # {{{ state setup volq_flux = self.flux(self.volq_state()) faceq_flux = self.flux(self.faceq_state()) from hedge.optemplate.primitives import CFunction sqrt = CFunction("sqrt") speed = self.characteristic_velocity_optemplate(self.state()) has_viscosity = not is_zero(self.get_mu(self.state(), to_quad_op=None)) # }}} # {{{ operator assembly ----------------------------------------------- from hedge.flux.tools import make_lax_friedrichs_flux from hedge.optemplate.operators import InverseMassOperator from hedge.optemplate.tools import make_stiffness_t primitive_bcs_as_quad_conservative = dict( (tag, self.primitive_to_conservative(to_bdry_quad(bc))) for tag, bc in self.get_primitive_boundary_conditions().iteritems()) def get_bc_tuple(tag): state = self.state() bc = make_obj_array([ self.get_boundary_condition_for(tag, s_i) for s_i in state]) return tag, bc, self.flux(bc) first_order_part = InverseMassOperator()( numpy.dot(make_stiffness_t(self.dimensions), volq_flux) - make_lax_friedrichs_flux( wave_speed=cse(to_int_face_quad(speed), "emax_c"), state=self.faceq_state(), fluxes=faceq_flux, bdry_tags_states_and_fluxes=[ get_bc_tuple(tag) for tag in self.get_boundary_tags()], strong=False)) if viscosity_only: first_order_part = 0*first_order_part result = join_fields( first_order_part + self.make_second_order_part() + make_artificial_diffusion() + self.make_extra_terms(), speed) if self.source is not None: result = result + join_fields( make_sym_vector("source_vect", len(self.state())), # extra field for speed 0) return result
def cse_rho_u(self, q): return cse(self.rho_u(q), "rho_u")
def cse_p(self, q): return cse(self.p(q), "p")
def cse_rho(self, q): return cse(self.rho(q), "rho")
def cse_u(self, q): return cse(self.u(q), "u")
def cse_temperature(self, q): return cse(self.temperature(q), "temperature")
def minv_all(self): from hedge.optemplate.primitives import make_common_subexpression as cse from hedge.optemplate.operators import InverseMassOperator return ( cse(InverseMassOperator()(self.local_derivatives), "grad_loc") + cse(InverseMassOperator()(self.fluxes), "grad_flux"))
def op_template_struct(self, u, with_baseline=True): from hedge.optemplate.operators import ( MassOperator, OnesOperator, InverseVandermondeOperator, InverseMassOperator) from hedge.optemplate.primitives import Field from hedge.optemplate.tools import get_flux_operator from hedge.optemplate.primitives import make_common_subexpression as cse from hedge.optemplate.primitives import CFunction from pymbolic.primitives import Variable if u is None: u = Field("u") from hedge.flux import ( FluxScalarPlaceholder, ElementOrder, ElementJacobian, FaceJacobian, flux_abs) log, exp, sqrt = CFunction("log"), CFunction("exp"), CFunction("sqrt") if False: # On the whole, this should scale like u. # Columns of lift scale like 1/N^2, compensate for that. # Further compensate for all geometric factors. u_flux = FluxScalarPlaceholder(0) jump_part = InverseMassOperator()( get_flux_operator( ElementJacobian()/(ElementOrder()**2 * FaceJacobian()) *flux_abs(u_flux.ext - u_flux.int))(u)) baseline_squared = Field("baseline_squared") el_norm_u_squared = cse( OnesOperator()(MassOperator()(u)*u), "l2_norm_u") indicator_modal_coeffs = cse( InverseVandermondeOperator()(u), #InverseChebyshevVandermondeOperator()(u), "u_modes") indicator_modal_coeffs_squared = indicator_modal_coeffs**2 if self.mode_processor is not None: indicator_modal_coeffs_squared = \ Variable("mode_processor")(indicator_modal_coeffs_squared) log_modal_coeffs = cse( log(indicator_modal_coeffs_squared + baseline_squared*el_norm_u_squared )/2, "log_modal_coeffs") if False: modal_coeffs_jump = cse( InverseVandermondeOperator()(jump_part), "jump_modes") log_modal_coeffs_jump = cse( log(modal_coeffs_jump**2)/2, "lmc_jump") # fit to c * n**s expt_op = DecayExponentOperator( self.ignored_modes, self.weight_mode) log_const_op = LogDecayConstantOperator( self.ignored_modes, self.weight_mode) mode_weights = Field("mode_weights") weighted_log_modal_coeffs = mode_weights*log_modal_coeffs s = cse(expt_op(weighted_log_modal_coeffs), "first_decay_expt") log_c = cse(log_const_op(weighted_log_modal_coeffs), "first_decay_coeff") c = exp(log_const_op(weighted_log_modal_coeffs)) log_mode_numbers = Field("log_mode_numbers") estimated_log_modal_coeffs = cse( log_c + s*log_mode_numbers, "estimated_log_modal_coeffs") estimate_error = cse( sqrt((estimated_log_modal_coeffs-weighted_log_modal_coeffs)**2), "estimate_error") log_modal_coeffs_corrected = log_modal_coeffs + estimate_error s_corrected = expt_op(mode_weights*log_modal_coeffs_corrected) return DecayInformation( indicator_modal_coeffs=indicator_modal_coeffs, decay_expt=s, c=c, log_modal_coeffs=log_modal_coeffs, weighted_log_modal_coeffs=weighted_log_modal_coeffs, estimated_log_modal_coeffs=estimated_log_modal_coeffs, decay_expt_corrected=s_corrected, )
def volq_state(self): return cse(to_vol_quad(self.state()), "vol_quad_state")
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 grad_interior_flux(self, tgt, u): from hedge.optemplate.primitives import make_common_subexpression as cse n_times = tgt.normal_times_flux return n_times(cse(u.avg, "u_avg"))
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