Migrate current callers to level-indexed refinement API

This commit is contained in:
Frank14f
2026-10-28 09:53:20 +08:00
parent b4eacf7526
commit 55067652e4
38 changed files with 210 additions and 199 deletions
@@ -269,7 +269,7 @@ def remap_case(ctx, shifted, raw):
refinements=refs[:2],level_blocks=blocks[:3],explosion='projected_linear') as run:
initialize(run); run.step(1)
before = snapshot(run,raw)
with run.remap_child([(22,22,42,42),(72,68,76,76)]) as clone:
with run.remap_finest([(22,22,42,42),(72,68,76,76)]) as clone:
if clone._explosion != 'projected_linear' or any(p.neighbors is None for p in clone._pairs):
raise AssertionError('remap lost projected selection')
if clone.step_count != 1: raise AssertionError('remap lost synchronized count')
@@ -113,7 +113,7 @@ class ChannelRootGPU(unittest.TestCase):
arrays = [state(*level.shape[1:]) for level in backend._levels]
backend.initialize(*arrays)
backend.step(4)
if bodies: backend.set_jet_amplitude(0, -.001)
if bodies: backend.set_jet_amplitude(0, -.001, level=1)
backend.step(4)
raw = backend._download_raw()
physical = backend.download()
@@ -128,7 +128,7 @@ class ChannelRootGPU(unittest.TestCase):
else:
for a,b in zip(reference, raw.values): np.testing.assert_array_equal(a,b)
with self.assertRaisesRegex(ValueError, "periodic"):
backend.remap_child([])
backend.remap_finest([])
if __name__ == "__main__": unittest.main()
@@ -66,31 +66,31 @@ class ExchangeWindowCPU(unittest.TestCase):
arrays = [np.full(level.shape, 1 / 9, np.float32) for level in backend._levels]
backend.initialize(*arrays)
with self.assertRaisesRegex(RuntimeError, "no valid exchange window"):
backend.read_exchange_window(0)
backend.read_exchange_window(0, level=1)
backend.step(1)
self.assertEqual(len(accumulations(m)), 2) # closed window: interval ledger only
backend.start_exchange_window()
with self.assertRaisesRegex(RuntimeError, "at least one completed"):
backend.read_exchange_window(0)
backend.read_exchange_window(0, level=1)
m["calls"].clear()
backend.step(2)
calls = accumulations(m)
self.assertEqual(len(calls), 8) # two fine hops x two ledgers x two base steps
self.assertEqual({id(c[1][1]) for c in calls},
{id(b.interval_integral), id(b.window_integral)})
out = backend.read_exchange_window(0)
out = backend.read_exchange_window(0, level=1)
self.assertEqual((out["time_start"], out["time_end"], out["sample_count"]), (1., 3, 4))
self.assertEqual(backend.read_exchange_window(0)["time_end"], 3) # non-destructive
self.assertEqual(backend.read_exchange_window(0, level=1)["time_end"], 3) # non-destructive
backend.initialize(*arrays) # invalidates
with self.assertRaisesRegex(RuntimeError, "no valid exchange window"):
backend.read_exchange_window(0)
backend.read_exchange_window(0, level=1)
backend.start_exchange_window()
with patch.object(backend, "_hop", side_effect=RuntimeError("injected")):
with self.assertRaises(RuntimeError):
backend.step(1)
self.assertFalse(backend._window_valid)
with self.assertRaises(RuntimeError):
backend.read_exchange_window(0) # failed status
backend.read_exchange_window(0, level=1) # failed status
def test_disabled_default_has_no_window_cost(self):
with mocked_backend() as m, ExitStack() as stack:
@@ -140,12 +140,12 @@ class ExchangeWindowGPU(unittest.TestCase):
summed = {part: [0., 0., 0., 0.] for part in ("total", "wall", "aperture")}
steps = 0
for speed in (0., .002, .002, -.001, 0., 0.): # amplitude updates stay in-window
windowed.set_jet_amplitude(0, speed)
plain.set_jet_amplitude(0, speed)
windowed.set_jet_amplitude(0, speed, level=1)
plain.set_jet_amplitude(0, speed, level=1)
windowed.step(1)
plain.step(1)
steps += 1
obs = windowed.read_raw_exchange(0)
obs = windowed.read_raw_exchange(0, level=1)
for part in summed:
o = obs[part]
summed[part] = [summed[part][0] + o["impulse"][0], summed[part][1] + o["impulse"][1],
@@ -153,7 +153,7 @@ class ExchangeWindowGPU(unittest.TestCase):
summed[part][3] + o["mass_into_fluid"]]
for a, e in zip(windowed._download_raw().values, plain._download_raw().values):
same_bits(self, a, e)
out = windowed.read_exchange_window(0)
out = windowed.read_exchange_window(0, level=1)
self.assertEqual((out["time_end"] - out["time_start"], out["sample_count"]),
(steps, 2 * steps))
self.assertEqual(substeps, 2 * steps)
@@ -165,11 +165,11 @@ class ExchangeWindowGPU(unittest.TestCase):
diff = np.abs(got - np.array(summed[part]))
self.assertTrue((diff <= bound).all(), f"{part}: {diff} > {bound}")
np.testing.assert_array_equal(o["force"], o["impulse"] / steps)
again = windowed.read_exchange_window(0)
again = windowed.read_exchange_window(0, level=1)
np.testing.assert_array_equal(again["total"]["impulse"], out["total"]["impulse"])
windowed.initialize(*arrays)
with self.assertRaises(RuntimeError):
windowed.read_exchange_window(0)
windowed.read_exchange_window(0, level=1)
def audit_substeps(stepper, b, count, record):
@@ -220,7 +220,7 @@ class ExchangeWindowShiftedMRTGPU(unittest.TestCase):
for _ in range(steps):
windowed.step(1)
plain.step(1)
summed += components(windowed.read_raw_exchange(0))
summed += components(windowed.read_raw_exchange(0, level=1))
for a, e in zip(windowed._download_raw().values, plain._download_raw().values):
same_bits(self, a, e)
split.step(steps) # one call: same ledger arithmetic as five step(1) calls
@@ -231,28 +231,28 @@ class ExchangeWindowShiftedMRTGPU(unittest.TestCase):
cuda.memcpy_dtoh(rows[1], split._level_boundaries[1].window_integral)
np.testing.assert_array_equal(rows[0].view(np.uint64), rows[1].view(np.uint64))
out = windowed.read_exchange_window(0)
out = windowed.read_exchange_window(0, level=1)
self.assertEqual(record["substeps"], 2 * steps)
self.assertEqual((out["time_end"] - out["time_start"], out["sample_count"]),
(steps, 2 * steps))
bound = 4 * (count * record["substeps"]) * EPS * record["scale"] + 1e-300
diff = np.abs(components(out) - summed)
self.assertTrue((diff <= bound).all(), f"{diff} > {bound}")
np.testing.assert_array_equal(split.read_exchange_window(0)["total"]["impulse"],
np.testing.assert_array_equal(split.read_exchange_window(0, level=1)["total"]["impulse"],
out["total"]["impulse"])
windowed.step(0) # no interval: window and its duration unchanged
again = windowed.read_exchange_window(0)
again = windowed.read_exchange_window(0, level=1)
self.assertEqual(again["time_end"], out["time_end"])
np.testing.assert_array_equal(again["total"]["impulse"], out["total"]["impulse"])
windowed.start_exchange_window() # reset after a window
with self.assertRaisesRegex(RuntimeError, "at least one completed"):
windowed.read_exchange_window(0)
windowed.read_exchange_window(0, level=1)
record.update(scale=np.zeros(4), substeps=0)
windowed.step(1)
single = components(windowed.read_raw_exchange(0))
reset = windowed.read_exchange_window(0)
single = components(windowed.read_raw_exchange(0, level=1))
reset = windowed.read_exchange_window(0, level=1)
self.assertEqual(reset["time_end"] - reset["time_start"], 1)
bound = 4 * (count * record["substeps"]) * EPS * record["scale"] + 1e-300
self.assertTrue((np.abs(components(reset) - single) <= bound).all())
@@ -81,7 +81,7 @@ def run_blocked_patch(speed):
level_objects=[(), (source,)],
observe_raw_exchange=True) as backend:
c, f = backend._levels
flags = backend.fine_boundary.flags.reshape(40, 40)
flags = backend.boundaries[1].flags.reshape(40, 40)
active = np.zeros((40, 40), bool)
active[4:-4, 4:-4] = True
active &= ((flags & FLUID) != 0) & ((flags & SOLID) == 0)
@@ -101,7 +101,7 @@ def run_blocked_patch(speed):
with patch.object(f, "kernel", fine):
backend.step(2)
assert len(traces) == 4 and backend.step_count == 2
mass = backend.read_raw_exchange(0)["total"]["mass_into_fluid"]
mass = backend.read_raw_exchange(0, level=1)["total"]["mass_into_fluid"]
return traces, roi, backend.download(), float(mass)
@@ -56,8 +56,8 @@ def make(context):
def topology(run, rectangles, objects):
return RemapTopology.from_config(
CFG, run.patch, rectangles, child_objects=objects,
child_jets=run._boundaries[2].jets,
CFG, run.hierarchy.pairs[0], rectangles, child_objects=objects,
child_jets=run._level_boundaries[2].jets,
)
@@ -74,8 +74,8 @@ class MultiplePinnedRemapGPU(unittest.TestCase):
def change_amplitudes(self, run, amplitudes):
# Each jet selects a different body. Updating one must preserve the
# other body's current per-link velocities, including its driven links.
boundary = run._boundaries[2]
body_ids = run.child_boundary.curved_host[3]
boundary = run._level_boundaries[2]
body_ids = run.boundaries[2].curved_host[3]
for index, amplitude in enumerate(amplitudes):
before = boundary.tables['surface_velocity'].copy()
run.set_jet_amplitude(index, amplitude, level=2)
@@ -87,11 +87,11 @@ class MultiplePinnedRemapGPU(unittest.TestCase):
def check_boundary(self, old, new, mesh, amplitudes):
self.assertEqual(mesh.pinned_rectangles, PINS)
self.assertTrue(same_physical_boundary(old.child_boundary, new.child_boundary))
self.assertTrue(same_physical_boundary(new.child_boundary, mesh.boundary))
self.assertTrue(same_physical_boundary(old.boundaries[2], new.boundaries[2]))
self.assertTrue(same_physical_boundary(new.boundaries[2], mesh.boundary))
# Compare physical cut-link rows, never layout-dependent blocked addresses.
for run in (old, new):
boundary = run._boundaries[2]
boundary = run._level_boundaries[2]
self.assertEqual(tuple(jet.amplitude for jet in boundary.jets), amplitudes)
exact(self, boundary.tables['surface_velocity'], mesh.surface_velocity,
'latest physical per-link velocities')
@@ -107,7 +107,7 @@ class MultiplePinnedRemapGPU(unittest.TestCase):
before, count = old.download(), old.step_count
mesh = topology(old, START, objects)
# Input order is irrelevant even with several pins and fluid regions.
new = owned.enter_context(old.remap_child(START[::-1], child_objects=objects))
new = owned.enter_context(old.remap_finest(START[::-1], objects=objects))
self.assertIsNot(old, new)
self.assertEqual((old.step_count, new.step_count), (count, count))
self.check_boundary(old, new, mesh, amplitudes)
@@ -133,7 +133,7 @@ class MultiplePinnedRemapGPU(unittest.TestCase):
previous = current
self.change_amplitudes(previous, amplitudes)
before, count = previous.download(), previous.step_count
old_mesh = topology(previous, previous.child_patch.bounds, objects)
old_mesh = topology(previous, previous.hierarchy.pairs[1].bounds, objects)
new_mesh = topology(previous, rectangles, objects)
expected = remap_synchronized(
old_mesh, new_mesh, before, base_count=count,
@@ -141,7 +141,7 @@ class MultiplePinnedRemapGPU(unittest.TestCase):
phase='postcollision_g',
).g
current = owned.enter_context(
previous.remap_child(rectangles, child_objects=objects))
previous.remap_finest(rectangles, objects=objects))
self.assertIsNot(previous, current)
self.assertEqual((previous.step_count, current.step_count), (count, count))
self.check_boundary(previous, current, new_mesh, amplitudes)
@@ -36,12 +36,12 @@ class PinnedBodyRemapGPU(unittest.TestCase):
def check_boundary(self, before, after):
for name in ('flags','boundary_cells','curved_hits'):
exact(self,getattr(after.child_boundary,name),getattr(before.child_boundary,name),name)
for a,b in zip(after.child_boundary.curved_host,before.child_boundary.curved_host):
exact(self,getattr(after.boundaries[2],name),getattr(before.boundaries[2],name),name)
for a,b in zip(after.boundaries[2].curved_host,before.boundaries[2].curved_host):
exact(self,a,b,'physical cut links')
exact(self,after._boundaries[2].tables['surface_velocity'],
before._boundaries[2].tables['surface_velocity'],'current per-link velocities')
self.assertEqual(after._boundaries[2].jets[0].amplitude,.017)
exact(self,after._level_boundaries[2].tables['surface_velocity'],
before._level_boundaries[2].tables['surface_velocity'],'current per-link velocities')
self.assertEqual(after._level_boundaries[2].jets[0].amplitude,.017)
def test_noop_next_step_bitwise(self):
with CudaContext(0) as ctx, ExitStack() as owned:
@@ -49,7 +49,7 @@ class PinnedBodyRemapGPU(unittest.TestCase):
old.initialize(*initial(old,False));old.step(2)
old.set_jet_amplitude(0,.017,level=2)
before=old.download()
new=owned.enter_context(old.remap_child(A,child_objects=objects))
new=owned.enter_context(old.remap_finest(A,objects=objects))
self.check_boundary(old,new);self.check_reset(new,before)
old.step();new.step()
for a,b in zip(new.download(),old.download()): exact(self,a,b,'no-op next step bitwise')
@@ -63,14 +63,14 @@ class PinnedBodyRemapGPU(unittest.TestCase):
current.set_jet_amplitude(0,.017,level=2)
for rects in (B,A):
previous=current;before=previous.download();count=previous.step_count
jets=previous._boundaries[2].jets
old=RemapTopology.from_config(CFG,previous.patch,previous.child_patch.bounds,
jets=previous._level_boundaries[2].jets
old=RemapTopology.from_config(CFG,previous.hierarchy.pairs[0],previous.hierarchy.pairs[1].bounds,
child_objects=objects,child_jets=jets)
new=RemapTopology.from_config(CFG,previous.patch,rects,
new=RemapTopology.from_config(CFG,previous.hierarchy.pairs[0],rects,
child_objects=objects,child_jets=jets)
expected=remap_synchronized(old,new,before,base_count=count,
level_steps=(count,2*count,4*count),phase='postcollision_g').g
current=owned.enter_context(previous.remap_child(rects,child_objects=objects))
current=owned.enter_context(previous.remap_finest(rects,objects=objects))
self.check_boundary(previous,current);self.check_reset(current,expected)
for a,b,om,nm in zip(current.download(),before,old.leaf_masks,new.leaf_masks):
exact(self,a[:,om & nm],b[:,om & nm],'physical-fluid overlap')
@@ -61,7 +61,7 @@ def census(run, index, buffer):
layout, b = level.layout, level.boundary
g = download(buffer, layout.blocked_shape)
dense = layout.to_dense(g)
leaf = run._leaf[index]
leaf = run.leaf[index]
ny, nx = leaf.shape
solid = (b.host.flags.reshape(ny, nx) & SOLID) != 0
y, x = np.nonzero(leaf)
@@ -119,7 +119,7 @@ class RawExchangeGPU(unittest.TestCase):
measured._stream.synchronize()
after = measured._levels[1].layout.to_dense(
download(dst, measured._levels[1].layout.blocked_shape))
change = totals(after, measured._leaf[1])-before
change = totals(after, measured.leaf[1])-before
expected = external + np.array([-raw[:, 0].astype(float).sum(),
-raw[:, 1].astype(float).sum(),
raw[:, 3].astype(float).sum()])
@@ -127,8 +127,8 @@ class RawExchangeGPU(unittest.TestCase):
samples.append(raw.copy())
measured._levels[1].kernel = audited_step
for speed in (0., .002, -.001, 0.):
measured.set_jet_amplitude(0, speed)
plain.set_jet_amplitude(0, speed)
measured.set_jet_amplitude(0, speed, level=1)
plain.set_jet_amplitude(0, speed, level=1)
samples.clear()
measured.step()
plain.step()
@@ -139,11 +139,11 @@ class RawExchangeGPU(unittest.TestCase):
np.testing.assert_array_equal(integral, expected)
last = download(b.last_raw, (count, 4))
np.testing.assert_array_equal(last, samples[-1])
obs = measured.read_raw_exchange(0)
obs = measured.read_raw_exchange(0, level=1)
assert obs['sample_count'] == 2
assert b.tables['aperture'].any()
measured.step(0)
np.testing.assert_array_equal(measured.read_raw_exchange(0)['total']['impulse'],
np.testing.assert_array_equal(measured.read_raw_exchange(0, level=1)['total']['impulse'],
obs['total']['impulse'])
def test_depth_four_interval_storage_and_sampling(self):
@@ -171,7 +171,7 @@ class RawExchangeGPU(unittest.TestCase):
run._stream.synchronize()
after = run._levels[3].layout.to_dense(
download(dst, run._levels[3].layout.blocked_shape))
change = totals(after, run._leaf[3])-before
change = totals(after, run.leaf[3])-before
expected = external + np.array([-independent[:, 0].sum(),
-independent[:, 1].sum(), independent[:, 3].sum()])
np.testing.assert_allclose(change, expected, rtol=2e-4, atol=8e-5)
@@ -234,7 +234,7 @@ class RawExchangeGPU(unittest.TestCase):
samples.append(download(raw, (count, 4)))
root.kernel = measured_boundary
for speed in (0., .002, -.001, 0.):
amr.set_jet_amplitude(0, speed)
amr.set_jet_amplitude(0, speed, level=1)
cuda.memcpy_htod(velocity, b.tables['surface_velocity'])
samples.clear()
amr.step(); uniform.step(2)
@@ -204,7 +204,7 @@ class BlockedBaseCPU(unittest.TestCase):
level_blocks=[(3, 4), FINE_BLOCK],
level_objects=[(), (circle(actuation(.002)),)])
try:
backend.initialize(state(NY, NX, 1), state(*backend.patch.fine_shape, 2))
backend.initialize(state(NY, NX, 1), state(*backend.hierarchy.pairs[0].fine_shape, 2))
coarse, fine = backend._levels
current, spare, fine_current = coarse.current, coarse.spare, fine.current
backend.step(2)
@@ -255,7 +255,7 @@ class BlockedBaseCPU(unittest.TestCase):
with mocked_backend() as m:
backend = FixedPatchStepper(config("periodic"), context=m["context"], refinements=[BOUNDS],
level_blocks=[(3, 4), FINE_BLOCK])
backend.initialize(state(NY, NX, 1), state(*backend.patch.fine_shape, 2))
backend.initialize(state(NY, NX, 1), state(*backend.hierarchy.pairs[0].fine_shape, 2))
m["functions"]["BlockCoalesce"].side_effect = RuntimeError("injected parent stage failure")
current = backend._levels[0].current
with self.assertRaisesRegex(RuntimeError, "injected parent stage"):
@@ -125,7 +125,7 @@ class BlockedFineCPU(unittest.TestCase):
patch.object(cuda, "mem_alloc", side_effect=alloc), patch.object(cuda, "memcpy_htod"):
backend = FixedPatchStepper(config("periodic"), context=context, refinements=[BOUNDS],
level_blocks=[(12, 8), FINE_BLOCKS[0]])
self.assertEqual(len(backend.fine_layout.halo_dst), 0)
self.assertEqual(len(backend.layouts[1].halo_dst), 0)
self.assertIsNone(backend._levels[1].halo_dst)
backend._gather_halo(backend._levels[1], Mock()) # no launch without pairs
module.get_function.return_value.assert_not_called()
@@ -178,7 +178,7 @@ class BlockedFineCPU(unittest.TestCase):
backend = FixedPatchStepper(config("periodic"), context=context, refinements=[BOUNDS],
level_blocks=[(12, 8), FINE_BLOCKS[1]],
level_objects=[(), tuple(objects)])
backend.initialize(state(NY, NX, 1), state(*backend.patch.fine_shape, 2))
backend.initialize(state(NY, NX, 1), state(*backend.hierarchy.pairs[0].fine_shape, 2))
return backend, calls
def test_same_buffer_halo_bfl_step_launch_order(self):
@@ -212,7 +212,7 @@ class BlockedFineCPU(unittest.TestCase):
def test_actuation_without_velocity_buffer_fails_before_bfl(self):
for speed in (0.0, .002): # any spec, even zero amplitude
backend, calls = self.mocked_backend([circle(actuation(speed))])
self.assertIsNotNone(backend._fine_tables["surface_velocity"])
self.assertIsNotNone(backend._level_boundaries[1].tables["surface_velocity"])
del backend._level_boundaries[1].device["surface_velocity"]
with self.assertRaisesRegex(RuntimeError, "Surface velocity device buffer is missing"):
backend.step(1)
@@ -304,7 +304,7 @@ class NormalBuildGPU(unittest.TestCase):
if not (x0 <= sx < x1 and y0 <= sy < y1):
corners.add(target)
self.assertEqual(len(corners), 8)
self.assertEqual(set(backend.patch.coalesce_coarse.tolist()), targets)
self.assertEqual(set(backend.hierarchy.pairs[0].coalesce_coarse.tolist()), targets)
backend.initialize(*initial)
before = discrete_mass(initial)
for step in range(1, 9):
@@ -383,8 +383,8 @@ class NormalBuildGPU(unittest.TestCase):
expected = scalar_interval(*[a.astype(np.float64) for a in initial], 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
self.assertEqual(backend.hierarchy.pairs[0].fine_shape, (14, 16))
p = backend.hierarchy.pairs[0]
allocated = 2 * 4 * sum(int(np.prod(level.layout.blocked_shape)) for level in backend._levels) \
+ sum(a.nbytes for a in (p.ghost_fine, p.ghost_coarse, p.coalesce_coarse, p.coalesce_fine))
self.assertLess(allocated, 128*1024)
@@ -91,8 +91,8 @@ class CoupledGPU(unittest.TestCase):
ddf_shifting=shifted)
with FixedPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)],
**storage) as backend:
self.assertAlmostEqual(backend.patch.tau_coarse, spec.tau_coarse)
self.assertAlmostEqual(backend.patch.tau_fine, spec.tau_fine)
self.assertAlmostEqual(backend.hierarchy.pairs[0].tau_coarse, spec.tau_coarse)
self.assertAlmostEqual(backend.hierarchy.pairs[0].tau_fine, spec.tau_fine)
self.assertEqual(tuple(level.shape for level in backend._levels),
((9, 16, 16), (9, 24, 24)))
# Physical FP64 g is encoded by initialize before FP32 rounding.
@@ -101,7 +101,7 @@ class CoupledGPU(unittest.TestCase):
backend.step(1)
actual = backend.download()
self.assertEqual(backend.step_count, 1)
backend.patch.check_synchronization(
backend.hierarchy.pairs[0].check_synchronization(
1, next_state.tick, phase="postcollision_g")
for got, want, arrival in zip(actual, expected, arrivals):
np.testing.assert_array_equal(np.isnan(got), np.isnan(want))
@@ -165,13 +165,13 @@ class CoupledGPU(unittest.TestCase):
with self.assertRaisesRegex(RuntimeError, "failed"):
operation()
raw = level_storage(fine)
self.assertTrue(np.isfinite(raw.ravel()[backend.patch.coalesce_fine]).all())
self.assertTrue(np.isfinite(raw.ravel()[backend.hierarchy.pairs[0].coalesce_fine]).all())
self.assertFalse(context.is_closed)
print("partial failure: two fine hops completed, no coarse step published; cleanup PASS", flush=True)
def eight_steps(self, backend, spec, maps):
"""Rest and seeded nonequilibrium, 8 steps against the scalar reference."""
p = backend.patch
p = backend.hierarchy.pairs[0]
for case in ("rest", "nonequilibrium_seed1"):
with self.subTest(case=case):
state = ref.make_state(spec, velocity=(0, 0) if case == "rest" else (.03, -.02))
@@ -62,8 +62,8 @@ class JetStepperCPU(unittest.TestCase):
C = (16.0, 12.0)
whole = Jet(Sector(C, .1, math.pi, 3.), Radial(C, inward=False), amplitude=0.)
backend, _ = mocked([circle()], [whole], FINE_BLOCKS[1])
_, jet_id = backend._jet_cache
self.assertGreater(len(np.unique(backend._fine_tables["block"][jet_id == 0])), 1)
_, jet_id = backend._level_boundaries[1].jet_cache
self.assertGreater(len(np.unique(backend._level_boundaries[1].tables["block"][jet_id == 0])), 1)
backend.close()
def test_fine_ownership_uses_remapped_physical_owner(self):
@@ -76,10 +76,10 @@ class JetStepperCPU(unittest.TestCase):
source = SimObject(99, geometry=CircleGeometry(*C, 2.15), center=C, radius=2.15)
whole = Jet(Sector(C, .1, math.pi, 3.), Radial(C, inward=False), amplitude=0.)
backend, _ = mocked([source], [whole], FINE_BLOCKS[1])
_, jet_id = backend._jet_cache
owners = backend.fine_boundary.curved_host[3][jet_id == 0]
_, jet_id = backend._level_boundaries[1].jet_cache
owners = backend.boundaries[1].curved_host[3][jet_id == 0]
self.assertEqual(np.unique(owners).tolist(), [0])
self.assertGreater(len(np.unique(backend._fine_tables["block"][jet_id == 0])), 1)
self.assertGreater(len(np.unique(backend._level_boundaries[1].tables["block"][jet_id == 0])), 1)
self.assertEqual(source.obj_id, 99)
backend.close()
cfg = config("periodic")
@@ -97,8 +97,8 @@ class JetStepperCPU(unittest.TestCase):
def test_blocked_jet_velocity_matches_legacy_rows(self):
legacy, _ = mocked([circle(actuation(SPEED))], (), FINE_BLOCKS[1])
driven, _ = mocked([circle()], [jet()], FINE_BLOCKS[1])
a = legacy._fine_tables["surface_velocity"]
b = driven._fine_tables["surface_velocity"]
a = legacy._level_boundaries[1].tables["surface_velocity"]
b = driven._level_boundaries[1].tables["surface_velocity"]
diff = np.abs(a - b).max()
print(f"fine jet vs legacy velocity rows: max |dU| = {diff:.3e} (exact={diff == 0})")
self.assertLessEqual(diff, 4 * np.finfo(np.float32).eps * SPEED)
@@ -106,20 +106,20 @@ class JetStepperCPU(unittest.TestCase):
def test_blocked_amplitude_update_rewrites_only_velocity_column(self):
backend, htod = mocked([circle()], [jet()], FINE_BLOCKS[1])
before = backend._fine_tables["surface_velocity"].copy()
before = backend._level_boundaries[1].tables["surface_velocity"].copy()
device = backend._level_boundaries[1].device["surface_velocity"]
with patch.object(cuda, "memcpy_htod", htod):
htod.reset_mock()
backend.set_jet_amplitude(0, -SPEED)
backend.set_jet_amplitude(0, -SPEED, level=1)
(ptr, sent), _ = htod.call_args
self.assertEqual(htod.call_count, 1)
self.assertIs(ptr, device)
np.testing.assert_allclose(sent, -before, rtol=1e-6, atol=0)
np.testing.assert_array_equal(backend._fine_tables["surface_velocity"], sent)
np.testing.assert_array_equal(backend._level_boundaries[1].tables["surface_velocity"], sent)
with self.assertRaises(ValueError):
backend.set_jet_amplitude(0, 1.5)
backend.set_jet_amplitude(0, 1.5, level=1)
self.assertEqual(htod.call_count, 1)
self.assertEqual(backend._jets[0].amplitude, -SPEED)
self.assertEqual(backend.jets[1][0].amplitude, -SPEED)
backend.close()
def test_copy_failure_marks_failed_and_keeps_host_amplitude(self):
@@ -128,24 +128,24 @@ class JetStepperCPU(unittest.TestCase):
status = backend._status
for bad, error in ((1.5, ValueError), (float("nan"), ValueError)):
with self.assertRaises(error):
backend.set_jet_amplitude(0, bad)
backend.set_jet_amplitude(0, bad, level=1)
self.assertEqual(backend._status, status) # invalid input stays usable
with self.assertRaises(IndexError):
backend.set_jet_amplitude(1, -SPEED)
backend.set_jet_amplitude(1, -SPEED, level=1)
self.assertEqual(backend._status, status)
before = backend._fine_tables["surface_velocity"].copy()
before = backend._level_boundaries[1].tables["surface_velocity"].copy()
boom = Mock(side_effect=RuntimeError("copy failed"))
with patch.object(cuda, "memcpy_htod", boom), patch.object(cuda, "memcpy_htod_async", boom), \
patch.object(cuda, "pagelocked_empty", side_effect=lambda shape, dtype: np.empty(shape, dtype)):
with self.assertRaisesRegex(RuntimeError, "copy failed"):
backend.set_jet_amplitude(0, -SPEED)
backend.set_jet_amplitude(0, -SPEED, level=1)
self.assertEqual(backend._status, "failed", fine_block)
self.assertEqual(backend._jets[0].amplitude, SPEED)
np.testing.assert_array_equal(backend._fine_tables["surface_velocity"], before)
self.assertEqual(backend.jets[1][0].amplitude, SPEED)
np.testing.assert_array_equal(backend._level_boundaries[1].tables["surface_velocity"], before)
with self.assertRaisesRegex(RuntimeError, "failed"):
backend.step(1)
with self.assertRaisesRegex(RuntimeError, "failed"):
backend.set_jet_amplitude(0, -SPEED)
backend.set_jet_amplitude(0, -SPEED, level=1)
backend.close()
def test_jet_overlapping_legacy_aperture_rejected_before_cuda(self):
@@ -170,7 +170,7 @@ def run(mode, fine_block, *, objects, jets, switch=None):
backend.step(STEPS)
else:
backend.step(STEPS // 2)
backend.set_jet_amplitude(0, switch)
backend.set_jet_amplitude(0, switch, level=1)
backend.step(STEPS - STEPS // 2)
return backend.download(), raw(backend)
@@ -36,14 +36,14 @@ def level_fine(patch_set, windows):
"""Level-wide fine array with each patch window filled from `windows`."""
out = np.full((9, *patch_set.fine_shape), np.nan, np.float32)
for p, w in zip(patch_set.patches, windows):
y0, x0 = p.fine_level_origin
y0, x0 = p.fine_level_offset
out[:, y0:y0 + p.fine_shape[0], x0:x0 + p.fine_shape[1]] = w
return out
def window(patch_set, index, fine):
p = patch_set.patches[index]
y0, x0 = p.fine_level_origin
y0, x0 = p.fine_level_offset
return fine[:, y0:y0 + p.fine_shape[0], x0:x0 + p.fine_shape[1]]
@@ -175,7 +175,7 @@ class MultipatchBodiesGPU(unittest.TestCase):
for step in self.STEPS:
if switch is not None and step == 8:
for index, amplitude in switch:
backend.set_jet_amplitude(index, amplitude)
backend.set_jet_amplitude(index, amplitude, level=1)
backend.step(step - backend.step_count)
out.append(backend.download() + raw(backend))
return out
@@ -128,8 +128,10 @@ class ThreeLevelCPU(unittest.TestCase):
run = mocked_child()
b = run._levels[2].boundary
before = b.tables["surface_velocity"].copy()
with self.assertRaises(TypeError):
run.set_jet_amplitude(0, -.002) # level is required
with self.assertRaises(IndexError):
run.set_jet_amplitude(0, -.002) # default stays L1
run.set_jet_amplitude(0, -.002, level=1) # level 1 has no Jets
for level in (0, 3, True):
with self.assertRaises(ValueError):
run.set_jet_amplitude(0, -.002, level=level)
@@ -138,7 +140,7 @@ class ThreeLevelCPU(unittest.TestCase):
self.assertEqual(upload.call_count, 1)
self.assertIs(upload.call_args.args[0], b.device["surface_velocity"])
np.testing.assert_array_equal(b.tables["surface_velocity"], -before)
self.assertEqual(run._jets, ())
self.assertEqual(run.jets[1], ())
with patch.object(cuda, "memcpy_htod", side_effect=RuntimeError("copy failed")):
with self.assertRaisesRegex(RuntimeError, "copy failed"):
run.set_jet_amplitude(0, .002, level=2)
@@ -150,17 +152,17 @@ class ThreeLevelCPU(unittest.TestCase):
def test_child_public_masks_include_solids(self):
from CelerisLab.lbm.descriptors import SOLID
run = mocked_child()
solid = run.child_boundary.flags.reshape(run.child_patch.fine_shape) & SOLID != 0
solid = run.boundaries[2].flags.reshape(run.hierarchy.pairs[1].fine_shape) & SOLID != 0
self.assertTrue(solid.any())
self.assertFalse(run._child_leaf[solid].any())
self.assertFalse(run.leaf[2][solid].any())
arrays = [np.ones(level.shape, np.float32) for level in run._levels]
run._mask_nonleaves(*arrays)
self.assertTrue(np.isnan(arrays[2][:, solid]).all())
with patch.object(cuda, "memcpy_htod") as upload:
run.initialize(*arrays)
sent = upload.call_args_list[-1].args[1]
dense = run.child_layout.to_dense(sent)
self.assertTrue(np.isnan(dense[:, ~run._child_leaf]).all())
dense = run.layouts[2].to_dense(sent)
self.assertTrue(np.isnan(dense[:, ~run.leaf[2]]).all())
run.close()
@@ -169,7 +171,7 @@ class ThreeLevelGPU(unittest.TestCase):
from CelerisLab.cuda.context import CudaContext
feq = np.asarray(compute_feq_d2q9(1.0, .03, -.02), np.float32)[:, None, None]
with CudaContext(0) as ctx, FixedPatchStepper(CFG, context=ctx, **KW) as run:
shapes = ((16, 16), run.patch.fine_shape, run.child_patch.fine_shape)
shapes = ((16, 16), run.hierarchy.pairs[0].fine_shape, run.hierarchy.pairs[1].fine_shape)
run.initialize(*(np.broadcast_to(feq, (9, *s)).copy() for s in shapes))
run.step(8)
self.assertEqual(run.step_count, 8)
@@ -182,7 +184,7 @@ class ThreeLevelGPU(unittest.TestCase):
def test_nonequilibrium_masks_and_fresh_middle_feeds(self):
from CelerisLab.cuda.context import CudaContext
with CudaContext(0) as ctx, FixedPatchStepper(CFG, context=ctx, **KW) as run:
p1, p2 = run.patch, run.child_patch
p1, p2 = run.hierarchy.pairs[0], run.hierarchy.pairs[1]
run.initialize(state(16, 16, 1), state(*p1.fine_shape, 2), state(*p2.fine_shape, 3))
f = run._levels[1]
feeds, original = [], run._advance
@@ -195,7 +197,7 @@ class ThreeLevelGPU(unittest.TestCase):
run.step(1)
self.assertEqual(feeds, [cur, spare]) # current G, then the new G of hop 1
run.step(7)
middle = run._middle_kind
middle = run.hierarchy.kinds[1]
for g, leaf in zip(run.download(), (~p1.covered, middle == ACTIVE, p2.fine_kind == ACTIVE)):
self.assertTrue(np.isfinite(g[:, leaf]).all())
self.assertTrue(np.isnan(g[:, ~leaf]).all())
@@ -227,15 +229,15 @@ class ThreeLevelBodyGPU(unittest.TestCase):
if stop == 4 and switch:
run.set_jet_amplitude(0, -.002, level=2)
public, stored = run.download(), raw(run)
leaves = [~run.patch.covered, run._fine_leaf, run._child_leaf]
leaves = [~run.hierarchy.pairs[0].covered, run.leaf[1], run.leaf[2]]
if mode != "periodic":
leaves[0][[0, -1]] = False
for g, mask in zip(public, leaves):
self.assertTrue(np.isfinite(g[:, mask]).all())
self.assertTrue(np.isnan(g[:, ~mask]).all())
invalid = [run.patch.covered.copy(), run._middle_kind == OUTER_GHOST,
(run.child_patch.fine_kind == OUTER_GHOST) |
((run.child_boundary.flags.reshape(run.child_patch.fine_shape) & SOLID) != 0)]
invalid = [run.hierarchy.pairs[0].covered.copy(), run.hierarchy.kinds[1] == OUTER_GHOST,
(run.hierarchy.pairs[1].fine_kind == OUTER_GHOST) |
((run.boundaries[2].flags.reshape(run.hierarchy.pairs[1].fine_shape) & SOLID) != 0)]
if mode != "periodic":
invalid[0][[0, -1]] = True
for g, mask in zip(stored, invalid):
@@ -54,9 +54,9 @@ def jets(speed):
def frames(run):
middle_origin = np.asarray(run.patch.fine_origin)
middle_origin = np.asarray(run.hierarchy.pairs[0].fine_origin)
return ((np.zeros(2), 1.), (middle_origin, .5),
(middle_origin + .5*np.asarray(run.child_patch.fine_origin), .25))
(middle_origin + .5*np.asarray(run.hierarchy.pairs[1].fine_origin), .25))
def physical_state(shape, origin, spacing):
@@ -92,15 +92,15 @@ class ThreeLevelMultipatchGPU(unittest.TestCase):
for index in range(len(drive)):
run.set_jet_amplitude(index, -.002, level=2)
public, stored = run.download(), raw(run)
masks = [~run.patch.covered, run._fine_leaf, run._child_leaf]
masks = [~run.hierarchy.pairs[0].covered, run.leaf[1], run.leaf[2]]
if mode != 'periodic':
masks[0][[0, -1]] = False
invalid = [run.patch.covered.copy(), run._middle_kind == OUTER_GHOST,
run.child_patch.fine_kind == OUTER_GHOST]
invalid = [run.hierarchy.pairs[0].covered.copy(), run.hierarchy.kinds[1] == OUTER_GHOST,
run.hierarchy.pairs[1].fine_kind == OUTER_GHOST]
if mode != 'periodic':
invalid[0][[0, -1]] = True
if run.child_boundary is not None:
invalid[2] |= (run.child_boundary.flags.reshape(run.child_patch.fine_shape) & SOLID) != 0
if run.boundaries[2] is not None:
invalid[2] |= (run.boundaries[2].flags.reshape(run.hierarchy.pairs[1].fine_shape) & SOLID) != 0
for level, (g, mask, dense, bad) in enumerate(zip(public, masks, stored, invalid)):
label = f'{mode} stop={stop} level={level}'
self.assertTrue(np.isfinite(g[:, mask]).all(), label)
@@ -39,7 +39,7 @@ def initial(run, uniform):
class RuntimeChildRemapGPU(unittest.TestCase):
def check_public(self, run):
for array, leaf in zip(run.download(), (~run.patch.covered, run._fine_leaf, run._child_leaf)):
for array, leaf in zip(run.download(), (~run.hierarchy.pairs[0].covered, run.leaf[1], run.leaf[2])):
self.assertTrue(np.isfinite(array[:, leaf]).all())
self.assertTrue(np.isnan(array[:, ~leaf]).all())
@@ -57,7 +57,7 @@ class RuntimeChildRemapGPU(unittest.TestCase):
old.initialize(*initial(old, False))
old.step(2)
before = old.download()
new = owned.enter_context(old.remap_child(A))
new = owned.enter_context(old.remap_finest(A))
self.assertEqual((old.step_count, new.step_count), (2, 2))
self.check_reset(new, before)
for got, want in zip(old.download(), before): exact(self, got, want, 'old unchanged')
@@ -75,12 +75,12 @@ class RuntimeChildRemapGPU(unittest.TestCase):
current.step(2)
for rectangles in (B, A):
before, count = current.download(), current.step_count
old_mesh = RemapTopology.from_config(CFG, current.patch, current.child_patch.bounds)
new_mesh = RemapTopology.from_config(CFG, current.patch, rectangles)
old_mesh = RemapTopology.from_config(CFG, current.hierarchy.pairs[0], current.hierarchy.pairs[1].bounds)
new_mesh = RemapTopology.from_config(CFG, current.hierarchy.pairs[0], rectangles)
expected = remap_synchronized(old_mesh, new_mesh, before, base_count=count,
level_steps=(count, 2*count, 4*count), phase='postcollision_g').g
previous = current
current = owned.enter_context(previous.remap_child(rectangles))
current = owned.enter_context(previous.remap_finest(rectangles))
self.assertEqual(current.step_count, count)
self.check_reset(current, expected)
for got, want, old_g, old_leaf, new_leaf in zip(
@@ -25,10 +25,10 @@ class ShearRefinementGPU(unittest.TestCase):
self.assertGreater(report['requested'], 0)
self.assertEqual(report['corridor_unknown'], 0)
self.assertEqual(report['corridor_unavailable'], 0)
auto = owned.enter_context(old.remap_child(chosen, child_objects=objects()))
explicit = owned.enter_context(old.remap_child(manual, child_objects=objects()))
auto = owned.enter_context(old.remap_finest(chosen, objects=objects()))
explicit = owned.enter_context(old.remap_finest(manual, objects=objects()))
for run in (auto, explicit):
self.assertEqual(run.child_patch.bounds[0], CHILDREN[0])
self.assertEqual(run.hierarchy.pairs[1].bounds[0], CHILDREN[0])
self.assertEqual(run.step_count, 2)
run.step(2)
for a, b, leaf in zip(auto.download(), explicit.download(), topology(manual).leaf_masks):
@@ -58,7 +58,7 @@ def census(run,index,buffer):
"""Independent physical link/face census of actual staged receiver windows."""
level=run._levels[index];layout=level.layout;b=level.boundary
stored=download(buffer,layout.blocked_shape);dense=layout.to_dense(stored)
leaf=run._leaf[index];ny,nx=leaf.shape
leaf=run.leaf[index];ny,nx=leaf.shape
solid=(b.host.flags.reshape(ny,nx)&SOLID)!=0
y,x=np.nonzero(leaf);owner=layout.owner[y,x].astype(np.intp)
cells=int(np.prod(layout.local_shape));block,cell=np.divmod(owner,cells)
@@ -93,7 +93,7 @@ class Ledger:
self.max_row=max(self.max_row,float(abs(raw.astype(float)-independent).max()))
self.original(src,dst,*args,**kwargs);run._stream.synchronize()
after=level.layout.to_dense(download(dst,level.layout.blocked_shape))
change=raw_totals(after,run._leaf[index])-before
change=raw_totals(after,run.leaf[index])-before
expected=external+np.array([-independent[:,0].sum(),-independent[:,1].sum(),independent[:,3].sum()])
np.testing.assert_allclose(change,expected,rtol=2e-4,atol=8e-5)
self.max_balance=max(self.max_balance,float(abs(change-expected).max()))
@@ -113,7 +113,7 @@ class Ledger:
for name in ('impulse','angular_impulse','mass_into_fluid'):
np.testing.assert_allclose(obs['total'][name],np.asarray(obs['wall'][name])+obs['aperture'][name],rtol=0,atol=2e-13)
self.test.assertEqual(obs['sample_count'],2**self.index)
for a,leaf in zip(run._download_raw().values,run._leaf):
for a,leaf in zip(run._download_raw().values,run.leaf):
self.test.assertTrue(np.isfinite(a[:,leaf]).all())
self.test.assertTrue((1+a[:,leaf].sum(axis=0,dtype=np.float64)>0).all())
return obs
@@ -143,7 +143,7 @@ class ShiftedJetsGPU(unittest.TestCase):
self.assertTrue(run._level_boundaries[1].tables['aperture'].all())
for _ in range(4):ledger.step()
error=max(float(abs(a[:,leaf]-b[:,leaf]).max()) for a,b,leaf in
zip(run._download_raw().values,expected.values,run._leaf))
zip(run._download_raw().values,expected.values,run.leaf))
self.assertLessEqual(error,1e-6) # inherited uniform-state cap
print(f'matched whole-circle rho={rho}: max_abs_raw_state={error:.9g}',flush=True)
ledger.report(f'matched whole-circle rho={rho}')
@@ -161,7 +161,7 @@ class ShiftedJetsGPU(unittest.TestCase):
ledger=Ledger(self,measured,1)
for speed in SPEEDS:
before=measured._download_raw();count=measured.step_count
measured.set_jet_amplitude(0,speed);plain.set_jet_amplitude(0,speed)
measured.set_jet_amplitude(0,speed, level=1);plain.set_jet_amplitude(0,speed, level=1)
self.exact_raw(before,measured._download_raw());self.assertEqual(measured.step_count,count)
ledger.step();plain.step()
self.exact_raw(measured._download_raw(),plain._download_raw())
@@ -193,14 +193,14 @@ class ShiftedJetsGPU(unittest.TestCase):
old._initialize_raw(initial(old,.99));ledger=Ledger(self,old,2)
for speed in (.002,-.001):old.set_jet_amplitude(0,speed,level=2);ledger.step()
before=old._download_raw();count=old.step_count
topology=lambda rects:RemapTopology.from_config(cfg,old.patch,rects,child_objects=(obj,),
child_jets=old._level_jets[2],_shifted_blocked=True)
topology=lambda rects:RemapTopology.from_config(cfg,old.hierarchy.pairs[0],rects,child_objects=(obj,),
child_jets=old.jets[2],_shifted_blocked=True)
expected=_remap_stored(topology(a),topology(b),before,shifted=True,base_count=count,
level_steps=(count,2*count,4*count),phase='postcollision_g')
new=owned.enter_context(old.remap_child(b,child_objects=(obj,)))
new=owned.enter_context(old.remap_finest(b,objects=(obj,)))
self.exact_raw(before,old._download_raw())
self.exact_raw(_StoredPopulations(expected.g,True),new._download_raw())
self.assertEqual(new._level_jets[2][0].amplitude,-.001)
self.assertEqual(new.jets[2][0].amplitude,-.001)
np.testing.assert_array_equal(new._level_boundaries[2].tables['surface_velocity'],old._level_boundaries[2].tables['surface_velocity'])
newledger=Ledger(self,new,2);ledger.step();newledger.step()
self.assertEqual((old.step_count,new.step_count),(count+1,count+1))
@@ -61,7 +61,7 @@ class ShiftedRemapGPU(unittest.TestCase):
def check_finite(self,run):
raw=run._download_raw()
self.assertTrue(raw.shifted)
for a,leaf in zip(raw.values,run._leaf):
for a,leaf in zip(raw.values,run.leaf):
self.assertTrue(np.isfinite(a[:,leaf]).all())
self.assertTrue(np.isnan(a[:,~leaf]).all())
self.assertTrue((1+a[:,leaf].sum(axis=0,dtype=np.float64)>0).all())
@@ -71,7 +71,7 @@ class ShiftedRemapGPU(unittest.TestCase):
old=owned.enter_context(make(ctx))
old._initialize_raw(initial(old));old.step(2)
before=old._download_raw()
new=owned.enter_context(old.remap_child(A))
new=owned.enter_context(old.remap_finest(A))
self.check_reset(new,before.values)
self.snapshot_equal(old._download_raw(),before,'old unchanged')
self.snapshot_equal(new._download_raw(),before,'identity raw copy')
@@ -85,11 +85,11 @@ class ShiftedRemapGPU(unittest.TestCase):
old=owned.enter_context(make(ctx))
old._initialize_raw(initial(old));old.step(2)
before=old._download_raw();count=old.step_count
old_mesh=RemapTopology.from_config(CFG,old.patch,A)
new_mesh=RemapTopology.from_config(CFG,old.patch,B)
old_mesh=RemapTopology.from_config(CFG,old.hierarchy.pairs[0],A)
new_mesh=RemapTopology.from_config(CFG,old.hierarchy.pairs[0],B)
expected=_remap_stored(old_mesh,new_mesh,before,shifted=True,
base_count=count,level_steps=(count,2*count,4*count),phase='postcollision_g')
new=owned.enter_context(old.remap_child(B))
new=owned.enter_context(old.remap_finest(B))
self.check_reset(new,expected.g)
self.snapshot_equal(new._download_raw(),_StoredPopulations(expected.g,True),'host raw fill')
for a,b,om,nm in zip(before.values,new._download_raw().values,old_mesh.leaf_masks,new_mesh.leaf_masks):
@@ -103,7 +103,7 @@ class ShiftedRemapGPU(unittest.TestCase):
with CudaContext(0) as ctx,make(ctx) as run:
run._initialize_raw(initial(run));run.step(2)
before=run._download_raw()
with self.assertRaises(ValueError):run.remap_child([])
with self.assertRaises(ValueError):run.remap_finest([])
self.snapshot_equal(run._download_raw(),before,'rejection preserves source')
self.assertEqual(run.step_count,2)
run.step();self.check_finite(run)
+5 -4
View File
@@ -81,7 +81,7 @@ def public_jets(center, radius, scenario):
)
def jet_interval(handle, scenario, begin, n, diameter):
def jet_interval(handle, scenario, begin, n, diameter, *, level=None):
"""Apply a reversal only at a completed interval boundary, before advancing."""
if scenario != "none":
boundaries = [round(t * diameter / SPEED) for t in (250, 260, 270, 280, 290, 300, 305)]
@@ -92,8 +92,9 @@ def jet_interval(handle, scenario, begin, n, diameter):
if begin < switch:
return min(n, switch - begin), None
if begin == switch:
handle.set_jet_amplitude(0, -JET_PEAK)
handle.set_jet_amplitude(1, JET_PEAK)
target = {} if level is None else dict(level=level)
handle.set_jet_amplitude(0, -JET_PEAK, **target)
handle.set_jet_amplitude(1, JET_PEAK, **target)
return n, dict(step=begin, tstar=300.0, amplitudes=[-JET_PEAK, JET_PEAK])
return n, None
@@ -448,7 +449,7 @@ def run_case(a, h, periodic, case):
)
n = min(max(1, round(width * p["diameter"] / SPEED)), max_steps - begin)
n, change = jet_interval(backend if refined else sim, a.jet_scenario,
begin, n, p["diameter"])
begin, n, p["diameter"], level=1 if refined else None)
if change is not None:
amplitude_changes.append(change)
impulse = np.zeros(2)
+1 -1
View File
@@ -73,7 +73,7 @@ def run_variant(backend, variant, n_intervals, deadline):
else:
for _ in range(INTERVAL):
backend.step(1)
totals.append(components(backend.read_exchange_window(0)))
totals.append(components(backend.read_exchange_window(0, level=1)))
t.check_deadline(deadline)
return np.array(totals), (np.array(scales) if scales else None)