fix(esopull): correct init layout and pre-streaming semantics (v0.5.1)

EsoPull curved boundaries and wall BCs now use consistent backing-layout
reads; InitEsoPull writes equilibrium in t=0 EsoPull layout. Cache N_OBJS
after compile and atomic config header writes to avoid parallel races.
Adds config screening tools, flume configs, and FP16S/EsoPull diagnosis doc.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Frank14fandCursor committed 2026-06-27 22:32:01 +08:00
1 parent 00b957f904
commit 6e3756c587
28 files changed
+1536 -157

No files matched your search

+25 -31
View File
@@ -48,8 +48,12 @@ OMEGA_SIGN_FROM_ACTION = -1.0
VORT_VMIN = -0.003
VORT_VMAX = 0.003
STEALTH_REF_OMEGA_M_S = 0.01806
STEALTH_STEADY_FRAC = 1.25 # s125 from steady sweep
STEALTH_STEADY_OMEGA_M_S = STEALTH_REF_OMEGA_M_S * STEALTH_STEADY_FRAC
CONFIG_PATH = _REPO / "src/CelerisLab/configs/config_lbm_three_cylinder_triangle.json"
DEFAULT_OUT = _REPO / "tests" / "output" / "exp_ctrl_matrix_vort_ny300"
DEFAULT_OUT = _REPO / "tests" / "output" / "exp_ctrl_matrix_vort_nx1500"
FIXED_STEPS = 100000 # keep constant while grid changes
# Body order: 0=apex, 1=rear-lower(y_lower), 2=rear-upper(y_upper); swap action2/action3 targets.
SWAP_ACTION23_BODIES = True
@@ -70,8 +74,8 @@ CONTROL_CASES: List[Tuple[str, str, Dict[str, Any]]] = [
"stealth",
{
"action1": {"mean": 0.0, "components": [(0.1354, 0.0, 1.600)]},
"action2": {"mean": -0.01806, "components": [(0.1354, 0.0, 2.099)]},
"action3": {"mean": 0.01806, "components": [(0.1354, 0.0, 1.639)]},
"action2": {"mean": -STEALTH_STEADY_OMEGA_M_S, "components": [(0.1354, 0.0, 2.099)]},
"action3": {"mean": STEALTH_STEADY_OMEGA_M_S, "components": [(0.1354, 0.0, 1.639)]},
},
),
(
@@ -308,43 +312,31 @@ def run_case(
dt_phys = dx_phys * (u_lb / INLET_U_PHYS_M_S)
cylinders = cylinders_from_triangle_layout(layout)
print(f"--- {case_id} {slug} steps={steps} u_lb={u_lb} dt_phys={dt_phys} batch={batch} ---")
stream = sim.stream
batch_size = max(1, int(batch))
print(f"--- {case_id} {slug} steps={steps} u_lb={u_lb} dt_phys={dt_phys} ---")
# Main loop: precompute actions, batch-step, read forces/sensors at intervals
for batch_start in range(0, steps, batch_size):
batch_end = min(batch_start + batch_size, steps)
for j in range(batch_start, batch_end):
t_phys = j * dt_phys
a1, a2, a3 = _actions_at_time(t_phys, features)
w1 = _action_to_omega_lb(a1, u_lb)
w2 = _action_to_omega_lb(a2, u_lb)
w3 = _action_to_omega_lb(a3, u_lb)
if SWAP_ACTION23_BODIES:
_set_body_omegas(sim, w1, w3, w2)
else:
_set_body_omegas(sim, w1, w2, w3)
for step in range(steps):
t_phys = step * dt_phys
a1, a2, a3 = _actions_at_time(t_phys, features)
w1 = _action_to_omega_lb(a1, u_lb)
w2 = _action_to_omega_lb(a2, u_lb)
w3 = _action_to_omega_lb(a3, u_lb)
if SWAP_ACTION23_BODIES:
_set_body_omegas(sim, w1, w3, w2)
else:
_set_body_omegas(sim, w1, w2, w3)
sim.run(1, sync_obs=False)
n = batch_end - batch_start
sim.stepper.step(
n,
action_gpu=sim.bodies.action_gpu,
obs_gpu=sim.bodies.obs_gpu,
stream=stream,
)
if report_every > 0 and (batch_end % report_every == 0 or batch_end == steps):
stream.synchronize()
if report_every > 0 and ((step + 1) % report_every == 0 or step + 1 == steps):
sim.stream.synchronize()
for bid in range(sim.bodies.count):
fx = sim.bodies.read_force(bid)
print(
f" step={batch_end} body={bid}"
f" step={step + 1} body={bid}"
f" fx={float(fx[0]):+.6f} fy={float(fx[1]):+.6f}",
flush=True,
)
stream.synchronize()
sim.stream.synchronize()
macro = sim.get_macroscopic()
vort = compute_vorticity(macro["ux"], macro["uy"])
png = out_dir / f"vorticity_{case_id}_{slug}.png"
@@ -461,6 +453,8 @@ def main() -> int:
"device_id": int(args.device_id),
"vort_vmin": VORT_VMIN,
"vort_vmax": VORT_VMAX,
"stealth_steady_omega_m_s": STEALTH_STEADY_OMEGA_M_S,
"stealth_steady_frac": STEALTH_STEADY_FRAC,
"swap_action23_bodies": bool(SWAP_ACTION23_BODIES),
"cases": summaries,
}