From 396e335f4650176ec9821f3e8b5d82efa8e8b037 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 19 Jul 2017 20:18:31 -0500 Subject: [PATCH 01/41] Fix a wait_for pattern in traversal building --- boxtree/traversal.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 27936c8..96d8afa 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1457,7 +1457,7 @@ class FMMTraversalBuilder: tree.stick_out_factor, target_boxes.data, colleagues.starts.data, colleagues.lists.data) - wait_for = [] + sep_smaller_wait_for = [] sep_smaller_by_level = [] for ilevel in range(tree.nlevels): @@ -1469,7 +1469,7 @@ class FMMTraversalBuilder: wait_for=wait_for) sep_smaller_by_level.append(result["sep_smaller"]) - wait_for.append(evt) + sep_smaller_wait_for.append(evt) if with_extent: fin_debug("finding separated smaller close ('list 3 close')") @@ -1480,13 +1480,16 @@ class FMMTraversalBuilder: sep_close_smaller_starts = result["sep_close_smaller"].starts sep_close_smaller_lists = result["sep_close_smaller"].lists - wait_for.append(evt) + sep_smaller_wait_for.append(evt) else: sep_close_smaller_starts = None sep_close_smaller_lists = None # }}} + wait_for = sep_smaller_wait_for + del sep_smaller_wait_for + # {{{ separated bigger ("list 4") fin_debug("finding separated bigger ('list 4')") -- GitLab From 317ddbfed92e98c7a2d6ac7e2663f2b0760891b5 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 19 Jul 2017 20:21:16 -0500 Subject: [PATCH 02/41] First steps towards a two-away FMM --- boxtree/traversal.py | 144 ++++++++++++++++++++++++++++++----------- test/test_traversal.py | 29 +++++---- 2 files changed, 121 insertions(+), 52 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 96d8afa..814343c 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -195,16 +195,22 @@ inline bool is_adjacent_or_overlapping_with_stick_out( } -inline bool is_adjacent_or_overlapping( +inline bool is_adjacent_or_overlapping_with_neighborhood( coord_t root_extent, // note: order does not matter coord_vec_t target_center, int target_level, - coord_vec_t source_center, int source_level) { - // This checks if the two boxes overlap. + coord_t target_box_neighborhood_size, + coord_vec_t source_center, int source_level) +{ + // This checks if the source box overlaps the target box + // including a neighborhood of target_box_neighborhood_size boxes + // of the same size as the target box. coord_t target_rad = LEVEL_TO_RAD(target_level); coord_t source_rad = LEVEL_TO_RAD(source_level); - coord_t rad_sum = target_rad + source_rad; + coord_t rad_sum = ( + (2*(target_box_neighborhood_size-1) + 1) * target_rad + + source_rad); coord_t slack = rad_sum + fmin(target_rad, source_rad); coord_t max_dist = 0; @@ -215,6 +221,19 @@ inline bool is_adjacent_or_overlapping( return max_dist <= slack; } +inline bool is_adjacent_or_overlapping( + coord_t root_extent, + // note: order does not matter + coord_vec_t target_center, int target_level, + coord_vec_t source_center, int source_level) +{ + return is_adjacent_or_overlapping_with_neighborhood( + root_extent, + target_center, target_level, + 1, + source_center, source_level); +} + """ # }}} @@ -281,9 +300,9 @@ LEVEL_START_BOX_NR_EXTRACTOR_TEMPLATE = ElementwiseTemplate( # }}} -# {{{ colleagues +# {{{ same-level non-well-separated boxes (generalization of "colleagues") -COLLEAGUES_TEMPLATE = r"""//CL// +SAME_LEVEL_NON_WELL_SEP_BOXES_TEMPLATE = r"""//CL// void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) { @@ -314,16 +333,19 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) { ${load_center("child_center", "child_box_id")} - bool a_or_o = is_adjacent_or_overlapping(root_extent, - center, level, child_center, box_levels[child_box_id]); + bool a_or_o = is_adjacent_or_overlapping_with_neighborhood( + root_extent, + center, level, + ${well_sep_is_n_away}, + child_center, box_levels[child_box_id]); if (a_or_o) { // child_box_id lives on walk_level+1. - if (walk_level+1 == level && child_box_id != box_id) + if (walk_level+1 == level && child_box_id != box_id) { - dbg_printf((" colleague\n")); - APPEND_colleagues(child_box_id); + dbg_printf((" found same-lev nws\n")); + APPEND_same_level_non_well_sep_boxes(child_box_id); } else { @@ -395,8 +417,10 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) { ${load_center("child_center", "child_box_id")} - bool a_or_o = is_adjacent_or_overlapping(root_extent, - center, level, child_center, box_levels[child_box_id]); + bool a_or_o = is_adjacent_or_overlapping( + root_extent, + center, level, + child_center, box_levels[child_box_id]); if (a_or_o) { @@ -451,23 +475,26 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) if (parent == box_id) return; - box_id_t parent_coll_start = colleagues_starts[parent]; - box_id_t parent_coll_stop = colleagues_starts[parent+1]; + box_id_t parent_slnf_start = same_level_non_well_sep_boxes_starts[parent]; + box_id_t parent_slnf_stop = same_level_non_well_sep_boxes_starts[parent+1]; - // /!\ i is not a box_id, it's an index into colleagues_list. - for (box_id_t i = parent_coll_start; i < parent_coll_stop; ++i) + // /!\ i is not a box_id, it's an index into same_level_non_well_sep_boxes_list. + for (box_id_t i = parent_slnf_start; i < parent_slnf_stop; ++i) { - box_id_t parent_colleague = colleagues_list[i]; + box_id_t parent_nf = same_level_non_well_sep_boxes_lists[i]; for (int morton_nr = 0; morton_nr < ${2**dimensions}; ++morton_nr) { box_id_t sib_box_id = box_child_ids[ - morton_nr * aligned_nboxes + parent_colleague]; + morton_nr * aligned_nboxes + parent_nf]; ${load_center("sib_center", "sib_box_id")} - bool sep = !is_adjacent_or_overlapping(root_extent, - center, level, sib_center, box_levels[sib_box_id]); + bool sep = !is_adjacent_or_overlapping_with_neighborhood( + root_extent, + center, level, + ${well_sep_is_n_away}, + sib_center, box_levels[sib_box_id]); if (sep) { @@ -792,7 +819,7 @@ class FMMTraversalInfo(DeviceDataRecord): """Interaction lists needed for a fast-multipole-like linear-time gather of particle interactions. - Terminology follows this article: + Terminology (largely) follows this article: Carrier, J., Greengard, L. and Rokhlin, V. "A Fast Adaptive Multipole Algorithm for Particle Simulations." SIAM Journal on @@ -806,6 +833,12 @@ class FMMTraversalInfo(DeviceDataRecord): An instance of :class:`boxtree.Tree`. + .. attribute:: well_sep_is_n_away + + The distance (measured in target box diameters in the :math:`l^\infty` + norm) from the edge of the target box at which the 'well-separated' + (i.e. M2L-handled) 'far-field' starts. + .. ------------------------------------------------------------------------ .. rubric:: Basic box lists for iteration .. ------------------------------------------------------------------------ @@ -872,16 +905,21 @@ class FMMTraversalInfo(DeviceDataRecord): each level starts and ends. .. ------------------------------------------------------------------------ - .. rubric:: Colleagues + .. rubric:: Same-level non-well-separated boxes .. ------------------------------------------------------------------------ - Immediately adjacent boxes on the same level. See :ref:`csr`. + Boxes considered to be within the 'non-well-separated area' according to + :attr:`well_sep_is_n_away` that are on the same level as their reference + box. See :ref:`csr`. + + This is a generalization of the "colleagues" concept from the Carrier paper + to the case in which :attr:`well_sep_is_n_away` is not 1. - .. attribute:: colleagues_starts + .. attribute:: same_level_non_well_sep_boxes_starts ``box_id_t [nboxes+1]`` - .. attribute:: colleagues_lists + .. attribute:: same_level_non_well_sep_boxes_lists ``box_id_t [*]`` @@ -1156,8 +1194,9 @@ class _KernelInfo(Record): class FMMTraversalBuilder: - def __init__(self, context): + def __init__(self, context, well_sep_is_n_away=1): self.context = context + self.well_sep_is_n_away = well_sep_is_n_away # {{{ kernel builder @@ -1186,6 +1225,7 @@ class FMMTraversalBuilder: sources_are_targets=sources_are_targets, sources_have_extent=sources_have_extent, targets_have_extent=targets_have_extent, + well_sep_is_n_away=self.well_sep_is_n_away, ) from pyopencl.algorithm import ListOfListsBuilder from pyopencl.tools import VectorArg, ScalarArg @@ -1238,7 +1278,8 @@ class FMMTraversalBuilder: ] for list_name, template, extra_args, extra_lists in [ - ("colleagues", COLLEAGUES_TEMPLATE, [], []), + ("same_level_non_well_sep_boxes", + SAME_LEVEL_NON_WELL_SEP_BOXES_TEMPLATE, [], []), ("neighbor_source_boxes", NEIGBHOR_SOURCE_BOXES_TEMPLATE, [ VectorArg(box_id_dtype, "target_boxes"), @@ -1247,8 +1288,10 @@ class FMMTraversalBuilder: [ VectorArg(box_id_dtype, "target_or_target_parent_boxes"), VectorArg(box_id_dtype, "box_parent_ids"), - VectorArg(box_id_dtype, "colleagues_starts"), - VectorArg(box_id_dtype, "colleagues_list"), + VectorArg(box_id_dtype, + "same_level_non_well_sep_boxes_starts"), + VectorArg(box_id_dtype, + "same_level_non_well_sep_boxes_lists"), ], []), ("sep_smaller", SEP_SMALLER_TEMPLATE, [ @@ -1400,17 +1443,20 @@ class FMMTraversalBuilder: # }}} - # {{{ colleagues + # {{{ same-level near-field + + # If well_sep_is_n_away is 1, this agrees with the definition of + # 'colleagues' from the classical FMM literature. - fin_debug("finding colleagues") + fin_debug("finding same-level near-field boxes") - result, evt = knl_info.colleagues_builder( + result, evt = knl_info.same_level_non_well_sep_boxes_builder( queue, tree.nboxes, tree.box_centers.data, tree.root_extent, tree.box_levels.data, tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, wait_for=wait_for) wait_for = [evt] - colleagues = result["colleagues"] + same_level_non_well_sep_boxes = result["same_level_non_well_sep_boxes"] # }}} @@ -1438,7 +1484,9 @@ class FMMTraversalBuilder: tree.box_centers.data, tree.root_extent, tree.box_levels.data, tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, target_or_target_parent_boxes.data, tree.box_parent_ids.data, - colleagues.starts.data, colleagues.lists.data, wait_for=wait_for) + same_level_non_well_sep_boxes.starts.data, + same_level_non_well_sep_boxes.lists.data, + wait_for=wait_for) wait_for = [evt] sep_siblings = result["sep_siblings"] @@ -1455,7 +1503,9 @@ class FMMTraversalBuilder: tree.box_centers.data, tree.root_extent, tree.box_levels.data, tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, tree.stick_out_factor, target_boxes.data, - colleagues.starts.data, colleagues.lists.data) + same_level_non_well_sep_boxes.starts.data, + same_level_non_well_sep_boxes.lists.data, + ) sep_smaller_wait_for = [] sep_smaller_by_level = [] @@ -1500,7 +1550,10 @@ class FMMTraversalBuilder: tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, tree.stick_out_factor, target_or_target_parent_boxes.data, tree.box_parent_ids.data, - colleagues.starts.data, colleagues.lists.data, wait_for=wait_for) + same_level_non_well_sep_boxes.starts.data, + same_level_non_well_sep_boxes.lists.data, + wait_for=wait_for) + wait_for = [evt] sep_bigger = result["sep_bigger"] @@ -1513,12 +1566,20 @@ class FMMTraversalBuilder: # }}} + if self.well_sep_is_n_away == 1: + colleagues_starts = same_level_non_well_sep_boxes.starts + colleagues_lists = same_level_non_well_sep_boxes.lists + else: + colleagues_starts = None + colleagues_lists = None + evt, = wait_for logger.info("traversal built") return FMMTraversalInfo( tree=tree, + well_sep_is_n_away=self.well_sep_is_n_away, source_boxes=source_boxes, target_boxes=target_boxes, @@ -1533,8 +1594,13 @@ class FMMTraversalBuilder: level_start_target_or_target_parent_box_nrs=( level_start_target_or_target_parent_box_nrs), - colleagues_starts=colleagues.starts, - colleagues_lists=colleagues.lists, + same_level_non_well_sep_boxes_starts=( + same_level_non_well_sep_boxes.starts), + same_level_non_well_sep_boxes_lists=( + same_level_non_well_sep_boxes.lists), + # Deprecated, but we'll keep these alive for the time being. + colleagues_starts=colleagues_starts, + colleagues_lists=colleagues_lists, neighbor_source_boxes_starts=neighbor_source_boxes.starts, neighbor_source_boxes_lists=neighbor_source_boxes.lists, diff --git a/test/test_traversal.py b/test/test_traversal.py index 1769ca9..be94234 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -253,7 +253,7 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # {{{ visualization helper (not a test) -def plot_traversal(ctx_getter, do_plot=False): +def plot_traversal(ctx_getter, do_plot=False, well_sep_is_n_away=1): ctx = ctx_getter() queue = cl.CommandQueue(ctx) @@ -277,11 +277,14 @@ def plot_traversal(ctx_getter, do_plot=False): tb = TreeBuilder(ctx) queue.finish() - tree = tb(queue, particles, max_particles_in_box=30, debug=True) + tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True) from boxtree.traversal import FMMTraversalBuilder - tg = FMMTraversalBuilder(ctx) - trav = tg(queue, tree).get() + tg = FMMTraversalBuilder(ctx, well_sep_is_n_away=well_sep_is_n_away) + trav, _ = tg(queue, tree) + + tree = tree.get(queue=queue) + trav = trav.get(queue=queue) from boxtree.visualization import TreePlotter plotter = TreePlotter(tree) @@ -295,7 +298,7 @@ def plot_traversal(ctx_getter, do_plot=False): # {{{ generic box drawing helper def draw_some_box_lists(starts, lists, key_to_box=None, - count=5): + count=1): actual_count = 0 while actual_count < count: if key_to_box is not None: @@ -319,28 +322,28 @@ def plot_traversal(ctx_getter, do_plot=False): # }}} if 0: - # colleagues + # same-level near field draw_some_box_lists( - trav.colleagues_starts, - trav.colleagues_lists) + trav.same_level_near_field_boxes_starts, + trav.same_level_near_field_boxes_lists) elif 0: # near neighbors ("list 1") draw_some_box_lists( - trav.neighbor_leaves_starts, - trav.neighbor_leaves_lists, + trav.neighbor_source_boxes_starts, + trav.neighbor_source_boxes_lists, key_to_box=trav.source_boxes) - elif 0: + elif 1: # well-separated siblings (list 2) draw_some_box_lists( trav.sep_siblings_starts, trav.sep_siblings_lists) - elif 1: + elif 0: # separated smaller (list 3) draw_some_box_lists( trav.sep_smaller_starts, trav.sep_smaller_lists, key_to_box=trav.source_boxes) - elif 1: + elif 0: # separated bigger (list 4) draw_some_box_lists( trav.sep_bigger_starts, -- GitLab From 5c5915503585ef7589a94e7d72b73ad6edc748f8 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 27 Jul 2017 14:57:16 -0500 Subject: [PATCH 03/41] draw_box: support shrink_factor --- boxtree/visualization.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boxtree/visualization.py b/boxtree/visualization.py index 46fdc33..1ad865f 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -86,6 +86,12 @@ class TreePlotter: el, eh = self.tree.get_box_extent(ibox) + shrink_factor = kwargs.pop("shrink_factor", 0) + if shrink_factor: + center = 0.5*(el+eh) + el += (center-el)*shrink_factor + eh += (center-eh)*shrink_factor + import matplotlib.pyplot as pt import matplotlib.patches as mpatches from matplotlib.path import Path -- GitLab From a1cdc7d82437e216d17ce2b51627be4866f1b8d3 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 27 Jul 2017 14:57:47 -0500 Subject: [PATCH 04/41] plot_traversal: support showing all lists for one box --- test/test_traversal.py | 111 ++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/test/test_traversal.py b/test/test_traversal.py index be94234..56ca9c7 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -297,57 +297,74 @@ def plot_traversal(ctx_getter, do_plot=False, well_sep_is_n_away=1): # {{{ generic box drawing helper - def draw_some_box_lists(starts, lists, key_to_box=None, - count=1): - actual_count = 0 - while actual_count < count: - if key_to_box is not None: - key = randrange(len(key_to_box)) - ibox = key_to_box[key] + def draw_box_list(ibox, starts, lists, key_to_box=None, **kwargs): + if key_to_box is not None: + ind, = np.where(key_to_box == ibox) + if ind: + key, = ind else: - key = ibox = randrange(tree.nboxes) - - start, end = starts[key:key+2] - if start == end: - continue - - #print ibox, start, end, lists[start:end] - for jbox in lists[start:end]: - plotter.draw_box(jbox, facecolor='yellow') - - plotter.draw_box(ibox, facecolor='red') - - actual_count += 1 + return + else: + key = ibox + + start, end = starts[key:key+2] + if start == end: + return + + actual_kwargs = { + "facecolor": "yellow", + "linewidth": 0, + "alpha": 0.5, + "shrink_factor": 0.2, + } + actual_kwargs.update(kwargs) + #print ibox, start, end, lists[start:end] + for jbox in lists[start:end]: + plotter.draw_box(jbox, **actual_kwargs) # }}} - if 0: - # same-level near field - draw_some_box_lists( - trav.same_level_near_field_boxes_starts, - trav.same_level_near_field_boxes_lists) - elif 0: - # near neighbors ("list 1") - draw_some_box_lists( - trav.neighbor_source_boxes_starts, - trav.neighbor_source_boxes_lists, - key_to_box=trav.source_boxes) - elif 1: - # well-separated siblings (list 2) - draw_some_box_lists( - trav.sep_siblings_starts, - trav.sep_siblings_lists) - elif 0: - # separated smaller (list 3) - draw_some_box_lists( - trav.sep_smaller_starts, - trav.sep_smaller_lists, - key_to_box=trav.source_boxes) - elif 0: - # separated bigger (list 4) - draw_some_box_lists( - trav.sep_bigger_starts, - trav.sep_bigger_lists) + def draw_box_lists(ibox): + plotter.draw_box(ibox, facecolor='red', + alpha=0.5) + + if 0: + # same-level near field + draw_box_list(ibox, + trav.same_level_near_field_boxes_starts, + trav.same_level_near_field_boxes_lists, + facecolor="green") + else: + # near neighbors ("list 1") + draw_box_list(ibox, + trav.neighbor_source_boxes_starts, + trav.neighbor_source_boxes_lists, + key_to_box=trav.source_boxes, + facecolor="green") + + # well-separated siblings (list 2) + draw_box_list(ibox, + trav.sep_siblings_starts, + trav.sep_siblings_lists, + facecolor="blue") + + # separated smaller (list 3) + for ilev in range(tree.nlevels): + draw_box_list(ibox, + trav.sep_smaller_by_level[ilev].starts, + trav.sep_smaller_by_level[ilev].lists, + key_to_box=trav.source_boxes, + facecolor="yellow") + + # separated bigger (list 4) + draw_box_list(ibox, + trav.sep_bigger_starts, + trav.sep_bigger_lists, + facecolor="purple") + + #draw_box_lists(randrange(tree.nboxes)) + draw_box_lists(320) + #plotter.draw_box_numbers() import matplotlib.pyplot as pt pt.show() -- GitLab From a3e6d684611555db3808419358bf7f26bbf82ba3 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 27 Jul 2017 17:02:26 -0500 Subject: [PATCH 05/41] Generalize list 3 for 2-away --- boxtree/traversal.py | 66 ++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 814343c..44d05ea 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -38,17 +38,37 @@ logger = logging.getLogger(__name__) # {{{ preamble TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// -<%def name="walk_init(start_box_id)"> +<%def name="walk_init(start_box_id, include_start_box=False)"> box_id_t box_stack[NLEVELS]; int morton_nr_stack[NLEVELS]; // start at root int walk_level = 0; box_id_t walk_box_id = ${start_box_id}; - int walk_morton_nr = 0; + %if include_start_box: + int walk_morton_nr = -1; + %else: + int walk_morton_nr = 0; + %endif bool continue_walk = true; +## "True" is the safe default here because it handles all cases. +<%def name="walk_get_child_box_id(include_start_box=True)"> + + box_id_t child_box_id; + %if include_start_box: + if (walk_morton_nr == -1) + child_box_id = walk_box_id; + else + child_box_id = box_child_ids[ + walk_morton_nr * aligned_nboxes + walk_box_id]; + %else: + child_box_id = box_child_ids[ + walk_morton_nr * aligned_nboxes + walk_box_id]; + %endif + + <%def name="walk_advance()"> while (true) { @@ -324,8 +344,8 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) while (continue_walk) { - box_id_t child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; + ${walk_get_child_box_id(include_start_box=False)} + dbg_printf((" level: %d walk box id: %d morton: %d child id: %d\n", walk_level, walk_box_id, walk_morton_nr, child_box_id)); @@ -407,8 +427,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) while (continue_walk) { - box_id_t child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; + ${walk_get_child_box_id(include_start_box=False)} dbg_printf((" walk box id: %d morton: %d child id: %d level: %d\n", walk_box_id, walk_morton_nr, child_box_id, walk_level)); @@ -522,20 +541,25 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) int level = box_levels[box_id]; - box_id_t coll_start = colleagues_starts[box_id]; - box_id_t coll_stop = colleagues_starts[box_id+1]; + box_id_t slnws_start = same_level_non_well_sep_boxes_starts[box_id]; + box_id_t slnws_stop = same_level_non_well_sep_boxes_starts[box_id+1]; - // /!\ i is not a box_id, it's an index into colleagues_list. - for (box_id_t i = coll_start; i < coll_stop; ++i) + // /!\ i is not a box_id, it's an index into same_level_non_well_sep_boxes_lists. + for (box_id_t i = slnws_start; i < slnws_stop; ++i) { - box_id_t colleague = colleagues_list[i]; + box_id_t same_lev_nws_box = same_level_non_well_sep_boxes_lists[i]; - ${walk_init("colleague")} + // Colleagues (same-level NWS boxes) for 1-away are always adjacent, so + // we always want to descend into them. For 2-away, we may already + // satisfy the criteria for being in list 3 and therefore may never + // need to descend. Hence include the start box in the search here + // if we're in the two-or-more-away case. + ${walk_init("same_lev_nws_box", include_start_box=well_sep_is_n_away > 1)} while (continue_walk) { // Loop invariant: walk_box_id is, at first, always adjacent to box_id. - // This is true at the first level because colleagues are by adjacent + // This is true at the first level because colleagues are adjacent // by definition, and is kept true throughout the walk by only descending // into adjacent boxes. // @@ -553,8 +577,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) // done by direct evaluation. We also need to descend into that // child. - box_id_t child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; + ${walk_get_child_box_id(include_start_box=well_sep_is_n_away > 1)} dbg_printf((" walk box id: %d morton: %d child id: %d\n", walk_box_id, walk_morton_nr, child_box_id)); @@ -631,7 +654,6 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) } } } - ${walk_advance()} } } @@ -1297,8 +1319,10 @@ class FMMTraversalBuilder: [ ScalarArg(coord_dtype, "stick_out_factor"), VectorArg(box_id_dtype, "target_boxes"), - VectorArg(box_id_dtype, "colleagues_starts"), - VectorArg(box_id_dtype, "colleagues_list"), + VectorArg(box_id_dtype, + "same_level_non_well_sep_boxes_starts"), + VectorArg(box_id_dtype, + "same_level_non_well_sep_boxes_lists"), ScalarArg(box_id_dtype, "sep_smaller_source_level"), ], ["sep_close_smaller"] @@ -1357,6 +1381,12 @@ class FMMTraversalBuilder: if not tree._is_pruned: raise ValueError("tree must be pruned for traversal generation") + if tree.sources_have_extent: + # YAGNI + raise NotImplementedError( + "trees with source extent are not supported for " + "traversal generation") + # Generated code shouldn't depend on the *exact* number of tree levels. # So round up to the next multiple of 5. from pytools import div_ceil -- GitLab From 979f32be3049a78f9eb2fd0c34a0ee91af2a5f0a Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 27 Jul 2017 17:22:46 -0500 Subject: [PATCH 06/41] Disable source-with-extent traversal tests --- test/test_fmm.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/test_fmm.py b/test/test_fmm.py index f3b72b3..bab4961 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -32,7 +32,7 @@ import pytest from pyopencl.tools import ( # noqa pytest_generate_tests_for_pyopencl as pytest_generate_tests) -from boxtree.tools import ( +from boxtree.tools import ( # noqa: F401 make_normal_particle_array as p_normal, make_surface_particle_array as p_surface, make_uniform_particle_array as p_uniform, @@ -237,31 +237,31 @@ class ConstantOneExpansionWranglerWithFilteredTargetsInUserOrder( [ (2, 10**5, None, "", p_normal, p_normal, None), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, None), - (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), - (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), + #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), + #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, None), - (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), + #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), (3, 10**5, None, "", p_normal, p_normal, None), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, None), - (3, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), - (3, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), + #(3, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), + #(3, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), (3, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, None), - (3, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), + #(3, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), (2, 10**5, None, "", p_normal, p_normal, "user"), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, "user"), - (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "user"), - (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "user"), + #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "user"), + #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "user"), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, "user"), - (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "user"), + #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "user"), (2, 10**5, None, "", p_normal, p_normal, "tree"), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, "tree"), - (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "tree"), - (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "tree"), + #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "tree"), + #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "tree"), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, "tree"), - (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), + #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), ]) def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, who_has_extent, source_gen, target_gen, filter_kind): -- GitLab From 430cff6f3bdf7b0e7f36bb4f69b67d788b8aea21 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 27 Jul 2017 17:23:44 -0500 Subject: [PATCH 07/41] More colleague -> slnws renames, mostly for list 4 --- boxtree/traversal.py | 50 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 44d05ea..933102a 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -330,7 +330,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) if (box_id == 0) { - // The root has no colleagues. + // The root has no boxes on the same level, nws or not. return; } @@ -338,7 +338,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) dbg_printf(("box id: %d level: %d\n", box_id, level)); - // To find this box's colleagues, start at the top of the tree, descend + // To find this box's same-level nws boxes, start at the top of the tree, descend // into adjacent (or overlapping) parents. ${walk_init(0)} @@ -421,7 +421,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) } } - // To find this box's colleagues, start at the top of the tree, descend + // To find this box's adjacent boxes, start at the top of the tree, descend // into adjacent (or overlapping) parents. ${walk_init(0)} @@ -755,11 +755,12 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) box_flags_t tgt_box_flags = box_flags[tgt_ibox]; - // Look for colleagues of parents that are non-adjacent to tgt_ibox. + // Look for same-level non-well-separated boxes of parents that are + // non-adjacent to tgt_ibox. // Walk up the tree from tgt_ibox. - // Box 0 (== level 0) doesn't have any colleagues, so we can stop the - // search for such colleagues there. + // Box 0 (== level 0) doesn't have any slnws boxes, so we can stop the + // search for such slnws boxes there. for (int walk_level = box_level - 1; walk_level != 0; // {{{ advance --walk_level, @@ -767,19 +768,22 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) // }}} ) { - box_id_t coll_start = colleagues_starts[current_parent_box_id]; - box_id_t coll_stop = colleagues_starts[current_parent_box_id+1]; - - // /!\ i is not a box id, it's an index into colleagues_list. - for (box_id_t i = coll_start; i < coll_stop; ++i) + box_id_t slnws_start = + same_level_non_well_sep_boxes_starts[current_parent_box_id]; + box_id_t slnws_stop = + same_level_non_well_sep_boxes_starts[current_parent_box_id+1]; + + // /!\ i is not a box id, it's an index into + // same_level_non_well_sep_boxes_lists. + for (box_id_t i = slnws_start; i < slnws_stop; ++i) { - box_id_t colleague_box_id = colleagues_list[i]; + box_id_t slnws_box_id = same_level_non_well_sep_boxes_lists[i]; - if (box_flags[colleague_box_id] & BOX_HAS_OWN_SOURCES) + if (box_flags[slnws_box_id] & BOX_HAS_OWN_SOURCES) { - ${load_center("colleague_center", "colleague_box_id")} + ${load_center("slnws_center", "slnws_box_id")} bool a_or_o = is_adjacent_or_overlapping(root_extent, - center, box_level, colleague_center, walk_level); + center, box_level, slnws_center, walk_level); if (!a_or_o) { @@ -788,18 +792,18 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) %if sources_have_extent or targets_have_extent: const bool a_or_o_with_stick_out = is_adjacent_or_overlapping_with_stick_out(root_extent, - center, box_level, colleague_center, + center, box_level, slnws_center, walk_level, stick_out_factor); if (a_or_o_with_stick_out) { - // "Case 1" above: colleague_box_id is too close and + // "Case 1" above: slnws_box_id is too close and // overlaps our stick_out region. We're obliged to do // the interaction directly. if (tgt_box_flags & BOX_HAS_OWN_TARGETS) { - APPEND_sep_close_bigger(colleague_box_id); + APPEND_sep_close_bigger(slnws_box_id); } } else @@ -807,7 +811,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { bool parent_a_or_o_with_stick_out = is_adjacent_or_overlapping_with_stick_out(root_extent, - parent_center, box_level-1, colleague_center, + parent_center, box_level-1, slnws_center, walk_level, stick_out_factor); if (parent_a_or_o_with_stick_out) @@ -815,7 +819,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) // "Case 2" above: We're the first box down the chain // to be far enough away to let the interaction into // our local downward subtree. - APPEND_sep_bigger(colleague_box_id); + APPEND_sep_bigger(slnws_box_id); } else { @@ -1333,8 +1337,10 @@ class FMMTraversalBuilder: ScalarArg(coord_dtype, "stick_out_factor"), VectorArg(box_id_dtype, "target_or_target_parent_boxes"), VectorArg(box_id_dtype, "box_parent_ids"), - VectorArg(box_id_dtype, "colleagues_starts"), - VectorArg(box_id_dtype, "colleagues_list"), + VectorArg(box_id_dtype, + "same_level_non_well_sep_boxes_starts"), + VectorArg(box_id_dtype, + "same_level_non_well_sep_boxes_lists"), #ScalarArg(box_id_dtype, "sep_bigger_source_level"), ], ["sep_close_bigger"] -- GitLab From bc39130c07fdc4ff77fffaf372d2c3a390304ada Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 27 Jul 2017 17:24:05 -0500 Subject: [PATCH 08/41] Flake8 fix for tests --- test/test_traversal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_traversal.py b/test/test_traversal.py index 56ca9c7..9e7a361 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -292,7 +292,7 @@ def plot_traversal(ctx_getter, do_plot=False, well_sep_is_n_away=1): #plotter.draw_box_numbers() plotter.set_bounding_box() - from random import randrange, seed + from random import randrange, seed # noqa seed(7) # {{{ generic box drawing helper -- GitLab From 956648c512238deaf82b0513144720b5daf0404f Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 28 Jul 2017 10:54:38 -0500 Subject: [PATCH 09/41] Move box list drawing to a global utility --- boxtree/visualization.py | 89 ++++++++++++++++++++++++++++++++++++++-- test/test_traversal.py | 69 +------------------------------ 2 files changed, 87 insertions(+), 71 deletions(-) diff --git a/boxtree/visualization.py b/boxtree/visualization.py index 1ad865f..558d046 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -1,7 +1,4 @@ -from __future__ import division -from __future__ import absolute_import -from six.moves import range -from six.moves import zip +from __future__ import division, absolute_import __copyright__ = "Copyright (C) 2012 Andreas Kloeckner" @@ -25,6 +22,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +from six.moves import range, zip +import numpy as np + + +# {{{ utilities def int_to_roman(inp): """ @@ -48,6 +50,10 @@ def int_to_roman(inp): inp -= ints[i] * count return result +# }}} + + +# {{{ tree plotting class TreePlotter: """Assumes that the tree has data living on the host. @@ -164,4 +170,79 @@ class TreePlotter: r"}}") return "\n".join(lines) +# }}} + + +# {{{ traversal plotting + +def _draw_box_list(tree_plotter, ibox, starts, lists, key_to_box=None, **kwargs): + if key_to_box is not None: + ind, = np.where(key_to_box == ibox) + if ind: + key, = ind + else: + return + else: + key = ibox + + start, end = starts[key:key+2] + if start == end: + return + + actual_kwargs = { + "facecolor": "yellow", + "linewidth": 0, + "alpha": 0.5, + "shrink_factor": 0.2, + } + actual_kwargs.update(kwargs) + #print ibox, start, end, lists[start:end] + for jbox in lists[start:end]: + tree_plotter.draw_box(jbox, **actual_kwargs) + + +def draw_same_level_non_well_sep_boxes(tree_plotter, traversal, ibox): + tree_plotter.draw_box(ibox, facecolor='red', + alpha=0.5) + + # same-level non-well-sep + _draw_box_list(ibox, + traversal.same_level_non_well_sep_boxes_starts, + traversal.same_level_non_well_sep_boxes_lists, + facecolor="green") + + +def draw_box_lists(tree_plotter, traversal, ibox): + tree_plotter.draw_box(ibox, facecolor='red', + alpha=0.5) + + # near neighbors ("list 1") + _draw_box_list(tree_plotter, ibox, + traversal.neighbor_source_boxes_starts, + traversal.neighbor_source_boxes_lists, + key_to_box=traversal.source_boxes, + facecolor="green") + + # well-separated siblings (list 2) + _draw_box_list(tree_plotter, ibox, + traversal.sep_siblings_starts, + traversal.sep_siblings_lists, + facecolor="blue") + + # separated smaller (list 3) + for ilev in range(tree_plotter.tree.nlevels): + _draw_box_list(tree_plotter, ibox, + traversal.sep_smaller_by_level[ilev].starts, + traversal.sep_smaller_by_level[ilev].lists, + key_to_box=traversal.source_boxes, + facecolor="yellow") + + # separated bigger (list 4) + _draw_box_list(tree_plotter, ibox, + traversal.sep_bigger_starts, + traversal.sep_bigger_lists, + facecolor="purple") + +# }}} + # vim: filetype=pyopencl:fdm=marker diff --git a/test/test_traversal.py b/test/test_traversal.py index 9e7a361..0073074 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -295,75 +295,10 @@ def plot_traversal(ctx_getter, do_plot=False, well_sep_is_n_away=1): from random import randrange, seed # noqa seed(7) - # {{{ generic box drawing helper - - def draw_box_list(ibox, starts, lists, key_to_box=None, **kwargs): - if key_to_box is not None: - ind, = np.where(key_to_box == ibox) - if ind: - key, = ind - else: - return - else: - key = ibox - - start, end = starts[key:key+2] - if start == end: - return - - actual_kwargs = { - "facecolor": "yellow", - "linewidth": 0, - "alpha": 0.5, - "shrink_factor": 0.2, - } - actual_kwargs.update(kwargs) - #print ibox, start, end, lists[start:end] - for jbox in lists[start:end]: - plotter.draw_box(jbox, **actual_kwargs) - - # }}} - - def draw_box_lists(ibox): - plotter.draw_box(ibox, facecolor='red', - alpha=0.5) - - if 0: - # same-level near field - draw_box_list(ibox, - trav.same_level_near_field_boxes_starts, - trav.same_level_near_field_boxes_lists, - facecolor="green") - else: - # near neighbors ("list 1") - draw_box_list(ibox, - trav.neighbor_source_boxes_starts, - trav.neighbor_source_boxes_lists, - key_to_box=trav.source_boxes, - facecolor="green") - - # well-separated siblings (list 2) - draw_box_list(ibox, - trav.sep_siblings_starts, - trav.sep_siblings_lists, - facecolor="blue") - - # separated smaller (list 3) - for ilev in range(tree.nlevels): - draw_box_list(ibox, - trav.sep_smaller_by_level[ilev].starts, - trav.sep_smaller_by_level[ilev].lists, - key_to_box=trav.source_boxes, - facecolor="yellow") - - # separated bigger (list 4) - draw_box_list(ibox, - trav.sep_bigger_starts, - trav.sep_bigger_lists, - facecolor="purple") + from boxtree.visualization import draw_box_lists #draw_box_lists(randrange(tree.nboxes)) - draw_box_lists(320) + draw_box_lists(plotter, trav, 320) #plotter.draw_box_numbers() import matplotlib.pyplot as pt -- GitLab From 9269aee67ab13fcb952e6a723c8b192d283db4dd Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 28 Jul 2017 13:57:19 -0500 Subject: [PATCH 10/41] Various fixes to interaction list plotting --- boxtree/visualization.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/boxtree/visualization.py b/boxtree/visualization.py index 558d046..f43d3a8 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -176,11 +176,21 @@ class TreePlotter: # {{{ traversal plotting def _draw_box_list(tree_plotter, ibox, starts, lists, key_to_box=None, **kwargs): + default_facecolor = "blue" + if key_to_box is not None: ind, = np.where(key_to_box == ibox) - if ind: + if len(ind): key, = ind else: + # indicate empty list + actual_kwargs = { + "edgecolor": getattr(kwargs, "facecolor", default_facecolor), + "fill": False, + "alpha": 0.5, + "shrink_factor": -0.1+0.1*np.random.rand(), + } + tree_plotter.draw_box(ibox, **actual_kwargs) return else: key = ibox @@ -190,7 +200,7 @@ def _draw_box_list(tree_plotter, ibox, starts, lists, key_to_box=None, **kwargs) return actual_kwargs = { - "facecolor": "yellow", + "facecolor": default_facecolor, "linewidth": 0, "alpha": 0.5, "shrink_factor": 0.2, @@ -220,13 +230,14 @@ def draw_box_lists(tree_plotter, traversal, ibox): _draw_box_list(tree_plotter, ibox, traversal.neighbor_source_boxes_starts, traversal.neighbor_source_boxes_lists, - key_to_box=traversal.source_boxes, + key_to_box=traversal.target_boxes, facecolor="green") # well-separated siblings (list 2) _draw_box_list(tree_plotter, ibox, traversal.sep_siblings_starts, traversal.sep_siblings_lists, + key_to_box=traversal.target_or_target_parent_boxes, facecolor="blue") # separated smaller (list 3) @@ -234,13 +245,14 @@ def draw_box_lists(tree_plotter, traversal, ibox): _draw_box_list(tree_plotter, ibox, traversal.sep_smaller_by_level[ilev].starts, traversal.sep_smaller_by_level[ilev].lists, - key_to_box=traversal.source_boxes, - facecolor="yellow") + key_to_box=traversal.target_or_target_parent_boxes, + facecolor="yellow", shrink_factor=0.25) # separated bigger (list 4) _draw_box_list(tree_plotter, ibox, traversal.sep_bigger_starts, traversal.sep_bigger_lists, + key_to_box=traversal.target_or_target_parent_boxes, facecolor="purple") # }}} -- GitLab From 3e01c5a1f10446a14d64d97f3a2483821b171681 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 28 Jul 2017 13:58:15 -0500 Subject: [PATCH 11/41] Traversal doc clarifications --- boxtree/traversal.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 933102a..0561d48 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -954,7 +954,8 @@ class FMMTraversalInfo(DeviceDataRecord): .. ------------------------------------------------------------------------ List of source boxes immediately adjacent to each target box. Indexed like - :attr:`target_boxes`. See :ref:`csr`. + :attr:`target_boxes`. See :ref:`csr`. (Note: This list contains global box + numbers, not indices into :attr:`source_boxes`.) .. attribute:: neighbor_source_boxes_starts @@ -984,6 +985,8 @@ class FMMTraversalInfo(DeviceDataRecord): .. ------------------------------------------------------------------------ Smaller source boxes separated from the target box by their own size. + (Note: This list contains global box numbers, not indices into + :attr:`source_boxes`.) If :attr:`boxtree.Tree.targets_have_extent`, then :attr:`sep_close_smaller_starts` will be non-*None*. It records @@ -1000,7 +1003,7 @@ class FMMTraversalInfo(DeviceDataRecord): attributes *count*, *starts* and *lists*, which form a CSR list of List 3source boxes. - *starts* has shape/type ``box_id_t [ntargets+1]``. *lists* is of type + *starts* has shape/type ``box_id_t [ntarget_boxes+1]``. *lists* is of type ``box_id_t``. .. attribute:: sep_close_smaller_starts @@ -1017,6 +1020,8 @@ class FMMTraversalInfo(DeviceDataRecord): Bigger source boxes separated from the target box by the (smaller) target box's size. + (Note: This list contains global box numbers, not indices into + :attr:`source_boxes`.) If :attr:`boxtree.Tree.sources_have_extent`, then :attr:`sep_close_bigger_starts` will be non-*None*. It records -- GitLab From 1ba23c02d45bc588910550111a850a140d0f6724 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 17:04:27 -0500 Subject: [PATCH 12/41] Interaction list plotting tweaks/fixes --- boxtree/visualization.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/boxtree/visualization.py b/boxtree/visualization.py index f43d3a8..f204c8e 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -203,10 +203,10 @@ def _draw_box_list(tree_plotter, ibox, starts, lists, key_to_box=None, **kwargs) "facecolor": default_facecolor, "linewidth": 0, "alpha": 0.5, - "shrink_factor": 0.2, + "shrink_factor": 0.1 + np.random.rand()*0.2, } actual_kwargs.update(kwargs) - #print ibox, start, end, lists[start:end] + print(actual_kwargs["facecolor"], ibox, lists[start:end]) for jbox in lists[start:end]: tree_plotter.draw_box(jbox, **actual_kwargs) @@ -216,7 +216,7 @@ def draw_same_level_non_well_sep_boxes(tree_plotter, traversal, ibox): alpha=0.5) # same-level non-well-sep - _draw_box_list(ibox, + _draw_box_list(tree_plotter, ibox, traversal.same_level_non_well_sep_boxes_starts, traversal.same_level_non_well_sep_boxes_lists, facecolor="green") @@ -245,8 +245,8 @@ def draw_box_lists(tree_plotter, traversal, ibox): _draw_box_list(tree_plotter, ibox, traversal.sep_smaller_by_level[ilev].starts, traversal.sep_smaller_by_level[ilev].lists, - key_to_box=traversal.target_or_target_parent_boxes, - facecolor="yellow", shrink_factor=0.25) + key_to_box=traversal.target_boxes, + facecolor="orange") # separated bigger (list 4) _draw_box_list(tree_plotter, ibox, -- GitLab From 65ebed48faf7ae9c9afb4c5c759ae54f47d567fd Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 17:06:47 -0500 Subject: [PATCH 13/41] Traversal: comment/documentation improvements --- boxtree/traversal.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 0561d48..1ffe3f1 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -690,10 +690,10 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # (X: yes, O:no, exclamation marks denote that this *must* be the case. Entries # without exclamation mark are choices for this case) # -# Case 1: A->B interaction enters the downward propagation at B, i.e. A is in +# Case 2: A->B interaction enters the downward propagation at B, i.e. A is in # B's "sep_bigger". (list 4) # -# Case 2: A->B interaction entered the downward propagation at B's parent, i.e. +# Case 3: A->B interaction entered the downward propagation at B's parent, i.e. # A is not in B's "sep_bigger". (list 4) # Sources/targets with extent @@ -721,7 +721,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # "adj": adjacent to A without stick-out # # Note that once a parent is no longer "adj" or "so", its children won't be -# either. Also note that "adj" => "so". (And there by "not so" => "not adj".) +# either. Also note that "adj" => "so". (And thereby "not so" => "not adj".) # # (X: yes, O:no, ?: doesn't matter, exclamation marks denote that this *must* # be the case. Entries without exclamation mark are choices for this case) @@ -818,12 +818,12 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { // "Case 2" above: We're the first box down the chain // to be far enough away to let the interaction into - // our local downward subtree. + // our local downward propagation. APPEND_sep_bigger(slnws_box_id); } else { - // "Case 2" above: A parent box was already far + // "Case 3" above: A parent box was already far // enough away to let the interaction into its // local downward subtree. We'll get the interaction // that way. Nothing to do. @@ -985,8 +985,6 @@ class FMMTraversalInfo(DeviceDataRecord): .. ------------------------------------------------------------------------ Smaller source boxes separated from the target box by their own size. - (Note: This list contains global box numbers, not indices into - :attr:`source_boxes`.) If :attr:`boxtree.Tree.targets_have_extent`, then :attr:`sep_close_smaller_starts` will be non-*None*. It records @@ -1001,10 +999,11 @@ class FMMTraversalInfo(DeviceDataRecord): A list of :attr:`boxtree.Tree.nlevels` (corresponding to the levels on which each listed source box resides) objects, each of which has attributes *count*, *starts* and *lists*, which form a CSR list of List - 3source boxes. + 3 source boxes. *starts* has shape/type ``box_id_t [ntarget_boxes+1]``. *lists* is of type - ``box_id_t``. + ``box_id_t``. (Note: This list contains global box numbers, not + indices into :attr:`source_boxes`.) .. attribute:: sep_close_smaller_starts -- GitLab From 74a6425ec0732b9abf7ebec1914b5527b9d0f041 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 17:07:51 -0500 Subject: [PATCH 14/41] Implement/test no-extent 2-away FMM --- boxtree/traversal.py | 130 +++++++++++++++++++++++++++++++++---------- test/test_fmm.py | 74 +++++++++++++++--------- 2 files changed, 151 insertions(+), 53 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 1ffe3f1..1952588 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -37,6 +37,16 @@ logger = logging.getLogger(__name__) # {{{ preamble +# This 'walk' mechanism walks over 'child' boxes in the tree. +# +# "include_start_box=True" determines that the start box should +# occur as one such 'child' box. + +# FIXME: Rename: +# walk_box_id -> walk_parent_box_id +# child_box_id -> walk_box_id +# walk_level -> walk_stack_count + TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// <%def name="walk_init(start_box_id, include_start_box=False)"> box_id_t box_stack[NLEVELS]; @@ -69,17 +79,35 @@ TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// %endif -<%def name="walk_advance()"> +<%def name="walk_advance(include_start_box=False)"> while (true) { ++walk_morton_nr; - if (walk_morton_nr < ${2**dimensions}) + if ( + %if include_start_box: + // If we just got done walking the start box, + // we *do* want to continue with the remaining + // checks. + walk_morton_nr && + %endif + walk_morton_nr < ${2**dimensions}) break; // Ran out of children, pull the next guy off the stack // and advance him. - continue_walk = walk_level > 0; + continue_walk = ( + // Stack empty? Abort. + walk_level > 0 + + %if include_start_box: + // Since we encountered the start box as part of the walk, + // there's no need to go find its children. + && walk_morton_nr != 0 + %endif + + ); + if (continue_walk) { --walk_level; @@ -181,6 +209,7 @@ inline bool is_adjacent_or_overlapping_with_stick_out( coord_t root_extent, // target and source order only matter if include_stick_out is true. coord_vec_t target_center, int target_level, + coord_t target_box_neighborhood_size, coord_vec_t source_center, int source_level, const coord_t stick_out_factor ) @@ -193,7 +222,9 @@ inline bool is_adjacent_or_overlapping_with_stick_out( coord_t target_rad = LEVEL_TO_RAD(target_level); coord_t source_rad = LEVEL_TO_RAD(source_level); - coord_t rad_sum = target_rad + source_rad; + coord_t rad_sum = ( + (2*(target_box_neighborhood_size-1) + 1) * target_rad + + source_rad); coord_t slack = rad_sum + fmin(target_rad, source_rad); slack += stick_out_factor * ( @@ -549,12 +580,15 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) { box_id_t same_lev_nws_box = same_level_non_well_sep_boxes_lists[i]; + if (same_lev_nws_box == box_id) + continue; + // Colleagues (same-level NWS boxes) for 1-away are always adjacent, so // we always want to descend into them. For 2-away, we may already // satisfy the criteria for being in list 3 and therefore may never // need to descend. Hence include the start box in the search here // if we're in the two-or-more-away case. - ${walk_init("same_lev_nws_box", include_start_box=well_sep_is_n_away > 1)} + ${walk_init("same_lev_nws_box")} while (continue_walk) { @@ -577,7 +611,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) // done by direct evaluation. We also need to descend into that // child. - ${walk_get_child_box_id(include_start_box=well_sep_is_n_away > 1)} + ${walk_get_child_box_id()} dbg_printf((" walk box id: %d morton: %d child id: %d\n", walk_box_id, walk_morton_nr, child_box_id)); @@ -592,10 +626,10 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) int child_level = box_levels[child_box_id]; - bool a_or_o = is_adjacent_or_overlapping(root_extent, + bool in_list_1 = is_adjacent_or_overlapping(root_extent, center, level, child_center, child_level); - if (a_or_o) + if (in_list_1) { if (child_box_flags & BOX_HAS_CHILD_SOURCES) { @@ -616,8 +650,10 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) %if sources_have_extent or targets_have_extent: const bool a_or_o_with_stick_out = is_adjacent_or_overlapping_with_stick_out(root_extent, - center, level, child_center, - child_level, stick_out_factor); + center, level, + 1, + child_center, child_level, + stick_out_factor); %else: const bool a_or_o_with_stick_out = false; %endif @@ -742,26 +778,38 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) box_id_t tgt_ibox = target_or_target_parent_boxes[itarget_or_target_parent_box]; ${load_center("center", "tgt_ibox")} - int box_level = box_levels[tgt_ibox]; + int tgt_box_level = box_levels[tgt_ibox]; // The root box has no parents, so no list 4. - if (box_level == 0) + if (tgt_box_level == 0) return; box_id_t parent_box_id = box_parent_ids[tgt_ibox]; ${load_center("parent_center", "parent_box_id")} - box_id_t current_parent_box_id = parent_box_id; - int walk_level = box_level - 1; - box_flags_t tgt_box_flags = box_flags[tgt_ibox]; + %if well_sep_is_n_away == 1: + // In a 1-away FMM, tgt_ibox's colleagues are by default uninteresting + // (i.e. not in list 4) because they're adjacent. So in this case, we + // may directly jump to the parent level. + + int walk_level = tgt_box_level - 1; + box_id_t current_parent_box_id = parent_box_id; + %else: + // In a 2+-away FMM, tgt_ibox's same-level well-separated boxes *may* + // be sufficiently separated from tgt_ibox to be in its list 4. + + int walk_level = tgt_box_level; + box_id_t current_parent_box_id = tgt_ibox; + %endif + // Look for same-level non-well-separated boxes of parents that are // non-adjacent to tgt_ibox. // Walk up the tree from tgt_ibox. // Box 0 (== level 0) doesn't have any slnws boxes, so we can stop the // search for such slnws boxes there. - for (int walk_level = box_level - 1; walk_level != 0; + for (; walk_level != 0; // {{{ advance --walk_level, current_parent_box_id = box_parent_ids[current_parent_box_id] @@ -782,18 +830,19 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) if (box_flags[slnws_box_id] & BOX_HAS_OWN_SOURCES) { ${load_center("slnws_center", "slnws_box_id")} - bool a_or_o = is_adjacent_or_overlapping(root_extent, - center, box_level, slnws_center, walk_level); + bool in_list_1 = is_adjacent_or_overlapping(root_extent, + center, tgt_box_level, + slnws_center, walk_level); - if (!a_or_o) + if (!in_list_1) { - // Found one. - %if sources_have_extent or targets_have_extent: const bool a_or_o_with_stick_out = is_adjacent_or_overlapping_with_stick_out(root_extent, - center, box_level, slnws_center, - walk_level, stick_out_factor); + center, tgt_box_level, + ${well_sep_is_n_away}, + slnws_center, walk_level, + stick_out_factor); if (a_or_o_with_stick_out) { @@ -809,12 +858,37 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) else %endif { - bool parent_a_or_o_with_stick_out = + bool in_parent_list_1 = is_adjacent_or_overlapping_with_stick_out(root_extent, - parent_center, box_level-1, slnws_center, - walk_level, stick_out_factor); - - if (parent_a_or_o_with_stick_out) + parent_center, tgt_box_level-1, + 1, + slnws_center, walk_level, + stick_out_factor); + + bool in_parent_list_4 = ( + !in_parent_list_1 + %if well_sep_is_n_away > 1: + /* + From-sep-bigger boxes can only be in the + parent's from-sep-bigger list if they're + actually bigger (or equal) to the target + box size. + + For 1-away, that's guaranteed at this + point, because we only start looking at the + parent's level, so any box we find here is + naturally big enough. For 2-away, we start + looking at the target box's level, so + slnws_box_id may actually be too small (at + too deep a level) to be in the parent's + from-sep-bigger list. + */ + + && walk_level < tgt_box_level + %endif + ); + + if (!in_parent_list_4) { // "Case 2" above: We're the first box down the chain // to be far enough away to let the interaction into diff --git a/test/test_fmm.py b/test/test_fmm.py index bab4961..c656b22 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -232,6 +232,7 @@ class ConstantOneExpansionWranglerWithFilteredTargetsInUserOrder( return self.tree.sorted_target_ids[user_target_ids] +@pytest.mark.parametrize("well_sep_is_n_away", [1, 2]) @pytest.mark.parametrize(("dims", "nsources_req", "ntargets_req", "who_has_extent", "source_gen", "target_gen", "filter_kind"), [ @@ -264,7 +265,7 @@ class ConstantOneExpansionWranglerWithFilteredTargetsInUserOrder( #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), ]) def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, - who_has_extent, source_gen, target_gen, filter_kind): + who_has_extent, source_gen, target_gen, filter_kind, well_sep_is_n_away): """Tests whether the built FMM traversal structures and driver completely capture all interactions. """ @@ -272,6 +273,10 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, sources_have_extent = "s" in who_has_extent targets_have_extent = "t" in who_has_extent + # FIXME: + if who_has_extent and well_sep_is_n_away > 1: + pytest.skip("2-away with extents is not right yet") + logging.basicConfig(level=logging.INFO) ctx = ctx_getter() @@ -321,13 +326,13 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, pt.show() from boxtree.traversal import FMMTraversalBuilder - tbuild = FMMTraversalBuilder(ctx) + tbuild = FMMTraversalBuilder(ctx, well_sep_is_n_away=well_sep_is_n_away) trav, _ = tbuild(queue, tree, debug=True) if trav.sep_close_smaller_starts is not None: trav = trav.merge_close_lists(queue) - weights = np.random.randn(nsources) - #weights = np.ones(nsources) + #weights = np.random.randn(nsources) + weights = np.ones(nsources) weights_sum = np.sum(weights) host_trav = trav.get(queue=queue) @@ -350,6 +355,8 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, raise ValueError("unsupported value of 'filter_kind'") else: wrangler = ConstantOneExpansionWrangler(host_tree) + flags = cl.array.empty(queue, ntargets or nsources, dtype=np.int8) + flags.fill(1) if ntargets is None and not filter_kind: # This check only works for targets == sources. @@ -358,10 +365,17 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, from boxtree.fmm import drive_fmm pot = drive_fmm(host_trav, wrangler, weights) + print(pot) - # {{{ build, evaluate matrix (and identify missing interactions) + if filter_kind: + pot = pot[flags.get() > 0] - if 0: + rel_err = la.norm((pot - weights_sum) / nsources) + good = rel_err < 1e-8 + + # {{{ build, evaluate matrix (and identify incorrect interactions) + + if 0 and not good: mat = np.zeros((ntargets, nsources), dtype) from pytools import ProgressBar @@ -379,52 +393,62 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, import matplotlib.pyplot as pt - if 1: - pt.spy(mat) + if 0: + pt.imshow(mat) + pt.colorbar() pt.show() - missing_tgts, missing_srcs = np.where(mat == 0) + incorrect_tgts, incorrect_srcs = np.where(mat != 1) - if 1 and len(missing_tgts): + if 1 and len(incorrect_tgts): from boxtree.visualization import TreePlotter plotter = TreePlotter(host_tree) plotter.draw_tree(fill=False, edgecolor="black") plotter.draw_box_numbers() plotter.set_bounding_box() - tree_order_missing_tgts = \ - host_tree.indices_to_tree_target_order(missing_tgts) - tree_order_missing_srcs = \ - host_tree.indices_to_tree_source_order(missing_srcs) + tree_order_incorrect_tgts = \ + host_tree.indices_to_tree_target_order(incorrect_tgts) + tree_order_incorrect_srcs = \ + host_tree.indices_to_tree_source_order(incorrect_srcs) src_boxes = [ host_tree.find_box_nr_for_source(i) - for i in tree_order_missing_srcs] + for i in tree_order_incorrect_srcs] tgt_boxes = [ host_tree.find_box_nr_for_target(i) - for i in tree_order_missing_tgts] + for i in tree_order_incorrect_tgts] print(src_boxes) print(tgt_boxes) + if 1: # plot all sources/targets + pt.plot( + host_tree.targets[0], + host_tree.targets[1], + "v", alpha=0.9) + pt.plot( + host_tree.sources[0], + host_tree.sources[1], + "gx", alpha=0.9) pt.plot( - host_tree.targets[0][tree_order_missing_tgts], - host_tree.targets[1][tree_order_missing_tgts], + host_tree.targets[0][tree_order_incorrect_tgts], + host_tree.targets[1][tree_order_incorrect_tgts], "rv") pt.plot( - host_tree.sources[0][tree_order_missing_srcs], - host_tree.sources[1][tree_order_missing_srcs], + host_tree.sources[0][tree_order_incorrect_srcs], + host_tree.sources[1][tree_order_incorrect_srcs], "go") pt.gca().set_aspect("equal") + from boxtree.visualization import draw_box_lists + draw_box_lists(plotter, host_trav, 22) + # from boxtree.visualization import draw_same_level_non_well_sep_boxes + # draw_same_level_non_well_sep_boxes(plotter, host_trav, 2) + pt.show() # }}} - if filter_kind: - pot = pot[flags.get() > 0] - - rel_err = la.norm((pot - weights_sum) / nsources) - good = rel_err < 1e-8 if 0 and not good: import matplotlib.pyplot as pt pt.plot(pot-weights_sum) -- GitLab From 327667d004db989d0869b35617205ff0238c1c4f Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 17:44:30 -0500 Subject: [PATCH 15/41] Traversal: Remove false-start 'include_start_box' feature from walk code --- boxtree/traversal.py | 48 +++++++++----------------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 1952588..6de0747 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -38,9 +38,6 @@ logger = logging.getLogger(__name__) # {{{ preamble # This 'walk' mechanism walks over 'child' boxes in the tree. -# -# "include_start_box=True" determines that the start box should -# occur as one such 'child' box. # FIXME: Rename: # walk_box_id -> walk_parent_box_id @@ -48,49 +45,29 @@ logger = logging.getLogger(__name__) # walk_level -> walk_stack_count TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// -<%def name="walk_init(start_box_id, include_start_box=False)"> +<%def name="walk_init(start_box_id)"> box_id_t box_stack[NLEVELS]; int morton_nr_stack[NLEVELS]; // start at root int walk_level = 0; box_id_t walk_box_id = ${start_box_id}; - %if include_start_box: - int walk_morton_nr = -1; - %else: - int walk_morton_nr = 0; - %endif + int walk_morton_nr = 0; bool continue_walk = true; -## "True" is the safe default here because it handles all cases. -<%def name="walk_get_child_box_id(include_start_box=True)"> +<%def name="walk_get_child_box_id()"> box_id_t child_box_id; - %if include_start_box: - if (walk_morton_nr == -1) - child_box_id = walk_box_id; - else - child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; - %else: - child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; - %endif + child_box_id = box_child_ids[ + walk_morton_nr * aligned_nboxes + walk_box_id]; -<%def name="walk_advance(include_start_box=False)"> +<%def name="walk_advance()"> while (true) { ++walk_morton_nr; - if ( - %if include_start_box: - // If we just got done walking the start box, - // we *do* want to continue with the remaining - // checks. - walk_morton_nr && - %endif - walk_morton_nr < ${2**dimensions}) + if (walk_morton_nr < ${2**dimensions}) break; // Ran out of children, pull the next guy off the stack @@ -99,13 +76,6 @@ TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// continue_walk = ( // Stack empty? Abort. walk_level > 0 - - %if include_start_box: - // Since we encountered the start box as part of the walk, - // there's no need to go find its children. - && walk_morton_nr != 0 - %endif - ); if (continue_walk) @@ -375,7 +345,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) while (continue_walk) { - ${walk_get_child_box_id(include_start_box=False)} + ${walk_get_child_box_id()} dbg_printf((" level: %d walk box id: %d morton: %d child id: %d\n", walk_level, walk_box_id, walk_morton_nr, child_box_id)); @@ -458,7 +428,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) while (continue_walk) { - ${walk_get_child_box_id(include_start_box=False)} + ${walk_get_child_box_id()} dbg_printf((" walk box id: %d morton: %d child id: %d level: %d\n", walk_box_id, walk_morton_nr, child_box_id, walk_level)); -- GitLab From f8367598a9819c5a4c62d7c067620cfad54753c3 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 18:24:54 -0500 Subject: [PATCH 16/41] Traversal: Make variable names in walk mechanism a bit more sane --- boxtree/traversal.py | 97 +++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 6de0747..56434bb 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -39,28 +39,21 @@ logger = logging.getLogger(__name__) # This 'walk' mechanism walks over 'child' boxes in the tree. -# FIXME: Rename: -# walk_box_id -> walk_parent_box_id -# child_box_id -> walk_box_id -# walk_level -> walk_stack_count - TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// <%def name="walk_init(start_box_id)"> - box_id_t box_stack[NLEVELS]; - int morton_nr_stack[NLEVELS]; + box_id_t walk_box_stack[NLEVELS]; + int walk_morton_nr_stack[NLEVELS]; // start at root - int walk_level = 0; - box_id_t walk_box_id = ${start_box_id}; + int walk_stack_size = 0; + box_id_t walk_parent_box_id = ${start_box_id}; int walk_morton_nr = 0; bool continue_walk = true; <%def name="walk_get_child_box_id()"> - - box_id_t child_box_id; - child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; + box_id_t walk_box_id = box_child_ids[ + walk_morton_nr * aligned_nboxes + walk_parent_box_id]; <%def name="walk_advance()"> @@ -75,15 +68,15 @@ TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// continue_walk = ( // Stack empty? Abort. - walk_level > 0 + walk_stack_size > 0 ); if (continue_walk) { - --walk_level; + --walk_stack_size; dbg_printf((" ascend\n")); - walk_box_id = box_stack[walk_level]; - walk_morton_nr = morton_nr_stack[walk_level]; + walk_parent_box_id = walk_box_stack[walk_stack_size]; + walk_morton_nr = walk_morton_nr_stack[walk_stack_size]; } else { @@ -94,19 +87,19 @@ TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// <%def name="walk_push(new_box)"> - box_stack[walk_level] = walk_box_id; - morton_nr_stack[walk_level] = walk_morton_nr; - ++walk_level; + walk_box_stack[walk_stack_size] = walk_parent_box_id; + walk_morton_nr_stack[walk_stack_size] = walk_morton_nr; + ++walk_stack_size; %if debug: - if (walk_level >= NLEVELS) + if (walk_stack_size >= NLEVELS) { dbg_printf((" ** ERROR: overran levels stack\n")); return; } %endif - walk_box_id = ${new_box}; + walk_parent_box_id = ${new_box}; walk_morton_nr = 0; @@ -347,26 +340,26 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) { ${walk_get_child_box_id()} - dbg_printf((" level: %d walk box id: %d morton: %d child id: %d\n", - walk_level, walk_box_id, walk_morton_nr, child_box_id)); + dbg_printf((" level: %d walk parent box id: %d morton: %d child id: %d\n", + walk_stack_size, walk_parent_box_id, walk_morton_nr, walk_box_id)); - if (child_box_id) + if (walk_box_id) { - ${load_center("child_center", "child_box_id")} + ${load_center("child_center", "walk_box_id")} bool a_or_o = is_adjacent_or_overlapping_with_neighborhood( root_extent, center, level, ${well_sep_is_n_away}, - child_center, box_levels[child_box_id]); + child_center, box_levels[walk_box_id]); if (a_or_o) { - // child_box_id lives on walk_level+1. - if (walk_level+1 == level && child_box_id != box_id) + // walk_box_id lives on walk_stack_size+1. + if (walk_stack_size+1 == level && walk_box_id != box_id) { dbg_printf((" found same-lev nws\n")); - APPEND_same_level_non_well_sep_boxes(child_box_id); + APPEND_same_level_non_well_sep_boxes(walk_box_id); } else { @@ -374,7 +367,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) // on the stack. dbg_printf((" descend\n")); - ${walk_push("child_box_id")} + ${walk_push("walk_box_id")} continue; } @@ -430,27 +423,27 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) { ${walk_get_child_box_id()} - dbg_printf((" walk box id: %d morton: %d child id: %d level: %d\n", - walk_box_id, walk_morton_nr, child_box_id, walk_level)); + dbg_printf((" walk parent box id: %d morton: %d child id: %d level: %d\n", + walk_parent_box_id, walk_morton_nr, walk_box_id, walk_stack_size)); - if (child_box_id) + if (walk_box_id) { - ${load_center("child_center", "child_box_id")} + ${load_center("child_center", "walk_box_id")} bool a_or_o = is_adjacent_or_overlapping( root_extent, center, level, - child_center, box_levels[child_box_id]); + child_center, box_levels[walk_box_id]); if (a_or_o) { - box_flags_t flags = box_flags[child_box_id]; - /* child_box_id == box_id is ok */ + box_flags_t flags = box_flags[walk_box_id]; + /* walk_box_id == box_id is ok */ if (flags & BOX_HAS_OWN_SOURCES) { dbg_printf((" neighbor source box\n")); - APPEND_neighbor_source_boxes(child_box_id); + APPEND_neighbor_source_boxes(walk_box_id); } if (flags & BOX_HAS_CHILD_SOURCES) @@ -460,7 +453,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) dbg_printf((" descend\n")); - ${walk_push("child_box_id")} + ${walk_push("walk_box_id")} continue; } @@ -562,7 +555,9 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) while (continue_walk) { - // Loop invariant: walk_box_id is, at first, always adjacent to box_id. + // Loop invariant: + // walk_parent_box_id is, at first, always adjacent to box_id. + // // This is true at the first level because colleagues are adjacent // by definition, and is kept true throughout the walk by only descending // into adjacent boxes. @@ -583,18 +578,18 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) ${walk_get_child_box_id()} - dbg_printf((" walk box id: %d morton: %d child id: %d\n", - walk_box_id, walk_morton_nr, child_box_id)); + dbg_printf((" walk parent box id: %d morton: %d child id: %d\n", + walk_parent_box_id, walk_morton_nr, walk_box_id)); - box_flags_t child_box_flags = box_flags[child_box_id]; + box_flags_t child_box_flags = box_flags[walk_box_id]; - if (child_box_id && + if (walk_box_id && (child_box_flags & (BOX_HAS_OWN_SOURCES | BOX_HAS_CHILD_SOURCES))) { - ${load_center("child_center", "child_box_id")} + ${load_center("child_center", "walk_box_id")} - int child_level = box_levels[child_box_id]; + int child_level = box_levels[walk_box_id]; bool in_list_1 = is_adjacent_or_overlapping(root_extent, center, level, child_center, child_level); @@ -609,7 +604,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) if (child_level <= sep_smaller_source_level || sep_smaller_source_level == -1) { - ${walk_push("child_box_id")} + ${walk_push("walk_box_id")} continue; } // otherwise there's no point to descending further. @@ -635,7 +630,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) if (!a_or_o_with_stick_out) { if (sep_smaller_source_level == child_level) - APPEND_sep_smaller(child_box_id); + APPEND_sep_smaller(walk_box_id); } else { @@ -649,11 +644,11 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) if ( (child_box_flags & BOX_HAS_OWN_SOURCES) && (sep_smaller_source_level == -1)) - APPEND_sep_close_smaller(child_box_id); + APPEND_sep_close_smaller(walk_box_id); if (child_box_flags & BOX_HAS_CHILD_SOURCES) { - ${walk_push("child_box_id")} + ${walk_push("walk_box_id")} continue; } %endif -- GitLab From f04d46552babd45dc81876c0653f3f4d2ac34406 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 19:08:09 -0500 Subject: [PATCH 17/41] Traversal: rename interaction lists to include 'from_' to indicate directionality --- boxtree/fmm.py | 22 ++--- boxtree/traversal.py | 209 ++++++++++++++++++++------------------- boxtree/visualization.py | 12 +-- test/test_fmm.py | 6 +- test/test_traversal.py | 31 +++--- 5 files changed, 141 insertions(+), 139 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index 69fc0f2..17a7acf 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -97,8 +97,8 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): local_exps = wrangler.multipole_to_local( traversal.level_start_target_or_target_parent_box_nrs, traversal.target_or_target_parent_boxes, - traversal.sep_siblings_starts, - traversal.sep_siblings_lists, + traversal.from_sep_siblings_starts, + traversal.from_sep_siblings_lists, mpole_exps) # local_exps represents both Gamma and Delta in [1] @@ -115,19 +115,19 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): potentials = potentials + wrangler.eval_multipoles( traversal.level_start_target_box_nrs, traversal.target_boxes, - traversal.sep_smaller_by_level, + traversal.from_sep_smaller_by_level, mpole_exps) # these potentials are called beta in [1] - if traversal.sep_close_smaller_starts is not None: + if traversal.from_sep_close_smaller_starts is not None: logger.debug("evaluate separated close smaller interactions directly " "('list 3 close')") potentials = potentials + wrangler.eval_direct( traversal.target_boxes, - traversal.sep_close_smaller_starts, - traversal.sep_close_smaller_lists, + traversal.from_sep_close_smaller_starts, + traversal.from_sep_close_smaller_lists, src_weights) # }}} @@ -139,18 +139,18 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): local_exps = local_exps + wrangler.form_locals( traversal.level_start_target_or_target_parent_box_nrs, traversal.target_or_target_parent_boxes, - traversal.sep_bigger_starts, - traversal.sep_bigger_lists, + traversal.from_sep_bigger_starts, + traversal.from_sep_bigger_lists, src_weights) - if traversal.sep_close_bigger_starts is not None: + if traversal.from_sep_close_bigger_starts is not None: logger.debug("evaluate separated close bigger interactions directly " "('list 4 close')") potentials = potentials + wrangler.eval_direct( traversal.target_or_target_parent_boxes, - traversal.sep_close_bigger_starts, - traversal.sep_close_bigger_lists, + traversal.from_sep_close_bigger_starts, + traversal.from_sep_close_bigger_lists, src_weights) # }}} diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 56434bb..9a4fcbd 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -472,9 +472,9 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # }}} -# {{{ well-separated siblings ("list 2") +# {{{ from well-separated siblings ("list 2") -SEP_SIBLINGS_TEMPLATE = r"""//CL// +FROM_SEP_SIBLINGS_TEMPLATE = r"""//CL// void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { @@ -511,7 +511,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) if (sep) { - APPEND_sep_siblings(sib_box_id); + APPEND_from_sep_siblings(sib_box_id); } } } @@ -522,7 +522,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) # {{{ from separated smaller ("list 3") -SEP_SMALLER_TEMPLATE = r"""//CL// +FROM_SEP_SMALLER_TEMPLATE = r"""//CL// void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) { @@ -566,13 +566,13 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) // non-adjacent to box_id. // // If neither sources nor targets have extent, then that - // nonadjacent child box is added to box_id's sep_smaller ("list 3 + // nonadjacent child box is added to box_id's from_sep_smaller ("list 3 // far") and that's it. // // If they have extent, then while they may be separated, the // intersection of box_id's and the child box's stick-out region // may be non-empty, and we thus need to add that child to - // sep_close_smaller ("list 3 close") for the interaction to be + // from_sep_close_smaller ("list 3 close") for the interaction to be // done by direct evaluation. We also need to descend into that // child. @@ -601,8 +601,8 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) // We want to descend into this box. Put the current state // on the stack. - if (child_level <= sep_smaller_source_level - || sep_smaller_source_level == -1) + if (child_level <= from_sep_smaller_source_level + || from_sep_smaller_source_level == -1) { ${walk_push("walk_box_id")} continue; @@ -629,13 +629,13 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) if (!a_or_o_with_stick_out) { - if (sep_smaller_source_level == child_level) - APPEND_sep_smaller(walk_box_id); + if (from_sep_smaller_source_level == walk_level) + APPEND_from_sep_smaller(walk_box_id); } else { %if sources_have_extent or targets_have_extent: - // sep_smaller_source_level == -1 means "only build + // from_sep_smaller_source_level == -1 means "only build // build list 3 close", with sources on any level. // This kernel will be run once per source level to // generate per-level list 3, and once @@ -643,8 +643,8 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) if ( (child_box_flags & BOX_HAS_OWN_SOURCES) - && (sep_smaller_source_level == -1)) - APPEND_sep_close_smaller(walk_box_id); + && (from_sep_smaller_source_level == -1)) + APPEND_from_sep_close_smaller(walk_box_id); if (child_box_flags & BOX_HAS_CHILD_SOURCES) { @@ -692,10 +692,10 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # without exclamation mark are choices for this case) # # Case 2: A->B interaction enters the downward propagation at B, i.e. A is in -# B's "sep_bigger". (list 4) +# B's "from_sep_bigger". (list 4) # # Case 3: A->B interaction entered the downward propagation at B's parent, i.e. -# A is not in B's "sep_bigger". (list 4) +# A is not in B's "from_sep_bigger". (list 4) # Sources/targets with extent # --------------------------- @@ -728,15 +728,15 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # be the case. Entries without exclamation mark are choices for this case) # # Case 1: A->B interaction must be processed by direct eval because of "so", -# i.e. it is in B's "sep_close_bigger". +# i.e. it is in B's "from_sep_close_bigger". # # Case 2: A->B interaction enters downward the propagation at B, -# i.e. it is in B's "sep_bigger". +# i.e. it is in B's "from_sep_bigger". # # Case 3: A->B interaction enters downward the propagation at B's parent, # i.e. A is not in B's "sep*bigger" -SEP_BIGGER_TEMPLATE = r"""//CL// +FROM_SEP_BIGGER_TEMPLATE = r"""//CL// void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { @@ -817,7 +817,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) if (tgt_box_flags & BOX_HAS_OWN_TARGETS) { - APPEND_sep_close_bigger(slnws_box_id); + APPEND_from_sep_close_bigger(slnws_box_id); } } else @@ -858,7 +858,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) // "Case 2" above: We're the first box down the chain // to be far enough away to let the interaction into // our local downward propagation. - APPEND_sep_bigger(slnws_box_id); + APPEND_from_sep_bigger(slnws_box_id); } else { @@ -1011,11 +1011,11 @@ class FMMTraversalInfo(DeviceDataRecord): Well-separated boxes on the same level. Indexed like :attr:`target_or_target_parent_boxes`. See :ref:`csr`. - .. attribute:: sep_siblings_starts + .. attribute:: from_sep_siblings_starts ``box_id_t [ntarget_or_target_parent_boxes+1]`` - .. attribute:: sep_siblings_lists + .. attribute:: from_sep_siblings_lists ``box_id_t [*]`` @@ -1026,14 +1026,14 @@ class FMMTraversalInfo(DeviceDataRecord): Smaller source boxes separated from the target box by their own size. If :attr:`boxtree.Tree.targets_have_extent`, then - :attr:`sep_close_smaller_starts` will be non-*None*. It records + :attr:`from_sep_close_smaller_starts` will be non-*None*. It records interactions between boxes that would ordinarily be handled through "List 3", but must be evaluated specially/directly because of :ref:`extent`. Indexed like :attr:`target_or_target_parent_boxes`. See :ref:`csr`. - .. attribute:: sep_smaller_by_level + .. attribute:: from_sep_smaller_by_level A list of :attr:`boxtree.Tree.nlevels` (corresponding to the levels on which each listed source box resides) objects, each of which has @@ -1044,11 +1044,11 @@ class FMMTraversalInfo(DeviceDataRecord): ``box_id_t``. (Note: This list contains global box numbers, not indices into :attr:`source_boxes`.) - .. attribute:: sep_close_smaller_starts + .. attribute:: from_sep_close_smaller_starts ``box_id_t [ntargets+1]`` (or *None*) - .. attribute:: sep_close_smaller_lists + .. attribute:: from_sep_close_smaller_lists ``box_id_t [*]`` (or *None*) @@ -1062,26 +1062,26 @@ class FMMTraversalInfo(DeviceDataRecord): :attr:`source_boxes`.) If :attr:`boxtree.Tree.sources_have_extent`, then - :attr:`sep_close_bigger_starts` will be non-*None*. It records + :attr:`from_sep_close_bigger_starts` will be non-*None*. It records interactions between boxes that would ordinarily be handled through "List 4", but must be evaluated specially/directly because of :ref:`extent`. Indexed like :attr:`target_or_target_parent_boxes`. See :ref:`csr`. - .. attribute:: sep_bigger_starts + .. attribute:: from_sep_bigger_starts ``box_id_t [ntarget_or_target_parent_boxes+1]`` - .. attribute:: sep_bigger_lists + .. attribute:: from_sep_bigger_lists ``box_id_t [*]`` - .. attribute:: sep_close_bigger_starts + .. attribute:: from_sep_close_bigger_starts ``box_id_t [ntarget_or_target_parent_boxes+1]`` (or *None*) - .. attribute:: sep_close_bigger_lists + .. attribute:: from_sep_close_bigger_lists ``box_id_t [*]`` (or *None*) """ @@ -1090,9 +1090,10 @@ class FMMTraversalInfo(DeviceDataRecord): def merge_close_lists(self, queue, debug=False): """Return a new :class:`FMMTraversalInfo` instance with the contents of - :attr:`sep_close_smaller_starts` and :attr:`sep_close_bigger_starts` - merged into :attr:`neighbor_source_boxes_starts` and these two - attributes set to *None*. + :attr:`from_sep_close_smaller_starts` and + :attr:`from_sep_close_bigger_starts` merged into + :attr:`neighbor_source_boxes_starts` and these two attributes set to + *None*. """ from boxtree.tools import reverse_index_array @@ -1112,13 +1113,13 @@ class FMMTraversalInfo(DeviceDataRecord): /* input: */ box_id_t *target_or_target_parent_boxes_from_tgt_boxes, box_id_t *neighbor_source_boxes_starts, - box_id_t *sep_close_smaller_starts, - box_id_t *sep_close_bigger_starts, + box_id_t *from_sep_close_smaller_starts, + box_id_t *from_sep_close_bigger_starts, %if not write_counts: box_id_t *neighbor_source_boxes_lists, - box_id_t *sep_close_smaller_lists, - box_id_t *sep_close_bigger_lists, + box_id_t *from_sep_close_smaller_lists, + box_id_t *from_sep_close_bigger_lists, box_id_t *new_neighbor_source_boxes_starts, %endif @@ -1142,17 +1143,17 @@ class FMMTraversalInfo(DeviceDataRecord): neighbor_source_boxes_starts[itgt_box + 1] - neighbor_source_boxes_start; - box_id_t sep_close_smaller_start = - sep_close_smaller_starts[itgt_box]; - box_id_t sep_close_smaller_count = - sep_close_smaller_starts[itgt_box + 1] - - sep_close_smaller_start; + box_id_t from_sep_close_smaller_start = + from_sep_close_smaller_starts[itgt_box]; + box_id_t from_sep_close_smaller_count = + from_sep_close_smaller_starts[itgt_box + 1] + - from_sep_close_smaller_start; - box_id_t sep_close_bigger_start = - sep_close_bigger_starts[itarget_or_target_parent_box]; - box_id_t sep_close_bigger_count = - sep_close_bigger_starts[itarget_or_target_parent_box + 1] - - sep_close_bigger_start; + box_id_t from_sep_close_bigger_start = + from_sep_close_bigger_starts[itarget_or_target_parent_box]; + box_id_t from_sep_close_bigger_count = + from_sep_close_bigger_starts[itarget_or_target_parent_box + 1] + - from_sep_close_bigger_start; %if write_counts: if (itgt_box == 0) @@ -1160,8 +1161,8 @@ class FMMTraversalInfo(DeviceDataRecord): new_neighbor_source_boxes_counts[itgt_box + 1] = neighbor_source_boxes_count - + sep_close_smaller_count - + sep_close_bigger_count + + from_sep_close_smaller_count + + from_sep_close_bigger_count ; %else: @@ -1173,8 +1174,8 @@ class FMMTraversalInfo(DeviceDataRecord): NAME##_lists[NAME##_start+i]; COPY_FROM(neighbor_source_boxes) - COPY_FROM(sep_close_smaller) - COPY_FROM(sep_close_bigger) + COPY_FROM(from_sep_close_smaller) + COPY_FROM(from_sep_close_bigger) %endif """).build( @@ -1194,8 +1195,8 @@ class FMMTraversalInfo(DeviceDataRecord): # input: target_or_target_parent_boxes_from_tgt_boxes, self.neighbor_source_boxes_starts, - self.sep_close_smaller_starts, - self.sep_close_bigger_starts, + self.from_sep_close_smaller_starts, + self.from_sep_close_bigger_starts, # output: new_neighbor_source_boxes_counts, @@ -1218,11 +1219,11 @@ class FMMTraversalInfo(DeviceDataRecord): target_or_target_parent_boxes_from_tgt_boxes, self.neighbor_source_boxes_starts, - self.sep_close_smaller_starts, - self.sep_close_bigger_starts, + self.from_sep_close_smaller_starts, + self.from_sep_close_bigger_starts, self.neighbor_source_boxes_lists, - self.sep_close_smaller_lists, - self.sep_close_bigger_lists, + self.from_sep_close_smaller_lists, + self.from_sep_close_bigger_lists, new_neighbor_source_boxes_starts, @@ -1234,10 +1235,10 @@ class FMMTraversalInfo(DeviceDataRecord): return self.copy( neighbor_source_boxes_starts=new_neighbor_source_boxes_starts, neighbor_source_boxes_lists=new_neighbor_source_boxes_lists, - sep_close_smaller_starts=None, - sep_close_smaller_lists=None, - sep_close_bigger_starts=None, - sep_close_bigger_lists=None) + from_sep_close_smaller_starts=None, + from_sep_close_smaller_lists=None, + from_sep_close_bigger_starts=None, + from_sep_close_bigger_lists=None) # }}} @@ -1353,7 +1354,7 @@ class FMMTraversalBuilder: [ VectorArg(box_id_dtype, "target_boxes"), ], []), - ("sep_siblings", SEP_SIBLINGS_TEMPLATE, + ("from_sep_siblings", FROM_SEP_SIBLINGS_TEMPLATE, [ VectorArg(box_id_dtype, "target_or_target_parent_boxes"), VectorArg(box_id_dtype, "box_parent_ids"), @@ -1362,7 +1363,7 @@ class FMMTraversalBuilder: VectorArg(box_id_dtype, "same_level_non_well_sep_boxes_lists"), ], []), - ("sep_smaller", SEP_SMALLER_TEMPLATE, + ("from_sep_smaller", FROM_SEP_SMALLER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), VectorArg(box_id_dtype, "target_boxes"), @@ -1370,12 +1371,12 @@ class FMMTraversalBuilder: "same_level_non_well_sep_boxes_starts"), VectorArg(box_id_dtype, "same_level_non_well_sep_boxes_lists"), - ScalarArg(box_id_dtype, "sep_smaller_source_level"), + ScalarArg(box_id_dtype, "from_sep_smaller_source_level"), ], - ["sep_close_smaller"] + ["from_sep_close_smaller"] if sources_have_extent or targets_have_extent else []), - ("sep_bigger", SEP_BIGGER_TEMPLATE, + ("from_sep_bigger", FROM_SEP_BIGGER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), VectorArg(box_id_dtype, "target_or_target_parent_boxes"), @@ -1384,9 +1385,9 @@ class FMMTraversalBuilder: "same_level_non_well_sep_boxes_starts"), VectorArg(box_id_dtype, "same_level_non_well_sep_boxes_lists"), - #ScalarArg(box_id_dtype, "sep_bigger_source_level"), + #ScalarArg(box_id_dtype, "from_sep_bigger_source_level"), ], - ["sep_close_bigger"] + ["from_sep_close_bigger"] if sources_have_extent or targets_have_extent else []), ]: @@ -1558,7 +1559,7 @@ class FMMTraversalBuilder: fin_debug("finding well-separated siblings ('list 2')") - result, evt = knl_info.sep_siblings_builder( + result, evt = knl_info.from_sep_siblings_builder( queue, len(target_or_target_parent_boxes), tree.box_centers.data, tree.root_extent, tree.box_levels.data, tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, @@ -1567,7 +1568,7 @@ class FMMTraversalBuilder: same_level_non_well_sep_boxes.lists.data, wait_for=wait_for) wait_for = [evt] - sep_siblings = result["sep_siblings"] + from_sep_siblings = result["from_sep_siblings"] # }}} @@ -1577,7 +1578,7 @@ class FMMTraversalBuilder: fin_debug("finding separated smaller ('list 3')") - sep_smaller_base_args = ( + from_sep_smaller_base_args = ( queue, len(target_boxes), tree.box_centers.data, tree.root_extent, tree.box_levels.data, tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, @@ -1586,44 +1587,44 @@ class FMMTraversalBuilder: same_level_non_well_sep_boxes.lists.data, ) - sep_smaller_wait_for = [] - sep_smaller_by_level = [] + from_sep_smaller_wait_for = [] + from_sep_smaller_by_level = [] for ilevel in range(tree.nlevels): fin_debug("finding separated smaller ('list 3 level %d')" % ilevel) - result, evt = knl_info.sep_smaller_builder( - *(sep_smaller_base_args + (ilevel,)), - omit_lists=("sep_close_smaller",) if with_extent else (), + result, evt = knl_info.from_sep_smaller_builder( + *(from_sep_smaller_base_args + (ilevel,)), + omit_lists=("from_sep_close_smaller",) if with_extent else (), wait_for=wait_for) - sep_smaller_by_level.append(result["sep_smaller"]) - sep_smaller_wait_for.append(evt) + from_sep_smaller_by_level.append(result["from_sep_smaller"]) + from_sep_smaller_wait_for.append(evt) if with_extent: fin_debug("finding separated smaller close ('list 3 close')") - result, evt = knl_info.sep_smaller_builder( - *(sep_smaller_base_args + (-1,)), - omit_lists=("sep_smaller",), + result, evt = knl_info.from_sep_smaller_builder( + *(from_sep_smaller_base_args + (-1,)), + omit_lists=("from_sep_smaller",), wait_for=wait_for) - sep_close_smaller_starts = result["sep_close_smaller"].starts - sep_close_smaller_lists = result["sep_close_smaller"].lists + from_sep_close_smaller_starts = result["from_sep_close_smaller"].starts + from_sep_close_smaller_lists = result["from_sep_close_smaller"].lists - sep_smaller_wait_for.append(evt) + from_sep_smaller_wait_for.append(evt) else: - sep_close_smaller_starts = None - sep_close_smaller_lists = None + from_sep_close_smaller_starts = None + from_sep_close_smaller_lists = None # }}} - wait_for = sep_smaller_wait_for - del sep_smaller_wait_for + wait_for = from_sep_smaller_wait_for + del from_sep_smaller_wait_for # {{{ separated bigger ("list 4") fin_debug("finding separated bigger ('list 4')") - result, evt = knl_info.sep_bigger_builder( + result, evt = knl_info.from_sep_bigger_builder( queue, len(target_or_target_parent_boxes), tree.box_centers.data, tree.root_extent, tree.box_levels.data, tree.aligned_nboxes, tree.box_child_ids.data, tree.box_flags.data, @@ -1634,14 +1635,14 @@ class FMMTraversalBuilder: wait_for=wait_for) wait_for = [evt] - sep_bigger = result["sep_bigger"] + from_sep_bigger = result["from_sep_bigger"] if with_extent: - sep_close_bigger_starts = result["sep_close_bigger"].starts - sep_close_bigger_lists = result["sep_close_bigger"].lists + from_sep_close_bigger_starts = result["from_sep_close_bigger"].starts + from_sep_close_bigger_lists = result["from_sep_close_bigger"].lists else: - sep_close_bigger_starts = None - sep_close_bigger_lists = None + from_sep_close_bigger_starts = None + from_sep_close_bigger_lists = None # }}} @@ -1684,19 +1685,19 @@ class FMMTraversalBuilder: neighbor_source_boxes_starts=neighbor_source_boxes.starts, neighbor_source_boxes_lists=neighbor_source_boxes.lists, - sep_siblings_starts=sep_siblings.starts, - sep_siblings_lists=sep_siblings.lists, + from_sep_siblings_starts=from_sep_siblings.starts, + from_sep_siblings_lists=from_sep_siblings.lists, - sep_smaller_by_level=sep_smaller_by_level, + from_sep_smaller_by_level=from_sep_smaller_by_level, - sep_close_smaller_starts=sep_close_smaller_starts, - sep_close_smaller_lists=sep_close_smaller_lists, + from_sep_close_smaller_starts=from_sep_close_smaller_starts, + from_sep_close_smaller_lists=from_sep_close_smaller_lists, - sep_bigger_starts=sep_bigger.starts, - sep_bigger_lists=sep_bigger.lists, + from_sep_bigger_starts=from_sep_bigger.starts, + from_sep_bigger_lists=from_sep_bigger.lists, - sep_close_bigger_starts=sep_close_bigger_starts, - sep_close_bigger_lists=sep_close_bigger_lists, + from_sep_close_bigger_starts=from_sep_close_bigger_starts, + from_sep_close_bigger_lists=from_sep_close_bigger_lists, ).with_queue(None), evt # }}} diff --git a/boxtree/visualization.py b/boxtree/visualization.py index f204c8e..7c2168f 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -235,23 +235,23 @@ def draw_box_lists(tree_plotter, traversal, ibox): # well-separated siblings (list 2) _draw_box_list(tree_plotter, ibox, - traversal.sep_siblings_starts, - traversal.sep_siblings_lists, + traversal.from_sep_siblings_starts, + traversal.from_sep_siblings_lists, key_to_box=traversal.target_or_target_parent_boxes, facecolor="blue") # separated smaller (list 3) for ilev in range(tree_plotter.tree.nlevels): _draw_box_list(tree_plotter, ibox, - traversal.sep_smaller_by_level[ilev].starts, - traversal.sep_smaller_by_level[ilev].lists, + traversal.from_sep_smaller_by_level[ilev].starts, + traversal.from_sep_smaller_by_level[ilev].lists, key_to_box=traversal.target_boxes, facecolor="orange") # separated bigger (list 4) _draw_box_list(tree_plotter, ibox, - traversal.sep_bigger_starts, - traversal.sep_bigger_lists, + traversal.from_sep_bigger_starts, + traversal.from_sep_bigger_lists, key_to_box=traversal.target_or_target_parent_boxes, facecolor="purple") diff --git a/test/test_fmm.py b/test/test_fmm.py index c656b22..eb3d2ba 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -138,10 +138,10 @@ class ConstantOneExpansionWrangler(object): return local_exps def eval_multipoles(self, level_start_target_box_nrs, target_boxes, - sep_smaller_nonsiblings_by_level, mpole_exps): + from_sep_smaller_nonsiblings_by_level, mpole_exps): pot = self.potential_zeros() - for ssn in sep_smaller_nonsiblings_by_level: + for ssn in from_sep_smaller_nonsiblings_by_level: for itgt_box, tgt_ibox in enumerate(target_boxes): tgt_pslice = self._get_target_slice(tgt_ibox) @@ -328,7 +328,7 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, from boxtree.traversal import FMMTraversalBuilder tbuild = FMMTraversalBuilder(ctx, well_sep_is_n_away=well_sep_is_n_away) trav, _ = tbuild(queue, tree, debug=True) - if trav.sep_close_smaller_starts is not None: + if trav.from_sep_close_smaller_starts is not None: trav = trav.merge_close_lists(queue) #weights = np.random.randn(nsources) diff --git a/test/test_traversal.py b/test/test_traversal.py index 0073074..5f15131 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -117,8 +117,8 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # {{{ 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] + start, end = trav.from_sep_siblings_starts[itgt_box:itgt_box+2] + seps = trav.from_sep_siblings_lists[start:end] assert (levels[seps] == levels[tgt_ibox]).all() @@ -135,20 +135,21 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # }}} if sources_are_targets: - # {{{ sep_{smaller,bigger} are duals of each other + # {{{ from_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: + for ssn in trav.from_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] + rstart, rend = trav.from_sep_bigger_starts[jbox:jbox+2] - assert ibox in trav.sep_bigger_lists[rstart:rend], (ibox, jbox) + assert ibox in trav.from_sep_bigger_lists[rstart:rend], \ + (ibox, jbox) # }}} @@ -164,10 +165,10 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): tree.nboxes, dtype=tree.box_id_dtype)).all() for ibox in range(tree.nboxes): - start, end = trav.sep_bigger_starts[ibox:ibox+2] + start, end = trav.from_sep_bigger_starts[ibox:ibox+2] - for jbox in trav.sep_bigger_lists[start:end]: - # In principle, entries of sep_bigger_lists are + for jbox in trav.from_sep_bigger_lists[start:end]: + # In principle, entries of from_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. @@ -177,7 +178,7 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): good = False - for ssn in trav.sep_smaller_by_level: + for ssn in trav.from_sep_smaller_by_level: rstart, rend = ssn.starts[jtgt_box:jtgt_box+2] good = good or ibox in ssn.lists[rstart:rend] @@ -204,10 +205,10 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # }}} - # {{{ sep_smaller satisfies relative level assumption + # {{{ from_sep_smaller satisfies relative level assumption for itarget_box, ibox in enumerate(trav.target_boxes): - for ssn in trav.sep_smaller_by_level: + for ssn in trav.from_sep_smaller_by_level: start, end = ssn.starts[itarget_box:itarget_box+2] for jbox in ssn.lists[start:end]: @@ -217,12 +218,12 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # }}} - # {{{ sep_bigger satisfies relative level assumption + # {{{ from_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] + start, end = trav.from_sep_bigger_starts[itgt_box:itgt_box+2] - for jbox in trav.sep_bigger_lists[start:end]: + for jbox in trav.from_sep_bigger_lists[start:end]: assert levels[tgt_ibox] > levels[jbox] logger.info("list 4 satisfies relative level assumption") -- GitLab From 1d8056d951a548ad8c07d4c8d3183254c04d4efc Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 31 Jul 2017 19:12:41 -0500 Subject: [PATCH 18/41] Fixes for name changes in walk primitive --- boxtree/area_query.py | 44 +++++++++++++++++------------------ boxtree/traversal.py | 26 ++++++++++----------- boxtree/tree_build_kernels.py | 4 ++-- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/boxtree/area_query.py b/boxtree/area_query.py index 4a2e9c0..48fbf36 100644 --- a/boxtree/area_query.py +++ b/boxtree/area_query.py @@ -303,30 +303,29 @@ AREA_QUERY_WALKER_BODY = r""" while (continue_walk) { - box_id_t child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; + ${walk_get_box_id()} - if (child_box_id) + if (walk_box_id) { - if (!(box_flags[child_box_id] & BOX_HAS_CHILDREN)) + if (!(box_flags[walk_box_id] & BOX_HAS_CHILDREN)) { bool is_overlapping; ${check_l_infty_ball_overlap( - "is_overlapping", "child_box_id", + "is_overlapping", "walk_box_id", "ball_radius", "ball_center")} if (is_overlapping) { ${leaf_found_op( - "child_box_id", "ball_center", "ball_radius")} + "walk_box_id", "ball_center", "ball_radius")} } } else { // We want to descend into this box. Put the current state // on the stack. - ${walk_push("child_box_id")} + ${walk_push("walk_box_id")} continue; } } @@ -384,27 +383,26 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) while (continue_walk) { - box_id_t child_box_id = box_child_ids[ - walk_morton_nr * aligned_nboxes + walk_box_id]; + ${walk_get_box_id()} - if (child_box_id) + if (walk_box_id) { - ${load_center("child_center", "child_box_id")} + ${load_center("walk_center", "walk_box_id")} - // child_box_id lives on walk_level+1. + // walk_box_id lives on level walk_stack_size+1. bool a_or_o = is_adjacent_or_overlapping(root_extent, - center, level, child_center, walk_level+1); + center, level, walk_center, walk_stack_size+1); if (a_or_o) { - // child_box_id lives on walk_level+1. - if (walk_level+1 == level) + // walk_box_id lives on level walk_stack_size+1. + if (walk_stack_size+1 == level) { - APPEND_peers(child_box_id); + APPEND_peers(walk_box_id); } - else if (!(box_flags[child_box_id] & BOX_HAS_CHILDREN)) + else if (!(box_flags[walk_box_id] & BOX_HAS_CHILDREN)) { - APPEND_peers(child_box_id); + APPEND_peers(walk_box_id); } else { @@ -417,24 +415,24 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) ++morton_nr) { box_id_t next_child_id = box_child_ids[ - morton_nr * aligned_nboxes + child_box_id]; + morton_nr * aligned_nboxes + walk_box_id]; if (next_child_id) { - ${load_center("next_child_center", "next_child_id")} + ${load_center("next_walk_center", "next_child_id")} must_be_peer &= !is_adjacent_or_overlapping(root_extent, - center, level, next_child_center, walk_level+2); + center, level, next_walk_center, walk_stack_size+2); } } if (must_be_peer) { - APPEND_peers(child_box_id); + APPEND_peers(walk_box_id); } else { // We want to descend into this box. Put the current state // on the stack. - ${walk_push("child_box_id")} + ${walk_push("walk_box_id")} continue; } } diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 9a4fcbd..6facda0 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -51,7 +51,7 @@ TRAVERSAL_PREAMBLE_MAKO_DEFS = r"""//CL:mako// bool continue_walk = true; -<%def name="walk_get_child_box_id()"> +<%def name="walk_get_box_id()"> box_id_t walk_box_id = box_child_ids[ walk_morton_nr * aligned_nboxes + walk_parent_box_id]; @@ -338,20 +338,20 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) while (continue_walk) { - ${walk_get_child_box_id()} + ${walk_get_box_id()} dbg_printf((" level: %d walk parent box id: %d morton: %d child id: %d\n", walk_stack_size, walk_parent_box_id, walk_morton_nr, walk_box_id)); if (walk_box_id) { - ${load_center("child_center", "walk_box_id")} + ${load_center("walk_center", "walk_box_id")} bool a_or_o = is_adjacent_or_overlapping_with_neighborhood( root_extent, center, level, ${well_sep_is_n_away}, - child_center, box_levels[walk_box_id]); + walk_center, box_levels[walk_box_id]); if (a_or_o) { @@ -421,19 +421,19 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) while (continue_walk) { - ${walk_get_child_box_id()} + ${walk_get_box_id()} dbg_printf((" walk parent box id: %d morton: %d child id: %d level: %d\n", walk_parent_box_id, walk_morton_nr, walk_box_id, walk_stack_size)); if (walk_box_id) { - ${load_center("child_center", "walk_box_id")} + ${load_center("walk_center", "walk_box_id")} bool a_or_o = is_adjacent_or_overlapping( root_extent, center, level, - child_center, box_levels[walk_box_id]); + walk_center, box_levels[walk_box_id]); if (a_or_o) { @@ -576,7 +576,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) // done by direct evaluation. We also need to descend into that // child. - ${walk_get_child_box_id()} + ${walk_get_box_id()} dbg_printf((" walk parent box id: %d morton: %d child id: %d\n", walk_parent_box_id, walk_morton_nr, walk_box_id)); @@ -587,12 +587,12 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) (child_box_flags & (BOX_HAS_OWN_SOURCES | BOX_HAS_CHILD_SOURCES))) { - ${load_center("child_center", "walk_box_id")} + ${load_center("walk_center", "walk_box_id")} - int child_level = box_levels[walk_box_id]; + int walk_level = box_levels[walk_box_id]; bool in_list_1 = is_adjacent_or_overlapping(root_extent, - center, level, child_center, child_level); + center, level, walk_center, walk_level); if (in_list_1) { @@ -601,7 +601,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) // We want to descend into this box. Put the current state // on the stack. - if (child_level <= from_sep_smaller_source_level + if (walk_level <= from_sep_smaller_source_level || from_sep_smaller_source_level == -1) { ${walk_push("walk_box_id")} @@ -617,7 +617,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) is_adjacent_or_overlapping_with_stick_out(root_extent, center, level, 1, - child_center, child_level, + walk_center, walk_level, stick_out_factor); %else: const bool a_or_o_with_stick_out = false; diff --git a/boxtree/tree_build_kernels.py b/boxtree/tree_build_kernels.py index 5078db8..a158865 100644 --- a/boxtree/tree_build_kernels.py +++ b/boxtree/tree_build_kernels.py @@ -788,13 +788,13 @@ LEVEL_RESTRICT_TPL = Template( %for morton_nr in range(2**dimensions): if (walk_morton_nr == ${morton_nr}) { - child_box_id = box_child_ids_mnr_${morton_nr}[walk_box_id]; + child_box_id = box_child_ids_mnr_${morton_nr}[walk_parent_box_id]; } %endfor if (child_box_id) { - int child_level = walk_level + 1; + int child_level = walk_stack_size + 1; // Check adjacency. bool is_adjacent; -- GitLab From 26cf43e297640192f5d69edd113a3c43d43a2581 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 1 Aug 2017 11:33:03 -0500 Subject: [PATCH 19/41] Minor comment fix [ci skip] --- boxtree/traversal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 6facda0..b1655a5 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -355,7 +355,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t box_id) if (a_or_o) { - // walk_box_id lives on walk_stack_size+1. + // walk_box_id lives on level walk_stack_size+1. if (walk_stack_size+1 == level && walk_box_id != box_id) { dbg_printf((" found same-lev nws\n")); -- GitLab From c251e80122c594b8063a2c130db3e4ab2f506d13 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 2 Aug 2017 12:42:15 -0500 Subject: [PATCH 20/41] Require explicit choice of stick-out factor if targets/sources have extent --- boxtree/tree_build.py | 7 ++++++- test/test_fmm.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/boxtree/tree_build.py b/boxtree/tree_build.py index f9d116f..95e7ab0 100644 --- a/boxtree/tree_build.py +++ b/boxtree/tree_build.py @@ -76,7 +76,7 @@ class TreeBuilder(object): def __call__(self, queue, particles, kind="adaptive", max_particles_in_box=None, allocator=None, debug=False, targets=None, source_radii=None, target_radii=None, - stick_out_factor=0.25, refine_weights=None, + stick_out_factor=None, refine_weights=None, max_leaf_refine_weight=None, wait_for=None, **kwargs): """ :arg queue: a :class:`pyopencl.CommandQueue` instance @@ -174,6 +174,11 @@ class TreeBuilder(object): raise TypeError("dtypes of coordinate arrays and " "target_radii must agree") + if sources_have_extent or targets_have_extent: + if stick_out_factor is None: + raise ValueError("if sources or targets have extent, " + "stick_out_factor must be explicitly specified") + # }}} empty = partial(cl.array.empty, queue, allocator=allocator) diff --git a/test/test_fmm.py b/test/test_fmm.py index 5e9748a..f1ef8f9 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -319,7 +319,7 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, tree, _ = tb(queue, sources, targets=targets, max_particles_in_box=30, source_radii=source_radii, target_radii=target_radii, - debug=True) + debug=True, stick_out_factor=0.25) if 0: tree.get().plot() import matplotlib.pyplot as pt -- GitLab From c23210489cf1f7c081f27826891e922e6d16c4ab Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 2 Aug 2017 13:09:34 -0500 Subject: [PATCH 21/41] No-extents tree build: set stick_out_factor to zero to avoid breaking code that passes it to kernels --- boxtree/tree_build.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boxtree/tree_build.py b/boxtree/tree_build.py index 95e7ab0..9ad0692 100644 --- a/boxtree/tree_build.py +++ b/boxtree/tree_build.py @@ -178,6 +178,8 @@ class TreeBuilder(object): if stick_out_factor is None: raise ValueError("if sources or targets have extent, " "stick_out_factor must be explicitly specified") + else: + stick_out_factor = 0 # }}} -- GitLab From ccf182e53a6aadfb214be95035a2553b0a5a2c11 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 2 Aug 2017 16:39:32 -0500 Subject: [PATCH 22/41] Interaction list vis: separate out list 3/4 close [ci skip] --- boxtree/visualization.py | 23 +++++++++++++++++++---- test/test_fmm.py | 12 ++++++++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/boxtree/visualization.py b/boxtree/visualization.py index 7c2168f..ee65fae 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -226,21 +226,21 @@ def draw_box_lists(tree_plotter, traversal, ibox): tree_plotter.draw_box(ibox, facecolor='red', alpha=0.5) - # near neighbors ("list 1") + # from near neighbors ("list 1") _draw_box_list(tree_plotter, ibox, traversal.neighbor_source_boxes_starts, traversal.neighbor_source_boxes_lists, key_to_box=traversal.target_boxes, facecolor="green") - # well-separated siblings (list 2) + # from well-separated siblings (list 2) _draw_box_list(tree_plotter, ibox, traversal.from_sep_siblings_starts, traversal.from_sep_siblings_lists, key_to_box=traversal.target_or_target_parent_boxes, facecolor="blue") - # separated smaller (list 3) + # from separated smaller (list 3) for ilev in range(tree_plotter.tree.nlevels): _draw_box_list(tree_plotter, ibox, traversal.from_sep_smaller_by_level[ilev].starts, @@ -248,13 +248,28 @@ def draw_box_lists(tree_plotter, traversal, ibox): key_to_box=traversal.target_boxes, facecolor="orange") - # separated bigger (list 4) + # list 3 close + if traversal.from_sep_close_smaller_starts is not None: + _draw_box_list(tree_plotter, ibox, + traversal.from_sep_close_smaller_starts, + traversal.from_sep_close_smaller_lists, + key_to_box=traversal.target_boxes, + facecolor="orange", hatch=".") + + # from separated bigger (list 4) _draw_box_list(tree_plotter, ibox, traversal.from_sep_bigger_starts, traversal.from_sep_bigger_lists, key_to_box=traversal.target_or_target_parent_boxes, facecolor="purple") + # list 4 close + _draw_box_list(tree_plotter, ibox, + traversal.from_sep_close_bigger_starts, + traversal.from_sep_close_bigger_lists, + key_to_box=traversal.target_or_target_parent_boxes, + facecolor="purple", hatch=".") + # }}} # vim: filetype=pyopencl:fdm=marker diff --git a/test/test_fmm.py b/test/test_fmm.py index f1ef8f9..8cbbf45 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -328,7 +328,9 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, from boxtree.traversal import FMMTraversalBuilder tbuild = FMMTraversalBuilder(ctx, well_sep_is_n_away=well_sep_is_n_away) trav, _ = tbuild(queue, tree, debug=True) - if trav.from_sep_close_smaller_starts is not None: + + if who_has_extent: + pre_merge_trav = trav trav = trav.merge_close_lists(queue) #weights = np.random.randn(nsources) @@ -338,6 +340,9 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, host_trav = trav.get(queue=queue) host_tree = host_trav.tree + if who_has_extent: + pre_merge_host_trav = pre_merge_trav.get(queue=queue) + from boxtree.tree import ParticleListFilter plfilt = ParticleListFilter(ctx) @@ -444,7 +449,10 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, pt.gca().set_aspect("equal") from boxtree.visualization import draw_box_lists - draw_box_lists(plotter, host_trav, 22) + draw_box_lists( + plotter, + pre_merge_host_trav if who_has_extent else host_trav, + 22) # from boxtree.visualization import draw_same_level_non_well_sep_boxes # draw_same_level_non_well_sep_boxes(plotter, host_trav, 2) -- GitLab From 7ff2b8032c5db56d1cab9ef92727154f9d6675a4 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 3 Aug 2017 16:48:10 -0500 Subject: [PATCH 23/41] Traversal: Clarify naming/comments in L4 build --- boxtree/traversal.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index b1655a5..f9af6f3 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -741,7 +741,7 @@ FROM_SEP_BIGGER_TEMPLATE = r"""//CL// void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { box_id_t tgt_ibox = target_or_target_parent_boxes[itarget_or_target_parent_box]; - ${load_center("center", "tgt_ibox")} + ${load_center("tgt_center", "tgt_ibox")} int tgt_box_level = box_levels[tgt_ibox]; // The root box has no parents, so no list 4. @@ -795,8 +795,9 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) if (box_flags[slnws_box_id] & BOX_HAS_OWN_SOURCES) { ${load_center("slnws_center", "slnws_box_id")} + bool in_list_1 = is_adjacent_or_overlapping(root_extent, - center, tgt_box_level, + tgt_center, tgt_box_level, slnws_center, walk_level); if (!in_list_1) @@ -804,7 +805,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) %if sources_have_extent or targets_have_extent: const bool a_or_o_with_stick_out = is_adjacent_or_overlapping_with_stick_out(root_extent, - center, tgt_box_level, + tgt_center, tgt_box_level, ${well_sep_is_n_away}, slnws_center, walk_level, stick_out_factor); @@ -836,17 +837,17 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) /* From-sep-bigger boxes can only be in the parent's from-sep-bigger list if they're - actually bigger (or equal) to the target + actually bigger (or equal) to the parent box size. For 1-away, that's guaranteed at this - point, because we only start looking at the - parent's level, so any box we find here is - naturally big enough. For 2-away, we start - looking at the target box's level, so - slnws_box_id may actually be too small (at - too deep a level) to be in the parent's - from-sep-bigger list. + point, because we only start ascendng the + tree at the parent's level, so any box we + find here is naturally big enough. For + 2-away, we start looking at the target + box's level, so slnws_box_id may actually + be too small (at too deep a level) to be in + the parent's from-sep-bigger list. */ && walk_level < tgt_box_level -- GitLab From 6072239fb44ed8f7fdb415fa474f121210405c7f Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 3 Aug 2017 21:01:16 -0500 Subject: [PATCH 24/41] Fix interaction list vis in the case of list 4 close being unavailable --- boxtree/visualization.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/boxtree/visualization.py b/boxtree/visualization.py index ee65fae..c487a96 100644 --- a/boxtree/visualization.py +++ b/boxtree/visualization.py @@ -264,11 +264,12 @@ def draw_box_lists(tree_plotter, traversal, ibox): facecolor="purple") # list 4 close - _draw_box_list(tree_plotter, ibox, - traversal.from_sep_close_bigger_starts, - traversal.from_sep_close_bigger_lists, - key_to_box=traversal.target_or_target_parent_boxes, - facecolor="purple", hatch=".") + if traversal.from_sep_close_bigger_starts is not None: + _draw_box_list(tree_plotter, ibox, + traversal.from_sep_close_bigger_starts, + traversal.from_sep_close_bigger_lists, + key_to_box=traversal.target_or_target_parent_boxes, + facecolor="purple", hatch=".") # }}} -- GitLab From c26b0523aa77f44039307f7ada54d97dab86a041 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 3 Aug 2017 21:02:27 -0500 Subject: [PATCH 25/41] List 4 generation: Naming/readability improvements --- boxtree/traversal.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index f9af6f3..0498a40 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -741,7 +741,7 @@ FROM_SEP_BIGGER_TEMPLATE = r"""//CL// void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { box_id_t tgt_ibox = target_or_target_parent_boxes[itarget_or_target_parent_box]; - ${load_center("tgt_center", "tgt_ibox")} + ${load_center("tgt_box_center", "tgt_ibox")} int tgt_box_level = box_levels[tgt_ibox]; // The root box has no parents, so no list 4. @@ -749,6 +749,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) return; box_id_t parent_box_id = box_parent_ids[tgt_ibox]; + const int parent_level = tgt_box_level - 1; ${load_center("parent_center", "parent_box_id")} box_flags_t tgt_box_flags = box_flags[tgt_ibox]; @@ -797,7 +798,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) ${load_center("slnws_center", "slnws_box_id")} bool in_list_1 = is_adjacent_or_overlapping(root_extent, - tgt_center, tgt_box_level, + tgt_box_center, tgt_box_level, slnws_center, walk_level); if (!in_list_1) @@ -805,7 +806,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) %if sources_have_extent or targets_have_extent: const bool a_or_o_with_stick_out = is_adjacent_or_overlapping_with_stick_out(root_extent, - tgt_center, tgt_box_level, + tgt_box_center, tgt_box_level, ${well_sep_is_n_away}, slnws_center, walk_level, stick_out_factor); @@ -826,7 +827,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { bool in_parent_list_1 = is_adjacent_or_overlapping_with_stick_out(root_extent, - parent_center, tgt_box_level-1, + parent_center, parent_level, 1, slnws_center, walk_level, stick_out_factor); -- GitLab From 14827b0e83ea8a3ac01ac87459d724af92e56e7a Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 3 Aug 2017 21:04:34 -0500 Subject: [PATCH 26/41] List 4 generation: Fix with-extents 2-away case, enable tests --- boxtree/traversal.py | 20 +++++++++++++++++++- test/test_fmm.py | 4 ---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 0498a40..4adccbd 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -867,7 +867,25 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) // "Case 3" above: A parent box was already far // enough away to let the interaction into its // local downward subtree. We'll get the interaction - // that way. Nothing to do. + // that way. Nothing to do, unless the box was too + // close to the parent and ended up in the parent's + // from_sep_close_bigger. If that's the case, we'll + // simply let it enter the downward propagation + // here. + + %if sources_have_extent or targets_have_extent: + const bool a_or_o_parent_with_stick_out = + is_adjacent_or_overlapping_with_stick_out(root_extent, + parent_center, parent_level, + ${well_sep_is_n_away}, + slnws_center, walk_level, + stick_out_factor); + + if (a_or_o_parent_with_stick_out) + { + APPEND_from_sep_bigger(slnws_box_id); + } + %endif } } } diff --git a/test/test_fmm.py b/test/test_fmm.py index 8cbbf45..22cc342 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -273,10 +273,6 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, sources_have_extent = "s" in who_has_extent targets_have_extent = "t" in who_has_extent - # FIXME: - if who_has_extent and well_sep_is_n_away > 1: - pytest.skip("2-away with extents is not right yet") - logging.basicConfig(level=logging.INFO) ctx = ctx_getter() -- GitLab From 65492e5e03b396554e966f24e58100c06a744897 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 3 Aug 2017 21:05:39 -0500 Subject: [PATCH 27/41] Mess with particle plotting code in FMM test --- test/test_fmm.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/test_fmm.py b/test/test_fmm.py index 22cc342..f10d9ae 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -425,7 +425,8 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, print(src_boxes) print(tgt_boxes) - if 1: # plot all sources/targets + # plot all sources/targets + if 0: pt.plot( host_tree.targets[0], host_tree.targets[1], @@ -434,14 +435,17 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, host_tree.sources[0], host_tree.sources[1], "gx", alpha=0.9) - pt.plot( - host_tree.targets[0][tree_order_incorrect_tgts], - host_tree.targets[1][tree_order_incorrect_tgts], - "rv") - pt.plot( - host_tree.sources[0][tree_order_incorrect_srcs], - host_tree.sources[1][tree_order_incorrect_srcs], - "go") + + # plot offending sources/targets + if 0: + pt.plot( + host_tree.targets[0][tree_order_incorrect_tgts], + host_tree.targets[1][tree_order_incorrect_tgts], + "rv") + pt.plot( + host_tree.sources[0][tree_order_incorrect_srcs], + host_tree.sources[1][tree_order_incorrect_srcs], + "go") pt.gca().set_aspect("equal") from boxtree.visualization import draw_box_lists -- GitLab From 47a18af479df207913ad90501d743c15905d65bd Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 4 Aug 2017 00:25:21 -0500 Subject: [PATCH 28/41] Reenable sources-with-extent in traversal building --- boxtree/traversal.py | 6 ------ test/test_fmm.py | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 4adccbd..402d51e 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1451,12 +1451,6 @@ class FMMTraversalBuilder: if not tree._is_pruned: raise ValueError("tree must be pruned for traversal generation") - if tree.sources_have_extent: - # YAGNI - raise NotImplementedError( - "trees with source extent are not supported for " - "traversal generation") - # Generated code shouldn't depend on the *exact* number of tree levels. # So round up to the next multiple of 5. from pytools import div_ceil diff --git a/test/test_fmm.py b/test/test_fmm.py index f10d9ae..09c6016 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -238,31 +238,31 @@ class ConstantOneExpansionWranglerWithFilteredTargetsInUserOrder( [ (2, 10**5, None, "", p_normal, p_normal, None), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, None), - #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), - #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), + (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), + (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, None), - #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), + (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), (3, 10**5, None, "", p_normal, p_normal, None), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, None), - #(3, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), - #(3, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), + (3, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), + (3, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), (3, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, None), - #(3, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), + (3, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), (2, 10**5, None, "", p_normal, p_normal, "user"), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, "user"), - #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "user"), - #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "user"), + (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "user"), + (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "user"), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, "user"), - #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "user"), + (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "user"), (2, 10**5, None, "", p_normal, p_normal, "tree"), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, "tree"), - #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "tree"), - #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "tree"), + (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "tree"), + (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "tree"), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, "tree"), - #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), + (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), ]) def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, who_has_extent, source_gen, target_gen, filter_kind, well_sep_is_n_away): -- GitLab From 719d630889632f5e8b09568398ed8b4b84939734 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 4 Aug 2017 15:47:46 -0500 Subject: [PATCH 29/41] Improve list 4 finding comments --- boxtree/traversal.py | 182 +++++++++++++++++++++---------------------- 1 file changed, 90 insertions(+), 92 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 402d51e..af2b106 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -665,76 +665,54 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # {{{ from separated bigger ("list 4") -# "Normal" case: Sources/targets without extent -# --------------------------------------------- +# List 4 consists of lists that 'missed the boat' on entering the downward +# propagation through list 2. That is, they are non-well-separated from the +# target box itself or a box in its chain of parents. # -# List 4 interactions for box "B" are about a parent P's colleague A not -# adjacent to B. +# To be in list 4, a box must have its own sources. In the no-extents case, +# this will happen only if that box is a leaf, but for the with-extents case, +# any box can have sources. # -# -------|----------|----------| -# Case | 1 | 2 | -# | adj to A | adj to A | -# -------|----------|----------| -# | | | -# A---P | X ! | X ! | -# | | | | -# o | X | X | -# | | | | -# o | X | X | -# | | | | -# o | X | O | -# | | | | -# B | O ! | O ! | +# (Yes, you read that right--same-level non-well separated boxes *can* be in +# list 4, although only for 2+-away. They *could* also use list 3, but that +# would be less efficient because it would not make use of the downward +# propagation.) # -# Note that once a parent is no longer adjacent, its children won't be either. +# For a box not well-separated from the target box or one of its parents, we +# check whether the box is adjacent to our target box (in its list 1). If so, +# we don't need to conisder it (because the interaction to this box will be +# mediated by list 1). # -# (X: yes, O:no, exclamation marks denote that this *must* be the case. Entries -# without exclamation mark are choices for this case) +# Case I: Sources or targets do not have extent # -# Case 2: A->B interaction enters the downward propagation at B, i.e. A is in -# B's "from_sep_bigger". (list 4) +# In this case and once non-membership in list 1 has been verified, list 4 +# membership is simply a matter of deciding whether the source box's +# contribution should enter the downward propagation at this target box or +# whether it has already entered it at a parent of the target box. # -# Case 3: A->B interaction entered the downward propagation at B's parent, i.e. -# A is not in B's "from_sep_bigger". (list 4) - -# Sources/targets with extent -# --------------------------- -# -# List 4 interactions for box "B" are about a parent P's colleague A not -# adjacent to B. -# -# -------|----------|----------|----------| -# Case | 1 | 2 | 3 | -# | so adj | so adj | so adj | -# -------|----------|----------|----------| -# | | | | -# A---P | X! X! | X! X! | X! X! | -# | | | | | -# o | X ? | X ? | X ? | -# | | | | | -# o | X ? | X ? | X ? | -# | | | | | -# o | X ? | X ? | O O | -# | | | | | -# B | X O! | O O! | O O! | -# -# "so": adjacent or overlapping when stick-out is taken into account (to A) -# "adj": adjacent to A without stick-out -# -# Note that once a parent is no longer "adj" or "so", its children won't be -# either. Also note that "adj" => "so". (And thereby "not so" => "not adj".) +# It suffices to check this for the immediate parent because the check has to +# be monotone: Child boxes are subsets of parent boxes, and therefore any +# minimum distance requirement satisfied by the parent will also be satisfied +# by the child. Thus, if the source box is in the target box's parent's list 4, +# then it entered downward propgation with it or another ancestor. # -# (X: yes, O:no, ?: doesn't matter, exclamation marks denote that this *must* -# be the case. Entries without exclamation mark are choices for this case) +# Case II: Sources or targets have extent # -# Case 1: A->B interaction must be processed by direct eval because of "so", -# i.e. it is in B's "from_sep_close_bigger". +# The with-extents case is conceptually similar to the no-extents case, however +# there is an extra 'separation requirement' based on the extents that, if not +# satisfied, may prevent a source box from entering the downward propagation +# at a given box. If we once again assume monotonicity of this 'separation +# requirement' check, then simply verifying whether or not the interaction from +# the source box would be *allowed* to enter the downward propagation at the +# parent suffices to determine whether the target box may be responsible for +# entering the source interaction into the downward propagation. # -# Case 2: A->B interaction enters downward the propagation at B, -# i.e. it is in B's "from_sep_bigger". -# -# Case 3: A->B interaction enters downward the propagation at B's parent, -# i.e. A is not in B's "sep*bigger" +# In cases where the source box is not yet part of the downward propgation +# received from the parent and also not eligible for entering downward +# propagation at this box (noting that this can only happen in the with-extents +# case), the interaction is added to the (non-downward-propagating) 'list 4 +# close' (from_sep_close_bigger). + FROM_SEP_BIGGER_TEMPLATE = r"""//CL// @@ -769,12 +747,14 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) box_id_t current_parent_box_id = tgt_ibox; %endif - // Look for same-level non-well-separated boxes of parents that are - // non-adjacent to tgt_ibox. - // Walk up the tree from tgt_ibox. + /* + Look for same-level non-well-separated boxes of parents that are + non-adjacent to tgt_ibox. + Walk up the tree from tgt_ibox. - // Box 0 (== level 0) doesn't have any slnws boxes, so we can stop the - // search for such slnws boxes there. + Box 0 (== level 0) doesn't have any slnws boxes, so we can stop the + search for such slnws boxes there. + */ for (; walk_level != 0; // {{{ advance --walk_level, @@ -804,18 +784,26 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) if (!in_list_1) { %if sources_have_extent or targets_have_extent: - const bool a_or_o_with_stick_out = - is_adjacent_or_overlapping_with_stick_out(root_extent, + /* + With-extent list 4 separation criterion. + Needs to be monotone. (see main comment narrative + above for what that means) If you change this, also + change the equivalent check for the parent, below. + */ + const bool tgt_meets_with_ext_sep_criterion = + !is_adjacent_or_overlapping_with_stick_out(root_extent, tgt_box_center, tgt_box_level, ${well_sep_is_n_away}, slnws_center, walk_level, stick_out_factor); - if (a_or_o_with_stick_out) + if (!tgt_meets_with_ext_sep_criterion) { - // "Case 1" above: slnws_box_id is too close and - // overlaps our stick_out region. We're obliged to do - // the interaction directly. + /* + slnws_box_id failed the separation criterion (i.e. is + too close to the target box) for list 4 proper. Stick + it in list 4 close. + */ if (tgt_box_flags & BOX_HAS_OWN_TARGETS) { @@ -832,7 +820,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) slnws_center, walk_level, stick_out_factor); - bool in_parent_list_4 = ( + bool would_be_in_parent_list_4_not_considering_stickout = ( !in_parent_list_1 %if well_sep_is_n_away > 1: /* @@ -855,38 +843,48 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) %endif ); - if (!in_parent_list_4) + if (would_be_in_parent_list_4_not_considering_stickout) { - // "Case 2" above: We're the first box down the chain - // to be far enough away to let the interaction into - // our local downward propagation. - APPEND_from_sep_bigger(slnws_box_id); - } - else - { - // "Case 3" above: A parent box was already far - // enough away to let the interaction into its - // local downward subtree. We'll get the interaction - // that way. Nothing to do, unless the box was too - // close to the parent and ended up in the parent's - // from_sep_close_bigger. If that's the case, we'll - // simply let it enter the downward propagation - // here. + /* + Our immediate parent box was already far enough + away to (hypothetically) let the interaction into + its downward propagation--so this happened either + there or at a more distant ancestor. We'll get the + interaction that way. Nothing to do, unless the box + was too close to the parent and ended up in the + parent's from_sep_close_bigger. If that's the case, + we'll simply let it enter the downward propagation + here. + + With-extent list 4 separation criterion. + Needs to be monotone. (see main comment narrative + above for what that means) If you change this, also + change the equivalent check for the target box, above. + */ %if sources_have_extent or targets_have_extent: - const bool a_or_o_parent_with_stick_out = - is_adjacent_or_overlapping_with_stick_out(root_extent, + const bool parent_meets_with_ext_sep_criterion = + !is_adjacent_or_overlapping_with_stick_out(root_extent, parent_center, parent_level, ${well_sep_is_n_away}, slnws_center, walk_level, stick_out_factor); - if (a_or_o_parent_with_stick_out) + if (!parent_meets_with_ext_sep_criterion) { APPEND_from_sep_bigger(slnws_box_id); } %endif } + else + { + /* + We're the first box down the chain to be far enough + away to let the interaction into our local downward + propagation. + */ + APPEND_from_sep_bigger(slnws_box_id); + } } } } -- GitLab From 65e84be39398c1321b0b041ea334108483af9992 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 7 Aug 2017 13:44:14 -0500 Subject: [PATCH 30/41] Fix coment/doc typos that Matt found (thanks!) [ci skip] --- boxtree/traversal.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index af2b106..c8e1eca 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -636,7 +636,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) { %if sources_have_extent or targets_have_extent: // from_sep_smaller_source_level == -1 means "only build - // build list 3 close", with sources on any level. + // list 3 close", with sources on any level. // This kernel will be run once per source level to // generate per-level list 3, and once // (not per level) to generate list 3 close. @@ -680,7 +680,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # # For a box not well-separated from the target box or one of its parents, we # check whether the box is adjacent to our target box (in its list 1). If so, -# we don't need to conisder it (because the interaction to this box will be +# we don't need to consider it (because the interaction to this box will be # mediated by list 1). # # Case I: Sources or targets do not have extent @@ -694,7 +694,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # be monotone: Child boxes are subsets of parent boxes, and therefore any # minimum distance requirement satisfied by the parent will also be satisfied # by the child. Thus, if the source box is in the target box's parent's list 4, -# then it entered downward propgation with it or another ancestor. +# then it entered downward propagation with it or another ancestor. # # Case II: Sources or targets have extent # @@ -707,7 +707,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # parent suffices to determine whether the target box may be responsible for # entering the source interaction into the downward propagation. # -# In cases where the source box is not yet part of the downward propgation +# In cases where the source box is not yet part of the downward propagation # received from the parent and also not eligible for entering downward # propagation at this box (noting that this can only happen in the with-extents # case), the interaction is added to the (non-downward-propagating) 'list 4 @@ -830,7 +830,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) box size. For 1-away, that's guaranteed at this - point, because we only start ascendng the + point, because we only start ascending the tree at the parent's level, so any box we find here is naturally big enough. For 2-away, we start looking at the target @@ -1079,11 +1079,11 @@ class FMMTraversalInfo(DeviceDataRecord): (Note: This list contains global box numbers, not indices into :attr:`source_boxes`.) - If :attr:`boxtree.Tree.sources_have_extent`, then + If :attr:`boxtree.Tree.sources_have_extent` or + :attr:`boxtree.Tree.targets_have_extent`, then :attr:`from_sep_close_bigger_starts` will be non-*None*. It records - interactions between boxes that would ordinarily be handled - through "List 4", but must be evaluated specially/directly - because of :ref:`extent`. + interactions between boxes that would ordinarily be handled through "List + 4", but must be evaluated specially/directly because of :ref:`extent`. Indexed like :attr:`target_or_target_parent_boxes`. See :ref:`csr`. -- GitLab From 40013b20f6e8aadb783428f0906b141f37155947 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 7 Aug 2017 15:06:45 -0500 Subject: [PATCH 31/41] Traversal: Document tolerances of adjacency check [ci skip] --- boxtree/traversal.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index c8e1eca..2d4516d 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -168,6 +168,27 @@ TRAVERSAL_PREAMBLE_TEMPLATE = ( HELPER_FUNCTION_TEMPLATE = r"""//CL// +/* +These adjacency tests check the l^\infty distance between centers to check whether +two boxes are adjacent or overlapping. + +Rather than a 'small floating point number', these adjacency test routines use the +smaller of the source/target box radii as the floating point tolerance, which +calls the following configuration 'adjacent' even though it actually is not: + + +---------+ +---------+ + | | | | + | | | | + | o | | o<---> + | | r | r | + | |<--->| | + +---------+ +---------+ + +This is generically OK since one would expect the distance between the edge of +a large box and the edge of a smaller box to be a integer multiple of the +smaller box's diameter (which is twice its radius, our tolerance). +*/ + inline bool is_adjacent_or_overlapping_with_stick_out( coord_t root_extent, // target and source order only matter if include_stick_out is true. -- GitLab From e7db80d757275aea1cca9fad4a262ee33d854182 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 7 Aug 2017 15:51:52 -0500 Subject: [PATCH 32/41] Traversal: Fix in-parent-list-1 query in L4 builder --- boxtree/traversal.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 2d4516d..8bfa76e 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -835,11 +835,9 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) %endif { bool in_parent_list_1 = - is_adjacent_or_overlapping_with_stick_out(root_extent, + is_adjacent_or_overlapping(root_extent, parent_center, parent_level, - 1, - slnws_center, walk_level, - stick_out_factor); + slnws_center, walk_level); bool would_be_in_parent_list_4_not_considering_stickout = ( !in_parent_list_1 -- GitLab From 9e8a747cd54ac8a29103176c6508ba0b0cd92955 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 8 Aug 2017 00:33:14 -0500 Subject: [PATCH 33/41] Traversal: Implement v2 list 3/4 criteria --- boxtree/traversal.py | 113 +++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 53 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 8bfa76e..9dfddf1 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -145,6 +145,8 @@ typedef ${dtype_to_ctype(box_id_dtype)} box_id_t; typedef ${dtype_to_ctype(coord_dtype)} coord_t; typedef ${dtype_to_ctype(vec_types_dict[coord_dtype, dimensions])} coord_vec_t; +#define COORD_T_MACH_EPS ((coord_t) ${ repr(np.finfo(coord_dtype).eps) }) + #define NLEVELS ${max_levels} #define LEVEL_TO_RAD(level) \ @@ -189,50 +191,9 @@ a large box and the edge of a smaller box to be a integer multiple of the smaller box's diameter (which is twice its radius, our tolerance). */ -inline bool is_adjacent_or_overlapping_with_stick_out( - coord_t root_extent, - // target and source order only matter if include_stick_out is true. - coord_vec_t target_center, int target_level, - coord_t target_box_neighborhood_size, - coord_vec_t source_center, int source_level, - const coord_t stick_out_factor - ) -{ - // This checks if the two boxes overlap - // with an amount of 'slack' corresponding to half the - // width of the smaller of the two boxes. - // (Without the 'slack', there wouldn't be any - // overlap.) - - coord_t target_rad = LEVEL_TO_RAD(target_level); - coord_t source_rad = LEVEL_TO_RAD(source_level); - coord_t rad_sum = ( - (2*(target_box_neighborhood_size-1) + 1) * target_rad - + source_rad); - coord_t slack = rad_sum + fmin(target_rad, source_rad); - - slack += stick_out_factor * ( - 0 - %if targets_have_extent: - + target_rad - %endif - %if sources_have_extent: - + source_rad - %endif - ); - - coord_t max_dist = 0; - %for i in range(dimensions): - max_dist = fmax(max_dist, fabs(target_center.s${i} - source_center.s${i})); - %endfor - - return max_dist <= slack; -} - inline bool is_adjacent_or_overlapping_with_neighborhood( coord_t root_extent, - // note: order does not matter coord_vec_t target_center, int target_level, coord_t target_box_neighborhood_size, coord_vec_t source_center, int source_level) @@ -248,12 +209,14 @@ inline bool is_adjacent_or_overlapping_with_neighborhood( + source_rad); coord_t slack = rad_sum + fmin(target_rad, source_rad); - coord_t max_dist = 0; + coord_t l_inf_dist = 0; %for i in range(dimensions): - max_dist = fmax(max_dist, fabs(target_center.s${i} - source_center.s${i})); + l_inf_dist = fmax( + l_inf_dist, + fabs(target_center.s${i} - source_center.s${i})); %endfor - return max_dist <= slack; + return l_inf_dist <= slack; } inline bool is_adjacent_or_overlapping( @@ -545,6 +508,29 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) FROM_SEP_SMALLER_TEMPLATE = r"""//CL// +inline bool meets_sep_smaller_criterion( + coord_t root_extent, + coord_vec_t target_center, int target_level, + coord_vec_t source_center, int source_level, + coord_t stick_out_factor) +{ + coord_t target_rad = LEVEL_TO_RAD(target_level); + coord_t source_rad = LEVEL_TO_RAD(source_level); + coord_t max_allowed_center_l_inf_dist = ( + 3 * target_rad + + (1 + stick_out_factor) * source_rad); + + coord_t l_inf_dist = 0; + %for i in range(dimensions): + l_inf_dist = fmax( + l_inf_dist, + fabs(target_center.s${i} - source_center.s${i})); + %endfor + + return l_inf_dist >= max_allowed_center_l_inf_dist * (1 - 8 * COORD_T_MACH_EPS); +} + + void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) { // /!\ target_box_number is *not* a box_id, despite the type. @@ -634,21 +620,20 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) else { %if sources_have_extent or targets_have_extent: - const bool a_or_o_with_stick_out = - is_adjacent_or_overlapping_with_stick_out(root_extent, + const bool meets_crit = + meets_sep_smaller_criterion(root_extent, center, level, - 1, walk_center, walk_level, stick_out_factor); %else: - const bool a_or_o_with_stick_out = false; + const bool meets_sep_smaller_criterion = true; %endif // We're no longer *immediately* adjacent to our target // box, but our stick-out regions might still have a // non-empty intersection. - if (!a_or_o_with_stick_out) + if (meets_crit) { if (from_sep_smaller_source_level == walk_level) APPEND_from_sep_smaller(walk_box_id); @@ -737,6 +722,29 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) FROM_SEP_BIGGER_TEMPLATE = r"""//CL// +inline bool meets_sep_bigger_criterion( + coord_t root_extent, + coord_vec_t target_center, int target_level, + coord_vec_t source_center, int source_level, + coord_t stick_out_factor) +{ + coord_t target_rad = LEVEL_TO_RAD(target_level); + coord_t source_rad = LEVEL_TO_RAD(source_level); + coord_t max_allowed_center_l_inf_dist = ( + 3 * (1 + stick_out_factor) * target_rad + + source_rad); + + coord_t l_inf_dist = 0; + %for i in range(dimensions): + l_inf_dist = fmax( + l_inf_dist, + fabs(target_center.s${i} - source_center.s${i})); + %endfor + + return l_inf_dist >= max_allowed_center_l_inf_dist * (1 - 8 * COORD_T_MACH_EPS); +} + + void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) { box_id_t tgt_ibox = target_or_target_parent_boxes[itarget_or_target_parent_box]; @@ -812,9 +820,8 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) change the equivalent check for the parent, below. */ const bool tgt_meets_with_ext_sep_criterion = - !is_adjacent_or_overlapping_with_stick_out(root_extent, + meets_sep_bigger_criterion(root_extent, tgt_box_center, tgt_box_level, - ${well_sep_is_n_away}, slnws_center, walk_level, stick_out_factor); @@ -883,9 +890,8 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) %if sources_have_extent or targets_have_extent: const bool parent_meets_with_ext_sep_criterion = - !is_adjacent_or_overlapping_with_stick_out(root_extent, + meets_sep_bigger_criterion(root_extent, parent_center, parent_level, - ${well_sep_is_n_away}, slnws_center, walk_level, stick_out_factor); @@ -1319,6 +1325,7 @@ class FMMTraversalBuilder: from pyopencl.tools import dtype_to_ctype from boxtree.tree import box_flags_enum render_vars = dict( + np=np, dimensions=dimensions, dtype_to_ctype=dtype_to_ctype, particle_id_dtype=particle_id_dtype, -- GitLab From a7432f3124a5b958fb11fe606aaed8066ba30dd7 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 8 Aug 2017 00:34:28 -0500 Subject: [PATCH 34/41] Revert "Reenable sources-with-extent in traversal building" This reverts commit 47a18af479df207913ad90501d743c15905d65bd. --- boxtree/traversal.py | 6 ++++++ test/test_fmm.py | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 9dfddf1..733dc75 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1475,6 +1475,12 @@ class FMMTraversalBuilder: if not tree._is_pruned: raise ValueError("tree must be pruned for traversal generation") + if tree.sources_have_extent: + # YAGNI + raise NotImplementedError( + "trees with source extent are not supported for " + "traversal generation") + # Generated code shouldn't depend on the *exact* number of tree levels. # So round up to the next multiple of 5. from pytools import div_ceil diff --git a/test/test_fmm.py b/test/test_fmm.py index 09c6016..f10d9ae 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -238,31 +238,31 @@ class ConstantOneExpansionWranglerWithFilteredTargetsInUserOrder( [ (2, 10**5, None, "", p_normal, p_normal, None), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, None), - (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), - (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), + #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), + #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, None), - (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), + #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), (3, 10**5, None, "", p_normal, p_normal, None), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, None), - (3, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), - (3, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), + #(3, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, None), + #(3, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, None), (3, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, None), - (3, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), + #(3, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, None), (2, 10**5, None, "", p_normal, p_normal, "user"), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, "user"), - (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "user"), - (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "user"), + #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "user"), + #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "user"), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, "user"), - (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "user"), + #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "user"), (2, 10**5, None, "", p_normal, p_normal, "tree"), (3, 5 * 10**4, 4*10**4, "", p_normal, p_normal, "tree"), - (2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "tree"), - (2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "tree"), + #(2, 5 * 10**5, 4*10**4, "s", p_normal, p_normal, "tree"), + #(2, 5 * 10**5, 4*10**4, "st", p_normal, p_normal, "tree"), (2, 5 * 10**5, 4*10**4, "t", p_normal, p_normal, "tree"), - (2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), + #(2, 5 * 10**5, 4*10**4, "st", p_surface, p_uniform, "tree"), ]) def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, who_has_extent, source_gen, target_gen, filter_kind, well_sep_is_n_away): -- GitLab From 068b8a1dbc5feb91d2621dde9b65a83f5373ca10 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 8 Aug 2017 01:05:57 -0500 Subject: [PATCH 35/41] Remove debug print statements --- boxtree/tree.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/boxtree/tree.py b/boxtree/tree.py index cc70134..a6a7bb7 100644 --- a/boxtree/tree.py +++ b/boxtree/tree.py @@ -714,7 +714,6 @@ class ParticleListFilter(object): from pyopencl.tools import VectorArg, dtype_to_ctype from pyopencl.algorithm import ListOfListsBuilder from mako.template import Template - print("CACHE MISS 2") builder = ListOfListsBuilder(self.context, [("filt_tgt_list", particle_id_dtype)], Template("""//CL// @@ -782,7 +781,6 @@ class ParticleListFilter(object): from boxtree.tree_build_kernels import ( TREE_ORDER_TARGET_FILTER_SCAN_TPL, TREE_ORDER_TARGET_FILTER_INDEX_TPL) - print("CACHE MISS 3") scan_knl = TREE_ORDER_TARGET_FILTER_SCAN_TPL.build( self.context, -- GitLab From 810528d26ecce3df8d4502064821b75a48ce9924 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 8 Aug 2017 01:06:20 -0500 Subject: [PATCH 36/41] Fix more fallout from L3/4 criteria change --- boxtree/area_query.py | 2 ++ boxtree/traversal.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/boxtree/area_query.py b/boxtree/area_query.py index 48fbf36..fb886b4 100644 --- a/boxtree/area_query.py +++ b/boxtree/area_query.py @@ -533,6 +533,7 @@ class AreaQueryElementwiseTemplate(object): from boxtree.tree_build import TreeBuilder render_vars = ( + ("np", np), ("dimensions", dimensions), ("dtype_to_ctype", dtype_to_ctype), ("box_id_dtype", box_id_dtype), @@ -1047,6 +1048,7 @@ class PeerListFinder(object): strict_undefined=True) render_vars = dict( + np=np, dimensions=dimensions, dtype_to_ctype=dtype_to_ctype, box_id_dtype=box_id_dtype, diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 733dc75..73d7fa0 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -626,7 +626,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) walk_center, walk_level, stick_out_factor); %else: - const bool meets_sep_smaller_criterion = true; + const bool meets_crit = true; %endif // We're no longer *immediately* adjacent to our target -- GitLab From 84d88db791ca534c3e52edb8c390a7fa67384284 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 8 Aug 2017 10:10:17 -0500 Subject: [PATCH 37/41] More L3/4 criteria template gen fixes --- boxtree/area_query.py | 1 + 1 file changed, 1 insertion(+) diff --git a/boxtree/area_query.py b/boxtree/area_query.py index fb886b4..a824cfc 100644 --- a/boxtree/area_query.py +++ b/boxtree/area_query.py @@ -646,6 +646,7 @@ class AreaQueryBuilder(object): strict_undefined=True) render_vars = dict( + np=np, dimensions=dimensions, dtype_to_ctype=dtype_to_ctype, box_id_dtype=box_id_dtype, -- GitLab From 9833974690e4a13d22828fc7ae250d7af55c7430 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 15 Aug 2017 10:44:37 -0500 Subject: [PATCH 38/41] Clarify doc definition of stick-out radius (Thanks @mattwala) [ci skip] --- boxtree/tree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boxtree/tree.py b/boxtree/tree.py index a6a7bb7..84b0a94 100644 --- a/boxtree/tree.py +++ b/boxtree/tree.py @@ -106,9 +106,9 @@ class Tree(DeviceDataRecord): .. attribute:: stick_out_factor - The fraction of the box diameter by which the :math:`l^\infty` circles - given by :attr:`source_radii` may stick out the box in which they are - contained. A scalar. + The fraction of the (:math:`l^\infty`) box radius by which the + :math:`l^\infty` circles given by :attr:`source_radii` may stick out + the box in which they are contained. A scalar. .. attribute:: nsources -- GitLab From 533aeab989e98d47c4d146983b3bbfec9f19cc67 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 27 Aug 2017 20:32:32 -0500 Subject: [PATCH 39/41] Kill a leftover debug print [ci skip] --- test/test_fmm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_fmm.py b/test/test_fmm.py index 98090e5..7d6bb07 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -376,7 +376,6 @@ def test_fmm_completeness(ctx_getter, dims, nsources_req, ntargets_req, from boxtree.fmm import drive_fmm pot = drive_fmm(host_trav, wrangler, weights) - print(pot) if filter_kind: pot = pot[flags.get() > 0] -- GitLab From bbc2d897c44f464e11946c924227af9abf50c018 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 27 Aug 2017 21:55:46 -0500 Subject: [PATCH 40/41] Comment/doc changes suggested by Matt [ci skip] --- boxtree/traversal.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 73d7fa0..62633e4 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -671,9 +671,10 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # {{{ from separated bigger ("list 4") -# List 4 consists of lists that 'missed the boat' on entering the downward +# List 4 consists of source boxes that 'missed the boat' on entering the downward # propagation through list 2. That is, they are non-well-separated from the -# target box itself or a box in its chain of parents. +# target box itself or a box in its chain of parents. In addition, they are +# not adjacent to the target box and have the same size or are bigger. # # To be in list 4, a box must have its own sources. In the no-extents case, # this will happen only if that box is a leaf, but for the with-extents case, @@ -689,7 +690,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t target_box_number) # we don't need to consider it (because the interaction to this box will be # mediated by list 1). # -# Case I: Sources or targets do not have extent +# Case I: Neither sources nor targets have extent # # In this case and once non-membership in list 1 has been verified, list 4 # membership is simply a matter of deciding whether the source box's @@ -769,7 +770,7 @@ void generate(LIST_ARG_DECL USER_ARG_DECL box_id_t itarget_or_target_parent_box) int walk_level = tgt_box_level - 1; box_id_t current_parent_box_id = parent_box_id; %else: - // In a 2+-away FMM, tgt_ibox's same-level well-separated boxes *may* + // In a 2+-away FMM, tgt_ibox's same-level non-well-separated boxes *may* // be sufficiently separated from tgt_ibox to be in its list 4. int walk_level = tgt_box_level; -- GitLab From c11562afa9222cce64fcc296821a9ad52d49c7cd Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 27 Aug 2017 22:05:39 -0500 Subject: [PATCH 41/41] Delete unused, commented-out argument in list 4 builder? --- boxtree/traversal.py | 1 - 1 file changed, 1 deletion(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 62633e4..0bb5a31 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1430,7 +1430,6 @@ class FMMTraversalBuilder: "same_level_non_well_sep_boxes_starts"), VectorArg(box_id_dtype, "same_level_non_well_sep_boxes_lists"), - #ScalarArg(box_id_dtype, "from_sep_bigger_source_level"), ], ["from_sep_close_bigger"] if sources_have_extent or targets_have_extent -- GitLab