def map_constant(self, expr): from grudge.tools import is_zero if is_zero(expr): return 0 else: return op.OperatorBinding(op.InverseMassOperator(), self.outer_mass_contractor(expr))
def map_product(self, expr): def is_scalar(expr): return isinstance(expr, (int, float, complex, sym.ScalarParameter)) from pytools import len_iterable nonscalar_count = len_iterable(ch for ch in expr.children if not is_scalar(ch)) if nonscalar_count > 1: # too complicated, don't touch it self.extra_operator_count += 1 return op.InverseMassOperator()(self.outer_mass_contractor(expr)) else: def do_map(expr): if is_scalar(expr): return expr else: return self.rec(expr) return expr.__class__( tuple(do_map(child) for child in expr.children))
def map_operator_binding(self, binding): if isinstance(binding.op, op.MassOperator): return binding.field elif isinstance(binding.op, op.StiffnessOperator): return op.DifferentiationOperator(binding.op.xyz_axis)( self.outer_mass_contractor(binding.field)) elif isinstance(binding.op, op.StiffnessTOperator): return op.MInvSTOperator(binding.op.xyz_axis)( self.outer_mass_contractor(binding.field)) elif isinstance(binding.op, op.FluxOperator): assert not binding.op.is_lift return op.FluxOperator(binding.op.flux, is_lift=True)( self.outer_mass_contractor(binding.field)) elif isinstance(binding.op, op.BoundaryFluxOperator): assert not binding.op.is_lift return op.BoundaryFluxOperator( binding.op.flux, binding.op.boundary_tag, is_lift=True)(self.outer_mass_contractor(binding.field)) else: self.extra_operator_count += 1 return op.InverseMassOperator()( self.outer_mass_contractor(binding))
def map_operator_binding(self, expr): # Global-to-reference is run after operator specialization, so # if we encounter non-quadrature operators here, we know they # must be nodal. dd_in = expr.op.dd_in dd_out = expr.op.dd_out if dd_in.is_volume(): dim = self.dim else: dim = self.dim - 1 jac_in = sym.area_element(self.ambient_dim, dim, dd=dd_in) jac_noquad = sym.area_element(self.ambient_dim, dim, dd=dd_in.with_discr_tag( dof_desc.DISCR_TAG_BASE)) def rewrite_derivative(ref_class, field, dd_in, with_jacobian=True): def imd(rst): return sym.inverse_surface_metric_derivative( rst, expr.op.xyz_axis, ambient_dim=self.ambient_dim, dim=self.dim, dd=dd_in) rec_field = self.rec(field) if with_jacobian: jac_tag = sym.area_element(self.ambient_dim, self.dim, dd=dd_in) rec_field = jac_tag * rec_field return sum( ref_class(rst_axis, dd_in=dd_in)(rec_field * imd(rst_axis)) for rst_axis in range(self.dim)) else: return sum( ref_class(rst_axis, dd_in=dd_in)(rec_field) * imd(rst_axis) for rst_axis in range(self.dim)) if isinstance(expr.op, op.MassOperator): return op.RefMassOperator(dd_in, dd_out)(jac_in * self.rec(expr.field)) elif isinstance(expr.op, op.InverseMassOperator): # based on https://arxiv.org/pdf/1608.03836.pdf return ( 1.0 / jac_in * op.RefInverseMassOperator(dd_in, dd_out)(self.rec(expr.field))) elif isinstance(expr.op, op.FaceMassOperator): jac_in_surf = sym.area_element(self.ambient_dim, self.dim - 1, dd=dd_in) return op.RefFaceMassOperator(dd_in, dd_out)(jac_in_surf * self.rec(expr.field)) elif isinstance(expr.op, op.StiffnessOperator): return op.RefMassOperator(dd_in=dd_in, dd_out=dd_out)( jac_noquad * self.rec(op.DiffOperator(expr.op.xyz_axis)(expr.field))) elif isinstance(expr.op, op.DiffOperator): return rewrite_derivative(op.RefDiffOperator, expr.field, dd_in=dd_in, with_jacobian=False) elif isinstance(expr.op, op.StiffnessTOperator): return rewrite_derivative(op.RefStiffnessTOperator, expr.field, dd_in=dd_in) elif isinstance(expr.op, op.MInvSTOperator): return self.rec(op.InverseMassOperator()(op.StiffnessTOperator( expr.op.xyz_axis)(self.rec(expr.field)))) else: return IdentityMapper.map_operator_binding(self, expr)
def map_algebraic_leaf(self, expr): return op.OperatorBinding(op.InverseMassOperator(), self.outer_mass_contractor(expr))
def map_operator_binding(self, expr): # Global-to-reference is run after operator specialization, so # if we encounter non-quadrature operators here, we know they # must be nodal. if expr.op.dd_in.is_volume(): dim = self.dim else: dim = self.dim - 1 jac_in = sym.area_element(self.ambient_dim, dim, dd=expr.op.dd_in) jac_noquad = sym.area_element(self.ambient_dim, dim, dd=expr.op.dd_in.with_qtag(sym.QTAG_NONE)) def rewrite_derivative(ref_class, field, dd_in, with_jacobian=True): jac_tag = sym.area_element(self.ambient_dim, self.dim, dd=dd_in) rec_field = self.rec(field) if with_jacobian: rec_field = jac_tag * rec_field return sum( sym.inverse_metric_derivative( rst_axis, expr.op.xyz_axis, ambient_dim=self.ambient_dim, dim=self.dim) * ref_class(rst_axis, dd_in=dd_in)(rec_field) for rst_axis in range(self.dim)) if isinstance(expr.op, op.MassOperator): return op.RefMassOperator(expr.op.dd_in, expr.op.dd_out)( jac_in * self.rec(expr.field)) elif isinstance(expr.op, op.InverseMassOperator): return op.RefInverseMassOperator(expr.op.dd_in, expr.op.dd_out)( 1/jac_in * self.rec(expr.field)) elif isinstance(expr.op, op.FaceMassOperator): jac_in_surf = sym.area_element(self.ambient_dim, self.dim - 1, dd=expr.op.dd_in) return op.RefFaceMassOperator(expr.op.dd_in, expr.op.dd_out)( jac_in_surf * self.rec(expr.field)) elif isinstance(expr.op, op.StiffnessOperator): return op.RefMassOperator()( jac_noquad * self.rec( op.DiffOperator(expr.op.xyz_axis)(expr.field))) elif isinstance(expr.op, op.DiffOperator): return rewrite_derivative( op.RefDiffOperator, expr.field, dd_in=expr.op.dd_in, with_jacobian=False) elif isinstance(expr.op, op.StiffnessTOperator): return rewrite_derivative( op.RefStiffnessTOperator, expr.field, dd_in=expr.op.dd_in) elif isinstance(expr.op, op.MInvSTOperator): return self.rec( op.InverseMassOperator()( op.StiffnessTOperator(expr.op.xyz_axis)( self.rec(expr.field)))) else: return IdentityMapper.map_operator_binding(self, expr)