Add explicit synchronized L2 runtime continuation

This commit is contained in:
TRON committed 2026-10-16 10:12:40 -07:00
1 parent 999d3a0e94
commit 766658185f
4 files changed
+330 -5

No files matched your search

+60 -1
View File
@@ -3,7 +3,8 @@
The caller owns the CudaContext and must close this backend before that context.
Only synchronized postcollision_g leaf populations are public. No checkpoint,
snapshot, forcing, runtime parameter mutation or dynamic refinement is offered.
forcing or runtime parameter mutation is offered. Manual body-free periodic
L2 set replacement is available at completed base intervals via remap_child.
"""
from dataclasses import dataclass, replace
from numbers import Integral
@@ -307,6 +308,10 @@ class FixedPatchStepper:
self._child = None
if self.fine_boundary is not None:
self._fine_leaf &= (self.fine_boundary.flags.reshape(self.patch.fine_shape) & SOLID) == 0
# Private constructor inputs for the bounded manual L2 continuation.
self._remap_cfg = replace(cfg)
self._remap_blocks = tuple(None if b is None else tuple(b)
for b in (base_block, fine_block, child_block))
self.ctx = context
self._lock = RLock()
self._status = "new"
@@ -489,6 +494,60 @@ class FixedPatchStepper:
self._status = "failed"
raise
def remap_child(self, rectangles):
"""Return a NEW ready stepper with an L2 set replaced at this base time.
Only body-free periodic three-level set children are supported; L0/L1
and block sizes stay fixed. The lock and stream synchronization certify
current postcollision G and the completed 1:2:4 counts internally.
Both objects remain independently owned: the caller must close each,
and chooses when to stop using the unchanged old instance. Candidate
construction/upload errors never invalidate the old instance; failure
to synchronize/read its device state does, as with step/download.
"""
from .synchronized_remap import RemapTopology, remap_synchronized
with self._lock:
self._require("ready")
if (self._wall_aware or len(self._levels) != 3
or not isinstance(self.child_patch, FixedPatchSet2D)
or self.fine_boundary is not None or self.child_boundary is not None
or any(level.boundary is not None for level in self._levels)):
raise ValueError("remap_child requires body-free periodic three-level L2 sets")
cfg = self._remap_cfg
old = RemapTopology.from_config(cfg, self.patch, self.child_patch.bounds)
new = RemapTopology.from_config(cfg, self.patch, rectangles)
base_block, fine_block, child_block = self._remap_blocks
# Check sparse block alignment/launch size before any device read/allocation.
layout = new.child.fine_layout(child_block)
if layout.nblocks > MAX_GRID_DIM or layout.local_shape[0] > MAX_GRID_DIM:
raise ValueError("child blocks exceed launch limits")
with self.ctx.activate():
try:
self._stream.synchronize()
source = self.download()
except BaseException:
self._status = "failed"
raise
count = self._step_count
transferred = remap_synchronized(
old, new, source, base_count=count, level_steps=(count, 2*count, 4*count),
phase="postcollision_g")
candidate = type(self)(
cfg, self.patch.bounds, context=self.ctx, base_block=base_block,
fine_block=fine_block, child_block=child_block,
child_rectangles_in_parent=new.child.bounds)
try:
candidate.initialize(*transferred.g)
candidate._step_count = count
except BaseException:
try:
candidate.close()
except Exception:
pass # Preserve the original candidate initialization failure.
raise
return candidate
def _apply_fine_boundary(self, buffer, **kw):
"""Stage solid source slots; exchange buffer holds this fine substep only."""
cl = self._fine_curved