Tests load research drivers via importlib under unique module names instead of a bare 'import run' (shared-process collision between the Dütsch and VIV drivers). lifecycle.md qualifies immutable geometry and the host-only get_flags for translating circles; supported_settings.md points to the dense-only moving-circle feature; leontini_viv_predeclare.md is renamed viv_re150_predeclare.md (Re 150 Kolahdouz/Qin case) with references updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
149 lines
8.6 KiB
Markdown
149 lines
8.6 KiB
Markdown
# Single-cylinder free transverse VIV, Re 150 (Kolahdouz/Qin) — PREDECLARATION (agreed at 1abfe954)
|
||
|
||
(File renamed from `leontini_viv_predeclare.md`; the Leontini Re 200 case is only the queued second case below.)
|
||
|
||
Stage goal (Yanqi via TRON): prescribed Dütsch case + one VIV case both
|
||
"reasonably close" to a predeclared reference = development-stage success, then
|
||
cleanup. The frozen Dütsch settling failure (0/28 pairs at 31.25 T) stays on
|
||
record. Practical closeness is not a formal validation claim. Agreed by
|
||
Claude, Grok and Astra at 1abfe954; implemented in research/viv_re150/.
|
||
|
||
## Primary case (one case)
|
||
|
||
- Reference: Qin et al., arXiv:2003.12186, §4.5 (maximum amplitudes at
|
||
U_red = 3…8: .075, .551, .520, .459, .370, .084 D in the text, as quoted by
|
||
Grok/Astra) for the target; setup from Kolahdouz et al., arXiv:2003.12046,
|
||
§4.1.1 (read 2026-10-30 via ar5iv): U* sweep 3–8 with amplitudes only in
|
||
Fig. 3(b) (no text values), domain [−30, 45] D × [−30, 30] D with the
|
||
cylinder "initially at rest and centered at the origin", uniform inflow on
|
||
the left, zero normal traction and tangential velocity at the outlet, zero
|
||
normal velocity and tangential traction on y = ±30 D; no initial
|
||
perturbation and no total simulated time stated.
|
||
- Re = 150, U* = U/(f_n D) = 5, m/(rho D²) = 2 (m* = rho_s/rho_f = 8/pi),
|
||
zeta = 0, f_n = sqrt(K/M)/(2 pi) in vacuum. Transverse DOF only.
|
||
- Target: A_max = .520 D (peak amplitude, Qin §4.5). Multi-code reference
|
||
(Kolahdouz ILE-NS, Qin II-LBM). Reference uncertainty: not stated; the
|
||
spread between codes is not quantified here.
|
||
|
||
## Our reproduction (declared differences)
|
||
|
||
- D = 40, MRT, dense double buffer; U_lat = .04, nu = U D / 150 = .010667,
|
||
tau = .532.
|
||
- Box [0, 75 D] × [0, 60 D] (3000 × 2400) with the cylinder centre at
|
||
(30 D, 30 D): 30 D from the inlet, 45 D from the outlet, centred in y
|
||
(Kolahdouz §4.1.1). Qin's own box ([0, 40 D] × [0, 20 D], centre (10 D, 10 D))
|
||
is the target paper's, not ours.
|
||
- Boundaries: uniform Zou–He inlet, NEQ outlet (rho = 1, backflow clamp),
|
||
free-slip y walls. Kolahdouz uses a traction outlet: declared mismatch.
|
||
- Qin's own VIV box (40 D × 20 D) is not used; a smaller box would be a
|
||
declared cost cut with more blockage, not "the same case".
|
||
- Allowed y offset ±1.5 D; peak transverse speed ≈ .026 cells/step (bound .5).
|
||
|
||
## Structure, coupling and time levels
|
||
|
||
- M = 2 rho D² (lattice rho = 1), f_n = U/(5 D) = 2e-4 per step, K = M (2 pi f_n)²,
|
||
zeta = 0. Equation of motion uses the structural mass only.
|
||
- Per-step sequence (binding): known (y_n, v_n) and the last completed force
|
||
F_last → candidate (y_{n+1}, v_{n+1}) by the update below → `set_body` with
|
||
offset y_{n+1} and wall velocity (y_{n+1} − y_n)/dt with lattice dt = 1 (interval average; a
|
||
different quantity from the endpoint v_{n+1}) → `run(1)` → only on success:
|
||
commit y_n ← y_{n+1}, v_n ← v_{n+1}, F_last ← force read for that step (failure
|
||
semantics: see the window section). Whether the
|
||
measured force represents the interval's start, midpoint or end is not
|
||
asserted; the one-step lag is declared, not corrected.
|
||
- Initial state: fluid initialized by `Simulation.initialize()` to the uniform
|
||
inlet velocity U everywhere (the code's actual initial condition; the
|
||
source gives no fluid initial condition), body at rest at the declared
|
||
centre, y_0 = v_0 = 0, F_last = 0.
|
||
- Structural update over one step with constant force F = F_last (exact
|
||
harmonic solution, zeta = 0): y_e = F/K, w = 2 pi f_n,
|
||
y^{n+1} = y_e + (y^n − y_e) cos w + (v^n / w) sin w,
|
||
v^{n+1} = −(y^n − y_e) w sin w + v^n cos w.
|
||
- Primary RHS (single coupled run): CME + Wen (theory-motivated stage choice:
|
||
Galilean-invariant link correction; G4 could not separate it from CME).
|
||
Raw CME and the node terms are logged as diagnostics of that trajectory;
|
||
the node impulse is not added. A run with CME-only as RHS is a separate,
|
||
labelled sensitivity case, decided separately. Neither RHS is claimed proven.
|
||
|
||
## Window, failure semantics, acceptance (engineering, development stage)
|
||
|
||
Clocks: lattice dt = 1; T_n = 1/f_n = 5,000 steps. Response cycles are
|
||
counted from the measured signal; T_n is used only for the seed check.
|
||
|
||
- Start: body at rest at the declared centre (the only initial condition the
|
||
source states), y_0 = v_0 = 0, F_last = 0; fluid uniform at U (as
|
||
initialized by the code; our choice, not the source's).
|
||
- Seed (conditional, one time, declared): at step n_seed = 200,000
|
||
(t = 40 T_n), if max |y_t| over states t in [175,000, 200,000) is below
|
||
.01 D, then
|
||
in that step, after the check and before the candidate update, set
|
||
v_n += 2 pi f_n (.01 D) (F_last unchanged) and proceed normally; the
|
||
geometry moves continuously through the update. `seed_applied`, step and
|
||
size are logged; never repeated or changed.
|
||
- Cycle boundary (discrete, fixed threshold): step n closes a cycle iff
|
||
y[n−1] < 0 and y[n] ≥ 0 (upward crossing of the equilibrium y = 0);
|
||
y_0 = 0 is not a crossing; no boundary fewer than 2 samples after the
|
||
previous one.
|
||
- Per cycle: positive peak max(y), negative peak min(y), mean offset
|
||
(time-mean of y), amplitude a = (max − min)/2 (the only amplitude used for
|
||
settling).
|
||
- Eligibility: a completed cycle is counted (toward the settling proof and
|
||
the 150 budget) only if a ≥ .01 D; ineligible cycles are logged, never
|
||
counted, so near-zero motion cannot settle or pass.
|
||
- Seed reset: if the seed is applied, the incomplete cycle at n_seed is
|
||
discarded and the settling proof starts empty; the 150 budget and the
|
||
native cap keep running from t = 0.
|
||
- Windows: adjacent non-overlapping blocks of 10 counted cycles;
|
||
W_k = mean amplitude of block k (W_k ≥ .01 D by eligibility, so no zero
|
||
denominator).
|
||
- Block rule R(k), k ≥ 2: |W_k − W_{k−1}| / W_{k−1} ≤ .02 and, for the last 5
|
||
cycles of block k, max_i |a_i − ā_5| / ā_5 ≤ .01 with ā_5 their mean.
|
||
- Settled at the end of block k when R(k) holds. Scoring = the next two
|
||
blocks k+1, k+2 (20 counted cycles); both must satisfy R. If one fails,
|
||
that block becomes the new reference: the settling proof restarts from it
|
||
and continues within the caps (deterministic; no other retry). A pass
|
||
requires one complete stable 20-cycle scoring window before a cap; success
|
||
stops after its 20th cycle.
|
||
- Caps (both always armed; the first hit wins and is reported): 150 counted
|
||
response cycles including the 20 scoring cycles (so settling must complete
|
||
by counted cycle 130) → `timeout_response_cycles`; 1,000,000 native steps
|
||
(200 T_n) → `timeout_native_steps`.
|
||
- Durations reported: total steps, t U/D, counted and uncounted cycles,
|
||
measured T_resp (mean boundary interval); N_resp / f_n only as a labelled
|
||
secondary clock.
|
||
- Growth is not a failure: initial VIV growth is physical. Checked every
|
||
step (FAIL-CLOSED): non-finite y, v or force; |y| > 1.0 D (the tighter
|
||
gate; about twice the largest reference peak, .551 D) or the ±1.5 D offset
|
||
box reached; no_donor > 0; a failed upload/step/sync.
|
||
- On any failure the driver stops and reports; it never retries,
|
||
sub-iterates, retunes the RHS or parameters, or starts a second case.
|
||
Device-side failures (upload/step/sync, no_donor) mark the Simulation
|
||
failed through the existing lifecycle; input rejection by `set_body`
|
||
(offset box, speed, step bound) and timeouts end the driver run without
|
||
that mark.
|
||
- Target metric over the 20 scoring cycles: A_max/D = max over those cycles
|
||
of max(|positive peak|, |negative peak|) about y = 0 (Qin reports "maximum
|
||
amplitude"); also reported: mean amplitude, positive and negative peaks,
|
||
mean offset, f/f_n (no target).
|
||
- Acceptance: |A_max − .520 D| ≤ .052 D (±10 %), stated together with the
|
||
boundary mismatch and the absence of a quoted reference uncertainty. A pass
|
||
is "reasonably close" for the stage: not grid convergence, not force-RHS
|
||
validation, and it does not touch the Dütsch settling record.
|
||
- Driver reads force and the small diagnostics per step only; field reads
|
||
only at a few predeclared snapshots. No runtime claim: there is no measured
|
||
timing on this grid yet (the D40/60D receipt is a different, sampled case).
|
||
|
||
## Plumbing smoke (not the benchmark)
|
||
|
||
`run.py --smoke --D 20 --steps 32` runs exactly 32 steps of the same BC
|
||
package and coupling loop (no seed, settle or score; never scored);
|
||
status `smoke_ok` iff every step is finite, no_donor stays 0 and the body
|
||
stays inside its box. The physical case is only the default invocation
|
||
(`--D 40`, no `--smoke`).
|
||
|
||
## Queued, not in this stage
|
||
|
||
Leontini et al. JFS 22 (2006) Re = 200, m* = 10, zeta = 0.01, U* = 5.0 (needs
|
||
the owners' c_crit convention and a Fig. 1 digitization). D80, literature
|
||
claims, pinball, AMR, BC redesign, threshold changes.
|