feat(ccd): add dual-clock field sampling
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import os
|
||||
import sys
|
||||
import time
|
||||
from collections import deque
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -36,6 +37,7 @@ from CCD_analysis.utils.cfd_interface import (
|
||||
calc_lag, calc_dtw_sim,
|
||||
)
|
||||
from CCD_analysis.utils.resampling import analyze_harmonics, gen_target_states_at
|
||||
from CCD_analysis.utils.dual_clock import DualClockCollector, field_steps_from_interval
|
||||
|
||||
DATA_TYPE = np.float32
|
||||
L0 = 20.0
|
||||
@@ -44,9 +46,17 @@ FIFO_LEN = 150
|
||||
CONV_LEN = 36
|
||||
|
||||
|
||||
def run_single(scene_name: str, device_id: int, n_steps: int) -> dict:
|
||||
def run_single(
|
||||
scene_name: str,
|
||||
device_id: int,
|
||||
n_steps: int,
|
||||
*,
|
||||
field_interval: int | None = None,
|
||||
output_dir: str | None = None,
|
||||
) -> dict:
|
||||
cfg = get_scene(scene_name)
|
||||
out_dir = data_dir_for_scene(scene_name)
|
||||
out_dir = output_dir or data_dir_for_scene(scene_name)
|
||||
Path(out_dir).mkdir(parents=True, exist_ok=True)
|
||||
u0 = cfg["u0"]
|
||||
si = cfg["sample_interval"]
|
||||
ac_scale = cfg["action_scale"]
|
||||
@@ -152,6 +162,15 @@ def run_single(scene_name: str, device_id: int, n_steps: int) -> dict:
|
||||
|
||||
obs = np.zeros(s_dim, dtype=np.float32)
|
||||
sens_c, forc_c, act_c, rew_c, sim_c = [], [], [], [], []
|
||||
collector = None
|
||||
if field_interval is not None:
|
||||
collector = DualClockCollector(
|
||||
ff,
|
||||
control_interval=si,
|
||||
control_count=n_steps,
|
||||
u0=u0,
|
||||
field_steps=field_steps_from_interval(si * n_steps, field_interval),
|
||||
)
|
||||
|
||||
for step in range(n_steps):
|
||||
action, _ = model.predict(obs, deterministic=True)
|
||||
@@ -163,7 +182,10 @@ def run_single(scene_name: str, device_id: int, n_steps: int) -> dict:
|
||||
temp_a[3:6] = omega
|
||||
|
||||
ff.context.push()
|
||||
ff.run(si, temp_a)
|
||||
if collector is None:
|
||||
ff.run(si, temp_a)
|
||||
else:
|
||||
collector.run_interval(step, temp_a)
|
||||
ff.context.pop()
|
||||
|
||||
obs_slice = ff.obs.copy()[0:12]
|
||||
@@ -219,6 +241,8 @@ def run_single(scene_name: str, device_id: int, n_steps: int) -> dict:
|
||||
np.savez(os.path.join(out_dir, "controlled.npz"),
|
||||
sensors=sens_arr, forces=forc_arr, actions=act_arr,
|
||||
rewards=np.array(rew_c, dtype=np.float32))
|
||||
if collector is not None:
|
||||
collector.save(Path(out_dir) / "fields.npz")
|
||||
|
||||
save_vorticity_png(os.path.join(out_dir, "vorticity_controlled.png"),
|
||||
vorticity_from_ddf(ff, u0=u0),
|
||||
@@ -229,7 +253,13 @@ def run_single(scene_name: str, device_id: int, n_steps: int) -> dict:
|
||||
avg_sim = float(np.mean(sim_c[-tail:])) if sim_c else 0.0
|
||||
print(f" reward={avg_reward:.4f} similarity={avg_sim:.4f}")
|
||||
|
||||
result = {"scene": scene_name, "similarity": avg_sim, "avg_reward": avg_reward}
|
||||
result = {
|
||||
"scene": scene_name,
|
||||
"similarity": avg_sim,
|
||||
"avg_reward": avg_reward,
|
||||
"control_interval": si,
|
||||
"field_interval": field_interval,
|
||||
}
|
||||
with open(os.path.join(out_dir, "result.json"), "w") as f:
|
||||
json.dump(result, f, indent=2)
|
||||
|
||||
@@ -245,6 +275,10 @@ def main():
|
||||
help="Diameter shortcut (0.75, 1.0, 1.5)")
|
||||
ap.add_argument("--device", type=int, default=2)
|
||||
ap.add_argument("--steps", type=int, default=200)
|
||||
ap.add_argument("--field-interval", type=int, default=None,
|
||||
help="Save fields every N absolute lattice steps")
|
||||
ap.add_argument("--output-dir", type=str, default=None,
|
||||
help="Optional isolated output directory")
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.diameter is not None:
|
||||
@@ -257,7 +291,10 @@ def main():
|
||||
return 1
|
||||
|
||||
t0 = time.time()
|
||||
r = run_single(scene_name, args.device, args.steps)
|
||||
r = run_single(
|
||||
scene_name, args.device, args.steps,
|
||||
field_interval=args.field_interval, output_dir=args.output_dir,
|
||||
)
|
||||
print(f"Done in {time.time()-t0:.1f}s: sim={r['similarity']:.4f}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user