Wire Jets into FixedPatchStepper fine level (dense and blocked)
FixedPatchStepper(..., jets=()) passes jets (coarse cell-edge frame, as fine_objects) to prepare_fine_boundary, which runs the shared assignment checks before CUDA. Dense fine path: assign_surface with jets and the boundary's true hits. Blocked path: surface_link_velocity with jets/hits; unit-amplitude shapes cached. set_jet_amplitude (new/ready only) validates first, then rewrites the dense SoA column or the blocked jet rows and re-uploads only the velocity buffer after a stream sync. Scheduling, kernels and launch ABI unchanged. tests/validation/multigrid/test_refinement_jets.py: mocked-driver CPU checks and frozen GPU gates G1-G3 (layout identity, jet vs legacy <=1e-6, amplitude switch). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f26410f94a
commit
aebef52345
2 files changed
+170
-7
No files matched your search
@@ -16,6 +16,7 @@ import pycuda.driver as cuda
|
||||
from ..cuda import compiler_v2 as compiler
|
||||
from .blocks import BlockLayout2D, blocked_link_tables
|
||||
from .curved_links import surface_link_velocity
|
||||
from ..body.jets import jet_link_shapes, jet_link_velocity
|
||||
from .block_stepper import MAX_GRID_DIM
|
||||
from .refinement import ACTIVE, HALO, OUTER_GHOST, FixedPatch2D, prepare_fine_boundary
|
||||
from .descriptors import SOLID, D2Q9_EX, D2Q9_EY
|
||||
@@ -106,9 +107,12 @@ class FixedPatchStepper:
|
||||
covered cells are explicitly poisoned on every step. Public shapes stay dense.
|
||||
Blocked mode applies prescribed surface velocity only; its per-link
|
||||
exchange diagnostic is unavailable (rows keep physical cut-link order).
|
||||
``jets`` (body.jets.Jet) use the same edge frame as ``fine_objects`` and
|
||||
drive fine cut links selected at their true hits; ``set_jet_amplitude``
|
||||
re-uploads the per-link velocity column only.
|
||||
"""
|
||||
def __init__(self, cfg, bounds, *, context, coarse_boundary="periodic", fine_objects=(),
|
||||
fine_block=None, base_block=None):
|
||||
fine_block=None, base_block=None, jets=()):
|
||||
if HALO != 4:
|
||||
raise RuntimeError("refinement.cu requires a four-cell fine halo")
|
||||
if coarse_boundary not in ("periodic", "slot_reservoir"):
|
||||
@@ -143,9 +147,10 @@ class FixedPatchStepper:
|
||||
if (self.fine_layout.nblocks > MAX_GRID_DIM
|
||||
or self.fine_layout.local_shape[0] > MAX_GRID_DIM):
|
||||
raise ValueError("fine blocks exceed launch limits")
|
||||
self._jets = tuple(jets)
|
||||
self.fine_boundary = prepare_fine_boundary(
|
||||
cfg, self.patch, fine_objects, wall_aware=self._wall_aware)
|
||||
self._fine_tables, self._actuated = None, False
|
||||
cfg, self.patch, fine_objects, wall_aware=self._wall_aware, jets=self._jets)
|
||||
self._fine_tables, self._actuated, self._jet_cache = None, False, None
|
||||
if self.fine_layout is not None and self.fine_boundary is not None:
|
||||
fluid_idx, dirs, q, _, _, _, _, fallback = self.fine_boundary.curved_host
|
||||
self._fine_tables, _ = blocked_link_tables(
|
||||
@@ -172,12 +177,16 @@ class FixedPatchStepper:
|
||||
if self._fine_tables is not None:
|
||||
# Any actuation spec (even zero amplitude) requires the velocity buffer.
|
||||
b = self.fine_boundary
|
||||
self._actuated = any(obj.surface_actuation is not None for obj in b.objects)
|
||||
self._actuated = bool(self._jets) or any(
|
||||
obj.surface_actuation is not None for obj in b.objects)
|
||||
if self._actuated:
|
||||
fine_cfg.validate() # derives nq etc.; the unique-writer key needs them
|
||||
fluid_idx, dirs, _, body_id, rx, ry, _, _ = b.curved_host
|
||||
self._fine_tables["surface_velocity"], _ = surface_link_velocity(
|
||||
b.objects, fine_cfg, b.flags, fluid_idx, dirs, body_id, rx, ry)
|
||||
b.objects, fine_cfg, b.flags, fluid_idx, dirs, body_id, rx, ry,
|
||||
jets=self._jets, hits=b.curved_hits)
|
||||
if self._jets:
|
||||
self._jet_cache = jet_link_shapes(self._jets, b.curved_hits)
|
||||
with self.ctx.activate():
|
||||
try:
|
||||
self._stream = cuda.Stream()
|
||||
@@ -257,7 +266,8 @@ class FixedPatchStepper:
|
||||
# SoA owns its allocations; never also register them in _allocations.
|
||||
self._fine_curved = CurvedLinkSoA()
|
||||
self._fine_curved.assign_host(*boundary.curved_host)
|
||||
self._fine_curved.assign_surface(boundary.objects, fine_cfg, boundary.flags)
|
||||
self._fine_curved.assign_surface(boundary.objects, fine_cfg, boundary.flags,
|
||||
jets=self._jets, hits=boundary.curved_hits)
|
||||
self._fine_curved.upload()
|
||||
self._curved = self._levels[1].module.get_function("CurvedBoundaryKernel")
|
||||
except BaseException:
|
||||
@@ -333,7 +343,8 @@ class FixedPatchStepper:
|
||||
return
|
||||
if self._curved is None or cl.fluid_idx_gpu is None:
|
||||
raise RuntimeError("Fine boundary device buffers are missing")
|
||||
driven = any(obj.surface_actuation is not None for obj in self.fine_boundary.objects)
|
||||
driven = bool(self._jets) or any(
|
||||
obj.surface_actuation is not None for obj in self.fine_boundary.objects)
|
||||
if driven and (cl.surface_velocity_gpu is None or cl.link_exchange_gpu is None):
|
||||
raise RuntimeError("Surface boundary device buffers are missing")
|
||||
self._curved(buffer, cl.fluid_idx_gpu, cl.dir_gpu, cl.q_gpu,
|
||||
@@ -343,6 +354,24 @@ class FixedPatchStepper:
|
||||
cl.link_exchange_gpu if cl.link_exchange_gpu is not None else np.uintp(0),
|
||||
grid=((cl.count + self._block[0] - 1) // self._block[0], 1), **kw)
|
||||
|
||||
def set_jet_amplitude(self, index, amplitude):
|
||||
"""Replace one jet's amplitude between steps; no geometry/table rebuild."""
|
||||
with self._lock, self.ctx.activate():
|
||||
self._require("new", "ready")
|
||||
jets = list(self._jets)
|
||||
jets[index] = jets[index].with_amplitude(amplitude) # validates first
|
||||
if self._fine_curved is not None:
|
||||
self._fine_curved.set_jet_amplitude(index, amplitude, self._stream)
|
||||
elif self._jet_cache is not None:
|
||||
shape, jet_id = self._jet_cache
|
||||
velocity = self._fine_tables["surface_velocity"].copy()
|
||||
driven = jet_id >= 0
|
||||
velocity[driven] = jet_link_velocity(jets, shape, jet_id)[driven]
|
||||
self._stream.synchronize() # no in-flight step reads the column
|
||||
cuda.memcpy_htod(self._link_tables["surface_velocity"], velocity)
|
||||
self._fine_tables["surface_velocity"] = velocity
|
||||
self._jets = tuple(jets)
|
||||
|
||||
def _blocked_fine_boundary(self, buffer, **kw):
|
||||
if self._fine_tables is None:
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user