diff --git a/research/viv_re150/README.md b/research/viv_re150/README.md new file mode 100644 index 0000000..1467546 --- /dev/null +++ b/research/viv_re150/README.md @@ -0,0 +1,23 @@ +# Research VIV driver — coupling contract (not production) + +`run.py` couples a 1-DOF undamped spring–mass (`viv.py`) to the production +moving-circle API. Everything specific to fluid–structure coupling lives here, +not in `src/`. + +- Per step: known (y_n, v_n) and the last completed force F_last → exact + harmonic candidate (y_{n+1}, v_{n+1}) → `set_body(offset=(0, y_{n+1}), + vy=y_{n+1} − y_n)` (interval wall velocity, lattice dt = 1) → `run(1)` → + commit y, v and F_last only after the step succeeded. One step of explicit + force lag (weak coupling); no sub-iteration. +- Structural RHS = CME + Wen (y), read from `moving_diagnostics()` by the + names in `MovingTables.DIAG`; raw CME, the `obs` force and node terms are + logged as diagnostics. This is a stage choice, not a validated force law. +- Production guarantees used: fail-closed target commit (synchronized step, + `no_donor == 0`), input rejection before mutation, a failed device step + marks the Simulation failed. +- Not provided, by design: device-resident structure state or batched + (multi-step) coupling, strong/sub-iterated coupling (would need state + rollback), more than one DOF. These are future work and would be a separate + execution path, not an abstraction over this driver. +- Recorded result and limits: `docs/validation/moving_bodies_stage1.md`; + predeclaration: `docs/validation/viv_re150_predeclare.md`. diff --git a/research/viv_re150/run.py b/research/viv_re150/run.py index 4e96a63..31b9586 100644 --- a/research/viv_re150/run.py +++ b/research/viv_re150/run.py @@ -65,7 +65,8 @@ def main(): step_cap = args.steps centre = (30.0 * Dn, 0.5 * (ny - 1)) - from CelerisLab.body.motion import Translation + from CelerisLab.body.motion import MovingTables, Translation + col = {k: MovingTables.DIAG.index(k) for k in ("cme_y", "wen_y", "cover_jy", "uncover_jy", "no_donor")} from CelerisLab.simulation import Simulation with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False) as fh: json.dump(cfg, fh) @@ -95,9 +96,9 @@ def main(): sim.run(1) # device failures raise and mark the Simulation failed d = sim.moving_diagnostics()[0] f_obs = sim.read_force(body)[1] - f_rhs = float(d[1] + d[3]) # CME + Wen (y) - row = (n, y1, v1, f_rhs, float(d[1]), float(d[3]), float(f_obs), - float(d[7] - d[10]), float(d[13])) + f_rhs = float(d[col["cme_y"]] + d[col["wen_y"]]) # CME + Wen (y) + row = (n, y1, v1, f_rhs, float(d[col["cme_y"]]), float(d[col["wen_y"]]), float(f_obs), + float(d[col["cover_jy"]] - d[col["uncover_jy"]]), float(d[col["no_donor"]])) if not viv.finite(row): # every recorded output, not only the RHS status = "fail_nonfinite_output" break