Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
580397eaf8 | ||
|
|
ded0c52975 | ||
|
|
c2936a400e | ||
|
|
3c6c9c690a | ||
|
|
f04036e4e4 |
@@ -0,0 +1,116 @@
|
||||
"""Replay the frozen Legacy karman_re100 PPO policy on current CelerisLab.
|
||||
|
||||
Research only; nothing in src/ is changed. Plant: Legacy Karman cloak scene
|
||||
(1280x512, D=20, parabolic inlet, mean U0 .01, nu .004, Re_D 50; upstream
|
||||
cylinder r=20 at x=200; pinball front (600, 255.5), rear (626, 255.5+-15);
|
||||
probes r=5 at x=800, y=255.5+40/0/-40). Interface contract = DynamisLab
|
||||
legacy_test (the executor behind the Legacy rerun), not f2f88c phase3:
|
||||
|
||||
- command per interval: A = (8 a + b) U0, b = (0, -4, 4), a = deterministic
|
||||
policy output in [-1, 1]^3; wall speed command, omega = +A / R (both
|
||||
solvers impose u_w = omega x r, CCW positive);
|
||||
- smoothing per LATTICE step, A_eff <- .9 A_eff + .1 A, with A_eff = 0 at the
|
||||
start of every 800-step interval (legacy_test.runtime.run_historical_interval);
|
||||
- observation: interval means of the three pinball forces (front, top, bottom)
|
||||
and the three probe (ux, uy) sums, normalized by the frozen norm.json with
|
||||
legacy_test.runtime.policy_observation; the first observation is zero.
|
||||
|
||||
Output (--out, outside the checkout): signals.npz with sensors (N,6), forces
|
||||
(N,6), actions (N,3) in the f2f88c phase3 layout, so its comparator applies.
|
||||
|
||||
PYTHONPATH=src python research/karman_reproduce/run.py --dynamis DYN --model .../d1a3o12_re100.zip \\
|
||||
--norm .../karman_re100/norm.json --config .../config_lbm_pinball_legacy_compat.json \\
|
||||
--out /tmp/new-dir [--device 1]
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
L0, U0, NX, NY = 20.0, 0.01, 1280, 512
|
||||
R, YC = L0 / 2, (NY - 1) / 2
|
||||
SI, INTERVALS, WARMUP, FIFO_LEN = 800, 200, int(4 * NX / U0), 150
|
||||
BIAS = np.array([0.0, -4.0, 4.0])
|
||||
|
||||
|
||||
def git_head(path):
|
||||
return subprocess.run(["git", "-C", path, "rev-parse", "HEAD"], capture_output=True,
|
||||
text=True).stdout.strip()
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--dynamis", required=True, help="DynamisLab checkout (imported read-only)")
|
||||
ap.add_argument("--model", required=True, help="frozen d1a3o12_re100.zip")
|
||||
ap.add_argument("--norm", required=True, help="frozen karman_re100 norm.json")
|
||||
ap.add_argument("--config", required=True)
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--device", type=int, default=0)
|
||||
ap.add_argument("--intervals", type=int, default=INTERVALS)
|
||||
args = ap.parse_args()
|
||||
here = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
if os.path.realpath(args.out).startswith(here):
|
||||
raise SystemExit("--out must be outside the checkout")
|
||||
os.makedirs(args.out) # fresh directory only; never overwrite results
|
||||
|
||||
sys.dont_write_bytecode = True # import only: write nothing into the DynamisLab tree
|
||||
sys.path.insert(0, os.path.join(args.dynamis, "src"))
|
||||
from stable_baselines3 import PPO
|
||||
from drl_pinball.legacy_test.core.model_loader import _dummy_env
|
||||
from drl_pinball.legacy_test.runtime import load_policy_norm, policy_observation
|
||||
model = PPO.load(args.model, env=_dummy_env(12), device="cpu")
|
||||
norm = load_policy_norm(args.norm)
|
||||
|
||||
from CelerisLab.simulation import Simulation
|
||||
sim = Simulation(args.config, device_id=args.device)
|
||||
try:
|
||||
sim.add_body("circle", center=(10 * L0, YC, 0.0), radius=L0)
|
||||
probes = [sim.add_body("sensor", center=(40 * L0, YC + dy, 0.0), radius=5.0)
|
||||
for dy in (40.0, 0.0, -40.0)]
|
||||
sim.initialize()
|
||||
# Legacy build_karman_cloak order: stabilize disturbance + probes, then the
|
||||
# 150-interval zero-action target sampling (kept as flow time), then the pinball.
|
||||
sim.run(WARMUP + FIFO_LEN * SI)
|
||||
n0 = sim.bodies.count
|
||||
for c in ((30 * L0, YC, 0.0), (626.0, YC + 15, 0.0), (626.0, YC - 15, 0.0)):
|
||||
sim.add_body("circle", center=c, radius=R) # pending (negative) id until sync
|
||||
sim.sync_bodies()
|
||||
pinball = list(range(n0, n0 + 3)) # committed ids, as in f2f88c phase3
|
||||
sim.run(WARMUP)
|
||||
cells = float(len(sim.bodies.get(probes[0]).get_sensor_list(NX, NY)[0])) # probe sum = mean * cells
|
||||
|
||||
obs = np.zeros(12, np.float32)
|
||||
sensors, forces, actions = (np.zeros((args.intervals, n), np.float32) for n in (6, 6, 3))
|
||||
for n in range(args.intervals):
|
||||
a = np.asarray(model.predict(obs, deterministic=True)[0], np.float32).reshape(3)
|
||||
target, eff = (8.0 * a + BIAS) * U0, np.zeros(3)
|
||||
for k in range(SI):
|
||||
eff = 0.9 * eff + 0.1 * target
|
||||
for pid, w in zip(pinball, eff / R):
|
||||
sim.set_body(pid, omega=float(w))
|
||||
sim.run(1, zero_obs=(k == 0), sync_obs=(k == SI - 1))
|
||||
s = [v * cells for pid in probes for v in sim.read_sensor(pid)[:2]]
|
||||
f = [v for pid in pinball for v in sim.read_force(pid)[:2]]
|
||||
raw = np.asarray(s + f, np.float32)
|
||||
if not np.all(np.isfinite(raw)):
|
||||
raise RuntimeError(f"non-finite observation at interval {n}")
|
||||
sensors[n], forces[n], actions[n] = raw[:6], raw[6:], a
|
||||
obs = policy_observation(raw, norm)
|
||||
np.savez_compressed(os.path.join(args.out, "signals.npz"), sensors=sensors,
|
||||
forces=forces, actions=actions)
|
||||
with open(os.path.join(args.out, "case.json"), "w") as fh:
|
||||
json.dump(dict(celeris=git_head(here), dynamis=git_head(args.dynamis),
|
||||
config=os.path.realpath(args.config), model=os.path.realpath(args.model),
|
||||
norm=os.path.realpath(args.norm), warmup=WARMUP, target_sampling=FIFO_LEN * SI, interval=SI, intervals=args.intervals,
|
||||
probe_cells=cells), fh, indent=1)
|
||||
finally:
|
||||
sim.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user