From c300f8785ca98442362fad43aeeffab51d539a55 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Sat, 27 Jan 2018 23:21:41 -0600 Subject: [PATCH 01/17] Compress list 3 using ListOfListsBuilder --- boxtree/traversal.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 3448ee5..08440e4 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1536,7 +1536,8 @@ class _KernelInfo(Record): class FMMTraversalBuilder: - def __init__(self, context, well_sep_is_n_away=1, from_sep_smaller_crit=None): + def __init__(self, context, well_sep_is_n_away=1, from_sep_smaller_crit=None, + compress_list_3=False): """ :arg well_sep_is_n_away: Either An integer 1 or greater. (Only 2 is tested) The spacing between boxes that is considered "well-separated" for @@ -1548,10 +1549,13 @@ class FMMTraversalBuilder: (use the precise extent of targets in the box, including their radii), or ``"static_l2"`` (use the circumcircle of the box, possibly enlarged by :attr:`Tree.stick_out_factor`). + :arg compress_list_3: If set to True, only the target boxes with separated + smaller boxes will remain in list 3. """ self.context = context self.well_sep_is_n_away = well_sep_is_n_away self.from_sep_smaller_crit = from_sep_smaller_crit + self.compress_list_3 = compress_list_3 # {{{ kernel builder @@ -1692,13 +1696,13 @@ class FMMTraversalBuilder: VectorArg(box_flags_enum.dtype, "box_flags"), ] - for list_name, template, extra_args, extra_lists in [ + for list_name, template, extra_args, extra_lists, eliminate_empty_list in [ ("same_level_non_well_sep_boxes", - SAME_LEVEL_NON_WELL_SEP_BOXES_TEMPLATE, [], []), + SAME_LEVEL_NON_WELL_SEP_BOXES_TEMPLATE, [], [], False), ("neighbor_source_boxes", NEIGBHOR_SOURCE_BOXES_TEMPLATE, [ VectorArg(box_id_dtype, "target_boxes"), - ], []), + ], [], False), ("from_sep_siblings", FROM_SEP_SIBLINGS_TEMPLATE, [ VectorArg(box_id_dtype, "target_or_target_parent_boxes"), @@ -1707,7 +1711,7 @@ class FMMTraversalBuilder: "same_level_non_well_sep_boxes_starts"), VectorArg(box_id_dtype, "same_level_non_well_sep_boxes_lists"), - ], []), + ], [], False), ("from_sep_smaller", FROM_SEP_SMALLER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), @@ -1725,7 +1729,7 @@ class FMMTraversalBuilder: ], ["from_sep_close_smaller"] if sources_have_extent or targets_have_extent - else []), + else [], self.compress_list_3), ("from_sep_bigger", FROM_SEP_BIGGER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), @@ -1738,7 +1742,7 @@ class FMMTraversalBuilder: ], ["from_sep_close_bigger"] if sources_have_extent or targets_have_extent - else []), + else [], False), ]: src = Template( TRAVERSAL_PREAMBLE_TEMPLATE @@ -1753,7 +1757,8 @@ class FMMTraversalBuilder: str(src), arg_decls=base_args + extra_args, debug=debug, name_prefix=list_name, - complex_kernel=True) + complex_kernel=True, + eliminate_empty_output_lists=eliminate_empty_list) # }}} -- GitLab From d4e3c0a2ba47b6d0a578eb7e42159f2ea08b8c21 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 5 Feb 2018 22:04:46 -0600 Subject: [PATCH 02/17] Make DeviceDataRecord transformation handles all fields of BuiltList --- boxtree/tools.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/boxtree/tools.py b/boxtree/tools.py index ece152d..f030459 100644 --- a/boxtree/tools.py +++ b/boxtree/tools.py @@ -270,10 +270,11 @@ class DeviceDataRecord(Record): elif isinstance(val, list): return [transform_val(i) for i in val] elif isinstance(val, BuiltList): - return BuiltList( - count=val.count, - starts=f(val.starts), - lists=f(val.lists)) + transformed_list = { + field: f(getattr(val, field)) + for field in val.__dict__ if field != 'count' + } + return BuiltList(count=val.count, **transformed_list) else: return f(val) -- GitLab From 1af53276e21dd5c04c9fe380e49bc1537418b7c2 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 5 Feb 2018 22:06:16 -0600 Subject: [PATCH 03/17] Add a test script for checking list 3 compression --- test/test_compress.py | 67 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/test_compress.py diff --git a/test/test_compress.py b/test/test_compress.py new file mode 100644 index 0000000..5f4d94d --- /dev/null +++ b/test/test_compress.py @@ -0,0 +1,67 @@ +from __future__ import absolute_import +import pyopencl as cl +import numpy as np +from six.moves import range + +ctx = cl.create_some_context() +queue = cl.CommandQueue(ctx) + +dims = 2 +nparticles = 10**5 + +# ----------------------------------------------------------------------------- +# generate some random particle positions +# ----------------------------------------------------------------------------- +from pyopencl.clrandom import RanluxGenerator +rng = RanluxGenerator(queue, seed=15) + +from pytools.obj_array import make_obj_array +particles = make_obj_array([ + rng.normal(queue, nparticles, dtype=np.float64) + for i in range(dims)]) + +# ----------------------------------------------------------------------------- +# build tree and traversals (lists) +# ----------------------------------------------------------------------------- +from boxtree import TreeBuilder +tb = TreeBuilder(ctx) +tree, _ = tb(queue, particles, max_particles_in_box=30) + +from boxtree.traversal import FMMTraversalBuilder +tg1 = FMMTraversalBuilder(ctx) +trav1, _ = tg1(queue, tree) + +tg2 = FMMTraversalBuilder(ctx, compress_list_3=True) +trav2, _ = tg2(queue, tree) + +trav1 = trav1.get(queue) +trav2 = trav2.get(queue) + +for i in range(tree.nlevels): + count1 = trav1.from_sep_smaller_by_level[i].count + starts1 = trav1.from_sep_smaller_by_level[i].starts + lists1 = trav1.from_sep_smaller_by_level[i].lists + + count2 = trav2.from_sep_smaller_by_level[i].count + starts2 = trav2.from_sep_smaller_by_level[i].starts + lists2 = trav2.from_sep_smaller_by_level[i].lists + nonempty_indices = trav2.from_sep_smaller_by_level[i].nonempty_indices + num_nonempty_lists = trav2.from_sep_smaller_by_level[i].num_nonempty_lists + + assert count1 == count2 + + true_nonempty_starts = [] + true_nonempty_indices = [] + for j in range(trav1.target_boxes.shape[0]): + if starts1[j] != starts1[j + 1]: + true_nonempty_starts.append(starts1[j]) + true_nonempty_indices.append(j) + true_num_nonempty_lists = len(true_nonempty_indices) + true_nonempty_indices = np.array(true_nonempty_indices) + true_nonempty_starts.append(starts1[-1]) + true_nonempty_starts = np.array(true_nonempty_starts) + + assert np.all(starts2 == true_nonempty_starts) + assert np.all(lists1 == lists2) + assert np.all(nonempty_indices == true_nonempty_indices) + assert num_nonempty_lists == true_num_nonempty_lists -- GitLab From 981388a635e2949ce12c8eec1b9156f204fb93f3 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 6 Feb 2018 21:43:12 -0600 Subject: [PATCH 04/17] Integrate list3 compression test with pytest --- test/test_compress.py | 104 ++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/test/test_compress.py b/test/test_compress.py index 5f4d94d..6a47ba6 100644 --- a/test/test_compress.py +++ b/test/test_compress.py @@ -3,65 +3,69 @@ import pyopencl as cl import numpy as np from six.moves import range -ctx = cl.create_some_context() -queue = cl.CommandQueue(ctx) +from pyopencl.tools import ( # noqa + pytest_generate_tests_for_pyopencl as pytest_generate_tests) -dims = 2 -nparticles = 10**5 +def test_list3_compression(ctx_factory): + ctx = ctx_factory() + queue = cl.CommandQueue(ctx) -# ----------------------------------------------------------------------------- -# generate some random particle positions -# ----------------------------------------------------------------------------- -from pyopencl.clrandom import RanluxGenerator -rng = RanluxGenerator(queue, seed=15) + dims = 2 + nparticles = 10**5 -from pytools.obj_array import make_obj_array -particles = make_obj_array([ - rng.normal(queue, nparticles, dtype=np.float64) - for i in range(dims)]) + # ----------------------------------------------------------------------------- + # generate some random particle positions + # ----------------------------------------------------------------------------- + from pyopencl.clrandom import RanluxGenerator + rng = RanluxGenerator(queue, seed=15) -# ----------------------------------------------------------------------------- -# build tree and traversals (lists) -# ----------------------------------------------------------------------------- -from boxtree import TreeBuilder -tb = TreeBuilder(ctx) -tree, _ = tb(queue, particles, max_particles_in_box=30) + from pytools.obj_array import make_obj_array + particles = make_obj_array([ + rng.normal(queue, nparticles, dtype=np.float64) + for i in range(dims)]) -from boxtree.traversal import FMMTraversalBuilder -tg1 = FMMTraversalBuilder(ctx) -trav1, _ = tg1(queue, tree) + # ----------------------------------------------------------------------------- + # build tree and traversals (lists) + # ----------------------------------------------------------------------------- + from boxtree import TreeBuilder + tb = TreeBuilder(ctx) + tree, _ = tb(queue, particles, max_particles_in_box=30) -tg2 = FMMTraversalBuilder(ctx, compress_list_3=True) -trav2, _ = tg2(queue, tree) + from boxtree.traversal import FMMTraversalBuilder + tg1 = FMMTraversalBuilder(ctx) + trav1, _ = tg1(queue, tree) -trav1 = trav1.get(queue) -trav2 = trav2.get(queue) + tg2 = FMMTraversalBuilder(ctx, compress_list_3=True) + trav2, _ = tg2(queue, tree) -for i in range(tree.nlevels): - count1 = trav1.from_sep_smaller_by_level[i].count - starts1 = trav1.from_sep_smaller_by_level[i].starts - lists1 = trav1.from_sep_smaller_by_level[i].lists + trav1 = trav1.get(queue) + trav2 = trav2.get(queue) - count2 = trav2.from_sep_smaller_by_level[i].count - starts2 = trav2.from_sep_smaller_by_level[i].starts - lists2 = trav2.from_sep_smaller_by_level[i].lists - nonempty_indices = trav2.from_sep_smaller_by_level[i].nonempty_indices - num_nonempty_lists = trav2.from_sep_smaller_by_level[i].num_nonempty_lists + for i in range(tree.nlevels): + count1 = trav1.from_sep_smaller_by_level[i].count + starts1 = trav1.from_sep_smaller_by_level[i].starts + lists1 = trav1.from_sep_smaller_by_level[i].lists - assert count1 == count2 + count2 = trav2.from_sep_smaller_by_level[i].count + starts2 = trav2.from_sep_smaller_by_level[i].starts + lists2 = trav2.from_sep_smaller_by_level[i].lists + nonempty_indices = trav2.from_sep_smaller_by_level[i].nonempty_indices + num_nonempty_lists = trav2.from_sep_smaller_by_level[i].num_nonempty_lists - true_nonempty_starts = [] - true_nonempty_indices = [] - for j in range(trav1.target_boxes.shape[0]): - if starts1[j] != starts1[j + 1]: - true_nonempty_starts.append(starts1[j]) - true_nonempty_indices.append(j) - true_num_nonempty_lists = len(true_nonempty_indices) - true_nonempty_indices = np.array(true_nonempty_indices) - true_nonempty_starts.append(starts1[-1]) - true_nonempty_starts = np.array(true_nonempty_starts) + assert count1 == count2 - assert np.all(starts2 == true_nonempty_starts) - assert np.all(lists1 == lists2) - assert np.all(nonempty_indices == true_nonempty_indices) - assert num_nonempty_lists == true_num_nonempty_lists + true_nonempty_starts = [] + true_nonempty_indices = [] + for j in range(trav1.target_boxes.shape[0]): + if starts1[j] != starts1[j + 1]: + true_nonempty_starts.append(starts1[j]) + true_nonempty_indices.append(j) + true_num_nonempty_lists = len(true_nonempty_indices) + true_nonempty_indices = np.array(true_nonempty_indices) + true_nonempty_starts.append(starts1[-1]) + true_nonempty_starts = np.array(true_nonempty_starts) + + assert np.all(starts2 == true_nonempty_starts) + assert np.all(lists1 == lists2) + assert np.all(nonempty_indices == true_nonempty_indices) + assert num_nonempty_lists == true_num_nonempty_lists -- GitLab From 3ff19ae380ba116daef3b3b3a61e6265e3589371 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 6 Feb 2018 21:49:35 -0600 Subject: [PATCH 05/17] Fix Flake8 --- test/test_compress.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_compress.py b/test/test_compress.py index 6a47ba6..8ed0ee1 100644 --- a/test/test_compress.py +++ b/test/test_compress.py @@ -6,6 +6,7 @@ from six.moves import range from pyopencl.tools import ( # noqa pytest_generate_tests_for_pyopencl as pytest_generate_tests) + def test_list3_compression(ctx_factory): ctx = ctx_factory() queue = cl.CommandQueue(ctx) -- GitLab From 5c75220672c100ee1e1820d4bae755ac9de9a7bc Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 6 Feb 2018 22:10:51 -0600 Subject: [PATCH 06/17] Dict comprehension is not supported before Py2.7 --- boxtree/tools.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boxtree/tools.py b/boxtree/tools.py index f030459..86a6568 100644 --- a/boxtree/tools.py +++ b/boxtree/tools.py @@ -270,10 +270,10 @@ class DeviceDataRecord(Record): elif isinstance(val, list): return [transform_val(i) for i in val] elif isinstance(val, BuiltList): - transformed_list = { - field: f(getattr(val, field)) - for field in val.__dict__ if field != 'count' - } + transformed_list = {} + for field in val.__dict__: + if field != 'count': + transformed_list[field] = f(getattr(val, field)) return BuiltList(count=val.count, **transformed_list) else: return f(val) -- GitLab From 3f54215433945f1769242b375bdf26843dca2d19 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 6 Feb 2018 22:38:49 -0600 Subject: [PATCH 07/17] Remove compression switch --- boxtree/traversal.py | 6 ++-- test/test_compress.py | 72 ------------------------------------------- 2 files changed, 2 insertions(+), 76 deletions(-) delete mode 100644 test/test_compress.py diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 08440e4..dfab947 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1536,8 +1536,7 @@ class _KernelInfo(Record): class FMMTraversalBuilder: - def __init__(self, context, well_sep_is_n_away=1, from_sep_smaller_crit=None, - compress_list_3=False): + def __init__(self, context, well_sep_is_n_away=1, from_sep_smaller_crit=None): """ :arg well_sep_is_n_away: Either An integer 1 or greater. (Only 2 is tested) The spacing between boxes that is considered "well-separated" for @@ -1555,7 +1554,6 @@ class FMMTraversalBuilder: self.context = context self.well_sep_is_n_away = well_sep_is_n_away self.from_sep_smaller_crit = from_sep_smaller_crit - self.compress_list_3 = compress_list_3 # {{{ kernel builder @@ -1729,7 +1727,7 @@ class FMMTraversalBuilder: ], ["from_sep_close_smaller"] if sources_have_extent or targets_have_extent - else [], self.compress_list_3), + else [], True), ("from_sep_bigger", FROM_SEP_BIGGER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), diff --git a/test/test_compress.py b/test/test_compress.py deleted file mode 100644 index 8ed0ee1..0000000 --- a/test/test_compress.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import absolute_import -import pyopencl as cl -import numpy as np -from six.moves import range - -from pyopencl.tools import ( # noqa - pytest_generate_tests_for_pyopencl as pytest_generate_tests) - - -def test_list3_compression(ctx_factory): - ctx = ctx_factory() - queue = cl.CommandQueue(ctx) - - dims = 2 - nparticles = 10**5 - - # ----------------------------------------------------------------------------- - # generate some random particle positions - # ----------------------------------------------------------------------------- - from pyopencl.clrandom import RanluxGenerator - rng = RanluxGenerator(queue, seed=15) - - from pytools.obj_array import make_obj_array - particles = make_obj_array([ - rng.normal(queue, nparticles, dtype=np.float64) - for i in range(dims)]) - - # ----------------------------------------------------------------------------- - # build tree and traversals (lists) - # ----------------------------------------------------------------------------- - from boxtree import TreeBuilder - tb = TreeBuilder(ctx) - tree, _ = tb(queue, particles, max_particles_in_box=30) - - from boxtree.traversal import FMMTraversalBuilder - tg1 = FMMTraversalBuilder(ctx) - trav1, _ = tg1(queue, tree) - - tg2 = FMMTraversalBuilder(ctx, compress_list_3=True) - trav2, _ = tg2(queue, tree) - - trav1 = trav1.get(queue) - trav2 = trav2.get(queue) - - for i in range(tree.nlevels): - count1 = trav1.from_sep_smaller_by_level[i].count - starts1 = trav1.from_sep_smaller_by_level[i].starts - lists1 = trav1.from_sep_smaller_by_level[i].lists - - count2 = trav2.from_sep_smaller_by_level[i].count - starts2 = trav2.from_sep_smaller_by_level[i].starts - lists2 = trav2.from_sep_smaller_by_level[i].lists - nonempty_indices = trav2.from_sep_smaller_by_level[i].nonempty_indices - num_nonempty_lists = trav2.from_sep_smaller_by_level[i].num_nonempty_lists - - assert count1 == count2 - - true_nonempty_starts = [] - true_nonempty_indices = [] - for j in range(trav1.target_boxes.shape[0]): - if starts1[j] != starts1[j + 1]: - true_nonempty_starts.append(starts1[j]) - true_nonempty_indices.append(j) - true_num_nonempty_lists = len(true_nonempty_indices) - true_nonempty_indices = np.array(true_nonempty_indices) - true_nonempty_starts.append(starts1[-1]) - true_nonempty_starts = np.array(true_nonempty_starts) - - assert np.all(starts2 == true_nonempty_starts) - assert np.all(lists1 == lists2) - assert np.all(nonempty_indices == true_nonempty_indices) - assert num_nonempty_lists == true_num_nonempty_lists -- GitLab From 9bbf177c7d21c813ba123f76e96d77cd4c24aa26 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 12 Feb 2018 21:47:59 -0600 Subject: [PATCH 08/17] Adjust FMM interface to allow compression --- boxtree/fmm.py | 9 ++++++++- boxtree/pyfmmlib_integration.py | 4 ++-- boxtree/traversal.py | 10 +++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index bc0c773..25ead65 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -1,4 +1,5 @@ from __future__ import division +import numpy as np __copyright__ = "Copyright (C) 2012 Andreas Kloeckner" @@ -112,9 +113,15 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): # (the point of aiming this stage at particles is specifically to keep its # contribution *out* of the downward-propagating local expansions) + target_boxes_by_level = np.empty((traversal.tree.nlevels,), dtype=object) + for i, from_sep_smaller_current_level in \ + enumerate(traversal.from_sep_smaller_by_level): + target_boxes_by_level[i] = traversal.target_boxes[ + from_sep_smaller_current_level.nonempty_indices] + potentials = potentials + wrangler.eval_multipoles( traversal.level_start_target_box_nrs, - traversal.target_boxes, + target_boxes_by_level, traversal.from_sep_smaller_by_level, mpole_exps) diff --git a/boxtree/pyfmmlib_integration.py b/boxtree/pyfmmlib_integration.py index 812eae4..9136721 100644 --- a/boxtree/pyfmmlib_integration.py +++ b/boxtree/pyfmmlib_integration.py @@ -631,7 +631,7 @@ class FMMLibExpansionWrangler(object): return local_exps - def eval_multipoles(self, level_start_target_box_nrs, target_boxes, + def eval_multipoles(self, level_start_target_box_nrs, target_boxes_by_level, sep_smaller_nonsiblings_by_level, mpole_exps): output = self.output_zeros() @@ -643,7 +643,7 @@ class FMMLibExpansionWrangler(object): rscale = self.level_to_rscale(isrc_level) - for itgt_box, tgt_ibox in enumerate(target_boxes): + for itgt_box, tgt_ibox in enumerate(target_boxes_by_level[isrc_level]): tgt_pslice = self._get_target_slice(tgt_ibox) if tgt_pslice.stop - tgt_pslice.start == 0: diff --git a/boxtree/traversal.py b/boxtree/traversal.py index dfab947..a04528f 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1696,11 +1696,11 @@ class FMMTraversalBuilder: for list_name, template, extra_args, extra_lists, eliminate_empty_list in [ ("same_level_non_well_sep_boxes", - SAME_LEVEL_NON_WELL_SEP_BOXES_TEMPLATE, [], [], False), + SAME_LEVEL_NON_WELL_SEP_BOXES_TEMPLATE, [], [], []), ("neighbor_source_boxes", NEIGBHOR_SOURCE_BOXES_TEMPLATE, [ VectorArg(box_id_dtype, "target_boxes"), - ], [], False), + ], [], []), ("from_sep_siblings", FROM_SEP_SIBLINGS_TEMPLATE, [ VectorArg(box_id_dtype, "target_or_target_parent_boxes"), @@ -1709,7 +1709,7 @@ class FMMTraversalBuilder: "same_level_non_well_sep_boxes_starts"), VectorArg(box_id_dtype, "same_level_non_well_sep_boxes_lists"), - ], [], False), + ], [], []), ("from_sep_smaller", FROM_SEP_SMALLER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), @@ -1727,7 +1727,7 @@ class FMMTraversalBuilder: ], ["from_sep_close_smaller"] if sources_have_extent or targets_have_extent - else [], True), + else [], ["from_sep_smaller"]), ("from_sep_bigger", FROM_SEP_BIGGER_TEMPLATE, [ ScalarArg(coord_dtype, "stick_out_factor"), @@ -1740,7 +1740,7 @@ class FMMTraversalBuilder: ], ["from_sep_close_bigger"] if sources_have_extent or targets_have_extent - else [], False), + else [], []), ]: src = Template( TRAVERSAL_PREAMBLE_TEMPLATE -- GitLab From 506d54e89428bbc98812cc23f605be5c6ec63ca9 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 13 Feb 2018 21:14:17 -0600 Subject: [PATCH 09/17] Update fmm test --- test/test_fmm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_fmm.py b/test/test_fmm.py index e29d8bd..28317ad 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -141,12 +141,12 @@ class ConstantOneExpansionWrangler(object): return local_exps - def eval_multipoles(self, level_start_target_box_nrs, target_boxes, + def eval_multipoles(self, level_start_target_box_nrs, target_boxes_by_level, from_sep_smaller_nonsiblings_by_level, mpole_exps): pot = self.potential_zeros() - for ssn in from_sep_smaller_nonsiblings_by_level: - for itgt_box, tgt_ibox in enumerate(target_boxes): + for level, ssn in enumerate(from_sep_smaller_nonsiblings_by_level): + for itgt_box, tgt_ibox in enumerate(target_boxes_by_level[level]): tgt_pslice = self._get_target_slice(tgt_ibox) contrib = 0 -- GitLab From 9bf658351bf4f497f4057a602f9579353f90fc21 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 20 Feb 2018 22:07:21 -0600 Subject: [PATCH 10/17] Add target_boxes_sep_smaller_by_level to traversal object --- boxtree/fmm.py | 8 +------- boxtree/traversal.py | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index 25ead65..0341c2c 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -113,15 +113,9 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): # (the point of aiming this stage at particles is specifically to keep its # contribution *out* of the downward-propagating local expansions) - target_boxes_by_level = np.empty((traversal.tree.nlevels,), dtype=object) - for i, from_sep_smaller_current_level in \ - enumerate(traversal.from_sep_smaller_by_level): - target_boxes_by_level[i] = traversal.target_boxes[ - from_sep_smaller_current_level.nonempty_indices] - potentials = potentials + wrangler.eval_multipoles( traversal.level_start_target_box_nrs, - target_boxes_by_level, + traversal.target_boxes_sep_smaller_by_level, traversal.from_sep_smaller_by_level, mpole_exps) diff --git a/boxtree/traversal.py b/boxtree/traversal.py index a04528f..dc133fd 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -2035,6 +2035,7 @@ class FMMTraversalBuilder: from_sep_smaller_wait_for = [] from_sep_smaller_by_level = [] + target_boxes_sep_smaller_by_level = [] for ilevel in range(tree.nlevels): fin_debug("finding separated smaller ('list 3 level %d')" % ilevel) @@ -2044,7 +2045,11 @@ class FMMTraversalBuilder: omit_lists=("from_sep_close_smaller",) if with_extent else (), wait_for=wait_for) + target_boxes_sep_smaller = target_boxes[ + result["from_sep_smaller"].nonempty_indices] + from_sep_smaller_by_level.append(result["from_sep_smaller"]) + target_boxes_sep_smaller_by_level.append(target_boxes_sep_smaller) from_sep_smaller_wait_for.append(evt) if with_extent: @@ -2140,6 +2145,7 @@ class FMMTraversalBuilder: from_sep_siblings_lists=from_sep_siblings.lists, from_sep_smaller_by_level=from_sep_smaller_by_level, + target_boxes_sep_smaller_by_level=target_boxes_sep_smaller_by_level, from_sep_close_smaller_starts=from_sep_close_smaller_starts, from_sep_close_smaller_lists=from_sep_close_smaller_lists, -- GitLab From 55cad76555dcc1ae8ac6069e2b5c6dd49869d2c8 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 20 Feb 2018 22:07:50 -0600 Subject: [PATCH 11/17] Update test cases for list 3 compression --- test/test_traversal.py | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/test/test_traversal.py b/test/test_traversal.py index 6c4096e..6805c72 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -140,9 +140,10 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): 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.from_sep_smaller_by_level: + for level, ssn in enumerate(trav.from_sep_smaller_by_level): + for itarget_box, ibox in \ + enumerate(trav.target_boxes_sep_smaller_by_level[level]): start, end = ssn.starts[itarget_box:itarget_box+2] for jbox in ssn.lists[start:end]: @@ -155,10 +156,19 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # {{{ list 4 <= list 3 - box_to_target_box_index = np.empty(tree.nboxes, tree.box_id_dtype) - box_to_target_box_index.fill(-1) - box_to_target_box_index[trav.target_boxes] = np.arange( - len(trav.target_boxes), dtype=tree.box_id_dtype) + box_to_target_boxes_sep_smaller_by_level = [] + for level in range(trav.tree.nlevels): + box_to_target_boxes_sep_smaller = np.empty( + tree.nboxes, tree.box_id_dtype) + box_to_target_boxes_sep_smaller.fill(-1) + box_to_target_boxes_sep_smaller[ + trav.target_boxes_sep_smaller_by_level[level] + ] = np.arange( + len(trav.target_boxes_sep_smaller_by_level[level]), + dtype=tree.box_id_dtype + ) + box_to_target_boxes_sep_smaller_by_level.append( + box_to_target_boxes_sep_smaller) assert (trav.source_boxes == trav.target_boxes).all() assert (trav.target_or_target_parent_boxes == np.arange( @@ -173,13 +183,13 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # are the same thing (i.e. leaves--see assertion above), so we # may treat them as targets anyhow. - jtgt_box = box_to_target_box_index[jbox] - assert jtgt_box != -1 - good = False - for ssn in trav.from_sep_smaller_by_level: - rstart, rend = ssn.starts[jtgt_box:jtgt_box+2] + for level, ssn in enumerate(trav.from_sep_smaller_by_level): + jtgt_box = box_to_target_boxes_sep_smaller_by_level[level][jbox] + if jtgt_box == -1: + continue + rstart, rend = ssn.starts[jtgt_box:jtgt_box + 2] good = good or ibox in ssn.lists[rstart:rend] if not good: @@ -207,8 +217,11 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # {{{ from_sep_smaller satisfies relative level assumption - for itarget_box, ibox in enumerate(trav.target_boxes): - for ssn in trav.from_sep_smaller_by_level: + # for itarget_box, ibox in enumerate(trav.target_boxes): + # for ssn in trav.from_sep_smaller_by_level: + for level, ssn in enumerate(trav.from_sep_smaller_by_level): + for itarget_box, ibox in enumerate( + trav.target_boxes_sep_smaller_by_level[level]): start, end = ssn.starts[itarget_box:itarget_box+2] for jbox in ssn.lists[start:end]: -- GitLab From 124626c0f658db0bf41bf9d456986d5bc6237e51 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 20 Feb 2018 22:11:52 -0600 Subject: [PATCH 12/17] Flake 8 --- boxtree/fmm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index 0341c2c..fb8e6ca 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -1,5 +1,4 @@ from __future__ import division -import numpy as np __copyright__ = "Copyright (C) 2012 Andreas Kloeckner" -- GitLab From 7b124d3628a9b78c5d585a53cc435aa4c5d3fbf0 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Thu, 22 Feb 2018 20:32:57 -0600 Subject: [PATCH 13/17] Update documentation --- boxtree/fmm.py | 13 +++++++------ boxtree/traversal.py | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index fb8e6ca..ee30b99 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -273,12 +273,13 @@ class ExpansionWranglerInterface: :meth:`local_expansion_zeros`. """ - def eval_multipoles(self, level_start_target_box_nrs, target_boxes, - starts, lists, mpole_exps): - """For each box in *target_boxes*, evaluate the multipole expansion in - *mpole_exps* in the nearby boxes given in *starts* and *lists*, and - return a new potential array. *starts* and *lists* use :ref:`csr` and - *starts* is indexed like *target_boxes*. + def eval_multipoles(self, level_start_target_box_nrs, + target_boxes_by_level, starts, lists, mpole_exps): + """For a level *i*, each box in *target_boxes_by_level[i]*, evaluate + the multipole expansion in *mpole_exps* in the nearby boxes given in + *starts* and *lists*, and return a new potential array. *starts* and + *lists* use :ref:`csr` and *starts* is indexed like + *target_boxes_by_level[i]*. :returns: a new potential array, see :meth:`output_zeros`. """ diff --git a/boxtree/traversal.py b/boxtree/traversal.py index dc133fd..5d72f2b 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1305,17 +1305,26 @@ class FMMTraversalInfo(DeviceDataRecord): Indexed like :attr:`target_or_target_parent_boxes`. See :ref:`csr`. + .. attribute:: target_boxes_sep_smaller_by_level + + A list of :attr:`boxtree.Tree.nlevels` objects, each of which records target + boxes (in global box numbers) with "List 3" source boxes on that 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 - attributes *count*, *starts* and *lists*, which form a CSR list of List - 3 source boxes. + attributes *count*, *starts*, *lists*, *num_nonempty_lists*, and + *nonempty_indices*, which form a CSR list of List 3 source boxes. - *starts* has shape/type ``box_id_t [ntarget_boxes+1]``. *lists* is of type - ``box_id_t``. (Note: This list contains global box numbers, not + *starts* has shape/type ``box_id_t [num_nonempty_lists+1]``. *lists* is of + type ``box_id_t``. (Note: This list contains global box numbers, not indices into :attr:`source_boxes`.) + Note *starts* are indexed by `target_boxes_sep_smaller_by_level`. For + example, for level *i*, *lists[starts[j]:starts[j+1]]* represents "List 3" + source boxes of *target_boxes_sep_smaller_by_level[i][j]* on level *i*. + .. attribute:: from_sep_close_smaller_starts ``box_id_t [ntarget_boxes+1]`` (or *None*) -- GitLab From b122165c57d16f058449e60f34126c1391f10600 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Fri, 23 Feb 2018 12:35:21 -0600 Subject: [PATCH 14/17] Update documentation [ci skip] --- boxtree/fmm.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index ee30b99..b32b924 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -274,12 +274,12 @@ class ExpansionWranglerInterface: """ def eval_multipoles(self, level_start_target_box_nrs, - target_boxes_by_level, starts, lists, mpole_exps): + target_boxes_by_level, from_sep_smaller_by_level, mpole_exps): """For a level *i*, each box in *target_boxes_by_level[i]*, evaluate the multipole expansion in *mpole_exps* in the nearby boxes given in - *starts* and *lists*, and return a new potential array. *starts* and - *lists* use :ref:`csr` and *starts* is indexed like - *target_boxes_by_level[i]*. + *from_sep_smaller_by_level*, and return a new potential array. + *starts* and *lists* in *from_sep_smaller_by_level[i]* use :ref:`csr` + and *starts* is indexed like *target_boxes_by_level[i]*. :returns: a new potential array, see :meth:`output_zeros`. """ -- GitLab From 269a361d49ecd893f4540b9a5732ec6056a3c5f0 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Fri, 23 Feb 2018 13:23:44 -0600 Subject: [PATCH 15/17] Use more descriptive name --- boxtree/fmm.py | 8 ++++---- boxtree/pyfmmlib_integration.py | 8 +++++--- boxtree/traversal.py | 14 ++++++++------ test/test_fmm.py | 8 +++++--- test/test_traversal.py | 15 ++++++++------- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index b32b924..d856a5d 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -114,7 +114,7 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): potentials = potentials + wrangler.eval_multipoles( traversal.level_start_target_box_nrs, - traversal.target_boxes_sep_smaller_by_level, + traversal.target_boxes_sep_smaller_by_source_level, traversal.from_sep_smaller_by_level, mpole_exps) @@ -274,12 +274,12 @@ class ExpansionWranglerInterface: """ def eval_multipoles(self, level_start_target_box_nrs, - target_boxes_by_level, from_sep_smaller_by_level, mpole_exps): - """For a level *i*, each box in *target_boxes_by_level[i]*, evaluate + target_boxes_by_source_level, from_sep_smaller_by_level, mpole_exps): + """For a level *i*, each box in *target_boxes_by_source_level[i]*, evaluate the multipole expansion in *mpole_exps* in the nearby boxes given in *from_sep_smaller_by_level*, and return a new potential array. *starts* and *lists* in *from_sep_smaller_by_level[i]* use :ref:`csr` - and *starts* is indexed like *target_boxes_by_level[i]*. + and *starts* is indexed like *target_boxes_by_source_level[i]*. :returns: a new potential array, see :meth:`output_zeros`. """ diff --git a/boxtree/pyfmmlib_integration.py b/boxtree/pyfmmlib_integration.py index 9136721..958099a 100644 --- a/boxtree/pyfmmlib_integration.py +++ b/boxtree/pyfmmlib_integration.py @@ -631,8 +631,9 @@ class FMMLibExpansionWrangler(object): return local_exps - def eval_multipoles(self, level_start_target_box_nrs, target_boxes_by_level, - sep_smaller_nonsiblings_by_level, mpole_exps): + def eval_multipoles(self, level_start_target_box_nrs, + target_boxes_by_source_level, + sep_smaller_nonsiblings_by_level, mpole_exps): output = self.output_zeros() mpeval = self.get_expn_eval_routine("mp") @@ -643,7 +644,8 @@ class FMMLibExpansionWrangler(object): rscale = self.level_to_rscale(isrc_level) - for itgt_box, tgt_ibox in enumerate(target_boxes_by_level[isrc_level]): + for itgt_box, tgt_ibox in \ + enumerate(target_boxes_by_source_level[isrc_level]): tgt_pslice = self._get_target_slice(tgt_ibox) if tgt_pslice.stop - tgt_pslice.start == 0: diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 5d72f2b..597d1a0 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1305,7 +1305,7 @@ class FMMTraversalInfo(DeviceDataRecord): Indexed like :attr:`target_or_target_parent_boxes`. See :ref:`csr`. - .. attribute:: target_boxes_sep_smaller_by_level + .. attribute:: target_boxes_sep_smaller_by_source_level A list of :attr:`boxtree.Tree.nlevels` objects, each of which records target boxes (in global box numbers) with "List 3" source boxes on that level. @@ -1321,9 +1321,10 @@ class FMMTraversalInfo(DeviceDataRecord): type ``box_id_t``. (Note: This list contains global box numbers, not indices into :attr:`source_boxes`.) - Note *starts* are indexed by `target_boxes_sep_smaller_by_level`. For + Note *starts* are indexed by `target_boxes_sep_smaller_by_source_level`. For example, for level *i*, *lists[starts[j]:starts[j+1]]* represents "List 3" - source boxes of *target_boxes_sep_smaller_by_level[i][j]* on level *i*. + source boxes of *target_boxes_sep_smaller_by_source_level[i][j]* on level + *i*. .. attribute:: from_sep_close_smaller_starts @@ -2044,7 +2045,7 @@ class FMMTraversalBuilder: from_sep_smaller_wait_for = [] from_sep_smaller_by_level = [] - target_boxes_sep_smaller_by_level = [] + target_boxes_sep_smaller_by_source_level = [] for ilevel in range(tree.nlevels): fin_debug("finding separated smaller ('list 3 level %d')" % ilevel) @@ -2058,7 +2059,7 @@ class FMMTraversalBuilder: result["from_sep_smaller"].nonempty_indices] from_sep_smaller_by_level.append(result["from_sep_smaller"]) - target_boxes_sep_smaller_by_level.append(target_boxes_sep_smaller) + target_boxes_sep_smaller_by_source_level.append(target_boxes_sep_smaller) from_sep_smaller_wait_for.append(evt) if with_extent: @@ -2154,7 +2155,8 @@ class FMMTraversalBuilder: from_sep_siblings_lists=from_sep_siblings.lists, from_sep_smaller_by_level=from_sep_smaller_by_level, - target_boxes_sep_smaller_by_level=target_boxes_sep_smaller_by_level, + target_boxes_sep_smaller_by_source_level=( + target_boxes_sep_smaller_by_source_level), from_sep_close_smaller_starts=from_sep_close_smaller_starts, from_sep_close_smaller_lists=from_sep_close_smaller_lists, diff --git a/test/test_fmm.py b/test/test_fmm.py index 28317ad..3d633a5 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -141,12 +141,14 @@ class ConstantOneExpansionWrangler(object): return local_exps - def eval_multipoles(self, level_start_target_box_nrs, target_boxes_by_level, - from_sep_smaller_nonsiblings_by_level, mpole_exps): + def eval_multipoles(self, level_start_target_box_nrs, + target_boxes_by_source_level, + from_sep_smaller_nonsiblings_by_level, mpole_exps): pot = self.potential_zeros() for level, ssn in enumerate(from_sep_smaller_nonsiblings_by_level): - for itgt_box, tgt_ibox in enumerate(target_boxes_by_level[level]): + for itgt_box, tgt_ibox in \ + enumerate(target_boxes_by_source_level[level]): tgt_pslice = self._get_target_slice(tgt_ibox) contrib = 0 diff --git a/test/test_traversal.py b/test/test_traversal.py index 6805c72..8f7935e 100644 --- a/test/test_traversal.py +++ b/test/test_traversal.py @@ -143,7 +143,7 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): for level, ssn in enumerate(trav.from_sep_smaller_by_level): for itarget_box, ibox in \ - enumerate(trav.target_boxes_sep_smaller_by_level[level]): + enumerate(trav.target_boxes_sep_smaller_by_source_level[level]): start, end = ssn.starts[itarget_box:itarget_box+2] for jbox in ssn.lists[start:end]: @@ -156,18 +156,18 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # {{{ list 4 <= list 3 - box_to_target_boxes_sep_smaller_by_level = [] + box_to_target_boxes_sep_smaller_by_source_level = [] for level in range(trav.tree.nlevels): box_to_target_boxes_sep_smaller = np.empty( tree.nboxes, tree.box_id_dtype) box_to_target_boxes_sep_smaller.fill(-1) box_to_target_boxes_sep_smaller[ - trav.target_boxes_sep_smaller_by_level[level] + trav.target_boxes_sep_smaller_by_source_level[level] ] = np.arange( - len(trav.target_boxes_sep_smaller_by_level[level]), + len(trav.target_boxes_sep_smaller_by_source_level[level]), dtype=tree.box_id_dtype ) - box_to_target_boxes_sep_smaller_by_level.append( + box_to_target_boxes_sep_smaller_by_source_level.append( box_to_target_boxes_sep_smaller) assert (trav.source_boxes == trav.target_boxes).all() @@ -186,7 +186,8 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): good = False for level, ssn in enumerate(trav.from_sep_smaller_by_level): - jtgt_box = box_to_target_boxes_sep_smaller_by_level[level][jbox] + jtgt_box = \ + box_to_target_boxes_sep_smaller_by_source_level[level][jbox] if jtgt_box == -1: continue rstart, rend = ssn.starts[jtgt_box:jtgt_box + 2] @@ -221,7 +222,7 @@ def test_tree_connectivity(ctx_getter, dims, sources_are_targets): # for ssn in trav.from_sep_smaller_by_level: for level, ssn in enumerate(trav.from_sep_smaller_by_level): for itarget_box, ibox in enumerate( - trav.target_boxes_sep_smaller_by_level[level]): + trav.target_boxes_sep_smaller_by_source_level[level]): start, end = ssn.starts[itarget_box:itarget_box+2] for jbox in ssn.lists[start:end]: -- GitLab From 3c665c32cdadfa804858632ecce3c1a8285cfc41 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 5 Mar 2018 08:21:23 -0600 Subject: [PATCH 16/17] Remove the first arg in eval_multipoles --- boxtree/fmm.py | 3 +-- boxtree/pyfmmlib_integration.py | 6 +++--- test/test_fmm.py | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/boxtree/fmm.py b/boxtree/fmm.py index d856a5d..dc38cda 100644 --- a/boxtree/fmm.py +++ b/boxtree/fmm.py @@ -113,7 +113,6 @@ def drive_fmm(traversal, expansion_wrangler, src_weights): # contribution *out* of the downward-propagating local expansions) potentials = potentials + wrangler.eval_multipoles( - traversal.level_start_target_box_nrs, traversal.target_boxes_sep_smaller_by_source_level, traversal.from_sep_smaller_by_level, mpole_exps) @@ -273,7 +272,7 @@ class ExpansionWranglerInterface: :meth:`local_expansion_zeros`. """ - def eval_multipoles(self, level_start_target_box_nrs, + def eval_multipoles(self, target_boxes_by_source_level, from_sep_smaller_by_level, mpole_exps): """For a level *i*, each box in *target_boxes_by_source_level[i]*, evaluate the multipole expansion in *mpole_exps* in the nearby boxes given in diff --git a/boxtree/pyfmmlib_integration.py b/boxtree/pyfmmlib_integration.py index 958099a..693c13a 100644 --- a/boxtree/pyfmmlib_integration.py +++ b/boxtree/pyfmmlib_integration.py @@ -631,9 +631,9 @@ class FMMLibExpansionWrangler(object): return local_exps - def eval_multipoles(self, level_start_target_box_nrs, - target_boxes_by_source_level, - sep_smaller_nonsiblings_by_level, mpole_exps): + def eval_multipoles(self, + target_boxes_by_source_level, sep_smaller_nonsiblings_by_level, + mpole_exps): output = self.output_zeros() mpeval = self.get_expn_eval_routine("mp") diff --git a/test/test_fmm.py b/test/test_fmm.py index 3d633a5..fd10c75 100644 --- a/test/test_fmm.py +++ b/test/test_fmm.py @@ -141,9 +141,9 @@ class ConstantOneExpansionWrangler(object): return local_exps - def eval_multipoles(self, level_start_target_box_nrs, - target_boxes_by_source_level, - from_sep_smaller_nonsiblings_by_level, mpole_exps): + def eval_multipoles(self, + target_boxes_by_source_level, from_sep_smaller_nonsiblings_by_level, + mpole_exps): pot = self.potential_zeros() for level, ssn in enumerate(from_sep_smaller_nonsiblings_by_level): -- GitLab From 737f26212c9101cb764bc2585d67e4f562693094 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Tue, 6 Mar 2018 20:45:36 -0600 Subject: [PATCH 17/17] Improve code/documentation quality --- boxtree/tools.py | 2 +- boxtree/traversal.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/boxtree/tools.py b/boxtree/tools.py index 86a6568..68ac5f4 100644 --- a/boxtree/tools.py +++ b/boxtree/tools.py @@ -272,7 +272,7 @@ class DeviceDataRecord(Record): elif isinstance(val, BuiltList): transformed_list = {} for field in val.__dict__: - if field != 'count': + if field != 'count' and not field.startswith('_'): transformed_list[field] = f(getattr(val, field)) return BuiltList(count=val.count, **transformed_list) else: diff --git a/boxtree/traversal.py b/boxtree/traversal.py index 597d1a0..6caadc3 100644 --- a/boxtree/traversal.py +++ b/boxtree/traversal.py @@ -1307,8 +1307,11 @@ class FMMTraversalInfo(DeviceDataRecord): .. attribute:: target_boxes_sep_smaller_by_source_level - A list of :attr:`boxtree.Tree.nlevels` objects, each of which records target - boxes (in global box numbers) with "List 3" source boxes on that level. + A list of arrays, one per level, indicating which target boxes are used with + the interaction list entries of :attr:`from_sep_smaller_by_level`. + ``target_boxes_sep_smaller_by_source_level[i]`` has length + ``from_sep_smaller_by_level[i].num_nonempty_lists`. + .. attribute:: from_sep_smaller_by_level @@ -1558,8 +1561,6 @@ class FMMTraversalBuilder: (use the precise extent of targets in the box, including their radii), or ``"static_l2"`` (use the circumcircle of the box, possibly enlarged by :attr:`Tree.stick_out_factor`). - :arg compress_list_3: If set to True, only the target boxes with separated - smaller boxes will remain in list 3. """ self.context = context self.well_sep_is_n_away = well_sep_is_n_away -- GitLab