From ed30a2dcea81105c38877363288482053ad2886a Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 25 Oct 2015 14:34:43 -0500 Subject: [PATCH] Detect and make use of permutation-matrix resampling matrices in connection --- meshmode/discretization/connection.py | 127 +++++++++++++++++++++++--- test/test_meshmode.py | 21 +++-- 2 files changed, 130 insertions(+), 18 deletions(-) diff --git a/meshmode/discretization/connection.py b/meshmode/discretization/connection.py index 0eb5568a..fec50f0e 100644 --- a/meshmode/discretization/connection.py +++ b/meshmode/discretization/connection.py @@ -120,6 +120,11 @@ class DiscretizationConnection(object): a list of :class:`MeshConnectionGroup` instances, with a one-to-one correspondence to the groups in :attr:`to_discr`. + + .. automethod:: __call__ + + .. automethod:: full_resample_matrix + """ def __init__(self, from_discr, to_discr, groups): @@ -129,6 +134,16 @@ class DiscretizationConnection(object): self.cl_context = from_discr.cl_context + if from_discr.mesh.vertex_id_dtype != to_discr.mesh.vertex_id_dtype: + raise ValueError("from_discr and to_discr must agree on the " + "vertex_id_dtype") + + if from_discr.mesh.element_id_dtype != to_discr.mesh.element_id_dtype: + raise ValueError("from_discr and to_discr must agree on the " + "element_id_dtype") + + self.cl_context = from_discr.cl_context + self.from_discr = from_discr self.to_discr = to_discr self.groups = groups @@ -139,11 +154,60 @@ class DiscretizationConnection(object): ibatch = self.groups[to_group_index].batches[ibatch_index] from_grp = self.from_discr.groups[ibatch.from_group_index] - return mp.resampling_matrix( + result = mp.resampling_matrix( mp.simplex_onb(self.from_discr.dim, from_grp.order), ibatch.result_unit_nodes, from_grp.unit_nodes) + with cl.CommandQueue(self.cl_context) as queue: + return cl.array.to_device(queue, result).with_queue(None) + + @memoize_method + def _resample_point_pick_indices(self, to_group_index, ibatch_index, + tol_multiplier=None): + """If :meth:`_resample_matrix` *R* is a row subset of a permutation matrix *P*, + return the index subset I so that, loosely, ``x[I] == R @ x``. + + Will return *None* if no such index array exists, or a + :class:`pyopencl.array.Array` containing the index subset. + """ + + with cl.CommandQueue(self.cl_context) as queue: + mat = self._resample_matrix(to_group_index, ibatch_index).get( + queue=queue) + + nrows, ncols = mat.shape + result = np.zeros(nrows, dtype=self.to_discr.mesh.element_id_dtype) + + if tol_multiplier is None: + tol_multiplier = 50 + + tol = np.finfo(mat.dtype).eps * tol_multiplier + + for irow in range(nrows): + one_indices, = np.where(np.abs(mat[irow] - 1) < tol) + zero_indices, = np.where(np.abs(mat[irow]) < tol) + + if len(one_indices) != 1: + return None + if len(zero_indices) != ncols - 1: + return None + + one_index, = one_indices + result[irow] = one_index + + with cl.CommandQueue(self.cl_context) as queue: + return cl.array.to_device(queue, result).with_queue(None) + def full_resample_matrix(self, queue): + """Build a dense matrix representing this discretization connection. + + .. warning:: + + On average, this will be exceedingly expensive (:math:`O(N^2)` in + the number *N* of discretization points) in terms of memory usage + and thus not what you'd typically want. + """ + @memoize_in(self, "oversample_mat_knl") def knl(): import loopy as lp @@ -193,8 +257,8 @@ class DiscretizationConnection(object): return result def __call__(self, queue, vec): - @memoize_in(self, "oversample_knl") - def knl(): + @memoize_in(self, "resample_by_mat_knl") + def mat_knl(): import loopy as lp knl = lp.make_kernel( """{[k,i,j]: @@ -215,7 +279,33 @@ class DiscretizationConnection(object): lp.ValueArg("nelements_vec", np.int32), "...", ], - name="oversample") + name="resample_by_mat") + + knl = lp.split_iname(knl, "i", 16, inner_tag="l.0") + return lp.tag_inames(knl, dict(k="g.0")) + + @memoize_in(self, "resample_by_picking_knl") + def pick_knl(): + import loopy as lp + knl = lp.make_kernel( + """{[k,i,j]: + 0<=k %d elements" % ( h, sum(mgrp.nelements for mgrp in mesh.groups))) @@ -97,7 +104,7 @@ def test_boundary_interpolation(ctx_getter): f = 0.1*cl.clmath.sin(30*x) bdry_mesh, bdry_discr, bdry_connection = make_face_restriction( - queue, vol_discr, InterpolatoryQuadratureSimplexGroupFactory(order), + queue, vol_discr, group_factory(order), BTAG_ALL) bdry_x = bdry_discr.nodes()[0].with_queue(queue) @@ -113,7 +120,9 @@ def test_boundary_interpolation(ctx_getter): eoc_rec.add_data_point(h, err) print(eoc_rec) - assert eoc_rec.order_estimate() >= order-0.5 + assert ( + eoc_rec.order_estimate() >= order-0.5 + or eoc_rec.max_error() < 1e-14) def test_element_orientation(): -- GitLab