Example #1
0
def test_target_association_failure(ctx_factory):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # {{{ generate circle

    order = 5
    nelements = 40

    # Make the curve mesh.
    curve_f = partial(ellipse, 1)
    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 and check

    close_circle = 0.999 * np.exp(
        2j * np.pi * np.linspace(0, 1, 500, endpoint=False))
    from pytential.target import PointsTarget
    close_circle_target = (PointsTarget(
        actx.from_numpy(np.array([close_circle.real, close_circle.imag]))))

    targets = ((close_circle_target, 0), )

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

    from pytential.qbx.utils import TreeCodeContainer

    code_container = TargetAssociationCodeContainer(actx,
                                                    TreeCodeContainer(actx))

    with pytest.raises(QBXTargetAssociationFailedException):
        associate_targets_to_qbx_centers(places,
                                         places.auto_source,
                                         code_container.get_wrangler(actx),
                                         targets,
                                         target_association_tolerance=1e-10)
Example #2
0
def test_target_association_failure(ctx_getter):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    # {{{ generate circle

    order = 5
    nelements = 40

    # Make the curve mesh.
    curve_f = partial(ellipse, 1)
    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(cl_ctx, mesh, factory)
    lpot_source = QBXLayerPotentialSource(discr,
            qbx_order=order,  # not used in target association
            fine_order=order)

    # }}}

    # {{{ generate targets and check

    close_circle = 0.999 * np.exp(
        2j * np.pi * np.linspace(0, 1, 500, endpoint=False))
    from pytential.target import PointsTarget
    close_circle_target = (
        PointsTarget(cl.array.to_device(
            queue, np.array([close_circle.real, close_circle.imag]))))

    targets = (
        (close_circle_target, 0),
        )

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

    from pytential.qbx.utils import TreeCodeContainer

    code_container = TargetAssociationCodeContainer(
            cl_ctx, TreeCodeContainer(cl_ctx))

    with pytest.raises(QBXTargetAssociationFailedException):
        associate_targets_to_qbx_centers(
            lpot_source,
            code_container.get_wrangler(queue),
            targets,
            target_association_tolerance=1e-10)
Example #3
0
def _get_centers_and_expansion_radii(queue, source, target_discr,
                                     qbx_forced_limit):
    """
    :arg queue: a :class:`pyopencl.CommandQueue`.
    :arg source: a :class:`pytential.source.LayerPotentialSourceBase`.
    :arg target_discr: a :class:`meshmode.discretization.Discretization`.
    :arg qbx_forced_limit: an integer (*+1* or *-1*).

    :return: a tuple of `(centers, radii)` for each node in *target_discr*.
    """

    if source.density_discr is target_discr:
        # NOTE: skip expensive target association
        centers = bind(
            source, sym.expansion_centers(source.ambient_dim,
                                          qbx_forced_limit))(queue)
        radii = bind(source, sym.expansion_radii(source.ambient_dim))(queue)
    else:
        from pytential.qbx.utils import get_interleaved_centers
        centers = get_interleaved_centers(queue, source)
        radii = bind(
            source,
            sym.expansion_radii(source.ambient_dim,
                                granularity=sym.GRANULARITY_CENTER))(queue)

        # NOTE: using a very small tolerance to make sure all the stage2
        # targets are associated to a center. We can't use the user provided
        # source.target_association_tolerance here because it will likely be
        # way too small.
        target_association_tolerance = 1.0e-1

        from pytential.qbx.target_assoc import associate_targets_to_qbx_centers
        code_container = source.target_association_code_container
        assoc = associate_targets_to_qbx_centers(
            source,
            code_container.get_wrangler(queue),
            [(target_discr, qbx_forced_limit)],
            target_association_tolerance=target_association_tolerance)

        centers = [
            cl.array.take(c, assoc.target_to_center, queue=queue)
            for c in centers
        ]
        radii = cl.array.take(radii, assoc.target_to_center, queue=queue)

    return centers, radii
Example #4
0
    def user_target_to_center(self):
        """Find which QBX center, if any, is to be used for each target.
        :attr:`target_state.NO_QBX_NEEDED` if none. :attr:`target_state.FAILED`
        if a center needs to be used, but none was found.
        See :meth:`center_to_tree_targets` for the reverse look-up table.

        Shape: ``[ntargets]`` of :attr:`boxtree.Tree.particle_id_dtype`, with extra
        values from :class:`target_state` allowed. Targets occur in user order.
        """
        from pytential.qbx.target_assoc import associate_targets_to_qbx_centers
        target_info = self.target_info()

        from pytential.target import PointsTarget

        queue = self.array_context.queue

        target_side_prefs = (
            self.target_side_preferences()[self.ncenters:].get(queue=queue))

        target_discrs_and_qbx_sides = [
            (PointsTarget(target_info.targets[:, self.ncenters:]),
             target_side_prefs.astype(np.int32))
        ]

        target_association_wrangler = (
            self.lpot_source.target_association_code_container.get_wrangler(
                self.array_context))

        tgt_assoc_result = associate_targets_to_qbx_centers(
            self.places,
            self.source_dd,
            target_association_wrangler,
            target_discrs_and_qbx_sides,
            target_association_tolerance=(self.target_association_tolerance),
            debug=self.debug)

        result = cl.array.empty(queue, target_info.ntargets,
                                tgt_assoc_result.target_to_center.dtype)
        result[:self.ncenters].fill(target_state.NO_QBX_NEEDED)
        result[self.ncenters:] = tgt_assoc_result.target_to_center

        return result.with_queue(None)
Example #5
0
    def user_target_to_center(self):
        """Find which QBX center, if any, is to be used for each target.
        :attr:`target_state.NO_QBX_NEEDED` if none. :attr:`target_state.FAILED`
        if a center needs to be used, but none was found.
        See :meth:`center_to_tree_targets` for the reverse look-up table.

        Shape: ``[ntargets]`` of :attr:`boxtree.Tree.particle_id_dtype`, with extra
        values from :class:`target_state` allowed. Targets occur in user order.
        """
        from pytential.qbx.target_assoc import associate_targets_to_qbx_centers
        tgt_info = self.target_info()

        from pytential.target import PointsTarget

        with cl.CommandQueue(self.cl_context) as queue:
            target_side_prefs = (self
                    .target_side_preferences()[self.ncenters:].get(queue=queue))

            target_discrs_and_qbx_sides = [(
                    PointsTarget(tgt_info.targets[:, self.ncenters:]),
                    target_side_prefs.astype(np.int32))]

            target_association_wrangler = (
                    self.lpot_source.target_association_code_container
                    .get_wrangler(queue))

            tgt_assoc_result = associate_targets_to_qbx_centers(
                    self.lpot_source,
                    target_association_wrangler,
                    target_discrs_and_qbx_sides,
                    target_association_tolerance=(
                        self.target_association_tolerance))

            result = cl.array.empty(queue, tgt_info.ntargets,
                    tgt_assoc_result.target_to_center.dtype)
            result[:self.ncenters].fill(target_state.NO_QBX_NEEDED)
            result[self.ncenters:] = tgt_assoc_result.target_to_center

        return result.with_queue(None)
Example #6
0
def _get_centers_and_expansion_radii(queue, source, target_discr, qbx_forced_limit):
    """
    :arg queue: a :class:`pyopencl.CommandQueue`.
    :arg source: a :class:`pytential.source.LayerPotentialSourceBase`.
    :arg target_discr: a :class:`meshmode.discretization.Discretization`.
    :arg qbx_forced_limit: an integer (*+1* or *-1*).

    :return: a tuple of `(centers, radii)` for each node in *target_discr*.
    """

    if source.density_discr is target_discr:
        # NOTE: skip expensive target association
        from pytential.qbx.utils import get_centers_on_side
        centers = get_centers_on_side(source, qbx_forced_limit)
        radii = source._expansion_radii('nsources')
    else:
        from pytential.qbx.utils import get_interleaved_centers
        centers = get_interleaved_centers(queue, source)
        radii = source._expansion_radii('ncenters')

        # NOTE: using a very small tolerance to make sure all the stage2
        # targets are associated to a center. We can't use the user provided
        # source.target_association_tolerance here because it will likely be
        # way too small.
        target_association_tolerance = 1.0e-1

        from pytential.qbx.target_assoc import associate_targets_to_qbx_centers
        code_container = source.target_association_code_container
        assoc = associate_targets_to_qbx_centers(
                source,
                code_container.get_wrangler(queue),
                [(target_discr, qbx_forced_limit)],
                target_association_tolerance=target_association_tolerance)

        centers = [cl.array.take(c, assoc.target_to_center, queue=queue)
                   for c in centers]
        radii = cl.array.take(radii, assoc.target_to_center, queue=queue)

    return centers, radii
Example #7
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()
Example #8
0
def test_target_association(ctx_getter, curve_name, curve_f, nelements,
        visualize=False):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    # {{{ 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(cl_ctx, mesh, factory)

    lpot_source, conn = QBXLayerPotentialSource(discr,
            qbx_order=order,  # not used in target association
            fine_order=order).with_refinement()
    del discr

    from pytential.qbx.utils import get_interleaved_centers
    centers = np.array([ax.get(queue)
            for ax in get_interleaved_centers(queue, lpot_source)])

    # }}}

    # {{{ generate targets

    from pyopencl.clrandom import PhiloxGenerator
    rng = PhiloxGenerator(cl_ctx, seed=RNG_SEED)
    nsources = lpot_source.density_discr.nnodes
    noise = rng.uniform(queue, nsources, dtype=np.float, a=0.01, b=1.0)
    tunnel_radius = \
            lpot_source._close_target_tunnel_radius("nsources").with_queue(queue)

    def targets_from_sources(sign, dist):
        from pytential import sym, bind
        dim = 2
        nodes = bind(lpot_source.density_discr, sym.nodes(dim))(queue)
        normals = bind(lpot_source.density_discr, sym.normal(dim))(queue)
        return (nodes + normals * sign * dist).as_vector(np.object)

    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
        (lpot_source.density_discr, -1),
        # On-surface targets, exterior
        (lpot_source.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.nnodes 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(
            cl_ctx, TreeCodeContainer(cl_ctx))

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

    expansion_radii = lpot_source._expansion_radii("ncenters").get(queue)

    surf_targets = np.array(
            [axis.get(queue) for axis in lpot_source.density_discr.nodes()])
    int_targets = np.array([axis.get(queue) for axis in int_targets.nodes()])
    ext_targets = np.array([axis.get(queue) for axis in ext_targets.nodes()])

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

        draw_curve(lpot_source.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()