diff --git a/grudge/op.py b/grudge/op.py index 4e80ed46740a42fbcf7ed30ced9d35d1846c63f2..2cd529c94ce99947b94a5874dd1a3f2bc85bde2b 100644 --- a/grudge/op.py +++ b/grudge/op.py @@ -54,7 +54,7 @@ from numbers import Number from pytools import ( memoize_in, memoize_on_first_arg, - # keyed_memoize_in + keyed_memoize_in ) from pytools.obj_array import obj_array_vectorize from meshmode.array_context import ( @@ -66,9 +66,10 @@ import numpy as np import grudge.dof_desc as dof_desc from meshmode.mesh import BTAG_ALL, BTAG_NONE, BTAG_PARTITION # noqa -from meshmode.dof_array import freeze, flatten, unflatten +from meshmode.dof_array import flatten, unflatten from grudge.symbolic.primitives import TracePair +from grudge import sym, bind # {{{ tags @@ -118,6 +119,7 @@ def project(dcoll, src, tgt, vec): # }}} + # {{{ geometric properties def nodes(dcoll, dd=None): @@ -159,9 +161,9 @@ def normal(dcoll, dd): # {{{ Derivative operators def reference_derivative_matrices(actx, element_group): - # @keyed_memoize_in( - # actx, reference_derivative_matrices, - # lambda grp: grp.discretization_key()) + @keyed_memoize_in( + actx, reference_derivative_matrices, + lambda grp: grp.discretization_key()) def get_ref_derivative_mats(grp): from meshmode.discretization.poly_element import diff_matrices return tuple( @@ -271,10 +273,10 @@ def local_div(dcoll, vecs): def reference_stiffness_transpose_matrix(actx, out_element_group, in_element_group): # FIXME: Think about how to compose this better with existing functions - # @keyed_memoize_in( - # actx, reference_stiffness_transpose_matrix, - # lambda out_grp, in_grp: (out_grp.discretization_key(), - # in_grp.discretization_key())) + @keyed_memoize_in( + actx, reference_stiffness_transpose_matrix, + lambda out_grp, in_grp: (out_grp.discretization_key(), + in_grp.discretization_key())) def get_ref_stiffness_transpose_mat(out_grp, in_grp): if in_grp == out_grp: mmat = reference_mass_matrix(actx, out_grp, in_grp) @@ -438,10 +440,10 @@ def weak_local_div(dcoll, *args): # {{{ Mass operator def reference_mass_matrix(actx, out_element_group, in_element_group): - # @keyed_memoize_in( - # actx, reference_mass_matrix, - # lambda out_grp, in_grp: (out_grp.discretization_key(), - # in_grp.discretization_key())) + @keyed_memoize_in( + actx, reference_mass_matrix, + lambda out_grp, in_grp: (out_grp.discretization_key(), + in_grp.discretization_key())) def get_ref_mass_mat(out_grp, in_grp): if out_grp == in_grp: from meshmode.discretization.poly_element import mass_matrix @@ -525,9 +527,9 @@ def mass(dcoll, *args): # {{{ Mass inverse operator def reference_inverse_mass_matrix(actx, element_group): - # @keyed_memoize_in( - # actx, reference_inverse_mass_matrix, - # lambda grp: grp.discretization_key()) + @keyed_memoize_in( + actx, reference_inverse_mass_matrix, + lambda grp: grp.discretization_key()) def get_ref_inv_mass_mat(grp): from modepy import inverse_mass_matrix basis = grp.basis_obj() @@ -614,10 +616,10 @@ def inverse_mass(dcoll, vec): def reference_face_mass_matrix(actx, face_element_group, vol_element_group, dtype): - # @keyed_memoize_in( - # actx, reference_mass_matrix, - # lambda face_grp, vol_grp: (face_grp.discretization_key(), - # vol_grp.discretization_key())) + @keyed_memoize_in( + actx, reference_mass_matrix, + lambda face_grp, vol_grp: (face_grp.discretization_key(), + vol_grp.discretization_key())) def get_ref_face_mass_mat(face_grp, vol_grp): nfaces = vol_grp.mesh_el_group.nfaces assert (face_grp.nelements @@ -771,30 +773,63 @@ def face_mass(dcoll, *args): # }}} -# {{{ Nodal reductions +# {{{ Nodal reductions TODO: Convert these over def norm(dcoll, vec, p, dd=None): # Raise a warning if `dd` is not None? - actx = vec.array_context - return actx.np.linalg.norm(vec, ord=p) + # actx = vec.array_context + # return actx.np.linalg.norm(vec, ord=p) + if dd is None: + dd = "vol" + + dd = dof_desc.as_dofdesc(dd) + + if isinstance(vec, np.ndarray): + if p == 2: + return sum(norm(dcoll, vec[idx], p, dd=dd)**2 + for idx in np.ndindex(vec.shape))**0.5 + elif p == np.inf: + return max(norm(dcoll, vec[idx], np.inf, dd=dd) + for idx in np.ndindex(vec.shape)) + else: + raise ValueError("unsupported norm order") + + return _norm(dcoll, p, dd)(arg=vec) + # actx = vec.array_context + # return actx.np.linalg.norm(vec, ord=p) + + +@memoize_on_first_arg +def _norm(dcoll, p, dd): + return bind(dcoll, + sym.norm(p, sym.var("arg", dd=dd), dd=dd), + local_only=True) def nodal_sum(dcoll, dd, vec): # Raise a warning if `dd` is not None? - actx = vec.array_context - return np.sum([actx.np.sum(vec_i) for vec_i in vec]) + # actx = vec.array_context + # return np.sum([actx.np.sum(vec_i) for vec_i in vec]) + return _nodal_reduction(dcoll, sym.NodalSum, dd)(arg=vec) def nodal_min(dcoll, dd, vec): # Raise a warning if `dd` is not None? - actx = vec.array_context - return np.min([actx.np.min(vec_i) for vec_i in vec]) + # actx = vec.array_context + # return np.min([actx.np.min(vec_i) for vec_i in vec]) + return _nodal_reduction(dcoll, sym.NodalMin, dd)(arg=vec) def nodal_max(dcoll, dd, vec): # Raise a warning if `dd` is not None? - actx = vec.array_context - return np.max([actx.np.max(vec_i) for vec_i in vec]) + # actx = vec.array_context + # return np.max([actx.np.max(vec_i) for vec_i in vec]) + return _nodal_reduction(dcoll, sym.NodalMax, dd)(arg=vec) + + +@memoize_on_first_arg +def _nodal_reduction(dcoll, operator, dd): + return bind(dcoll, operator(dd)(sym.var("arg")), local_only=True) # }}} @@ -899,6 +934,8 @@ def cross_rank_trace_pairs(dcoll, ary, tag=None): :class:`~meshmode.dof_array.DOFArray`, or an object array of ``DOFArray``\ s of arbitrary shape. """ + from pytools.obj_array import make_obj_array + if isinstance(ary, np.ndarray): oshape = ary.shape comm_vec = ary.flatten()