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 integral(arg, dd=None): import grudge.symbolic.primitives as prim if dd is None: dd = prim.DD_VOLUME dd = prim.as_dofdesc(dd) return NodalSum(dd)(arg * prim.cse( MassOperator(dd_in=dd)(prim.Ones(dd)), "mass_quad_weights", prim.cse_scope.DISCRETIZATION))
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 grudge.symbolic.primitives import make_common_subexpression as cse from grudge.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 grudge.symbolic import make_normal normal = make_normal(self.outflow_tag, self.dimensions) bc = self.make_bc_info("bc_q_out", self.outflow_tag, state) # see grudge/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 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 grudge.symbolic import RestrictToBoundary result = RestrictToBoundary(tag)(self.sensor()) return cse(to_bdry_quad(result), "bdry_sensor")
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 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 grudge.symbolic import RestrictToBoundary bdrize_op = RestrictToBoundary(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 grad_interior_flux(self, tgt, u): from grudge.symbolic.primitives import make_common_subexpression as cse n_times = tgt.normal_times_flux return n_times(cse(u.avg, "u_avg"))
def minv_all(self): from grudge.symbolic.primitives import make_common_subexpression as cse from grudge.symbolic.operators import InverseMassOperator return ( cse(InverseMassOperator()(self.local_derivatives), "grad_loc") + cse(InverseMassOperator()(self.fluxes), "grad_flux"))
def volq_state(self): return cse(to_vol_quad(self.state()), "vol_quad_state")
def sym_operator(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 grudge.symbolic.primitives import FunctionSymbol sqrt = FunctionSymbol("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 grudge.flux.tools import make_lax_friedrichs_flux from grudge.symbolic.operators import InverseMassOperator from grudge.symbolic.tools import make_stiffness_t primitive_bcs_as_quad_conservative = { tag: self.primitive_to_conservative(to_bdry_quad(bc)) for tag, bc in self.get_primitive_boundary_conditions().items()} 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 faceq_state(self): return cse(to_int_face_quad(self.state()), "face_quad_state")
def cse_u(self, q): return cse(self.u(q), "u")
def cse_rho(self, q): return cse(self.rho(q), "rho")
def cse_temperature(self, q): return cse(self.temperature(q), "temperature")
def cse_p(self, q): return cse(self.p(q), "p")
def cse_rho_u(self, q): return cse(self.rho_u(q), "rho_u")