Esempio n. 1
0
    def check_expansion_disks_undisturbed_by_sources(self,
            stage1_density_discr, tree, peer_lists,
            expansion_disturbance_tolerance,
            refine_flags,
            debug, wait_for=None):

        # Avoid generating too many kernels.
        from pytools import div_ceil
        max_levels = MAX_LEVELS_INCREMENT * div_ceil(
                tree.nlevels, MAX_LEVELS_INCREMENT)

        knl = self.code_container.expansion_disk_undisturbed_by_sources_checker(
                tree.dimensions,
                tree.coord_dtype, tree.box_id_dtype,
                peer_lists.peer_list_starts.dtype,
                tree.particle_id_dtype,
                max_levels)

        if debug:
            npanels_to_refine_prev = cl.array.sum(refine_flags).get()

        found_panel_to_refine = cl.array.zeros(self.queue, 1, np.int32)
        found_panel_to_refine.finish()
        unwrap_args = AreaQueryElementwiseTemplate.unwrap_args

        from pytential import bind, sym
        center_danger_zone_radii = flatten(
            bind(stage1_density_discr,
                sym.expansion_radii(stage1_density_discr.ambient_dim,
                    granularity=sym.GRANULARITY_CENTER))(self.array_context))

        evt = knl(
            *unwrap_args(
                tree, peer_lists,
                tree.box_to_qbx_source_starts,
                tree.box_to_qbx_source_lists,
                tree.qbx_panel_to_source_starts,
                tree.qbx_panel_to_center_starts,
                tree.qbx_user_source_slice.start,
                tree.qbx_user_center_slice.start,
                tree.sorted_target_ids,
                center_danger_zone_radii,
                expansion_disturbance_tolerance,
                tree.nqbxpanels,
                refine_flags,
                found_panel_to_refine,
                *tree.sources),
            range=slice(tree.nqbxcenters),
            queue=self.queue,
            wait_for=wait_for)

        cl.wait_for_events([evt])

        if debug:
            npanels_to_refine = cl.array.sum(refine_flags).get()
            if npanels_to_refine > npanels_to_refine_prev:
                logger.debug("refiner: found {} panel(s) to refine".format(
                    npanels_to_refine - npanels_to_refine_prev))

        return found_panel_to_refine.get()[0] == 1
Esempio n. 2
0
    def __call__(self, actx: PyOpenCLArrayContext, source_dd,
                 indices: BlockIndexRanges, **kwargs) -> BlockProxyPoints:
        from pytential import bind, sym
        source_dd = sym.as_dofdesc(source_dd)

        radii = bind(self.places,
                     sym.expansion_radii(self.ambient_dim,
                                         dofdesc=source_dd))(actx)
        center_int = bind(
            self.places,
            sym.expansion_centers(self.ambient_dim, -1,
                                  dofdesc=source_dd))(actx)
        center_ext = bind(
            self.places,
            sym.expansion_centers(self.ambient_dim, +1,
                                  dofdesc=source_dd))(actx)

        return super().__call__(actx,
                                source_dd,
                                indices,
                                expansion_radii=flatten(radii, actx),
                                center_int=flatten(center_int,
                                                   actx,
                                                   leaf_class=DOFArray),
                                center_ext=flatten(center_ext,
                                                   actx,
                                                   leaf_class=DOFArray),
                                **kwargs)
Esempio n. 3
0
    def map_int_g(self, expr):
        lpot_source = self.places.get_geometry(expr.source.geometry)
        source_discr = self.places.get_discretization(expr.source.geometry,
                                                      expr.source.discr_stage)
        target_discr = self.places.get_discretization(expr.target.geometry,
                                                      expr.target.discr_stage)

        if source_discr is not target_discr:
            raise NotImplementedError

        rec_density = self._blk_mapper.rec(expr.density)
        if is_zero(rec_density):
            return 0

        if not np.isscalar(rec_density):
            raise NotImplementedError

        actx = self.array_context
        kernel = expr.kernel
        kernel_args = _get_layer_potential_args(self._mat_mapper, expr)

        from sumpy.expansion.local import LineTaylorLocalExpansion
        local_expn = LineTaylorLocalExpansion(kernel, lpot_source.qbx_order)

        from sumpy.qbx import LayerPotentialMatrixBlockGenerator
        mat_gen = LayerPotentialMatrixBlockGenerator(actx.context,
                                                     (local_expn, ))

        assert abs(expr.qbx_forced_limit) > 0
        from pytential import bind, sym
        radii = bind(
            self.places,
            sym.expansion_radii(source_discr.ambient_dim,
                                dofdesc=expr.target))(actx)
        centers = bind(
            self.places,
            sym.expansion_centers(source_discr.ambient_dim,
                                  expr.qbx_forced_limit,
                                  dofdesc=expr.target))(actx)

        from meshmode.dof_array import flatten, thaw
        _, (mat, ) = mat_gen(actx.queue,
                             targets=flatten(thaw(actx, target_discr.nodes())),
                             sources=flatten(thaw(actx, source_discr.nodes())),
                             centers=flatten(centers),
                             expansion_radii=flatten(radii),
                             index_set=self.index_set,
                             **kernel_args)

        waa = bind(
            self.places,
            sym.weights_and_area_elements(source_discr.ambient_dim,
                                          dofdesc=expr.source))(actx)
        waa = flatten(waa)

        mat *= waa[self.index_set.linear_col_indices]
        return rec_density * actx.to_numpy(mat)
Esempio n. 4
0
    def map_int_g(self, expr):
        lpot_source = self.places.get_geometry(expr.source.geometry)
        source_discr = self.places.get_discretization(expr.source.geometry,
                                                      expr.source.discr_stage)
        target_discr = self.places.get_discretization(expr.target.geometry,
                                                      expr.target.discr_stage)

        rec_density = self.rec(expr.density)
        if is_zero(rec_density):
            return 0

        assert isinstance(rec_density, np.ndarray)
        if not self.is_kind_matrix(rec_density):
            raise NotImplementedError("layer potentials on non-variables")

        actx = self.array_context
        kernel = expr.kernel
        kernel_args = _get_layer_potential_args(self, expr)

        from sumpy.expansion.local import LineTaylorLocalExpansion
        local_expn = LineTaylorLocalExpansion(kernel, lpot_source.qbx_order)

        from sumpy.qbx import LayerPotentialMatrixGenerator
        mat_gen = LayerPotentialMatrixGenerator(actx.context, (local_expn, ))

        assert abs(expr.qbx_forced_limit) > 0
        from pytential import bind, sym
        radii = bind(
            self.places,
            sym.expansion_radii(source_discr.ambient_dim,
                                dofdesc=expr.target))(actx)
        centers = bind(
            self.places,
            sym.expansion_centers(source_discr.ambient_dim,
                                  expr.qbx_forced_limit,
                                  dofdesc=expr.target))(actx)

        from meshmode.dof_array import flatten, thaw
        _, (mat, ) = mat_gen(actx.queue,
                             targets=flatten(thaw(actx, target_discr.nodes())),
                             sources=flatten(thaw(actx, source_discr.nodes())),
                             centers=flatten(centers),
                             expansion_radii=flatten(radii),
                             **kernel_args)
        mat = actx.to_numpy(mat)

        waa = bind(
            self.places,
            sym.weights_and_area_elements(source_discr.ambient_dim,
                                          dofdesc=expr.source))(actx)
        mat[:, :] *= actx.to_numpy(flatten(waa))
        mat = mat.dot(rec_density)

        return mat
Esempio n. 5
0
def get_interleaved_radii(queue, lpot_source):
    """
    Return an array of shape (dim, ncenters) in which interior centers are placed
    next to corresponding exterior centers.
    """
    from pytential import bind, sym

    radii = bind(lpot_source,
                 sym.expansion_radii(lpot_source.ambient_dim))(queue)

    from pytential.symbolic.dof_connection import CenterGranularityConnection
    interleaver = CenterGranularityConnection(lpot_source.density_discr)
    return interleaver(queue, radii)
Esempio n. 6
0
    def flat_expansion_radii(self):
        """Return an array of radii associated with the (interleaved)
        expansion centers.

        ``coord_t [ncenters]``
        """
        from pytential import bind, sym

        radii = bind(
            self.places,
            sym.expansion_radii(self.ambient_dim,
                                granularity=sym.GRANULARITY_CENTER,
                                dofdesc=self.source_dd.to_stage1()))(
                                    self.array_context)

        return self.array_context.freeze(flatten(radii))
Esempio n. 7
0
    def exec_compute_potential_insn_direct(self, queue, insn, bound_expr,
                                           evaluate, return_timing_data):
        if return_timing_data:
            from pytential.source import UnableToCollectTimingData
            from warnings import warn
            warn("Timing data collection not supported.",
                 category=UnableToCollectTimingData)

        lpot_applier = self.get_lpot_applier(insn.kernels)
        p2p = None
        lpot_applier_on_tgt_subset = None

        kernel_args = {}
        for arg_name, arg_expr in six.iteritems(insn.kernel_arguments):
            kernel_args[arg_name] = evaluate(arg_expr)

        strengths = (evaluate(insn.density).with_queue(queue) *
                     self.weights_and_area_elements())

        from pytential import bind, sym
        expansion_radii = bind(self,
                               sym.expansion_radii(self.ambient_dim))(queue)
        centers = {
            -1: bind(self, sym.expansion_centers(self.ambient_dim, -1))(queue),
            +1: bind(self, sym.expansion_centers(self.ambient_dim, +1))(queue)
        }

        # FIXME: Do this all at once
        result = []
        for o in insn.outputs:
            target_discr = bound_expr.get_discretization(o.target_name)

            is_self = self.density_discr is target_discr

            if is_self:
                # QBXPreprocessor is supposed to have taken care of this
                assert o.qbx_forced_limit is not None
                assert abs(o.qbx_forced_limit) > 0

                evt, output_for_each_kernel = lpot_applier(
                    queue,
                    target_discr.nodes(),
                    self.quad_stage2_density_discr.nodes(),
                    centers[o.qbx_forced_limit], [strengths],
                    expansion_radii=expansion_radii,
                    **kernel_args)
                result.append((o.name, output_for_each_kernel[o.kernel_index]))
            else:
                # no on-disk kernel caching
                if p2p is None:
                    p2p = self.get_p2p(insn.kernels)
                if lpot_applier_on_tgt_subset is None:
                    lpot_applier_on_tgt_subset = self.get_lpot_applier_on_tgt_subset(
                        insn.kernels)

                evt, output_for_each_kernel = p2p(
                    queue, target_discr.nodes(),
                    self.quad_stage2_density_discr.nodes(), [strengths],
                    **kernel_args)

                qbx_forced_limit = o.qbx_forced_limit
                if qbx_forced_limit is None:
                    qbx_forced_limit = 0

                geo_data = self.qbx_fmm_geometry_data(
                    target_discrs_and_qbx_sides=((target_discr,
                                                  qbx_forced_limit), ))

                # center-related info is independent of targets

                # First ncenters targets are the centers
                tgt_to_qbx_center = (
                    geo_data.user_target_to_center()[geo_data.ncenters:].copy(
                        queue=queue).with_queue(queue))

                qbx_tgt_numberer = self.get_qbx_target_numberer(
                    tgt_to_qbx_center.dtype)
                qbx_tgt_count = cl.array.empty(queue, (), np.int32)
                qbx_tgt_numbers = cl.array.empty_like(tgt_to_qbx_center)

                qbx_tgt_numberer(tgt_to_qbx_center,
                                 qbx_tgt_numbers,
                                 qbx_tgt_count,
                                 queue=queue)

                qbx_tgt_count = int(qbx_tgt_count.get())

                if (o.qbx_forced_limit is not None
                        and abs(o.qbx_forced_limit) == 1
                        and qbx_tgt_count < target_discr.nnodes):
                    raise RuntimeError("Did not find a matching QBX center "
                                       "for some targets")

                qbx_tgt_numbers = qbx_tgt_numbers[:qbx_tgt_count]
                qbx_center_numbers = tgt_to_qbx_center[qbx_tgt_numbers]
                qbx_center_numbers.finish()

                tgt_subset_kwargs = kernel_args.copy()
                for i, res_i in enumerate(output_for_each_kernel):
                    tgt_subset_kwargs["result_%d" % i] = res_i

                if qbx_tgt_count:
                    lpot_applier_on_tgt_subset(
                        queue,
                        targets=target_discr.nodes(),
                        sources=self.quad_stage2_density_discr.nodes(),
                        centers=geo_data.centers(),
                        expansion_radii=geo_data.expansion_radii(),
                        strengths=[strengths],
                        qbx_tgt_numbers=qbx_tgt_numbers,
                        qbx_center_numbers=qbx_center_numbers,
                        **tgt_subset_kwargs)

                result.append((o.name, output_for_each_kernel[o.kernel_index]))

        timing_data = {}
        return result, timing_data
Esempio n. 8
0
def run_source_refinement_test(ctx_factory,
                               mesh,
                               order,
                               helmholtz_k=None,
                               visualize=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # {{{ initial geometry

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import (
        InterpolatoryQuadratureSimplexGroupFactory)
    discr = Discretization(actx, mesh,
                           InterpolatoryQuadratureSimplexGroupFactory(order))

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in refinement
        fine_order=order)
    places = GeometryCollection(lpot_source)

    # }}}

    # {{{ refined geometry

    kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None
    expansion_disturbance_tolerance = 0.025

    from pytential.qbx.refinement import refine_geometry_collection
    places = refine_geometry_collection(
        places,
        kernel_length_scale=kernel_length_scale,
        expansion_disturbance_tolerance=expansion_disturbance_tolerance,
        visualize=visualize)

    # }}}

    dd = places.auto_source
    stage1_density_discr = places.get_discretization(dd.geometry)
    from meshmode.dof_array import thaw

    stage1_density_nodes = dof_array_to_numpy(
        actx, thaw(actx, stage1_density_discr.nodes()))

    quad_stage2_density_discr = places.get_discretization(
        dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2)
    quad_stage2_density_nodes = dof_array_to_numpy(
        actx, thaw(actx, quad_stage2_density_discr.nodes()))

    int_centers = dof_array_to_numpy(
        actx,
        bind(places, sym.expansion_centers(lpot_source.ambient_dim, -1))(actx))
    ext_centers = dof_array_to_numpy(
        actx,
        bind(places, sym.expansion_centers(lpot_source.ambient_dim, +1))(actx))
    expansion_radii = dof_array_to_numpy(
        actx,
        bind(places, sym.expansion_radii(lpot_source.ambient_dim))(actx))

    dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT)
    source_danger_zone_radii = dof_array_to_numpy(
        actx,
        bind(
            places,
            sym._source_danger_zone_radii(lpot_source.ambient_dim,
                                          dofdesc=dd.to_stage2()))(actx))
    quad_res = dof_array_to_numpy(
        actx,
        bind(places, sym._quad_resolution(lpot_source.ambient_dim,
                                          dofdesc=dd))(actx))

    # {{{ check if satisfying criteria

    def check_disk_undisturbed_by_sources(centers_panel, sources_panel):
        if centers_panel.element_nr == sources_panel.element_nr:
            # Same panel
            return

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = stage1_density_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # A center cannot be closer to another panel than to its originating
        # panel.

        rad = expansion_radii[centers_panel.discr_slice]
        assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \
                (dist, rad, centers_panel.element_nr, sources_panel.element_nr)

    def check_sufficient_quadrature_resolution(centers_panel, sources_panel):
        dz_radius = source_danger_zone_radii[sources_panel.element_nr]

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = quad_stage2_density_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # The quadrature contribution from each panel is as accurate
        # as from the center's own source panel.
        assert dist >= dz_radius, \
                (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr)

    def check_quad_res_to_helmholtz_k_ratio(panel):
        # Check wavenumber to panel size ratio.
        assert quad_res[panel.element_nr] * helmholtz_k <= 5

    for i, panel_1 in enumerate(iter_elements(stage1_density_discr)):
        for panel_2 in iter_elements(stage1_density_discr):
            check_disk_undisturbed_by_sources(panel_1, panel_2)
        for panel_2 in iter_elements(quad_stage2_density_discr):
            check_sufficient_quadrature_resolution(panel_1, panel_2)
        if helmholtz_k is not None:
            check_quad_res_to_helmholtz_k_ratio(panel_1)
Esempio n. 9
0
def test_target_association(ctx_factory,
                            curve_name,
                            curve_f,
                            nelements,
                            visualize=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # {{{ generate lpot source

    order = 16

    # Make the curve mesh.
    mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements + 1), order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
    factory = InterpolatoryQuadratureSimplexGroupFactory(order)
    discr = Discretization(actx, mesh, factory)

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in target association
        fine_order=order)
    places = GeometryCollection(lpot_source)

    # }}}

    # {{{ generate targets

    from pyopencl.clrandom import PhiloxGenerator
    rng = PhiloxGenerator(cl_ctx, seed=RNG_SEED)

    dd = places.auto_source.to_stage1()
    centers = dof_array_to_numpy(
        actx,
        bind(
            places,
            sym.interleaved_expansion_centers(lpot_source.ambient_dim,
                                              dofdesc=dd))(actx))

    density_discr = places.get_discretization(dd.geometry)

    noise = actx.to_numpy(
        rng.uniform(queue, density_discr.ndofs, dtype=np.float, a=0.01, b=1.0))

    tunnel_radius = dof_array_to_numpy(
        actx,
        bind(
            places,
            sym._close_target_tunnel_radii(lpot_source.ambient_dim,
                                           dofdesc=dd))(actx))

    def targets_from_sources(sign, dist, dim=2):
        nodes = dof_array_to_numpy(
            actx,
            bind(places, sym.nodes(dim,
                                   dofdesc=dd))(actx).as_vector(np.object))
        normals = dof_array_to_numpy(
            actx,
            bind(places, sym.normal(dim,
                                    dofdesc=dd))(actx).as_vector(np.object))
        return actx.from_numpy(nodes + normals * sign * dist)

    from pytential.target import PointsTarget
    int_targets = PointsTarget(targets_from_sources(-1, noise * tunnel_radius))
    ext_targets = PointsTarget(targets_from_sources(+1, noise * tunnel_radius))
    far_targets = PointsTarget(
        targets_from_sources(+1, FAR_TARGET_DIST_FROM_SOURCE))

    # Create target discretizations.
    target_discrs = (
        # On-surface targets, interior
        (density_discr, -1),
        # On-surface targets, exterior
        (density_discr, +1),
        # Interior close targets
        (int_targets, -2),
        # Exterior close targets
        (ext_targets, +2),
        # Far targets, should not need centers
        (far_targets, 0),
    )

    sizes = np.cumsum([discr.ndofs for discr, _ in target_discrs])

    (
        surf_int_slice,
        surf_ext_slice,
        vol_int_slice,
        vol_ext_slice,
        far_slice,
    ) = [slice(start, end) for start, end in zip(np.r_[0, sizes], sizes)]

    # }}}

    # {{{ run target associator and check

    from pytential.qbx.target_assoc import (TargetAssociationCodeContainer,
                                            associate_targets_to_qbx_centers)

    from pytential.qbx.utils import TreeCodeContainer
    code_container = TargetAssociationCodeContainer(actx,
                                                    TreeCodeContainer(actx))

    target_assoc = (associate_targets_to_qbx_centers(
        places,
        places.auto_source,
        code_container.get_wrangler(actx),
        target_discrs,
        target_association_tolerance=1e-10).get(queue=queue))

    expansion_radii = dof_array_to_numpy(
        actx,
        bind(
            places,
            sym.expansion_radii(lpot_source.ambient_dim,
                                granularity=sym.GRANULARITY_CENTER))(actx))
    from meshmode.dof_array import thaw
    surf_targets = dof_array_to_numpy(actx, thaw(actx, density_discr.nodes()))
    int_targets = actx.to_numpy(int_targets.nodes())
    ext_targets = actx.to_numpy(ext_targets.nodes())

    def visualize_curve_and_assoc():
        import matplotlib.pyplot as plt
        from meshmode.mesh.visualization import draw_curve

        draw_curve(density_discr.mesh)

        targets = int_targets
        tgt_slice = surf_int_slice

        plt.plot(centers[0], centers[1], "+", color="orange")
        ax = plt.gca()

        for tx, ty, tcenter in zip(targets[0, tgt_slice], targets[1,
                                                                  tgt_slice],
                                   target_assoc.target_to_center[tgt_slice]):
            if tcenter >= 0:
                ax.add_artist(
                    plt.Line2D(
                        (tx, centers[0, tcenter]),
                        (ty, centers[1, tcenter]),
                    ))

        ax.set_aspect("equal")
        plt.show()

    if visualize:
        visualize_curve_and_assoc()

    # Checks that the targets match with centers on the appropriate side and
    # within the allowable distance.
    def check_close_targets(centers, targets, true_side, target_to_center,
                            target_to_side_result, tgt_slice):
        targets_have_centers = (target_to_center >= 0).all()
        assert targets_have_centers

        assert (target_to_side_result == true_side).all()

        TOL = 1e-3
        dists = la.norm((targets.T - centers.T[target_to_center]), axis=1)
        assert (dists <= (1 + TOL) * expansion_radii[target_to_center]).all()

    # Center side order = -1, 1, -1, 1, ...
    target_to_center_side = 2 * (target_assoc.target_to_center % 2) - 1

    # interior surface
    check_close_targets(centers, surf_targets, -1,
                        target_assoc.target_to_center[surf_int_slice],
                        target_to_center_side[surf_int_slice], surf_int_slice)

    # exterior surface
    check_close_targets(centers, surf_targets, +1,
                        target_assoc.target_to_center[surf_ext_slice],
                        target_to_center_side[surf_ext_slice], surf_ext_slice)

    # interior volume
    check_close_targets(centers, int_targets, -1,
                        target_assoc.target_to_center[vol_int_slice],
                        target_to_center_side[vol_int_slice], vol_int_slice)

    # exterior volume
    check_close_targets(centers, ext_targets, +1,
                        target_assoc.target_to_center[vol_ext_slice],
                        target_to_center_side[vol_ext_slice], vol_ext_slice)

    # Checks that far targets are not assigned a center.
    assert (target_assoc.target_to_center[far_slice] == -1).all()
Esempio n. 10
0
def run_source_refinement_test(actx_factory,
                               mesh,
                               order,
                               helmholtz_k=None,
                               surface_name="surface",
                               visualize=False):
    actx = actx_factory()

    # {{{ initial geometry

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureGroupFactory
    discr = Discretization(actx, mesh,
                           InterpolatoryQuadratureGroupFactory(order))

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in refinement
        fine_order=order)
    places = GeometryCollection(lpot_source)

    logger.info("nelements: %d", discr.mesh.nelements)
    logger.info("ndofs: %d", discr.ndofs)

    # }}}

    # {{{ refined geometry

    def _visualize_quad_resolution(_places, dd, suffix):
        if dd.discr_stage is None:
            vis_discr = lpot_source.density_discr
        else:
            vis_discr = _places.get_discretization(dd.geometry, dd.discr_stage)

        stretch = bind(_places,
                       sym._simplex_mapping_max_stretch_factor(
                           _places.ambient_dim, with_elementwise_max=False),
                       auto_where=dd)(actx)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, vis_discr, order, force_equidistant=True)
        vis.write_vtk_file(
            f"global-qbx-source-refinement-{surface_name}-{order}-{suffix}.vtu",
            [("stretch", stretch)],
            overwrite=True,
            use_high_order=True)

    kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None
    expansion_disturbance_tolerance = 0.025

    from pytential.qbx.refinement import refine_geometry_collection
    places = refine_geometry_collection(
        places,
        kernel_length_scale=kernel_length_scale,
        expansion_disturbance_tolerance=expansion_disturbance_tolerance,
        visualize=False)

    if visualize:
        dd = places.auto_source
        _visualize_quad_resolution(places, dd.copy(discr_stage=None),
                                   "original")
        _visualize_quad_resolution(places, dd.to_stage1(), "stage1")
        _visualize_quad_resolution(places, dd.to_stage2(), "stage2")

    # }}}

    dd = places.auto_source
    ambient_dim = places.ambient_dim
    stage1_density_discr = places.get_discretization(dd.geometry)

    stage1_density_nodes = actx.to_numpy(
        flatten(stage1_density_discr.nodes(), actx)).reshape(ambient_dim, -1)

    quad_stage2_density_discr = places.get_discretization(
        dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2)
    quad_stage2_density_nodes = actx.to_numpy(
        flatten(quad_stage2_density_discr.nodes(),
                actx)).reshape(ambient_dim, -1)

    int_centers = actx.to_numpy(
        flatten(
            bind(places, sym.expansion_centers(ambient_dim, -1))(actx),
            actx)).reshape(ambient_dim, -1)
    ext_centers = actx.to_numpy(
        flatten(
            bind(places, sym.expansion_centers(ambient_dim, +1))(actx),
            actx)).reshape(ambient_dim, -1)
    expansion_radii = actx.to_numpy(
        flatten(bind(places, sym.expansion_radii(ambient_dim))(actx), actx))

    dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT)
    source_danger_zone_radii = actx.to_numpy(
        flatten(
            bind(
                places,
                sym._source_danger_zone_radii(ambient_dim,
                                              dofdesc=dd.to_stage2()))(actx),
            actx))
    quad_res = actx.to_numpy(
        flatten(
            bind(places, sym._quad_resolution(ambient_dim, dofdesc=dd))(actx),
            actx))

    # {{{ check if satisfying criteria

    def check_disk_undisturbed_by_sources(centers_element, sources_element):
        if centers_element.index == sources_element.index:
            # Same element
            return

        my_int_centers = int_centers[:, centers_element.discr_slice]
        my_ext_centers = ext_centers[:, centers_element.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = stage1_density_nodes[:, sources_element.discr_slice]

        # =distance(centers of element 1, element 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # A center cannot be closer to another element than to its originating
        # element.

        rad = expansion_radii[centers_element.discr_slice]
        assert np.all(
            dist >= rad *
            (1 - expansion_disturbance_tolerance)), (dist, rad,
                                                     centers_element.index,
                                                     sources_element.index)

    def check_sufficient_quadrature_resolution(centers_element,
                                               sources_element):
        dz_radius = source_danger_zone_radii[sources_element.index]

        my_int_centers = int_centers[:, centers_element.discr_slice]
        my_ext_centers = ext_centers[:, centers_element.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = quad_stage2_density_nodes[:, sources_element.discr_slice]

        # =distance(centers of element 1, element 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # The quadrature contribution from each element is as accurate
        # as from the center's own source element.
        assert dist >= dz_radius, \
                (dist, dz_radius, centers_element.index, sources_element.index)

    def check_quad_res_to_helmholtz_k_ratio(element):
        # Check wavenumber to element size ratio.
        assert quad_res[element.index] * helmholtz_k <= 5

    for element_1 in iter_elements(stage1_density_discr):
        for element_2 in iter_elements(stage1_density_discr):
            check_disk_undisturbed_by_sources(element_1, element_2)
        for element_2 in iter_elements(quad_stage2_density_discr):
            check_sufficient_quadrature_resolution(element_1, element_2)
        if helmholtz_k is not None:
            check_quad_res_to_helmholtz_k_ratio(element_1)
Esempio n. 11
0
    # {{{ visualization

    srcindices = srcindices.get(queue)
    if visualize:
        ambient_dim = places.ambient_dim
        if ambient_dim == 2:
            import matplotlib.pyplot as pt

            from pytential.utils import flatten_to_numpy
            density_nodes = np.vstack(
                flatten_to_numpy(actx, density_discr.nodes()))
            ci = bind(places, sym.expansion_centers(ambient_dim, -1))(actx)
            ci = np.vstack(flatten_to_numpy(actx, ci))
            ce = bind(places, sym.expansion_centers(ambient_dim, +1))(actx)
            ce = np.vstack(flatten_to_numpy(actx, ce))
            r = bind(places, sym.expansion_radii(ambient_dim))(actx)
            r = flatten_to_numpy(actx, r)

            for i in range(srcindices.nblocks):
                isrc = srcindices.block_indices(i)
                ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]]

                pt.figure(figsize=(10, 8))
                axis = pt.gca()
                for j in isrc:
                    c = pt.Circle(ci[:, j], r[j], color='k', alpha=0.1)
                    axis.add_artist(c)
                    c = pt.Circle(ce[:, j], r[j], color='k', alpha=0.1)
                    axis.add_artist(c)

                pt.plot(density_nodes[0],
Esempio n. 12
0
    def __call__(self, actx, source_dd, indices, **kwargs):
        """Generate proxy points for each given range of source points in
        the discretization in *source_dd*.

        :arg actx: a :class:`~meshmode.array_context.ArrayContext`.
        :arg source_dd: a :class:`~pytential.symbolic.primitives.DOFDescriptor`
            for the discretization on which the proxy points are to be
            generated.
        :arg indices: a :class:`sumpy.tools.BlockIndexRanges`.

        :return: a tuple of ``(proxies, pxyranges, pxycenters, pxyranges)``,
            where each element is a :class:`pyopencl.array.Array`. The
            sizes of the arrays are as follows: ``pxycenters`` is of size
            ``(2, nranges)``, ``pxyradii`` is of size ``(nranges,)``,
            ``pxyranges`` is of size ``(nranges + 1,)`` and ``proxies`` is
            of size ``(2, nranges * nproxy)``. The proxy points in a range
            :math:`i` can be obtained by a slice
            ``proxies[pxyranges[i]:pxyranges[i + 1]]`` and are all at a
            distance ``pxyradii[i]`` from the range center ``pxycenters[i]``.
        """

        def _affine_map(v, A, b):
            return np.dot(A, v) + b

        from pytential import bind, sym
        source_dd = sym.as_dofdesc(source_dd)
        discr = self.places.get_discretization(
                source_dd.geometry, source_dd.discr_stage)

        radii = bind(self.places, sym.expansion_radii(
            self.ambient_dim, dofdesc=source_dd))(actx)
        center_int = bind(self.places, sym.expansion_centers(
            self.ambient_dim, -1, dofdesc=source_dd))(actx)
        center_ext = bind(self.places, sym.expansion_centers(
            self.ambient_dim, +1, dofdesc=source_dd))(actx)

        from meshmode.dof_array import flatten, thaw
        knl = self.get_kernel()
        _, (centers_dev, radii_dev,) = knl(actx.queue,
            sources=flatten(thaw(actx, discr.nodes())),
            center_int=flatten(center_int),
            center_ext=flatten(center_ext),
            expansion_radii=flatten(radii),
            srcindices=indices.indices,
            srcranges=indices.ranges, **kwargs)

        from pytential.utils import flatten_to_numpy
        centers = flatten_to_numpy(actx, centers_dev)
        radii = flatten_to_numpy(actx, radii_dev)
        proxies = np.empty(indices.nblocks, dtype=np.object)
        for i in range(indices.nblocks):
            proxies[i] = _affine_map(self.ref_points,
                    A=(radii[i] * np.eye(self.ambient_dim)),
                    b=centers[:, i].reshape(-1, 1))

        pxyranges = actx.from_numpy(np.arange(
            0,
            proxies.shape[0] * proxies[0].shape[1] + 1,
            proxies[0].shape[1],
            dtype=indices.ranges.dtype))
        proxies = make_obj_array([
            actx.freeze(actx.from_numpy(np.hstack([p[idim] for p in proxies])))
            for idim in range(self.ambient_dim)
            ])
        centers = make_obj_array([
            actx.freeze(centers_dev[idim])
            for idim in range(self.ambient_dim)
            ])

        assert pxyranges[-1] == proxies[0].shape[0]
        return proxies, actx.freeze(pxyranges), centers, actx.freeze(radii_dev)
Esempio n. 13
0
    def __call__(self, queue, indices, **kwargs):
        """Generate proxy points for each given range of source points in
        the discretization in :attr:`source`.

        :arg queue: a :class:`pyopencl.CommandQueue`.
        :arg indices: a :class:`sumpy.tools.BlockIndexRanges`.

        :return: a tuple of ``(proxies, pxyranges, pxycenters, pxyranges)``,
            where each element is a :class:`pyopencl.array.Array`. The
            sizes of the arrays are as follows: ``pxycenters`` is of size
            ``(2, nranges)``, ``pxyradii`` is of size ``(nranges,)``,
            ``pxyranges`` is of size ``(nranges + 1,)`` and ``proxies`` is
            of size ``(2, nranges * nproxy)``. The proxy points in a range
            :math:`i` can be obtained by a slice
            ``proxies[pxyranges[i]:pxyranges[i + 1]]`` and are all at a
            distance ``pxyradii[i]`` from the range center ``pxycenters[i]``.
        """
        def _affine_map(v, A, b):
            return np.dot(A, v) + b

        from pytential import bind, sym
        radii = bind(self.source,
                     sym.expansion_radii(self.source.ambient_dim))(queue)
        center_int = bind(self.source,
                          sym.expansion_centers(self.source.ambient_dim,
                                                -1))(queue)
        center_ext = bind(self.source,
                          sym.expansion_centers(self.source.ambient_dim,
                                                +1))(queue)

        knl = self.get_kernel()
        _, (
            centers_dev,
            radii_dev,
        ) = knl(queue,
                sources=self.source.density_discr.nodes(),
                center_int=center_int,
                center_ext=center_ext,
                expansion_radii=radii,
                srcindices=indices.indices,
                srcranges=indices.ranges,
                **kwargs)
        centers = centers_dev.get()
        radii = radii_dev.get()

        proxies = np.empty(indices.nblocks, dtype=np.object)
        for i in range(indices.nblocks):
            proxies[i] = _affine_map(self.ref_points,
                                     A=(radii[i] * np.eye(self.ambient_dim)),
                                     b=centers[:, i].reshape(-1, 1))

        pxyranges = cl.array.arange(queue,
                                    0,
                                    proxies.shape[0] * proxies[0].shape[1] + 1,
                                    proxies[0].shape[1],
                                    dtype=indices.ranges.dtype)
        proxies = make_obj_array([
            cl.array.to_device(queue, np.hstack([p[idim] for p in proxies]))
            for idim in range(self.ambient_dim)
        ])
        centers = make_obj_array([
            centers_dev[idim].with_queue(queue).copy()
            for idim in range(self.ambient_dim)
        ])

        assert pxyranges[-1] == proxies[0].shape[0]
        return proxies, pxyranges, centers, radii_dev
Esempio n. 14
0
    def map_int_g(self, expr):
        lpot_source = self.places.get_geometry(expr.source.geometry)
        source_discr = self.places.get_discretization(expr.source.geometry,
                                                      expr.source.discr_stage)
        target_discr = self.places.get_discretization(expr.target.geometry,
                                                      expr.target.discr_stage)

        if source_discr is not target_discr:
            raise NotImplementedError

        result = 0
        for kernel, density in zip(expr.source_kernels, expr.densities):
            rec_density = self._blk_mapper.rec(density)
            if is_zero(rec_density):
                continue

            if not np.isscalar(rec_density):
                raise NotImplementedError

            actx = self.array_context
            kernel_args = _get_layer_potential_args(actx,
                                                    self.places,
                                                    expr,
                                                    context=self.context)
            local_expn = lpot_source.get_expansion_for_qbx_direct_eval(
                kernel.get_base_kernel(), (expr.target_kernel, ))

            from pytential.linalg import make_index_blockwise_product
            tgtindices, srcindices = make_index_blockwise_product(
                actx, self.index_set)

            from sumpy.qbx import LayerPotentialMatrixSubsetGenerator
            mat_gen = LayerPotentialMatrixSubsetGenerator(
                actx.context,
                local_expn,
                source_kernels=(kernel, ),
                target_kernels=(expr.target_kernel, ))

            assert abs(expr.qbx_forced_limit) > 0
            from pytential import bind, sym
            radii = bind(
                self.places,
                sym.expansion_radii(source_discr.ambient_dim,
                                    dofdesc=expr.target))(actx)
            centers = bind(
                self.places,
                sym.expansion_centers(source_discr.ambient_dim,
                                      expr.qbx_forced_limit,
                                      dofdesc=expr.target))(actx)

            _, (mat, ) = mat_gen(actx.queue,
                                 targets=flatten(target_discr.nodes(),
                                                 actx,
                                                 leaf_class=DOFArray),
                                 sources=flatten(source_discr.nodes(),
                                                 actx,
                                                 leaf_class=DOFArray),
                                 centers=flatten(centers,
                                                 actx,
                                                 leaf_class=DOFArray),
                                 expansion_radii=flatten(radii, actx),
                                 tgtindices=tgtindices,
                                 srcindices=srcindices,
                                 **kernel_args)

            waa = flatten(
                bind(
                    self.places,
                    sym.weights_and_area_elements(source_discr.ambient_dim,
                                                  dofdesc=expr.source))(actx),
                actx)
            mat *= waa[srcindices]

            result += actx.to_numpy(mat) * rec_density

        return result
Esempio n. 15
0
 def _flat_expansion_radii(dofdesc):
     radii = bind(
             bound_expr.places,
             sym.expansion_radii(self.ambient_dim, dofdesc=dofdesc),
             )(actx)
     return freeze(flatten(radii, actx), actx)
Esempio n. 16
0
def plot_proxy_geometry(actx,
                        places,
                        indices,
                        pxy=None,
                        nbrindices=None,
                        with_qbx_centers=False,
                        suffix=None):
    dofdesc = places.auto_source
    discr = places.get_discretization(dofdesc.geometry, dofdesc.discr_stage)
    ambient_dim = places.ambient_dim

    if suffix is None:
        suffix = f"{ambient_dim}d"
    suffix = suffix.replace(".", "_")

    import matplotlib.pyplot as pt
    pt.figure(figsize=(10, 8), dpi=300)
    pt.plot(np.diff(indices.ranges))
    pt.savefig(f"test_proxy_geometry_{suffix}_ranges")
    pt.clf()

    if ambient_dim == 2:
        sources = actx.to_numpy(flatten(discr.nodes(),
                                        actx)).reshape(ambient_dim, -1)

        if pxy is not None:
            proxies = np.stack(pxy.points)
            pxycenters = np.stack(pxy.centers)
            pxyranges = pxy.indices.ranges

        if with_qbx_centers:
            ci = actx.to_numpy(
                flatten(
                    bind(places, sym.expansion_centers(ambient_dim, -1))(actx),
                    actx)).reshape(ambient_dim, -1)
            ce = actx.to_numpy(
                flatten(
                    bind(places, sym.expansion_centers(ambient_dim, +1))(actx),
                    actx)).reshape(ambient_dim, -1)
            r = actx.to_numpy(
                flatten(
                    bind(places, sym.expansion_radii(ambient_dim))(actx),
                    actx))

        fig = pt.figure(figsize=(10, 8), dpi=300)
        if indices.indices.shape[0] != discr.ndofs:
            pt.plot(sources[0], sources[1], "ko", ms=2.0, alpha=0.5)

        for i in range(indices.nblocks):
            isrc = indices.block_indices(i)
            pt.plot(sources[0, isrc], sources[1, isrc], "o", ms=2.0)

            if with_qbx_centers:
                ax = pt.gca()
                for j in isrc:
                    c = pt.Circle(ci[:, j], r[j], color="k", alpha=0.1)
                    ax.add_artist(c)
                    c = pt.Circle(ce[:, j], r[j], color="k", alpha=0.1)
                    ax.add_artist(c)

            if pxy is not None:
                ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]]
                pt.plot(proxies[0, ipxy], proxies[1, ipxy], "o", ms=2.0)

            if nbrindices is not None:
                inbr = nbrindices.block_indices(i)
                pt.plot(sources[0, inbr], sources[1, inbr], "o", ms=2.0)

        pt.xlim([-2, 2])
        pt.ylim([-2, 2])
        pt.gca().set_aspect("equal")
        pt.savefig(f"test_proxy_geometry_{suffix}")
        pt.close(fig)
    elif ambient_dim == 3:
        from meshmode.discretization.visualization import make_visualizer
        marker = -42.0 * np.ones(discr.ndofs)

        for i in range(indices.nblocks):
            isrc = indices.block_indices(i)
            marker[isrc] = 10.0 * (i + 1.0)

        template_ary = thaw(discr.nodes()[0], actx)
        marker_dev = unflatten(template_ary, actx.from_numpy(marker), actx)

        vis = make_visualizer(actx, discr)
        vis.write_vtk_file(f"test_proxy_geometry_{suffix}.vtu",
                           [("marker", marker_dev)],
                           overwrite=False)

        if nbrindices:
            for i in range(indices.nblocks):
                isrc = indices.block_indices(i)
                inbr = nbrindices.block_indices(i)

                marker.fill(0.0)
                marker[indices.indices] = 0.0
                marker[isrc] = -42.0
                marker[inbr] = +42.0
                marker_dev = unflatten(template_ary, actx.from_numpy(marker),
                                       actx)

                vis.write_vtk_file(
                    f"test_proxy_geometry_{suffix}_neighbor_{i:04d}.vtu",
                    [("marker", marker_dev)],
                    overwrite=False)

        if pxy:
            # NOTE: this does not plot the actual proxy points, just sphere
            # with the same center and radius as the proxy balls
            from meshmode.mesh.processing import (affine_map,
                                                  merge_disjoint_meshes)
            from meshmode.discretization import Discretization
            from meshmode.discretization.poly_element import \
                InterpolatoryQuadratureSimplexGroupFactory

            from meshmode.mesh.generation import generate_sphere
            ref_mesh = generate_sphere(1, 4, uniform_refinement_rounds=1)
            pxycenters = np.stack(pxy.centers)

            for i in range(indices.nblocks):
                mesh = affine_map(ref_mesh,
                                  A=pxy.radii[i],
                                  b=pxycenters[:, i].reshape(-1))

                mesh = merge_disjoint_meshes([mesh, discr.mesh])
                discr = Discretization(
                    actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(4))

                vis = make_visualizer(actx, discr)
                filename = f"test_proxy_geometry_{suffix}_block_{i:04d}.vtu"
                vis.write_vtk_file(filename, [], overwrite=False)
    else:
        raise ValueError
Esempio n. 17
0
    def find_centers(self,
                     places,
                     dofdesc,
                     tree,
                     peer_lists,
                     target_status,
                     target_flags,
                     target_assoc,
                     target_association_tolerance,
                     debug,
                     wait_for=None):
        from pytential import bind, sym
        ambient_dim = places.ambient_dim

        # Round up level count--this gets included in the kernel as
        # a stack bound. Rounding avoids too many kernel versions.
        from pytools import div_ceil
        max_levels = 10 * div_ceil(tree.nlevels, 10)

        knl = self.code_container.center_finder(
            tree.dimensions, tree.coord_dtype, tree.box_id_dtype,
            peer_lists.peer_list_starts.dtype, tree.particle_id_dtype,
            max_levels)

        if debug:
            target_status.finish()
            marked_target_count = int(cl.array.sum(target_status).get())

        # Perform a space invader query over the centers.
        center_slice = (
            tree.sorted_target_ids[tree.qbx_user_center_slice].with_queue(
                self.queue))
        centers = [
            axis.with_queue(self.queue)[center_slice] for axis in tree.sources
        ]
        expansion_radii_by_center = bind(
            places,
            sym.expansion_radii(ambient_dim,
                                granularity=sym.GRANULARITY_CENTER,
                                dofdesc=dofdesc))(self.array_context)
        expansion_radii_by_center_with_tolerance = flatten(
            expansion_radii_by_center * (1 + target_association_tolerance))

        # Idea:
        #
        # (1) Tag leaf boxes around centers with max distance to usable center.
        # (2) Area query from targets with those radii to find closest eligible
        # center in terms of relative distance.

        box_to_search_dist, evt = self.code_container.space_invader_query()(
            self.queue,
            tree,
            centers,
            expansion_radii_by_center_with_tolerance,
            peer_lists,
            wait_for=wait_for)
        wait_for = [evt]

        def make_target_field(fill_val, dtype=tree.coord_dtype):
            arr = cl.array.empty(self.queue, tree.nqbxtargets, dtype)
            arr.fill(fill_val)
            wait_for.extend(arr.events)
            return arr

        target_to_center_plus = make_target_field(-1, np.int32)
        target_to_center_minus = make_target_field(-1, np.int32)

        min_dist_to_center_plus = make_target_field(np.inf)
        min_dist_to_center_minus = make_target_field(np.inf)

        min_rel_dist_to_center_plus = make_target_field(np.inf)
        min_rel_dist_to_center_minus = make_target_field(np.inf)

        evt = knl(*unwrap_args(
            tree, peer_lists, tree.box_to_qbx_center_starts,
            tree.box_to_qbx_center_lists, tree.qbx_user_center_slice.start,
            tree.qbx_user_target_slice.start, tree.sorted_target_ids,
            expansion_radii_by_center_with_tolerance, box_to_search_dist,
            target_flags, target_status, target_assoc.target_to_center,
            target_to_center_plus, target_to_center_minus,
            min_dist_to_center_plus, min_dist_to_center_minus,
            min_rel_dist_to_center_plus, min_rel_dist_to_center_minus,
            *tree.sources),
                  range=slice(tree.nqbxtargets),
                  queue=self.queue,
                  wait_for=wait_for)

        if debug:
            target_status.finish()
            # Associated target = 2, marked target = 1
            ntargets_associated = (int(cl.array.sum(target_status).get()) -
                                   marked_target_count)
            assert ntargets_associated >= 0
            logger.debug(
                "target association: {} targets were assigned centers".format(
                    ntargets_associated))

        cl.wait_for_events([evt])
Esempio n. 18
0
def test_proxy_generator(ctx_factory, ndim, factor, visualize=False):
    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    qbx = _build_qbx_discr(queue, ndim=ndim)
    srcindices = _build_block_index(qbx.density_discr, factor=factor)

    from pytential.linalg.proxy import ProxyGenerator
    generator = ProxyGenerator(qbx, ratio=1.1)
    proxies, pxyranges, pxycenters, pxyradii = generator(queue, srcindices)

    proxies = np.vstack([p.get() for p in proxies])
    pxyranges = pxyranges.get()
    pxycenters = np.vstack([c.get() for c in pxycenters])
    pxyradii = pxyradii.get()

    for i in range(srcindices.nblocks):
        ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]]

        r = la.norm(proxies[:, ipxy] - pxycenters[:, i].reshape(-1, 1), axis=0)
        assert np.allclose(r - pxyradii[i], 0.0, atol=1.0e-14)

    srcindices = srcindices.get(queue)
    if visualize:
        if qbx.ambient_dim == 2:
            import matplotlib.pyplot as pt

            density_nodes = qbx.density_discr.nodes().get(queue)
            ci = bind(qbx, sym.expansion_centers(qbx.ambient_dim, -1))(queue)
            ci = np.vstack([c.get(queue) for c in ci])
            ce = bind(qbx, sym.expansion_centers(qbx.ambient_dim, +1))(queue)
            ce = np.vstack([c.get(queue) for c in ce])
            r = bind(qbx, sym.expansion_radii(qbx.ambient_dim))(queue).get()

            for i in range(srcindices.nblocks):
                isrc = srcindices.block_indices(i)
                ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]]

                pt.figure(figsize=(10, 8))
                axis = pt.gca()
                for j in isrc:
                    c = pt.Circle(ci[:, j], r[j], color='k', alpha=0.1)
                    axis.add_artist(c)
                    c = pt.Circle(ce[:, j], r[j], color='k', alpha=0.1)
                    axis.add_artist(c)

                pt.plot(density_nodes[0],
                        density_nodes[1],
                        'ko',
                        ms=2.0,
                        alpha=0.5)
                pt.plot(density_nodes[0, srcindices.indices],
                        density_nodes[1, srcindices.indices],
                        'o',
                        ms=2.0)
                pt.plot(density_nodes[0, isrc],
                        density_nodes[1, isrc],
                        'o',
                        ms=2.0)
                pt.plot(proxies[0, ipxy], proxies[1, ipxy], 'o', ms=2.0)
                pt.xlim([-1.5, 1.5])
                pt.ylim([-1.5, 1.5])

                filename = "test_proxy_generator_{}d_{:04}.png".format(ndim, i)
                pt.savefig(filename, dpi=300)
                pt.clf()
        else:
            from meshmode.discretization.visualization import make_visualizer
            from meshmode.mesh.processing import (  # noqa
                affine_map, merge_disjoint_meshes)
            from meshmode.discretization import Discretization
            from meshmode.discretization.poly_element import \
                InterpolatoryQuadratureSimplexGroupFactory

            from meshmode.mesh.generation import generate_icosphere
            ref_mesh = generate_icosphere(1, generator.nproxy)

            # NOTE: this does not plot the actual proxy points
            for i in range(srcindices.nblocks):
                mesh = affine_map(ref_mesh,
                                  A=(pxyradii[i] * np.eye(ndim)),
                                  b=pxycenters[:, i].reshape(-1))

                mesh = merge_disjoint_meshes([mesh, qbx.density_discr.mesh])
                discr = Discretization(
                    ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(10))

                vis = make_visualizer(queue, discr, 10)
                filename = "test_proxy_generator_{}d_{:04}.vtu".format(ndim, i)
                vis.write_vtk_file(filename, [])
Esempio n. 19
0
def run_source_refinement_test(ctx_factory, mesh, order, helmholtz_k=None):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import (
        InterpolatoryQuadratureSimplexGroupFactory)

    factory = InterpolatoryQuadratureSimplexGroupFactory(order)

    discr = Discretization(cl_ctx, mesh, factory)

    from pytential.qbx.refinement import (RefinerCodeContainer,
                                          refine_for_global_qbx)

    from pytential.qbx.utils import TreeCodeContainer

    lpot_source = QBXLayerPotentialSource(
        discr,
        qbx_order=order,  # not used in refinement
        fine_order=order)
    del discr

    expansion_disturbance_tolerance = 0.025
    refiner_extra_kwargs = {
        "expansion_disturbance_tolerance": expansion_disturbance_tolerance,
    }
    if helmholtz_k is not None:
        refiner_extra_kwargs["kernel_length_scale"] = 5 / helmholtz_k

    lpot_source, conn = refine_for_global_qbx(
        lpot_source,
        RefinerCodeContainer(cl_ctx,
                             TreeCodeContainer(cl_ctx)).get_wrangler(queue),
        factory, **refiner_extra_kwargs)

    discr_nodes = lpot_source.density_discr.nodes().get(queue)
    fine_discr_nodes = \
            lpot_source.quad_stage2_density_discr.nodes().get(queue)

    int_centers = bind(lpot_source,
                       sym.expansion_centers(lpot_source.ambient_dim,
                                             -1))(queue)
    int_centers = np.array([axis.get(queue) for axis in int_centers])
    ext_centers = bind(lpot_source,
                       sym.expansion_centers(lpot_source.ambient_dim,
                                             +1))(queue)
    ext_centers = np.array([axis.get(queue) for axis in ext_centers])

    expansion_radii = bind(lpot_source,
                           sym.expansion_radii(
                               lpot_source.ambient_dim))(queue).get()
    source_danger_zone_radii = bind(
        lpot_source,
        sym._source_danger_zone_radii(
            lpot_source.ambient_dim,
            dofdesc=sym.GRANULARITY_ELEMENT))(queue).get()

    quad_res = bind(
        lpot_source,
        sym._quad_resolution(lpot_source.ambient_dim,
                             dofdesc=sym.GRANULARITY_ELEMENT))(queue)

    # {{{ check if satisfying criteria

    def check_disk_undisturbed_by_sources(centers_panel, sources_panel):
        if centers_panel.element_nr == sources_panel.element_nr:
            # Same panel
            return

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = discr_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # A center cannot be closer to another panel than to its originating
        # panel.

        rad = expansion_radii[centers_panel.discr_slice]
        assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \
                (dist, rad, centers_panel.element_nr, sources_panel.element_nr)

    def check_sufficient_quadrature_resolution(centers_panel, sources_panel):
        dz_radius = source_danger_zone_radii[sources_panel.element_nr]

        my_int_centers = int_centers[:, centers_panel.discr_slice]
        my_ext_centers = ext_centers[:, centers_panel.discr_slice]
        all_centers = np.append(my_int_centers, my_ext_centers, axis=-1)

        nodes = fine_discr_nodes[:, sources_panel.discr_slice]

        # =distance(centers of panel 1, panel 2)
        dist = (la.norm(
            (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T,
            axis=-1).min())

        # Criterion:
        # The quadrature contribution from each panel is as accurate
        # as from the center's own source panel.
        assert dist >= dz_radius, \
                (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr)

    def check_quad_res_to_helmholtz_k_ratio(panel):
        # Check wavenumber to panel size ratio.
        assert quad_res[panel.element_nr] * helmholtz_k <= 5

    for i, panel_1 in enumerate(iter_elements(lpot_source.density_discr)):
        for panel_2 in iter_elements(lpot_source.density_discr):
            check_disk_undisturbed_by_sources(panel_1, panel_2)
        for panel_2 in iter_elements(lpot_source.quad_stage2_density_discr):
            check_sufficient_quadrature_resolution(panel_1, panel_2)
        if helmholtz_k is not None:
            check_quad_res_to_helmholtz_k_ratio(panel_1)
Esempio n. 20
0
    def exec_compute_potential_insn_direct(self, actx, insn, bound_expr,
                                           evaluate, return_timing_data):
        from pytential import bind, sym
        if return_timing_data:
            from pytential.source import UnableToCollectTimingData
            from warnings import warn
            warn("Timing data collection not supported.",
                 category=UnableToCollectTimingData)

        lpot_applier = self.get_lpot_applier(insn.target_kernels,
                                             insn.source_kernels)
        p2p = None
        lpot_applier_on_tgt_subset = None

        from pytential.utils import flatten_if_needed
        kernel_args = {}
        for arg_name, arg_expr in insn.kernel_arguments.items():
            kernel_args[arg_name] = flatten_if_needed(actx, evaluate(arg_expr))

        waa = bind(
            bound_expr.places,
            sym.weights_and_area_elements(self.ambient_dim,
                                          dofdesc=insn.source))(actx)
        strength_vecs = [waa * evaluate(density) for density in insn.densities]

        from meshmode.discretization import Discretization
        flat_strengths = [flatten(strength) for strength in strength_vecs]

        source_discr = bound_expr.places.get_discretization(
            insn.source.geometry, insn.source.discr_stage)

        # FIXME: Do this all at once
        results = []
        for o in insn.outputs:
            source_dd = insn.source.copy(discr_stage=o.target_name.discr_stage)
            target_discr = bound_expr.places.get_discretization(
                o.target_name.geometry, o.target_name.discr_stage)
            density_discr = bound_expr.places.get_discretization(
                source_dd.geometry, source_dd.discr_stage)

            is_self = density_discr is target_discr
            if is_self:
                # QBXPreprocessor is supposed to have taken care of this
                assert o.qbx_forced_limit is not None
                assert abs(o.qbx_forced_limit) > 0

                expansion_radii = bind(
                    bound_expr.places,
                    sym.expansion_radii(self.ambient_dim,
                                        dofdesc=o.target_name))(actx)
                centers = bind(
                    bound_expr.places,
                    sym.expansion_centers(self.ambient_dim,
                                          o.qbx_forced_limit,
                                          dofdesc=o.target_name))(actx)

                evt, output_for_each_kernel = lpot_applier(
                    actx.queue,
                    flatten(thaw(actx, target_discr.nodes())),
                    flatten(thaw(actx, source_discr.nodes())),
                    flatten(centers),
                    flat_strengths,
                    expansion_radii=flatten(expansion_radii),
                    **kernel_args)

                result = output_for_each_kernel[o.target_kernel_index]
                if isinstance(target_discr, Discretization):
                    result = unflatten(actx, target_discr, result)

                results.append((o.name, result))
            else:
                # no on-disk kernel caching
                if p2p is None:
                    p2p = self.get_p2p(actx, insn.target_kernels,
                                       insn.source_kernels)
                if lpot_applier_on_tgt_subset is None:
                    lpot_applier_on_tgt_subset = self.get_lpot_applier_on_tgt_subset(
                        insn.target_kernels, insn.source_kernels)

                queue = actx.queue

                flat_targets = flatten_if_needed(actx, target_discr.nodes())
                flat_sources = flatten(thaw(actx, source_discr.nodes()))

                evt, output_for_each_kernel = p2p(queue, flat_targets,
                                                  flat_sources, flat_strengths,
                                                  **kernel_args)

                qbx_forced_limit = o.qbx_forced_limit
                if qbx_forced_limit is None:
                    qbx_forced_limit = 0

                target_discrs_and_qbx_sides = ((target_discr,
                                                qbx_forced_limit), )
                geo_data = self.qbx_fmm_geometry_data(
                    bound_expr.places,
                    insn.source.geometry,
                    target_discrs_and_qbx_sides=target_discrs_and_qbx_sides)

                # center-related info is independent of targets

                # First ncenters targets are the centers
                tgt_to_qbx_center = (
                    geo_data.user_target_to_center()[geo_data.ncenters:].copy(
                        queue=queue).with_queue(queue))

                qbx_tgt_numberer = self.get_qbx_target_numberer(
                    tgt_to_qbx_center.dtype)
                qbx_tgt_count = cl.array.empty(queue, (), np.int32)
                qbx_tgt_numbers = cl.array.empty_like(tgt_to_qbx_center)

                qbx_tgt_numberer(tgt_to_qbx_center,
                                 qbx_tgt_numbers,
                                 qbx_tgt_count,
                                 queue=queue)

                qbx_tgt_count = int(qbx_tgt_count.get())

                if (o.qbx_forced_limit is not None
                        and abs(o.qbx_forced_limit) == 1
                        and qbx_tgt_count < target_discr.ndofs):
                    raise RuntimeError("Did not find a matching QBX center "
                                       "for some targets")

                qbx_tgt_numbers = qbx_tgt_numbers[:qbx_tgt_count]
                qbx_center_numbers = tgt_to_qbx_center[qbx_tgt_numbers]
                qbx_center_numbers.finish()

                tgt_subset_kwargs = kernel_args.copy()
                for i, res_i in enumerate(output_for_each_kernel):
                    tgt_subset_kwargs[f"result_{i}"] = res_i

                if qbx_tgt_count:
                    lpot_applier_on_tgt_subset(
                        queue,
                        targets=flat_targets,
                        sources=flat_sources,
                        centers=geo_data.flat_centers(),
                        expansion_radii=geo_data.flat_expansion_radii(),
                        strengths=flat_strengths,
                        qbx_tgt_numbers=qbx_tgt_numbers,
                        qbx_center_numbers=qbx_center_numbers,
                        **tgt_subset_kwargs)

                result = output_for_each_kernel[o.target_kernel_index]
                if isinstance(target_discr, Discretization):
                    result = unflatten(actx, target_discr, result)

                results.append((o.name, result))

        timing_data = {}
        return results, timing_data
Esempio n. 21
0
    def map_int_g(self, expr):
        lpot_source = self.places.get_geometry(expr.source.geometry)
        source_discr = self.places.get_discretization(expr.source.geometry,
                                                      expr.source.discr_stage)
        target_discr = self.places.get_discretization(expr.target.geometry,
                                                      expr.target.discr_stage)

        result = 0
        for kernel, density in zip(expr.source_kernels, expr.densities):
            rec_density = self.rec(density)
            if is_zero(rec_density):
                continue

            assert isinstance(rec_density, np.ndarray)
            if not self.is_kind_matrix(rec_density):
                raise NotImplementedError("layer potentials on non-variables")

            actx = self.array_context
            kernel_args = _get_layer_potential_args(actx,
                                                    self.places,
                                                    expr,
                                                    context=self.context)
            local_expn = lpot_source.get_expansion_for_qbx_direct_eval(
                kernel.get_base_kernel(), (expr.target_kernel, ))

            from sumpy.qbx import LayerPotentialMatrixGenerator
            mat_gen = LayerPotentialMatrixGenerator(
                actx.context,
                expansion=local_expn,
                source_kernels=(kernel, ),
                target_kernels=(expr.target_kernel, ))

            assert abs(expr.qbx_forced_limit) > 0
            from pytential import bind, sym
            radii = bind(
                self.places,
                sym.expansion_radii(source_discr.ambient_dim,
                                    dofdesc=expr.target))(actx)
            centers = bind(
                self.places,
                sym.expansion_centers(source_discr.ambient_dim,
                                      expr.qbx_forced_limit,
                                      dofdesc=expr.target))(actx)

            _, (mat, ) = mat_gen(actx.queue,
                                 targets=flatten(target_discr.nodes(),
                                                 actx,
                                                 leaf_class=DOFArray),
                                 sources=flatten(source_discr.nodes(),
                                                 actx,
                                                 leaf_class=DOFArray),
                                 centers=flatten(centers,
                                                 actx,
                                                 leaf_class=DOFArray),
                                 expansion_radii=flatten(radii, actx),
                                 **kernel_args)
            mat = actx.to_numpy(mat)

            waa = bind(
                self.places,
                sym.weights_and_area_elements(source_discr.ambient_dim,
                                              dofdesc=expr.source))(actx)
            mat[:, :] *= actx.to_numpy(flatten(waa, actx))

            result += mat @ rec_density

        return result