Add one predeclared mass-four paired VIV exploration

This commit is contained in:
Frank14f committed 2026-11-01 00:35:34 +08:00
1 parent 516975ef64
commit 73d3f6214e
3 files changed
+154 -9

No files matched your search

+45 -5
View File
@@ -22,6 +22,7 @@ from research.steady_pinball.run import Structure, config, scaled_points, CENTRE
BIAS = np.array([0., -4., 4.])
MODEL_SHA = '148240c1dcb8b11d8e5a0a9e991f6874c4e799c9744707bf0fb32a8efeb0468d'
NORM_SHA = '534fda818c030a56960e95d0f3ac1e350d887d03db7f80f1d6453195a502b7f0'
RELEASE_SOURCE = '516975ef6482f983ace347cb10de7450d2fbd680'
STEP_COLUMNS = (*COLUMNS, 'omega_F', 'omega_U', 'omega_L')
@@ -161,12 +162,12 @@ def precursor(cfgpath, scale, warm, si, targets, out, start, cap):
return seed, force
def run_arm(name, cfgpath, scale, si, intervals, seed, initial_force, model, norm, out, start, cap):
def run_arm(name, cfgpath, scale, si, intervals, seed, initial_force, model, norm, out, start, cap, *, mass_ratio=2.):
from CelerisLab import Simulation
from CelerisLab.body.motion import MovingTables
cols = {k:i for i, k in enumerate(MovingTables.DIAG)}
diameter = 20.*scale
structure = Structure(2., 1.e-4/scale**2, 0., diameter)
structure = Structure(mass_ratio, 1.e-4/scale**2, 0., diameter)
arm = out/name
arm.mkdir()
rows = np.lib.format.open_memmap(arm/'steps.npy', mode='w+', dtype=np.float64,
@@ -244,16 +245,45 @@ def run_arm(name, cfgpath, scale, si, intervals, seed, initial_force, model, nor
(arm/'report.json').write_text(json.dumps(report,indent=2)+'\n')
def saved_release(directory):
"""Read the retained m*=2 static release; not a moving-state restart."""
case = json.loads((directory/'case.json').read_text())
expected = dict(source=RELEASE_SOURCE, model_sha256=MODEL_SHA, norm_sha256=NORM_SHA,
smoke=False, D=40, U=.005, nu=.004, warmup_each=2048000,
target_intervals=150, SI=3200)
if any(case.get(k) != v for k, v in expected.items()):
raise ValueError('saved release case does not match the frozen precursor')
if json.loads((directory/'config.json').read_text()) != config(40):
raise ValueError('saved release config differs')
with np.load(directory/'release.npz') as data:
seed = (data['current'], data['spare'], data['flags'], int(data['clock']))
force = float(data['force'])
transfer = json.loads((directory/'zero/report.json').read_text())['release_transfer']
if seed[3] != transfer['clock'] or seed[3] != 4576000 or not np.isfinite(force):
raise ValueError('saved release clock/force differs')
if [array_sha(a) for a in seed[:3]] != [transfer[k] for k in ('current','spare','flags')]:
raise ValueError('saved release buffer/flags hash differs')
target = np.load(directory/'target.npy')
if target.shape != (150,6) or not np.isfinite(target).all():
raise ValueError('saved target is incomplete or nonfinite')
return seed, force
def main():
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument('--model', type=Path, required=True)
ap.add_argument('--norm', type=Path, required=True)
ap.add_argument('--out', type=Path, required=True)
ap.add_argument('--smoke', action='store_true', help='short plumbing only; no physical conclusion')
ap.add_argument('--mass-ratio', type=float, choices=(2.,4.), default=2.,
help='4 is the single declared exploratory candidate; fn and damping unchanged')
ap.add_argument('--release-dir', type=Path, help='retained m*=2 precursor; skip warmup')
ap.add_argument('--wall-seconds', type=float, default=14400.)
args = ap.parse_args()
if not np.isfinite(args.wall_seconds) or args.wall_seconds<=0:
ap.error('positive finite wall cap required')
if args.release_dir is not None and args.smoke:
ap.error('saved physical release cannot be used for the plumbing smoke')
if sha(args.model)!=MODEL_SHA or sha(args.norm)!=NORM_SHA:
ap.error('model/normalizer must match frozen provenance')
out = args.out.resolve()
@@ -272,14 +302,24 @@ def main():
response_steps=si*intervals,response_tU_D=si*intervals*.005/40,
rhs='previous native step sum CME_y+Wen_y; policy uses interval packed CME',
probe_frame='lab-fixed; fine area mean * 2 * trained 78 cells',
ema_native_alpha=.9**.25, structural_damping=0., columns=STEP_COLUMNS)
ema_native_alpha=.9**.25, structural_damping=0., mass_ratio=args.mass_ratio,
exploratory=args.mass_ratio==4., columns=STEP_COLUMNS)
loaded = None
if args.release_dir is not None:
loaded = saved_release(args.release_dir)
cfgpath.write_bytes((args.release_dir/'config.json').read_bytes())
(out/'target.npy').write_bytes((args.release_dir/'target.npy').read_bytes())
receipt.update(release_dir=str(args.release_dir.resolve()), release_source=RELEASE_SOURCE,
release_sha256=sha(args.release_dir/'release.npz'),
warmup_executed=0, target_sha256=sha(out/'target.npy'))
(out/'case.json').write_text(json.dumps(receipt,indent=2)+'\n')
start = time.monotonic()
status = 'running'
try:
seed, force = precursor(cfgpath,scale,warm,si,targets,out,start,args.wall_seconds)
seed, force = loaded if loaded is not None else precursor(cfgpath,scale,warm,si,targets,out,start,args.wall_seconds)
for name in ('zero','controlled'):
run_arm(name,cfgpath,scale,si,intervals,seed,force,model,norm,out,start,args.wall_seconds)
run_arm(name,cfgpath,scale,si,intervals,seed,force,model,norm,out,start,args.wall_seconds,
mass_ratio=args.mass_ratio)
status = 'smoke_completed' if args.smoke else 'pair_completed_not_qualified'
except BaseException as exc:
status = f'error: {type(exc).__name__}: {exc}'