Generalize synchronized remap to multiple pinned body rectangles
This commit is contained in:
@@ -499,9 +499,9 @@ class FixedPatchStepper:
|
||||
|
||||
Periodic three-level set children only; L0/L1 and block sizes stay fixed.
|
||||
A body run requires its original root-edge-frame ``child_objects``:
|
||||
one stationary circle pinned in one of exactly two L2 rectangles.
|
||||
The complete body rectangle stays identical; only the other fluid
|
||||
rectangle may move. Current L2 Jets (including updated amplitudes)
|
||||
stationary circles pinned in unchanged complete L2 rectangles.
|
||||
Separated fluid-only rectangles may be added, moved or removed.
|
||||
Current L2 Jets (including updated amplitudes)
|
||||
are preserved. Local projected boundary objects are not valid inputs.
|
||||
The lock and stream synchronization certify
|
||||
current postcollision G and the completed 1:2:4 counts internally.
|
||||
@@ -538,10 +538,10 @@ class FixedPatchStepper:
|
||||
raise ValueError("child_objects changed boundary ownership or surface velocity")
|
||||
new = RemapTopology.from_config(cfg, self.patch, rectangles,
|
||||
child_objects=child_objects, child_jets=jets)
|
||||
if (old.pinned_rectangle != new.pinned_rectangle
|
||||
if (old.pinned_rectangles != new.pinned_rectangles
|
||||
or not same_physical_boundary(old.boundary, new.boundary)
|
||||
or not np.array_equal(old.surface_velocity, new.surface_velocity)):
|
||||
raise ValueError("remap requires the identical pinned body rectangle and boundary")
|
||||
raise ValueError("remap requires the identical pinned body rectangles and boundary")
|
||||
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)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""CPU-only whole-volume G transfer, not a runtime adaptive solver.
|
||||
|
||||
Periodic three-level grids with fixed L0/L1 topology are supported, including
|
||||
one stationary circle pinned inside an unchanged L2 rectangle. The caller
|
||||
stationary circles pinned inside unchanged L2 rectangles. The caller
|
||||
certifies that current owned leaves are quiescent,
|
||||
unshifted D2Q9 postcollision G at the supplied completed base interval.
|
||||
No device buffers, device boundary state, ghosts, collision or time advance
|
||||
@@ -25,12 +25,14 @@ class RemapTopology:
|
||||
Child rectangles are in the parent's allocated L1 coordinates, including
|
||||
its window offset/halo when the parent is a scalar patch. Dense masks are
|
||||
rebuilt from geometry, never inferred from finite values in input arrays.
|
||||
``pinned_rectangles`` canonically lists each body-containing rectangle once;
|
||||
fluid-only layouts have no pins.
|
||||
"""
|
||||
parent: object
|
||||
child: FixedPatchSet2D
|
||||
leaf_masks: tuple
|
||||
boundary: FineBoundary2D | None = None
|
||||
pinned_rectangle: tuple | None = None
|
||||
pinned_rectangles: tuple = ()
|
||||
surface_velocity: np.ndarray | None = None
|
||||
|
||||
@classmethod
|
||||
@@ -43,24 +45,24 @@ class RemapTopology:
|
||||
parent = type(parent).from_config(cfg, parent.bounds)
|
||||
child, middle_kind = nest_patch_set(cfg, parent, child_rectangles)
|
||||
child_objects, child_jets = tuple(child_objects), tuple(child_jets)
|
||||
if child_objects and (len(child_objects) != 1 or len(child.bounds) != 2):
|
||||
raise ValueError("body remap requires one stationary circle and two L2 rectangles")
|
||||
fine_cfg = replace(cfg, nx=parent.fine_shape[1], ny=parent.fine_shape[0],
|
||||
viscosity=2 * cfg.viscosity)
|
||||
boundary = prepare_fine_boundary(
|
||||
fine_cfg, child, child_objects, jets=child_jets,
|
||||
parent_origin=parent.fine_origin, parent_spacing=.5)
|
||||
pinned, velocity = None, None
|
||||
pinned, velocity = (), None
|
||||
child_leaf = child.fine_kind == ACTIVE
|
||||
if boundary is not None:
|
||||
child_leaf &= (boundary.flags.reshape(child.fine_shape) & SOLID) == 0
|
||||
# Whole circle containment, not merely the resolved solid cells.
|
||||
obj = child_objects[0]
|
||||
cx, cy = (np.asarray(obj.geometry.center) - parent.fine_origin) * 2
|
||||
radius = obj.geometry._radius * 2
|
||||
pinned = next(r for r in child.bounds if
|
||||
r[0] <= cx-radius and cx+radius <= r[2] and
|
||||
r[1] <= cy-radius and cy+radius <= r[3])
|
||||
containing = set()
|
||||
for obj in child_objects:
|
||||
cx, cy = (np.asarray(obj.geometry.center) - parent.fine_origin) * 2
|
||||
radius = obj.geometry._radius * 2
|
||||
containing.add(next(r for r in child.bounds if
|
||||
r[0] <= cx-radius and cx+radius <= r[2] and
|
||||
r[1] <= cy-radius and cy+radius <= r[3]))
|
||||
pinned = tuple(sorted(containing))
|
||||
velocity = boundary_velocity(cfg, child, boundary, child_jets)
|
||||
if velocity is not None:
|
||||
velocity.setflags(write=False)
|
||||
@@ -88,8 +90,11 @@ def same_physical_boundary(a, b):
|
||||
return a is b
|
||||
if not isinstance(a, FineBoundary2D) or not isinstance(b, FineBoundary2D):
|
||||
return False
|
||||
if (tuple(o.surface_actuation for o in a.objects)
|
||||
!= tuple(o.surface_actuation for o in b.objects)):
|
||||
# Exact ordered geometry also catches changes hidden by cut-table rounding.
|
||||
def signatures(boundary):
|
||||
return tuple((o.geometry.center, o.geometry._radius, o.surface_actuation)
|
||||
for o in boundary.objects)
|
||||
if signatures(a) != signatures(b):
|
||||
return False
|
||||
return all(np.array_equal(x, y) for x, y in zip(
|
||||
(a.flags, a.boundary_cells, a.curved_hits, *a.curved_host),
|
||||
@@ -162,10 +167,10 @@ def remap_synchronized(old, new, old_g, *, base_count, level_steps, phase,
|
||||
or not _same_parent(old.parent, new.parent)
|
||||
or old.child.tau_fine != new.child.tau_fine):
|
||||
raise ValueError("remap requires unchanged L0/L1 geometry and relaxation")
|
||||
if (old.pinned_rectangle != new.pinned_rectangle
|
||||
if (old.pinned_rectangles != new.pinned_rectangles
|
||||
or not same_physical_boundary(old.boundary, new.boundary)
|
||||
or not np.array_equal(old.surface_velocity, new.surface_velocity)):
|
||||
raise ValueError("remap requires the identical pinned body rectangle and physical boundary")
|
||||
raise ValueError("remap requires the identical pinned body rectangles and physical boundary")
|
||||
if not isinstance(level_steps, (tuple, list)):
|
||||
raise ValueError("level_steps must be three completed integer counts")
|
||||
counts = (base_count, *level_steps)
|
||||
|
||||
Reference in New Issue
Block a user