diff --git a/src/CelerisLab/lbm/block_stepper.py b/src/CelerisLab/lbm/block_stepper.py index c4c0cfe..76f2195 100644 --- a/src/CelerisLab/lbm/block_stepper.py +++ b/src/CelerisLab/lbm/block_stepper.py @@ -42,6 +42,10 @@ def _static_circles(layout, objects): or any(getattr(obj.state, name) != 0 for name in ("vx", "vy", "omega")) or any(vars(obj.control).values())): raise ValueError("Block bodies must be stationary passive circles") + cx, cy = obj.geometry.center + radius = obj.geometry._radius + if not np.isfinite([cx, cy, radius]).all() or radius <= 0: + raise ValueError("Block circle center/radius must be finite with radius > 0") mask = obj.geometry.build_flag_mask(nx, ny) solid = (mask & SOLID) != 0 if not solid.any() or np.any(flags[solid] & SOLID): @@ -93,7 +97,8 @@ class PeriodicBlockStepper: tpb = checked.threads_per_block if layout.nblocks > MAX_GRID_DIM or ly > MAX_GRID_DIM or not 0 < pairs < 2**31: raise ValueError("block count, block rows or halo pairs exceed launch limits") - self.boundary = _static_circles(layout, tuple(objects)) if objects else None + objects = tuple(objects) # an empty iterable takes the body-free path + self.boundary = _static_circles(layout, objects) if objects else None links = 0 if self.boundary is None else len(self.boundary["cell"]) if links >= 2**31: raise ValueError("cut links exceed launch limits") diff --git a/tests/validation/multigrid/test_block_stepper.py b/tests/validation/multigrid/test_block_stepper.py index 24e5634..ee84a49 100644 --- a/tests/validation/multigrid/test_block_stepper.py +++ b/tests/validation/multigrid/test_block_stepper.py @@ -134,6 +134,15 @@ class CpuContracts(unittest.TestCase): for objects in ([moving], [circle((1.5, 11.5), 2.0)], [circle(), circle()]): with self.assertRaises(ValueError): PeriodicBlockStepper(config(), layout, context=self.forbidden_context(), objects=objects) + for center, radius in (((15.5, 11.5), -.1), ((15.5, 11.5), -.5), ((15.5, 11.5), np.nan), + ((np.inf, 11.5), 4.3), ((15.5, np.nan), 4.3)): + with self.subTest(center=center, radius=radius), self.assertRaises(ValueError): + PeriodicBlockStepper(config(), layout, context=self.forbidden_context(), + objects=[circle(center, radius)]) + with patch.object(implementation, "_static_circles") as prepare: + with self.assertRaisesRegex(AssertionError, "CUDA reached"): # body-free path + PeriodicBlockStepper(config(), layout, context=self.forbidden_context(), objects=iter(())) + prepare.assert_not_called() with patch.object(CircleGeometry, "build_cut_links", lambda geometry, *a, **k: build_links(geometry, *a, **k)[1:]): with self.assertRaisesRegex(ValueError, "cover every fluid pull"):