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)
def tree(self): """Build and return a :class:`boxtree.tree.TreeWithLinkedPointSources` for this source with these targets. |cached| """ code_getter = self.code_getter lpot_src = self.lpot_source with cl.CommandQueue(self.cl_context) as queue: nelements = sum(grp.nelements for grp in lpot_src.fine_density_discr.groups) el_centers = cl.array.empty( self.cl_context, (lpot_src.ambient_dim, nelements), self.coord_dtype) el_radii = cl.array.empty(self.cl_context, nelements, self.coord_dtype) # {{{ find sources and radii (=element 'centroids') # FIXME: Should probably use quad weights to find 'centroids' to deal # with non-symmetric elements. i_el_base = 0 for grp in lpot_src.fine_density_discr.groups: el_centers_view = el_centers[:, i_el_base:i_el_base+grp.nelements] el_radii_view = el_radii[i_el_base:i_el_base+grp.nelements] nodes_view = grp.view(lpot_src.fine_density_discr.nodes()) code_getter.find_element_centers( queue, el_centers=el_centers_view, nodes=nodes_view) code_getter.find_element_radii( queue, el_centers=el_centers_view, nodes=nodes_view, el_radii=el_radii_view) i_el_base += grp.nelements # }}} target_info = self.target_info() tree, _ = code_getter.build_tree(queue, particles=el_centers, source_radii=el_radii, max_particles_in_box=30, targets=target_info.targets, target_radii=self.target_radii(), debug=self.debug) # {{{ link point sources point_source_starts = cl.array.empty(self.cl_context, nelements+1, tree.particle_id_dtype) i_el_base = 0 for grp in lpot_src.fine_density_discr.groups: point_source_starts.setitem( slice(i_el_base, i_el_base+grp.nelements), cl.array.arange(queue, grp.node_nr_base, grp.node_nr_base + grp.nnodes, grp.nunit_nodes, dtype=point_source_starts.dtype), queue=queue) i_el_base += grp.nelements point_source_starts.setitem( -1, self.lpot_source.fine_density_discr.nnodes, queue=queue) from boxtree.tree import link_point_sources tree = link_point_sources(queue, tree, point_source_starts, self.lpot_source.fine_density_discr.nodes()) # }}} return tree
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)
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)