コード例 #1
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_area_query_elwise(ctx_getter, dims, do_plot=False):
    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**5
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    from boxtree.area_query import (
        AreaQueryElementwiseTemplate, PeerListFinder)

    template = AreaQueryElementwiseTemplate(
        extra_args="""
            coord_t *ball_radii,
            %for ax in AXIS_NAMES[:dimensions]:
                coord_t *ball_${ax},
            %endfor
        """,
        ball_center_and_radius_expr="""
            %for ax in AXIS_NAMES[:dimensions]:
                ${ball_center}.${ax} = ball_${ax}[${i}];
            %endfor
            ${ball_radius} = ball_radii[${i}];
        """,
        leaf_found_op="")

    peer_lists, evt = PeerListFinder(ctx)(queue, tree)

    kernel = template.generate(
        ctx,
        dims,
        tree.coord_dtype,
        tree.box_id_dtype,
        peer_lists.peer_list_starts.dtype,
        tree.nlevels)

    evt = kernel(
        *template.unwrap_args(
            tree, peer_lists, ball_radii, *ball_centers),
        queue=queue,
        wait_for=[evt],
        range=slice(len(ball_radii)))

    cl.wait_for_events([evt])
コード例 #2
0
def test_leaves_to_balls_query(ctx_factory, dims, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**5
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    from boxtree.area_query import LeavesToBallsLookupBuilder
    lblb = LeavesToBallsLookupBuilder(ctx)

    lbl, _ = lblb(queue, tree, ball_centers, ball_radii)

    # get data to host for test
    tree = tree.get(queue=queue)
    lbl = lbl.get(queue=queue)
    ball_centers = np.array([x.get() for x in ball_centers]).T
    ball_radii = ball_radii.get()

    assert len(lbl.balls_near_box_starts) == tree.nboxes + 1

    from boxtree import box_flags_enum

    for ibox in range(tree.nboxes):
        # We only want leaves here.
        if tree.box_flags[ibox] & box_flags_enum.HAS_CHILDREN:
            continue

        box_center = tree.box_centers[:, ibox]
        ext_l, ext_h = tree.get_box_extent(ibox)
        box_rad = 0.5 * (ext_h - ext_l)[0]

        linf_circle_dists = np.max(np.abs(ball_centers - box_center), axis=-1)
        near_circles, = np.where(linf_circle_dists - ball_radii < box_rad)

        start, end = lbl.balls_near_box_starts[ibox:ibox + 2]
        assert sorted(
            lbl.balls_near_box_lists[start:end]) == sorted(near_circles)
コード例 #3
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_leaves_to_balls_query(ctx_getter, dims, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**5
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    from boxtree.area_query import LeavesToBallsLookupBuilder
    lblb = LeavesToBallsLookupBuilder(ctx)

    lbl, _ = lblb(queue, tree, ball_centers, ball_radii)

    # get data to host for test
    tree = tree.get(queue=queue)
    lbl = lbl.get(queue=queue)
    ball_centers = np.array([x.get() for x in ball_centers]).T
    ball_radii = ball_radii.get()

    assert len(lbl.balls_near_box_starts) == tree.nboxes + 1

    from boxtree import box_flags_enum

    for ibox in range(tree.nboxes):
        # We only want leaves here.
        if tree.box_flags[ibox] & box_flags_enum.HAS_CHILDREN:
            continue

        box_center = tree.box_centers[:, ibox]
        ext_l, ext_h = tree.get_box_extent(ibox)
        box_rad = 0.5*(ext_h-ext_l)[0]

        linf_circle_dists = np.max(np.abs(ball_centers-box_center), axis=-1)
        near_circles, = np.where(linf_circle_dists - ball_radii < box_rad)

        start, end = lbl.balls_near_box_starts[ibox:ibox+2]
        assert sorted(lbl.balls_near_box_lists[start:end]) == sorted(near_circles)
コード例 #4
0
def test_area_query_elwise(ctx_factory, dims, do_plot=False):
    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**5
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    from boxtree.area_query import (AreaQueryElementwiseTemplate,
                                    PeerListFinder)

    template = AreaQueryElementwiseTemplate(extra_args="""
            coord_t *ball_radii,
            %for ax in AXIS_NAMES[:dimensions]:
                coord_t *ball_${ax},
            %endfor
        """,
                                            ball_center_and_radius_expr="""
            %for ax in AXIS_NAMES[:dimensions]:
                ${ball_center}.${ax} = ball_${ax}[${i}];
            %endfor
            ${ball_radius} = ball_radii[${i}];
        """,
                                            leaf_found_op="")

    peer_lists, evt = PeerListFinder(ctx)(queue, tree)

    kernel = template.generate(ctx, dims, tree.coord_dtype, tree.box_id_dtype,
                               peer_lists.peer_list_starts.dtype, tree.nlevels)

    evt = kernel(*template.unwrap_args(tree, peer_lists, ball_radii,
                                       *ball_centers),
                 queue=queue,
                 wait_for=[evt],
                 range=slice(len(ball_radii)))

    cl.wait_for_events([evt])
コード例 #5
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_bounding_box(ctx_getter, dtype, dims, nparticles):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    from boxtree.tools import AXIS_NAMES
    from boxtree.bounding_box import BoundingBoxFinder

    bbf = BoundingBoxFinder(ctx)

    axis_names = AXIS_NAMES[:dims]

    logger.info("%s - %s %s" % (dtype, dims, nparticles))

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    bbox_min = [np.min(x.get()) for x in particles]
    bbox_max = [np.max(x.get()) for x in particles]

    bbox_cl, evt = bbf(particles, radii=None)
    bbox_cl = bbox_cl.get()

    bbox_min_cl = np.empty(dims, dtype)
    bbox_max_cl = np.empty(dims, dtype)

    for i, ax in enumerate(axis_names):
        bbox_min_cl[i] = bbox_cl["min_"+ax]
        bbox_max_cl[i] = bbox_cl["max_"+ax]

    assert (bbox_min == bbox_min_cl).all()
    assert (bbox_max == bbox_max_cl).all()
コード例 #6
0
def test_bounding_box(ctx_factory, dtype, dims, nparticles):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    from boxtree.tools import AXIS_NAMES
    from boxtree.bounding_box import BoundingBoxFinder

    bbf = BoundingBoxFinder(ctx)

    axis_names = AXIS_NAMES[:dims]

    logger.info("%s - %s %s" % (dtype, dims, nparticles))

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    bbox_min = [np.min(x.get()) for x in particles]
    bbox_max = [np.max(x.get()) for x in particles]

    bbox_cl, evt = bbf(particles, radii=None)
    bbox_cl = bbox_cl.get()

    bbox_min_cl = np.empty(dims, dtype)
    bbox_max_cl = np.empty(dims, dtype)

    for i, ax in enumerate(axis_names):
        bbox_min_cl[i] = bbox_cl["min_" + ax]
        bbox_max_cl[i] = bbox_cl["max_" + ax]

    assert (bbox_min == bbox_min_cl).all()
    assert (bbox_max == bbox_max_cl).all()
コード例 #7
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_area_query_balls_outside_bbox(ctx_getter, dims, do_plot=False):
    """
    The input to the area query includes balls whose centers are not within
    the tree bounding box.
    """
    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**4
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    from pyopencl.clrandom import PhiloxGenerator
    rng = PhiloxGenerator(ctx, seed=13)
    bbox_min = tree.bounding_box[0].min()
    bbox_max = tree.bounding_box[1].max()
    from pytools.obj_array import make_obj_array
    ball_centers = make_obj_array([
        rng.uniform(queue, nballs, dtype=dtype, a=bbox_min-1, b=bbox_max+1)
        for i in range(dims)])
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    run_area_query_test(ctx, queue, tree, ball_centers, ball_radii)
コード例 #8
0
def test_area_query(ctx_factory, dims, do_plot=False):
    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**5
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    run_area_query_test(ctx, queue, tree, ball_centers, ball_radii)
コード例 #9
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_area_query(ctx_getter, dims, do_plot=False):
    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**5
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    run_area_query_test(ctx, queue, tree, ball_centers, ball_radii)
コード例 #10
0
def test_area_query_balls_outside_bbox(ctx_factory, dims, do_plot=False):
    """
    The input to the area query includes balls whose centers are not within
    the tree bounding box.
    """
    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    nparticles = 10**4
    dtype = np.float64

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    from pyopencl.clrandom import PhiloxGenerator
    rng = PhiloxGenerator(ctx, seed=13)
    bbox_min = tree.bounding_box[0].min()
    bbox_max = tree.bounding_box[1].max()
    from pytools.obj_array import make_obj_array
    ball_centers = make_obj_array([
        rng.uniform(queue, nballs, dtype=dtype, a=bbox_min - 1, b=bbox_max + 1)
        for i in range(dims)
    ])
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    run_area_query_test(ctx, queue, tree, ball_centers, ball_radii)
コード例 #11
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def run_build_test(builder, queue, dims, dtype, nparticles, do_plot,
        max_particles_in_box=None, max_leaf_refine_weight=None,
        refine_weights=None, **kwargs):
    dtype = np.dtype(dtype)

    if dtype == np.float32:
        tol = 1e-4
    elif dtype == np.float64:
        tol = 1e-12
    else:
        raise RuntimeError("unsupported dtype: %s" % dtype)

    logger.info(75*"-")
    if max_particles_in_box is not None:
        logger.info("%dD %s - %d particles - max %d per box - %s" % (
            dims, dtype.type.__name__, nparticles, max_particles_in_box,
            " - ".join("%s: %s" % (k, v) for k, v in six.iteritems(kwargs))))
    else:
        logger.info("%dD %s - %d particles - max leaf weight %d  - %s" % (
            dims, dtype.type.__name__, nparticles, max_leaf_refine_weight,
            " - ".join("%s: %s" % (k, v) for k, v in six.iteritems(kwargs))))
    logger.info(75*"-")

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    queue.finish()

    tree, _ = builder(queue, particles,
                      max_particles_in_box=max_particles_in_box,
                      refine_weights=refine_weights,
                      max_leaf_refine_weight=max_leaf_refine_weight,
                      debug=True, **kwargs)
    tree = tree.get(queue=queue)

    sorted_particles = np.array(list(tree.sources))

    unsorted_particles = np.array([pi.get() for pi in particles])
    assert (sorted_particles
            == unsorted_particles[:, tree.user_source_ids]).all()

    if refine_weights is not None:
        refine_weights_reordered = refine_weights.get()[tree.user_source_ids]

    all_good_so_far = True

    if do_plot:
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.set_bounding_box()

    from boxtree import box_flags_enum as bfe

    scaled_tol = tol*tree.root_extent
    for ibox in range(tree.nboxes):
        # Empty boxes exist in non-pruned trees--which themselves are undocumented.
        # These boxes will fail these tests.
        if not (tree.box_flags[ibox] & bfe.HAS_OWN_SRCNTGTS):
            continue

        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low >= tree.bounding_box[0] - scaled_tol).all(), (
                ibox, extent_low, tree.bounding_box[0])
        assert (extent_high <= tree.bounding_box[1] + scaled_tol).all(), (
                ibox, extent_high, tree.bounding_box[1])

        start = tree.box_source_starts[ibox]

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox]
                + np.sum(tree.box_source_counts_cumul[existing_children])
                == tree.box_source_counts_cumul[ibox])

        box_particles = sorted_particles[:,
                start:start+tree.box_source_counts_cumul[ibox]]
        good = (
                (box_particles < extent_high[:, np.newaxis] + scaled_tol)
                & (extent_low[:, np.newaxis] - scaled_tol <= box_particles))

        all_good_here = good.all()
        if do_plot and not all_good_here and all_good_so_far:
            pt.plot(
                    box_particles[0, np.where(~good)[1]],
                    box_particles[1, np.where(~good)[1]], "ro")

            plotter.draw_box(ibox, edgecolor="red")

        if not all_good_here:
            print("BAD BOX", ibox)

        if not (tree.box_flags[ibox] & bfe.HAS_CHILDREN):
            # Check that leaf particle density is as promised.
            nparticles_in_box = tree.box_source_counts_cumul[ibox]
            if max_particles_in_box is not None:
                if nparticles_in_box > max_particles_in_box:
                    print("too many particles ({0} > {1}); box {2}".format(
                        nparticles_in_box, max_particles_in_box, ibox))
                    all_good_here = False
            else:
                assert refine_weights is not None
                box_weight = np.sum(
                    refine_weights_reordered[start:start+nparticles_in_box])
                if box_weight > max_leaf_refine_weight:
                    print("refine weight exceeded ({0} > {1}); box {2}".format(
                        box_weight, max_leaf_refine_weight, ibox))
                    all_good_here = False

        all_good_so_far = all_good_so_far and all_good_here

    if do_plot:
        pt.gca().set_aspect("equal", "datalim")
        pt.show()

    assert all_good_so_far
コード例 #12
0
def test_source_target_tree(ctx_factory, dims, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    nsources = 2 * 10**5
    ntargets = 3 * 10**5
    dtype = np.float64

    sources = make_normal_particle_array(queue, nsources, dims, dtype, seed=12)
    targets = make_normal_particle_array(queue, ntargets, dims, dtype, seed=19)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(sources[0].get(), sources[1].get(), "rx")
        pt.plot(targets[0].get(), targets[1].get(), "g+")
        pt.show()

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue,
                 sources,
                 targets=targets,
                 max_particles_in_box=10,
                 debug=True)
    tree = tree.get(queue=queue)

    sorted_sources = np.array(list(tree.sources))
    sorted_targets = np.array(list(tree.targets))

    unsorted_sources = np.array([pi.get() for pi in sources])
    unsorted_targets = np.array([pi.get() for pi in targets])
    assert (sorted_sources == unsorted_sources[:, tree.user_source_ids]).all()

    user_target_ids = np.empty(tree.ntargets, dtype=np.intp)
    user_target_ids[tree.sorted_target_ids] = np.arange(tree.ntargets,
                                                        dtype=np.intp)
    assert (sorted_targets == unsorted_targets[:, user_target_ids]).all()

    all_good_so_far = True

    if do_plot:
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.set_bounding_box()

    tol = 1e-15

    for ibox in range(tree.nboxes):
        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low >=
                tree.bounding_box[0] - 1e-12 * tree.root_extent).all(), ibox
        assert (extent_high <=
                tree.bounding_box[1] + 1e-12 * tree.root_extent).all(), ibox

        src_start = tree.box_source_starts[ibox]
        tgt_start = tree.box_target_starts[ibox]

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox] +
                np.sum(tree.box_source_counts_cumul[existing_children]) ==
                tree.box_source_counts_cumul[ibox])
        assert (tree.box_target_counts_nonchild[ibox] +
                np.sum(tree.box_target_counts_cumul[existing_children]) ==
                tree.box_target_counts_cumul[ibox])

        for what, particles in [
            ("sources", sorted_sources[:, src_start:src_start +
                                       tree.box_source_counts_cumul[ibox]]),
            ("targets", sorted_targets[:, tgt_start:tgt_start +
                                       tree.box_target_counts_cumul[ibox]]),
        ]:
            good = ((particles < extent_high[:, np.newaxis] + tol)
                    &
                    (extent_low[:, np.newaxis] - tol <= particles)).all(axis=0)

            all_good_here = good.all()

            if do_plot and not all_good_here:
                pt.plot(particles[0, np.where(~good)[0]],
                        particles[1, np.where(~good)[0]], "ro")

                plotter.draw_box(ibox, edgecolor="red")
                pt.show()

        if not all_good_here:
            print("BAD BOX %s %d" % (what, ibox))

        all_good_so_far = all_good_so_far and all_good_here
        assert all_good_so_far

    if do_plot:
        pt.gca().set_aspect("equal", "datalim")
        pt.show()
コード例 #13
0
def test_space_invader_query(ctx_factory, dims, dtype, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    dtype = np.dtype(dtype)
    nparticles = 10**5

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    from boxtree.area_query import (LeavesToBallsLookupBuilder,
                                    SpaceInvaderQueryBuilder)

    siqb = SpaceInvaderQueryBuilder(ctx)
    # We can use leaves-to-balls lookup to get the set of overlapping balls for
    # each box, and from there to compute the outer space invader distance.
    lblb = LeavesToBallsLookupBuilder(ctx)

    siq, _ = siqb(queue, tree, ball_centers, ball_radii)
    lbl, _ = lblb(queue, tree, ball_centers, ball_radii)

    # get data to host for test
    tree = tree.get(queue=queue)
    siq = siq.get(queue=queue)
    lbl = lbl.get(queue=queue)

    ball_centers = np.array([x.get() for x in ball_centers])
    ball_radii = ball_radii.get()

    # Find leaf boxes.
    from boxtree import box_flags_enum

    outer_space_invader_dist = np.zeros(tree.nboxes)

    for ibox in range(tree.nboxes):
        # We only want leaves here.
        if tree.box_flags[ibox] & box_flags_enum.HAS_CHILDREN:
            continue

        start, end = lbl.balls_near_box_starts[ibox:ibox + 2]
        space_invaders = lbl.balls_near_box_lists[start:end]
        if len(space_invaders) > 0:
            outer_space_invader_dist[ibox] = np.max(
                np.abs(tree.box_centers[:, ibox].reshape((-1, 1)) -
                       ball_centers[:, space_invaders]))

    assert np.allclose(siq, outer_space_invader_dist)
コード例 #14
0
def test_extent_tree(ctx_factory, dims, extent_norm, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    nsources = 100000
    ntargets = 200000
    dtype = np.float64
    npoint_sources_per_source = 16

    sources = make_normal_particle_array(queue, nsources, dims, dtype, seed=12)
    targets = make_normal_particle_array(queue, ntargets, dims, dtype, seed=19)

    refine_weights = cl.array.zeros(queue, nsources + ntargets, np.int32)
    refine_weights[:nsources] = 1

    from pyopencl.clrandom import PhiloxGenerator
    rng = PhiloxGenerator(queue.context, seed=13)
    source_radii = 2**rng.uniform(queue, nsources, dtype=dtype, a=-10, b=0)
    target_radii = 2**rng.uniform(queue, ntargets, dtype=dtype, a=-10, b=0)

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    dev_tree, _ = tb(
        queue,
        sources,
        targets=targets,
        source_radii=source_radii,
        target_radii=target_radii,
        extent_norm=extent_norm,
        refine_weights=refine_weights,
        max_leaf_refine_weight=20,

        #max_particles_in_box=10,

        # Set artificially small, to exercise the reallocation code.
        nboxes_guess=10,
        debug=True,
        stick_out_factor=0)

    logger.info("transfer tree, check orderings")

    tree = dev_tree.get(queue=queue)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(sources[0].get(), sources[1].get(), "rx")
        pt.plot(targets[0].get(), targets[1].get(), "g+")

        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.draw_box_numbers()
        plotter.set_bounding_box()

        pt.gca().set_aspect("equal", "datalim")
        pt.show()

    sorted_sources = np.array(list(tree.sources))
    sorted_targets = np.array(list(tree.targets))
    sorted_source_radii = tree.source_radii
    sorted_target_radii = tree.target_radii

    unsorted_sources = np.array([pi.get() for pi in sources])
    unsorted_targets = np.array([pi.get() for pi in targets])
    unsorted_source_radii = source_radii.get()
    unsorted_target_radii = target_radii.get()

    assert (sorted_sources == unsorted_sources[:, tree.user_source_ids]).all()
    assert (sorted_source_radii == unsorted_source_radii[tree.user_source_ids]
            ).all()

    # {{{ test box structure, stick-out criterion

    logger.info("test box structure, stick-out criterion")

    user_target_ids = np.empty(tree.ntargets, dtype=np.intp)
    user_target_ids[tree.sorted_target_ids] = np.arange(tree.ntargets,
                                                        dtype=np.intp)
    if ntargets:
        assert (sorted_targets == unsorted_targets[:, user_target_ids]).all()
        assert (sorted_target_radii == unsorted_target_radii[user_target_ids]
                ).all()

    all_good_so_far = True

    # {{{ check sources, targets

    assert np.sum(tree.box_source_counts_nonchild) == nsources
    assert np.sum(tree.box_target_counts_nonchild) == ntargets

    for ibox in range(tree.nboxes):
        kid_sum = sum(tree.box_target_counts_cumul[ichild_box]
                      for ichild_box in tree.box_child_ids[:, ibox]
                      if ichild_box != 0)
        assert (tree.box_target_counts_cumul[ibox] == (
            tree.box_target_counts_nonchild[ibox] + kid_sum)), ibox

    for ibox in range(tree.nboxes):
        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low >=
                tree.bounding_box[0] - 1e-12 * tree.root_extent).all(), ibox
        assert (extent_high <=
                tree.bounding_box[1] + 1e-12 * tree.root_extent).all(), ibox

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox] +
                np.sum(tree.box_source_counts_cumul[existing_children]) ==
                tree.box_source_counts_cumul[ibox])
        assert (tree.box_target_counts_nonchild[ibox] +
                np.sum(tree.box_target_counts_cumul[existing_children]) ==
                tree.box_target_counts_cumul[ibox])

    del existing_children
    del box_children

    for ibox in range(tree.nboxes):
        lev = int(tree.box_levels[ibox])
        box_radius = 0.5 * tree.root_extent / (1 << lev)
        box_center = tree.box_centers[:, ibox]
        extent_low = box_center - box_radius
        extent_high = box_center + box_radius

        stick_out_dist = tree.stick_out_factor * box_radius
        radius_with_stickout = (1 + tree.stick_out_factor) * box_radius

        for what, starts, counts, points, radii in [
            ("source", tree.box_source_starts, tree.box_source_counts_cumul,
             sorted_sources, sorted_source_radii),
            ("target", tree.box_target_starts, tree.box_target_counts_cumul,
             sorted_targets, sorted_target_radii),
        ]:
            bstart = starts[ibox]
            bslice = slice(bstart, bstart + counts[ibox])
            check_particles = points[:, bslice]
            check_radii = radii[bslice]

            if extent_norm == "linf":
                good = ((check_particles + check_radii <
                         extent_high[:, np.newaxis] + stick_out_dist)
                        &  # noqa: W504
                        (extent_low[:, np.newaxis] - stick_out_dist <=
                         check_particles - check_radii)).all(axis=0)

            elif extent_norm == "l2":
                center_dists = np.sqrt(
                    np.sum((check_particles - box_center.reshape(-1, 1))**2,
                           axis=0))

                good = ((center_dists + check_radii)**2 <
                        dims * radius_with_stickout**2)

            else:
                raise ValueError("unexpected value of extent_norm")

            all_good_here = good.all()

            if not all_good_here:
                print("BAD BOX %s %d level %d" %
                      (what, ibox, tree.box_levels[ibox]))

            all_good_so_far = all_good_so_far and all_good_here
            assert all_good_here

    # }}}

    assert all_good_so_far

    # }}}

    # {{{ create, link point sources

    logger.info("creating point sources")

    np.random.seed(20)

    from pytools.obj_array import make_obj_array
    point_sources = make_obj_array([
        cl.array.to_device(
            queue, unsorted_sources[i][:, np.newaxis] +
            unsorted_source_radii[:, np.newaxis] * np.random.uniform(
                -1, 1, size=(nsources, npoint_sources_per_source)))
        for i in range(dims)
    ])

    point_source_starts = cl.array.arange(queue,
                                          0, (nsources + 1) *
                                          npoint_sources_per_source,
                                          npoint_sources_per_source,
                                          dtype=tree.particle_id_dtype)

    from boxtree.tree import link_point_sources
    dev_tree = link_point_sources(queue,
                                  dev_tree,
                                  point_source_starts,
                                  point_sources,
                                  debug=True)
コード例 #15
0
def run_build_test(builder,
                   queue,
                   dims,
                   dtype,
                   nparticles,
                   do_plot,
                   max_particles_in_box=None,
                   max_leaf_refine_weight=None,
                   refine_weights=None,
                   **kwargs):
    dtype = np.dtype(dtype)

    if dtype == np.float32:
        tol = 1e-4
    elif dtype == np.float64:
        tol = 1e-12
    else:
        raise RuntimeError("unsupported dtype: %s" % dtype)

    logger.info(75 * "-")
    if max_particles_in_box is not None:
        logger.info(
            "%dD %s - %d particles - max %d per box - %s" %
            (dims, dtype.type.__name__, nparticles, max_particles_in_box,
             " - ".join("%s: %s" % (k, v) for k, v in six.iteritems(kwargs))))
    else:
        logger.info(
            "%dD %s - %d particles - max leaf weight %d  - %s" %
            (dims, dtype.type.__name__, nparticles, max_leaf_refine_weight,
             " - ".join("%s: %s" % (k, v) for k, v in six.iteritems(kwargs))))
    logger.info(75 * "-")

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    queue.finish()

    tree, _ = builder(queue,
                      particles,
                      max_particles_in_box=max_particles_in_box,
                      refine_weights=refine_weights,
                      max_leaf_refine_weight=max_leaf_refine_weight,
                      debug=True,
                      **kwargs)
    tree = tree.get(queue=queue)

    sorted_particles = np.array(list(tree.sources))

    unsorted_particles = np.array([pi.get() for pi in particles])
    assert (
        sorted_particles == unsorted_particles[:, tree.user_source_ids]).all()

    if refine_weights is not None:
        refine_weights_reordered = refine_weights.get()[tree.user_source_ids]

    all_good_so_far = True

    if do_plot:
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.set_bounding_box()

    from boxtree import box_flags_enum as bfe

    scaled_tol = tol * tree.root_extent
    for ibox in range(tree.nboxes):
        # Empty boxes exist in non-pruned trees--which themselves are undocumented.
        # These boxes will fail these tests.
        if not (tree.box_flags[ibox] & bfe.HAS_OWN_SRCNTGTS):
            continue

        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low >= tree.bounding_box[0] - scaled_tol).all(), (
            ibox, extent_low, tree.bounding_box[0])
        assert (extent_high <= tree.bounding_box[1] + scaled_tol).all(), (
            ibox, extent_high, tree.bounding_box[1])

        start = tree.box_source_starts[ibox]

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox] +
                np.sum(tree.box_source_counts_cumul[existing_children]) ==
                tree.box_source_counts_cumul[ibox])

        box_particles = sorted_particles[:, start:start +
                                         tree.box_source_counts_cumul[ibox]]
        good = ((box_particles < extent_high[:, np.newaxis] + scaled_tol)
                & (extent_low[:, np.newaxis] - scaled_tol <= box_particles))

        all_good_here = good.all()
        if do_plot and not all_good_here and all_good_so_far:
            pt.plot(box_particles[0, np.where(~good)[1]],
                    box_particles[1, np.where(~good)[1]], "ro")

            plotter.draw_box(ibox, edgecolor="red")

        if not all_good_here:
            print("BAD BOX", ibox)

        if not (tree.box_flags[ibox] & bfe.HAS_CHILDREN):
            # Check that leaf particle density is as promised.
            nparticles_in_box = tree.box_source_counts_cumul[ibox]
            if max_particles_in_box is not None:
                if nparticles_in_box > max_particles_in_box:
                    print("too many particles ({0} > {1}); box {2}".format(
                        nparticles_in_box, max_particles_in_box, ibox))
                    all_good_here = False
            else:
                assert refine_weights is not None
                box_weight = np.sum(
                    refine_weights_reordered[start:start + nparticles_in_box])
                if box_weight > max_leaf_refine_weight:
                    print("refine weight exceeded ({0} > {1}); box {2}".format(
                        box_weight, max_leaf_refine_weight, ibox))
                    all_good_here = False

        all_good_so_far = all_good_so_far and all_good_here

    if do_plot:
        pt.gca().set_aspect("equal", "datalim")
        pt.show()

    assert all_good_so_far
コード例 #16
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_extent_tree(ctx_getter, dims, extent_norm, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nsources = 100000
    ntargets = 200000
    dtype = np.float64
    npoint_sources_per_source = 16

    sources = make_normal_particle_array(queue, nsources, dims, dtype,
            seed=12)
    targets = make_normal_particle_array(queue, ntargets, dims, dtype,
            seed=19)

    refine_weights = cl.array.zeros(queue, nsources+ntargets, np.int32)
    refine_weights[:nsources] = 1

    from pyopencl.clrandom import PhiloxGenerator
    rng = PhiloxGenerator(queue.context, seed=13)
    source_radii = 2**rng.uniform(queue, nsources, dtype=dtype,
            a=-10, b=0)
    target_radii = 2**rng.uniform(queue, ntargets, dtype=dtype,
            a=-10, b=0)

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    dev_tree, _ = tb(queue, sources, targets=targets,
            source_radii=source_radii,
            target_radii=target_radii,
            extent_norm=extent_norm,

            refine_weights=refine_weights,
            max_leaf_refine_weight=20,

            #max_particles_in_box=10,

            # Set artificially small, to exercise the reallocation code.
            nboxes_guess=10,

            debug=True,
            stick_out_factor=0)

    logger.info("transfer tree, check orderings")

    tree = dev_tree.get(queue=queue)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(sources[0].get(), sources[1].get(), "rx")
        pt.plot(targets[0].get(), targets[1].get(), "g+")

        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.draw_box_numbers()
        plotter.set_bounding_box()

        pt.gca().set_aspect("equal", "datalim")
        pt.show()

    sorted_sources = np.array(list(tree.sources))
    sorted_targets = np.array(list(tree.targets))
    sorted_source_radii = tree.source_radii
    sorted_target_radii = tree.target_radii

    unsorted_sources = np.array([pi.get() for pi in sources])
    unsorted_targets = np.array([pi.get() for pi in targets])
    unsorted_source_radii = source_radii.get()
    unsorted_target_radii = target_radii.get()

    assert (sorted_sources
            == unsorted_sources[:, tree.user_source_ids]).all()
    assert (sorted_source_radii
            == unsorted_source_radii[tree.user_source_ids]).all()

    # {{{ test box structure, stick-out criterion

    logger.info("test box structure, stick-out criterion")

    user_target_ids = np.empty(tree.ntargets, dtype=np.intp)
    user_target_ids[tree.sorted_target_ids] = np.arange(tree.ntargets, dtype=np.intp)
    if ntargets:
        assert (sorted_targets
                == unsorted_targets[:, user_target_ids]).all()
        assert (sorted_target_radii
                == unsorted_target_radii[user_target_ids]).all()

    all_good_so_far = True

    # {{{ check sources, targets

    assert np.sum(tree.box_source_counts_nonchild) == nsources
    assert np.sum(tree.box_target_counts_nonchild) == ntargets

    for ibox in range(tree.nboxes):
        kid_sum = sum(
                    tree.box_target_counts_cumul[ichild_box]
                    for ichild_box in tree.box_child_ids[:, ibox]
                    if ichild_box != 0)
        assert (
                tree.box_target_counts_cumul[ibox]
                == (
                    tree.box_target_counts_nonchild[ibox]
                    + kid_sum)), ibox

    for ibox in range(tree.nboxes):
        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low
                >= tree.bounding_box[0] - 1e-12*tree.root_extent).all(), ibox
        assert (extent_high
                <= tree.bounding_box[1] + 1e-12*tree.root_extent).all(), ibox

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox]
                + np.sum(tree.box_source_counts_cumul[existing_children])
                == tree.box_source_counts_cumul[ibox])
        assert (tree.box_target_counts_nonchild[ibox]
                + np.sum(tree.box_target_counts_cumul[existing_children])
                == tree.box_target_counts_cumul[ibox])

    del existing_children
    del box_children

    for ibox in range(tree.nboxes):
        lev = int(tree.box_levels[ibox])
        box_radius = 0.5 * tree.root_extent / (1 << lev)
        box_center = tree.box_centers[:, ibox]
        extent_low = box_center - box_radius
        extent_high = box_center + box_radius

        stick_out_dist = tree.stick_out_factor * box_radius
        radius_with_stickout = (1 + tree.stick_out_factor) * box_radius

        for what, starts, counts, points, radii in [
                ("source", tree.box_source_starts, tree.box_source_counts_cumul,
                    sorted_sources, sorted_source_radii),
                ("target", tree.box_target_starts, tree.box_target_counts_cumul,
                    sorted_targets, sorted_target_radii),
                ]:
            bstart = starts[ibox]
            bslice = slice(bstart, bstart+counts[ibox])
            check_particles = points[:, bslice]
            check_radii = radii[bslice]

            if extent_norm == "linf":
                good = (
                        (check_particles + check_radii
                            < extent_high[:, np.newaxis] + stick_out_dist)
                        &  # noqa: W504
                        (extent_low[:, np.newaxis] - stick_out_dist
                            <= check_particles - check_radii)
                        ).all(axis=0)

            elif extent_norm == "l2":
                center_dists = np.sqrt(
                        np.sum(
                            (check_particles - box_center.reshape(-1, 1))**2,
                            axis=0))

                good = (
                        (center_dists + check_radii)**2
                        < dims * radius_with_stickout**2)

            else:
                raise ValueError("unexpected value of extent_norm")

            all_good_here = good.all()

            if not all_good_here:
                print("BAD BOX %s %d level %d"
                        % (what, ibox, tree.box_levels[ibox]))

            all_good_so_far = all_good_so_far and all_good_here
            assert all_good_here

    # }}}

    assert all_good_so_far

    # }}}

    # {{{ create, link point sources

    logger.info("creating point sources")

    np.random.seed(20)

    from pytools.obj_array import make_obj_array
    point_sources = make_obj_array([
            cl.array.to_device(queue,
                unsorted_sources[i][:, np.newaxis]
                + unsorted_source_radii[:, np.newaxis]
                * np.random.uniform(
                    -1, 1, size=(nsources, npoint_sources_per_source))
                 )
            for i in range(dims)])

    point_source_starts = cl.array.arange(queue,
            0, (nsources+1)*npoint_sources_per_source, npoint_sources_per_source,
            dtype=tree.particle_id_dtype)

    from boxtree.tree import link_point_sources
    dev_tree = link_point_sources(queue, dev_tree,
            point_source_starts, point_sources,
            debug=True)
コード例 #17
0
def run_build_test(builder, queue, dims, dtype, nparticles, do_plot,
        max_particles_in_box=30, **kwargs):
    dtype = np.dtype(dtype)

    if dtype == np.float32:
        tol = 1e-4
    elif dtype == np.float64:
        tol = 1e-12
    else:
        raise RuntimeError("unsupported dtype: %s" % dtype)

    if (dtype == np.float32
            and dims == 2
            and queue.device.platform.name == "Portable Computing Language"):
        pytest.xfail("2D float doesn't work on POCL")

    logger.info(75*"-")
    logger.info("%dD %s - %d particles - max %d per box - %s" % (
            dims, dtype.type.__name__, nparticles, max_particles_in_box,
            " - ".join("%s: %s" % (k, v) for k, v in six.iteritems(kwargs))))
    logger.info(75*"-")

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    queue.finish()

    tree, _ = builder(queue, particles,
            max_particles_in_box=max_particles_in_box, debug=True,
            **kwargs)
    tree = tree.get(queue=queue)

    sorted_particles = np.array(list(tree.sources))

    unsorted_particles = np.array([pi.get() for pi in particles])
    assert (sorted_particles
            == unsorted_particles[:, tree.user_source_ids]).all()

    all_good_so_far = True

    if do_plot:
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.set_bounding_box()

    from boxtree import box_flags_enum as bfe

    scaled_tol = tol*tree.root_extent
    for ibox in range(tree.nboxes):

        # Empty boxes exist in non-pruned trees--which themselves are undocumented.
        # These boxes will fail these tests.
        if not (tree.box_flags[ibox] & bfe.HAS_OWN_SRCNTGTS):
            continue

        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low >= tree.bounding_box[0] - scaled_tol).all(), (
                ibox, extent_low, tree.bounding_box[0])
        assert (extent_high <= tree.bounding_box[1] + scaled_tol).all(), (
                ibox, extent_high, tree.bounding_box[1])

        start = tree.box_source_starts[ibox]

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox]
                + np.sum(tree.box_source_counts_cumul[existing_children])
                == tree.box_source_counts_cumul[ibox])

        box_particles = sorted_particles[:,
                start:start+tree.box_source_counts_cumul[ibox]]
        good = (
                (box_particles < extent_high[:, np.newaxis] + scaled_tol)
                &
                (extent_low[:, np.newaxis] - scaled_tol <= box_particles)
                )

        all_good_here = good.all()
        if do_plot and not all_good_here and all_good_so_far:
            pt.plot(
                    box_particles[0, np.where(~good)[1]],
                    box_particles[1, np.where(~good)[1]], "ro")

            plotter.draw_box(ibox, edgecolor="red")

        if not all_good_here:
            print("BAD BOX", ibox)

        all_good_so_far = all_good_so_far and all_good_here

    if do_plot:
        pt.gca().set_aspect("equal", "datalim")
        pt.show()

    assert all_good_so_far
コード例 #18
0
def test_tree_connectivity(ctx_getter, dims, sources_are_targets):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    dtype = np.float64

    sources = make_normal_particle_array(queue, 1 * 10**5, dims, dtype)
    if sources_are_targets:
        targets = None
    else:
        targets = make_normal_particle_array(queue, 2 * 10**5, dims, dtype)

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)
    tree, _ = tb(queue,
                 sources,
                 max_particles_in_box=30,
                 targets=targets,
                 debug=True)

    from boxtree.traversal import FMMTraversalBuilder
    tg = FMMTraversalBuilder(ctx)
    trav, _ = tg(queue, tree, debug=True)
    tree = tree.get(queue=queue)
    trav = trav.get(queue=queue)

    levels = tree.box_levels
    parents = tree.box_parent_ids.T
    children = tree.box_child_ids.T
    centers = tree.box_centers.T

    # {{{ parent and child relations, levels match up

    for ibox in range(1, tree.nboxes):
        # /!\ Not testing box 0, has no parents
        parent = parents[ibox]

        assert levels[parent] + 1 == levels[ibox]
        assert ibox in children[parent], ibox

    # }}}

    if 0:
        import matplotlib.pyplot as pt
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black")
        plotter.draw_box_numbers()
        plotter.set_bounding_box()
        pt.show()

    # {{{ neighbor_source_boxes (list 1) consists of source boxes

    for itgt_box, ibox in enumerate(trav.target_boxes):
        start, end = trav.neighbor_source_boxes_starts[itgt_box:itgt_box + 2]
        nbl = trav.neighbor_source_boxes_lists[start:end]

        if sources_are_targets:
            assert ibox in nbl

        for jbox in nbl:
            assert (0 == children[jbox]).all(), (ibox, jbox, children[jbox])

    logger.info("list 1 consists of source boxes")

    # }}}

    # {{{ separated siblings (list 2) are actually separated

    for itgt_box, tgt_ibox in enumerate(trav.target_or_target_parent_boxes):
        start, end = trav.sep_siblings_starts[itgt_box:itgt_box + 2]
        seps = trav.sep_siblings_lists[start:end]

        assert (levels[seps] == levels[tgt_ibox]).all()

        # three-ish box radii (half of size)
        mindist = 2.5 * 0.5 * 2**-int(levels[tgt_ibox]) * tree.root_extent

        icenter = centers[tgt_ibox]
        for jbox in seps:
            dist = la.norm(centers[jbox] - icenter)
            assert dist > mindist, (dist, mindist)

    logger.info("separated siblings (list 2) are actually separated")

    # }}}

    if sources_are_targets:
        # {{{ sep_{smaller,bigger} are duals of each other

        assert (trav.target_or_target_parent_boxes == np.arange(
            tree.nboxes)).all()

        # {{{ list 4 <= list 3
        for itarget_box, ibox in enumerate(trav.target_boxes):

            for ssn in trav.sep_smaller_by_level:
                start, end = ssn.starts[itarget_box:itarget_box + 2]

                for jbox in ssn.lists[start:end]:
                    rstart, rend = trav.sep_bigger_starts[jbox:jbox + 2]

                    assert ibox in trav.sep_bigger_lists[rstart:rend], (ibox,
                                                                        jbox)

        # }}}

        # {{{ list 4 <= list 3

        box_to_target_box_index = np.empty(tree.nboxes, tree.box_id_dtype)
        box_to_target_box_index.fill(-1)
        box_to_target_box_index[trav.target_boxes] = np.arange(
            len(trav.target_boxes), dtype=tree.box_id_dtype)

        assert (trav.source_boxes == trav.target_boxes).all()
        assert (trav.target_or_target_parent_boxes == np.arange(
            tree.nboxes, dtype=tree.box_id_dtype)).all()

        for ibox in range(tree.nboxes):
            start, end = trav.sep_bigger_starts[ibox:ibox + 2]

            for jbox in trav.sep_bigger_lists[start:end]:
                # In principle, entries of sep_bigger_lists are
                # source boxes. In this special case, source and target boxes
                # are the same thing (i.e. leaves--see assertion above), so we
                # may treat them as targets anyhow.

                jtgt_box = box_to_target_box_index[jbox]
                assert jtgt_box != -1

                good = False

                for ssn in trav.sep_smaller_by_level:
                    rstart, rend = ssn.starts[jtgt_box:jtgt_box + 2]
                    good = good or ibox in ssn.lists[rstart:rend]

                if not good:
                    from boxtree.visualization import TreePlotter
                    plotter = TreePlotter(tree)
                    plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
                    plotter.set_bounding_box()

                    plotter.draw_box(ibox, facecolor='green', alpha=0.5)
                    plotter.draw_box(jbox, facecolor='red', alpha=0.5)

                    import matplotlib.pyplot as pt
                    pt.gca().set_aspect("equal")
                    pt.show()

                # This assertion failing means that ibox's list 4 contains a box
                # 'jbox' whose list 3 does not contain ibox.
                assert good, (ibox, jbox)

        # }}}

        logger.info("list 3, 4 are duals")

        # }}}

    # {{{ sep_smaller satisfies relative level assumption

    for itarget_box, ibox in enumerate(trav.target_boxes):
        for ssn in trav.sep_smaller_by_level:
            start, end = ssn.starts[itarget_box:itarget_box + 2]

            for jbox in ssn.lists[start:end]:
                assert levels[ibox] < levels[jbox]

    logger.info("list 3 satisfies relative level assumption")

    # }}}

    # {{{ sep_bigger satisfies relative level assumption

    for itgt_box, tgt_ibox in enumerate(trav.target_or_target_parent_boxes):
        start, end = trav.sep_bigger_starts[itgt_box:itgt_box + 2]

        for jbox in trav.sep_bigger_lists[start:end]:
            assert levels[tgt_ibox] > levels[jbox]

    logger.info("list 4 satisfies relative level assumption")

    # }}}

    # {{{ level_start_*_box_nrs lists make sense

    for name, ref_array in [("level_start_source_box_nrs", trav.source_boxes),
                            ("level_start_source_parent_box_nrs",
                             trav.source_parent_boxes),
                            ("level_start_target_box_nrs", trav.target_boxes),
                            ("level_start_target_or_target_parent_box_nrs",
                             trav.target_or_target_parent_boxes)]:
        level_starts = getattr(trav, name)
        for lev in range(tree.nlevels):
            start, stop = level_starts[lev:lev + 2]

            box_nrs = ref_array[start:stop]

            assert (tree.box_levels[box_nrs] == lev).all(), name
コード例 #19
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_space_invader_query(ctx_getter, dims, dtype, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    dtype = np.dtype(dtype)
    nparticles = 10**5

    particles = make_normal_particle_array(queue, nparticles, dims, dtype)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(particles[0].get(), particles[1].get(), "x")

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True)

    nballs = 10**4
    ball_centers = make_normal_particle_array(queue, nballs, dims, dtype)
    ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1)

    from boxtree.area_query import (
        LeavesToBallsLookupBuilder, SpaceInvaderQueryBuilder)

    siqb = SpaceInvaderQueryBuilder(ctx)
    # We can use leaves-to-balls lookup to get the set of overlapping balls for
    # each box, and from there to compute the outer space invader distance.
    lblb = LeavesToBallsLookupBuilder(ctx)

    siq, _ = siqb(queue, tree, ball_centers, ball_radii)
    lbl, _ = lblb(queue, tree, ball_centers, ball_radii)

    # get data to host for test
    tree = tree.get(queue=queue)
    siq = siq.get(queue=queue)
    lbl = lbl.get(queue=queue)

    ball_centers = np.array([x.get() for x in ball_centers])
    ball_radii = ball_radii.get()

    # Find leaf boxes.
    from boxtree import box_flags_enum

    outer_space_invader_dist = np.zeros(tree.nboxes)

    for ibox in range(tree.nboxes):
        # We only want leaves here.
        if tree.box_flags[ibox] & box_flags_enum.HAS_CHILDREN:
            continue

        start, end = lbl.balls_near_box_starts[ibox:ibox + 2]
        space_invaders = lbl.balls_near_box_lists[start:end]
        if len(space_invaders) > 0:
            outer_space_invader_dist[ibox] = np.max(np.abs(
                    tree.box_centers[:, ibox].reshape((-1, 1))
                    - ball_centers[:, space_invaders]))

    assert np.allclose(siq, outer_space_invader_dist)
コード例 #20
0
ファイル: test_tree.py プロジェクト: inducer/boxtree
def test_source_target_tree(ctx_getter, dims, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nsources = 2 * 10**5
    ntargets = 3 * 10**5
    dtype = np.float64

    sources = make_normal_particle_array(queue, nsources, dims, dtype,
            seed=12)
    targets = make_normal_particle_array(queue, ntargets, dims, dtype,
            seed=19)

    if do_plot:
        import matplotlib.pyplot as pt
        pt.plot(sources[0].get(), sources[1].get(), "rx")
        pt.plot(targets[0].get(), targets[1].get(), "g+")
        pt.show()

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    tree, _ = tb(queue, sources, targets=targets,
            max_particles_in_box=10, debug=True)
    tree = tree.get(queue=queue)

    sorted_sources = np.array(list(tree.sources))
    sorted_targets = np.array(list(tree.targets))

    unsorted_sources = np.array([pi.get() for pi in sources])
    unsorted_targets = np.array([pi.get() for pi in targets])
    assert (sorted_sources
            == unsorted_sources[:, tree.user_source_ids]).all()

    user_target_ids = np.empty(tree.ntargets, dtype=np.intp)
    user_target_ids[tree.sorted_target_ids] = np.arange(tree.ntargets, dtype=np.intp)
    assert (sorted_targets
            == unsorted_targets[:, user_target_ids]).all()

    all_good_so_far = True

    if do_plot:
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
        plotter.set_bounding_box()

    tol = 1e-15

    for ibox in range(tree.nboxes):
        extent_low, extent_high = tree.get_box_extent(ibox)

        assert (extent_low
                >= tree.bounding_box[0] - 1e-12*tree.root_extent).all(), ibox
        assert (extent_high
                <= tree.bounding_box[1] + 1e-12*tree.root_extent).all(), ibox

        src_start = tree.box_source_starts[ibox]
        tgt_start = tree.box_target_starts[ibox]

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox]
                + np.sum(tree.box_source_counts_cumul[existing_children])
                == tree.box_source_counts_cumul[ibox])
        assert (tree.box_target_counts_nonchild[ibox]
                + np.sum(tree.box_target_counts_cumul[existing_children])
                == tree.box_target_counts_cumul[ibox])

        for what, particles in [
                ("sources", sorted_sources[:,
                    src_start:src_start+tree.box_source_counts_cumul[ibox]]),
                ("targets", sorted_targets[:,
                    tgt_start:tgt_start+tree.box_target_counts_cumul[ibox]]),
                ]:
            good = (
                    (particles < extent_high[:, np.newaxis] + tol)
                    & (extent_low[:, np.newaxis] - tol <= particles)
                    ).all(axis=0)

            all_good_here = good.all()

            if do_plot and not all_good_here:
                pt.plot(
                        particles[0, np.where(~good)[0]],
                        particles[1, np.where(~good)[0]], "ro")

                plotter.draw_box(ibox, edgecolor="red")
                pt.show()

        if not all_good_here:
            print("BAD BOX %s %d" % (what, ibox))

        all_good_so_far = all_good_so_far and all_good_here
        assert all_good_so_far

    if do_plot:
        pt.gca().set_aspect("equal", "datalim")
        pt.show()
コード例 #21
0
def test_tree_connectivity(ctx_getter, dims, sources_are_targets):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    dtype = np.float64

    sources = make_normal_particle_array(queue, 1 * 10**5, dims, dtype)
    if sources_are_targets:
        targets = None
    else:
        targets = make_normal_particle_array(queue, 2 * 10**5, dims, dtype)

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)
    tree, _ = tb(queue, sources, max_particles_in_box=30,
            targets=targets, debug=True)

    from boxtree.traversal import FMMTraversalBuilder
    tg = FMMTraversalBuilder(ctx)
    trav, _ = tg(queue, tree, debug=True)
    tree = tree.get(queue=queue)
    trav = trav.get(queue=queue)

    levels = tree.box_levels
    parents = tree.box_parent_ids.T
    children = tree.box_child_ids.T
    centers = tree.box_centers.T

    # {{{ parent and child relations, levels match up

    for ibox in range(1, tree.nboxes):
        # /!\ Not testing box 0, has no parents
        parent = parents[ibox]

        assert levels[parent] + 1 == levels[ibox]
        assert ibox in children[parent], ibox

    # }}}

    if 0:
        import matplotlib.pyplot as pt
        from boxtree.visualization import TreePlotter
        plotter = TreePlotter(tree)
        plotter.draw_tree(fill=False, edgecolor="black")
        plotter.draw_box_numbers()
        plotter.set_bounding_box()
        pt.show()

    # {{{ neighbor_source_boxes (list 1) consists of source boxes

    for itgt_box, ibox in enumerate(trav.target_boxes):
        start, end = trav.neighbor_source_boxes_starts[itgt_box:itgt_box+2]
        nbl = trav.neighbor_source_boxes_lists[start:end]

        if sources_are_targets:
            assert ibox in nbl

        for jbox in nbl:
            assert (0 == children[jbox]).all(), (ibox, jbox, children[jbox])

    logger.info("list 1 consists of source boxes")

    # }}}

    # {{{ separated siblings (list 2) are actually separated

    for itgt_box, tgt_ibox in enumerate(trav.target_or_target_parent_boxes):
        start, end = trav.sep_siblings_starts[itgt_box:itgt_box+2]
        seps = trav.sep_siblings_lists[start:end]

        assert (levels[seps] == levels[tgt_ibox]).all()

        # three-ish box radii (half of size)
        mindist = 2.5 * 0.5 * 2**-int(levels[tgt_ibox]) * tree.root_extent

        icenter = centers[tgt_ibox]
        for jbox in seps:
            dist = la.norm(centers[jbox]-icenter)
            assert dist > mindist, (dist, mindist)

    logger.info("separated siblings (list 2) are actually separated")

    # }}}

    if sources_are_targets:
        # {{{ sep_{smaller,bigger} are duals of each other

        assert (trav.target_or_target_parent_boxes == np.arange(tree.nboxes)).all()

        # {{{ list 4 <= list 3
        for itarget_box, ibox in enumerate(trav.target_boxes):

            for ssn in trav.sep_smaller_by_level:
                start, end = ssn.starts[itarget_box:itarget_box+2]

                for jbox in ssn.lists[start:end]:
                    rstart, rend = trav.sep_bigger_starts[jbox:jbox+2]

                    assert ibox in trav.sep_bigger_lists[rstart:rend], (ibox, jbox)

        # }}}

        # {{{ list 4 <= list 3

        box_to_target_box_index = np.empty(tree.nboxes, tree.box_id_dtype)
        box_to_target_box_index.fill(-1)
        box_to_target_box_index[trav.target_boxes] = np.arange(
                len(trav.target_boxes), dtype=tree.box_id_dtype)

        assert (trav.source_boxes == trav.target_boxes).all()
        assert (trav.target_or_target_parent_boxes == np.arange(
                tree.nboxes, dtype=tree.box_id_dtype)).all()

        for ibox in range(tree.nboxes):
            start, end = trav.sep_bigger_starts[ibox:ibox+2]

            for jbox in trav.sep_bigger_lists[start:end]:
                # In principle, entries of sep_bigger_lists are
                # source boxes. In this special case, source and target boxes
                # are the same thing (i.e. leaves--see assertion above), so we
                # may treat them as targets anyhow.

                jtgt_box = box_to_target_box_index[jbox]
                assert jtgt_box != -1

                good = False

                for ssn in trav.sep_smaller_by_level:
                    rstart, rend = ssn.starts[jtgt_box:jtgt_box+2]
                    good = good or ibox in ssn.lists[rstart:rend]

                if not good:
                    from boxtree.visualization import TreePlotter
                    plotter = TreePlotter(tree)
                    plotter.draw_tree(fill=False, edgecolor="black", zorder=10)
                    plotter.set_bounding_box()

                    plotter.draw_box(ibox, facecolor='green', alpha=0.5)
                    plotter.draw_box(jbox, facecolor='red', alpha=0.5)

                    import matplotlib.pyplot as pt
                    pt.gca().set_aspect("equal")
                    pt.show()

                # This assertion failing means that ibox's list 4 contains a box
                # 'jbox' whose list 3 does not contain ibox.
                assert good, (ibox, jbox)

        # }}}

        logger.info("list 3, 4 are duals")

        # }}}

    # {{{ sep_smaller satisfies relative level assumption

    for itarget_box, ibox in enumerate(trav.target_boxes):
        for ssn in trav.sep_smaller_by_level:
            start, end = ssn.starts[itarget_box:itarget_box+2]

            for jbox in ssn.lists[start:end]:
                assert levels[ibox] < levels[jbox]

    logger.info("list 3 satisfies relative level assumption")

    # }}}

    # {{{ sep_bigger satisfies relative level assumption

    for itgt_box, tgt_ibox in enumerate(trav.target_or_target_parent_boxes):
        start, end = trav.sep_bigger_starts[itgt_box:itgt_box+2]

        for jbox in trav.sep_bigger_lists[start:end]:
            assert levels[tgt_ibox] > levels[jbox]

    logger.info("list 4 satisfies relative level assumption")

    # }}}

    # {{{ level_start_*_box_nrs lists make sense

    for name, ref_array in [
            ("level_start_source_box_nrs", trav.source_boxes),
            ("level_start_source_parent_box_nrs", trav.source_parent_boxes),
            ("level_start_target_box_nrs", trav.target_boxes),
            ("level_start_target_or_target_parent_box_nrs",
                trav.target_or_target_parent_boxes)
            ]:
        level_starts = getattr(trav, name)
        for lev in range(tree.nlevels):
            start, stop = level_starts[lev:lev+2]

            box_nrs = ref_array[start:stop]

            assert (tree.box_levels[box_nrs] == lev).all(), name
コード例 #22
0
def test_extent_tree(ctx_getter, dims, do_plot=False):
    logging.basicConfig(level=logging.INFO)

    ctx = ctx_getter()
    queue = cl.CommandQueue(ctx)

    nsources = 100000
    ntargets = 200000
    dtype = np.float64
    npoint_sources_per_source = 16

    sources = make_normal_particle_array(queue, nsources, dims, dtype,
            seed=12)
    targets = make_normal_particle_array(queue, ntargets, dims, dtype,
            seed=19)

    from pyopencl.clrandom import RanluxGenerator
    rng = RanluxGenerator(queue, seed=13)
    source_radii = 2**rng.uniform(queue, nsources, dtype=dtype,
            a=-10, b=0)
    target_radii = 2**rng.uniform(queue, ntargets, dtype=dtype,
            a=-10, b=0)

    from boxtree import TreeBuilder
    tb = TreeBuilder(ctx)

    queue.finish()
    dev_tree, _ = tb(queue, sources, targets=targets,
            source_radii=source_radii, target_radii=target_radii,
            max_particles_in_box=10, debug=True)

    logger.info("transfer tree, check orderings")

    tree = dev_tree.get(queue=queue)

    sorted_sources = np.array(list(tree.sources))
    sorted_targets = np.array(list(tree.targets))
    sorted_source_radii = tree.source_radii
    sorted_target_radii = tree.target_radii

    unsorted_sources = np.array([pi.get() for pi in sources])
    unsorted_targets = np.array([pi.get() for pi in targets])
    unsorted_source_radii = source_radii.get()
    unsorted_target_radii = target_radii.get()
    assert (sorted_sources
            == unsorted_sources[:, tree.user_source_ids]).all()
    assert (sorted_source_radii
            == unsorted_source_radii[tree.user_source_ids]).all()

    # {{{ test box structure, stick-out criterion

    logger.info("test box structure, stick-out criterion")

    user_target_ids = np.empty(tree.ntargets, dtype=np.intp)
    user_target_ids[tree.sorted_target_ids] = np.arange(tree.ntargets, dtype=np.intp)
    if ntargets:
        assert (sorted_targets
                == unsorted_targets[:, user_target_ids]).all()
        assert (sorted_target_radii
                == unsorted_target_radii[user_target_ids]).all()

    all_good_so_far = True

    # {{{ check sources, targets

    for ibox in range(tree.nboxes):
        extent_low, extent_high = tree.get_box_extent(ibox)

        box_radius = np.max(extent_high-extent_low) * 0.5
        stick_out_dist = tree.stick_out_factor * box_radius

        assert (extent_low >=
                tree.bounding_box[0] - 1e-12*tree.root_extent).all(), ibox
        assert (extent_high <=
                tree.bounding_box[1] + 1e-12*tree.root_extent).all(), ibox

        box_children = tree.box_child_ids[:, ibox]
        existing_children = box_children[box_children != 0]

        assert (tree.box_source_counts_nonchild[ibox]
                + np.sum(tree.box_source_counts_cumul[existing_children])
                == tree.box_source_counts_cumul[ibox])
        assert (tree.box_target_counts_nonchild[ibox]
                + np.sum(tree.box_target_counts_cumul[existing_children])
                == tree.box_target_counts_cumul[ibox])

        for what, starts, counts, points, radii in [
                ("source", tree.box_source_starts, tree.box_source_counts_cumul,
                    sorted_sources, sorted_source_radii),
                ("target", tree.box_target_starts, tree.box_target_counts_cumul,
                    sorted_targets, sorted_target_radii),
                ]:
            bstart = starts[ibox]
            bslice = slice(bstart, bstart+counts[ibox])
            check_particles = points[:, bslice]
            check_radii = radii[bslice]

            good = (
                    (check_particles + check_radii
                        < extent_high[:, np.newaxis] + stick_out_dist)
                    &
                    (extent_low[:, np.newaxis] - stick_out_dist
                        <= check_particles - check_radii)
                    ).all(axis=0)

            all_good_here = good.all()

            if not all_good_here:
                print("BAD BOX %s %d level %d" % (what, ibox, tree.box_levels[ibox]))

            all_good_so_far = all_good_so_far and all_good_here
            assert all_good_here

    # }}}

    assert all_good_so_far

    # }}}

    # {{{ create, link point sources

    logger.info("creating point sources")

    np.random.seed(20)

    from pytools.obj_array import make_obj_array
    point_sources = make_obj_array([
            cl.array.to_device(queue,
                unsorted_sources[i][:, np.newaxis]
                + unsorted_source_radii[:, np.newaxis]
                * np.random.uniform(
                    -1, 1, size=(nsources, npoint_sources_per_source))
                 )
            for i in range(dims)])

    point_source_starts = cl.array.arange(queue,
            0, (nsources+1)*npoint_sources_per_source, npoint_sources_per_source,
            dtype=tree.particle_id_dtype)

    from boxtree.tree import link_point_sources
    dev_tree = link_point_sources(queue, dev_tree,
            point_source_starts, point_sources,
            debug=True)