Compare commits

..
6 changed files with 74 additions and 18 deletions
+7
View File
@@ -3,6 +3,13 @@
Changes that can make a previously accepted setup or call behave differently.
Each entry names the commit, the affected entry points and the observable result.
## Redundant periodic stepper alias removed
`PeriodicPatchStepper` is no longer exported from `lbm.refinement_stepper`.
Use `FixedPatchStepper` with the same arguments, including explicit
`level_blocks`. The old name was an alias for that exact class; periodic
boundaries remain the default. Existing imports of the old name must be updated.
## 87c3a31: cut-link ownership is validated for every body
`validate_cut_link_ownership` (`body/preprocess/flag_overlay.py`) now runs for
+2 -2
View File
@@ -16,7 +16,7 @@ from CelerisLab.config import load_lbm_config
from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.equilibrium import compute_feq_d2q9, compute_macro_from_ddf
from CelerisLab.lbm.refinement import ACTIVE
from CelerisLab.lbm.refinement_stepper import PeriodicPatchStepper
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
def shear_equilibrium(shape, origin, dx, period):
@@ -48,7 +48,7 @@ def main():
nx=16, ny=16, viscosity=.1, velocity=1e-3, rho=1.0,
lattice_model="D2Q9", collision="SRT", streaming="double_buffer",
store_precision="FP32", ddf_shifting=False, les_enabled=False)
with CudaContext(0) as context, PeriodicPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
with CudaContext(0) as context, FixedPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
level_blocks=[(16, 16), (24, 24)]) as run:
p = run.patch
coarse = shear_equilibrium(p.coarse_shape, (0, 0), 1.0, cfg.ny)
-4
View File
@@ -910,7 +910,3 @@ class FixedPatchStepper:
_fine_leaf = property(lambda self: self._leaf[1])
_child_leaf = property(lambda self: self._leaf[2] if len(self._leaf) > 2 else None)
_middle_kind = property(lambda self: self.hierarchy.kinds[1] if self.hierarchy.depth > 2 else None)
# Preserve the original entry point and its periodic default.
PeriodicPatchStepper = FixedPatchStepper
+53
View File
@@ -0,0 +1,53 @@
"""Direct Simulation Jet control upload; boundary-law accuracy is tested elsewhere."""
import numpy as np
import pycuda.driver as cuda
from CelerisLab.body.jets import Jet, Radial, Sector
from CelerisLab.lbm.descriptors import FLUID
from ._cases import make_sim
def test_simulation_jet_amplitude_upload_and_continued_steps():
# Same grid/circle/sector as the existing uniform surface-actuation fixture.
center = (16., 12.)
with make_sim(nx=32, ny=24, velocity=0) as sim:
sim.add_body("circle", center=center, radius=4.3)
index = sim.add_jet(Jet(Sector(center, .7, .85, 4.4),
Radial(center, inward=False), "quartic", .002))
sim.initialize()
curved = sim.field.curved
shape, jet_id = curved.jet_shape.copy(), curved.jet_id.copy()
flags = sim.get_flags()
driven = jet_id == index
assert driven.any() and (~driven).any()
velocity_pointer = int(curved.surface_velocity_gpu)
previous = None
for interval, amplitude in enumerate((.002, -.001)):
if interval:
count = sim.stepper.step_count
sim.set_jet_amplitude(index, amplitude)
assert sim.stepper.step_count == count # update does not step
expected = np.zeros_like(curved.surface_velocity)
expected[driven] = (amplitude * shape[driven]).astype(np.float32)
actual = np.empty_like(expected)
with sim.ctx.activate():
cuda.memcpy_dtoh(actual, curved.surface_velocity_gpu)
np.testing.assert_array_equal(actual, expected) # actual device column
np.testing.assert_array_equal(curved.surface_velocity, expected)
assert np.any(actual[driven] != 0)
if previous is not None:
assert not np.array_equal(actual[driven], previous[driven])
previous = actual.copy()
assert sim.bodies.jets[index].amplitude == amplitude
assert curved.jets[index].amplitude == amplitude
assert int(curved.surface_velocity_gpu) == velocity_pointer
np.testing.assert_array_equal(curved.jet_shape, shape)
np.testing.assert_array_equal(curved.jet_id, jet_id)
np.testing.assert_array_equal(sim.get_flags(), flags)
sim.run(2)
assert sim.stepper.step_count == 2 * (interval + 1)
assert sim._failed is None
macro = sim.get_macroscopic()
fluid = (flags.reshape(24, 32) & FLUID) != 0
assert all(np.isfinite(value[fluid]).all() for value in macro.values())
assert np.all(macro["rho"][fluid] > 0)
@@ -20,7 +20,7 @@ from CelerisLab.lbm import refinement_stepper as implementation
from CelerisLab.lbm.blocks import BlockLayout2D
from test_refinement_gpu import (ROOT, POP_ATOL, MOMENT_ATOL, ref, postcollision,
totals, LBMConfig, CudaContext, compiler,
PeriodicPatchStepper)
FixedPatchStepper)
def scalar_interval(coarse, fine, bounds, slot=None):
@@ -123,7 +123,7 @@ class FaultGuardsCPU(unittest.TestCase):
refinements=[bounds], level_blocks=[(1, 1)] * 2)
def fake_backend(self):
backend = PeriodicPatchStepper.__new__(PeriodicPatchStepper)
backend = FixedPatchStepper.__new__(FixedPatchStepper)
layout = BlockLayout2D.build(1, 1, 1, 1, periodic=(False, False))
backend._layouts = [layout, layout] # blocked storage on both levels
backend._ddf_shifting = False # unshifted on every level, as _check_storage expects
@@ -175,7 +175,7 @@ class FaultGuardsCPU(unittest.TestCase):
context = Mock(activate=nullcontext, sm_arch="sm_70")
with patch.object(implementation, "HALO", 2):
with self.assertRaisesRegex(RuntimeError, "four-cell"):
PeriodicPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
FixedPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
level_blocks=[(16, 16), (24, 24)])
p = implementation.FixedPatch2D.from_config(cfg, (4, 4, 12, 12))
from CelerisLab.lbm import hierarchy
@@ -187,11 +187,11 @@ class FaultGuardsCPU(unittest.TestCase):
with patch.object(cuda, "Stream"), patch.object(cuda, "mem_get_info", return_value=(1 << 40, 1 << 40)), bad, patch.object(cuda, "mem_alloc") as alloc, \
patch.object(cuda, "memcpy_htod") as upload:
with self.assertRaisesRegex(RuntimeError, "config chain is inconsistent"):
PeriodicPatchStepper(cfg, context=context, refinements=[p.bounds],
FixedPatchStepper(cfg, context=context, refinements=[p.bounds],
level_blocks=[(16, 16), (24, 24)])
with patch.object(hierarchy, "_check_chain"), \
self.assertRaisesRegex(RuntimeError, "omega/tau"):
PeriodicPatchStepper(cfg, context=context, refinements=[p.bounds],
FixedPatchStepper(cfg, context=context, refinements=[p.bounds],
level_blocks=[(16, 16), (24, 24)])
alloc.assert_not_called()
upload.assert_not_called()
@@ -202,7 +202,7 @@ class FaultGuardsCPU(unittest.TestCase):
patch.object(compiler, "load_module", return_value=module), \
patch.object(cuda, "memcpy_htod") as upload:
with self.assertRaisesRegex(RuntimeError, "layout mismatch"):
PeriodicPatchStepper(cfg, context=context, refinements=[p.bounds],
FixedPatchStepper(cfg, context=context, refinements=[p.bounds],
level_blocks=[(16, 16), (24, 24)])
upload.assert_not_called()
@@ -348,7 +348,7 @@ class NormalBuildGPU(unittest.TestCase):
state = ref.State(*(a * (1 + 1e-3*rng.standard_normal(a.shape))
for a in (initial.coarse_f, initial.fine_f)))
max_pop = max_drift = max_moment = 0.0
with CudaContext(0) as context, PeriodicPatchStepper(
with CudaContext(0) as context, FixedPatchStepper(
LBMConfig(nx=16, ny=16, viscosity=.1), context=context,
refinements=[(4, 4, 12, 12)], level_blocks=[(16, 16), (24, 24)]) as backend:
backend.initialize(*postcollision(state, spec, maps))
@@ -381,7 +381,7 @@ class NormalBuildGPU(unittest.TestCase):
fine_mask[4:-4, 4:-4] = True
initial[1][:, ~fine_mask] = np.nan
expected = scalar_interval(*[a.astype(np.float64) for a in initial], bounds)
with CudaContext(0) as context, PeriodicPatchStepper(cfg, context=context, refinements=[bounds],
with CudaContext(0) as context, FixedPatchStepper(cfg, context=context, refinements=[bounds],
level_blocks=[(13, 17), (14, 16)]) as backend:
self.assertEqual(backend.patch.fine_shape, (14, 16))
p = backend.patch
@@ -22,7 +22,7 @@ import CelerisLab
from CelerisLab.config import LBMConfig
from CelerisLab.cuda import compiler
from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper, PeriodicPatchStepper
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
ROOT = Path(__file__).resolve().parents[3]
POP_ATOL = 3e-6
@@ -124,7 +124,7 @@ class CoupledGPU(unittest.TestCase):
"wrong-phase controls PASS", flush=True)
def test_cleanup_attempts_every_allocation(self):
backend = PeriodicPatchStepper.__new__(PeriodicPatchStepper)
backend = FixedPatchStepper.__new__(FixedPatchStepper)
backend.ctx = Mock(activate=nullcontext)
backend._lock = RLock()
backend._status = "failed"
@@ -146,7 +146,7 @@ class CoupledGPU(unittest.TestCase):
spec = ref.make_spec(collision="srt")
maps = ref.build_maps(spec)
with CudaContext(0) as context:
with PeriodicPatchStepper(LBMConfig(nx=16, ny=16, viscosity=.1),
with FixedPatchStepper(LBMConfig(nx=16, ny=16, viscosity=.1),
context=context, refinements=[(4, 4, 12, 12)],
level_blocks=[(16, 16), (24, 24)]) as backend:
backend.initialize(*postcollision(ref.make_state(spec), spec, maps))
@@ -223,7 +223,7 @@ class CoupledGPU(unittest.TestCase):
maps = ref.build_maps(spec)
cfg = LBMConfig(nx=16, ny=16, viscosity=.1)
with CudaContext(0) as context:
with PeriodicPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
with FixedPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
level_blocks=[(16, 16), (24, 24)]) as backend:
self.eight_steps(backend, spec, maps)
with patch.object(backend._pairs[0], "explode", side_effect=RuntimeError("injected launch failure")):