diff --git a/boxtree/tree_build.py b/boxtree/tree_build.py index 2566dc44de18e858fff799457d8960fc8997c9d2..b03c336e53205b5e61e2c91ce7c57610aeb295f3 100644 --- a/boxtree/tree_build.py +++ b/boxtree/tree_build.py @@ -36,6 +36,10 @@ import logging logger = logging.getLogger(__name__) +class MaxLevelsExceeded(RuntimeError): + pass + + class TreeBuilder(object): def __init__(self, context): """ @@ -454,7 +458,8 @@ class TreeBuilder(object): queue, box_parent_ids.data, np.zeros((), dtype=box_parent_ids.dtype)) prep_events.append(evt) - nlevels_max = np.iinfo(self.box_level_dtype).max + nlevels_max = np.finfo(coord_dtype).nmant + 1 # num bits in the significand + assert nlevels_max <= np.iinfo(self.box_level_dtype).max # level -> starting box on level level_start_box_nrs_dev, evt = zeros(nlevels_max, dtype=box_id_dtype) @@ -540,8 +545,11 @@ class TreeBuilder(object): assert level == len(level_used_box_counts) assert level == len(level_leaf_counts) - if level > np.iinfo(self.box_level_dtype).max: - raise RuntimeError("level count exceeded maximum") + if level + 1 >= nlevels_max: # level is zero-based + raise MaxLevelsExceeded("Level count exceeded number of significant " + "bits in coordinate dtype. That means that a large number " + "of particles was indistinguishable up to floating point " + "precision (because they ended up in the same box).") common_args = ((morton_bin_counts, morton_nrs, box_start_flags, diff --git a/test/test_tree.py b/test/test_tree.py index f68a885edf93ff5828e37ca4d1e4af81c866f91b..cf5e11063ee50c6904a025ece55f0be082c30f39 100644 --- a/test/test_tree.py +++ b/test/test_tree.py @@ -1122,6 +1122,25 @@ def test_same_tree_with_zero_weight_particles(ctx_factory, dims): # }}} +# {{{ test_max_levels_error + +def test_max_levels_error(ctx_factory): + ctx = ctx_factory() + queue = cl.CommandQueue(ctx) + + from boxtree import TreeBuilder + tb = TreeBuilder(ctx) + + logging.basicConfig(level=logging.INFO) + + sources = [cl.array.zeros(queue, 11, float) for i in range(2)] + from boxtree.tree_build import MaxLevelsExceeded + with pytest.raises(MaxLevelsExceeded): + tree, _ = tb(queue, sources, max_particles_in_box=10, debug=True) + +# }}} + + # You can test individual routines by typing # $ python test_tree.py 'test_routine(cl.create_some_context)'