fix(oid): code cleanup — fix NameError, remove ROI cropping, consolidate

- Fix NameError (cfg_sid -> cfg["scene_id"]) in collect_controlled.py
- Remove ROI cropping in phase1_correction_pod.py (use full 1280x512)
- Add pinball_baseline_illusion to configs.py and data_dir_for_scene()
- Deprecate compute_delta_fields.py (superseded by phase1_correction_pod)
- Fix absolute path in save_robustness.py
- Clean redundant import in phase3_force_oid.py
- Suppress module-level print in phase6_comparison.py

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Frank14f 2026-06-28 17:13:32 +08:00
parent 56e3c78a83
commit 225f653840
7 changed files with 54 additions and 33 deletions

View File

@ -107,13 +107,6 @@ def load_scene_fields(scene_key: str) -> Optional[Dict]:
return result return result
def mask_field(ux: np.ndarray, uy: np.ndarray,
x_start: int = 400, x_end: int = 1000,
y_start: int = 100, y_end: int = 400) -> Tuple[np.ndarray, np.ndarray]:
"""Crop field to ROI region."""
return ux[:, y_start:y_end, x_start:x_end], uy[:, y_start:y_end, x_start:x_end]
def fields_to_snapshot_matrix(ux: np.ndarray, uy: np.ndarray) -> np.ndarray: def fields_to_snapshot_matrix(ux: np.ndarray, uy: np.ndarray) -> np.ndarray:
"""Convert (N, ny, nx) field time series to (N, DOF) snapshot matrix.""" """Convert (N, ny, nx) field time series to (N, DOF) snapshot matrix."""
N = ux.shape[0] N = ux.shape[0]
@ -142,27 +135,22 @@ def run_phase1(scene_key: str):
ux_blk, uy_blk = fields["q_blk_dir"] ux_blk, uy_blk = fields["q_blk_dir"]
ux_ctl, uy_ctl = fields["q_ctl_dir"] ux_ctl, uy_ctl = fields["q_ctl_dir"]
# Mask to ROI # Build delta fields (full 1280x512, no ROI cropping per project rules)
ux_in_m, uy_in_m = mask_field(ux_in, uy_in) delta_ux_blk = ux_blk - ux_in
ux_blk_m, uy_blk_m = mask_field(ux_blk, uy_blk) delta_uy_blk = uy_blk - uy_in
ux_ctl_m, uy_ctl_m = mask_field(ux_ctl, uy_ctl) delta_ux_ctl = ux_ctl - ux_blk
delta_uy_ctl = uy_ctl - uy_blk
# Delta fields
ux_delta_blk = ux_blk_m - ux_in_m
uy_delta_blk = uy_blk_m - uy_in_m
ux_delta_ctl = ux_ctl_m - ux_blk_m
uy_delta_ctl = uy_ctl_m - uy_blk_m
# Save delta fields # Save delta fields
np.savez_compressed(os.path.join(out_dir, "delta_q_blk.npz"), np.savez_compressed(os.path.join(out_dir, "delta_q_blk.npz"),
ux=ux_delta_blk, uy=uy_delta_blk) ux=delta_ux_blk, uy=delta_uy_blk)
np.savez_compressed(os.path.join(out_dir, "delta_q_ctl.npz"), np.savez_compressed(os.path.join(out_dir, "delta_q_ctl.npz"),
ux=ux_delta_ctl, uy=uy_delta_ctl) ux=delta_ux_ctl, uy=delta_uy_ctl)
print(f" Delta fields saved") print(f" Delta fields saved")
# Snapshot matrices # Snapshot matrices
Q_delta = fields_to_snapshot_matrix(ux_delta_ctl, uy_delta_ctl) Q_delta = fields_to_snapshot_matrix(delta_ux_ctl, delta_uy_ctl)
Q_raw = fields_to_snapshot_matrix(ux_ctl_m, uy_ctl_m) Q_raw = fields_to_snapshot_matrix(ux_ctl, uy_ctl)
print(f" Snapshot matrix: {Q_delta.shape} (N={Q_delta.shape[0]}, DOF={Q_delta.shape[1]})") print(f" Snapshot matrix: {Q_delta.shape} (N={Q_delta.shape[0]}, DOF={Q_delta.shape[1]})")

View File

@ -21,7 +21,7 @@ if _REPO not in sys.path:
from OID_analysis.configs import DATA_DIR # noqa: E402 from OID_analysis.configs import DATA_DIR # noqa: E402
from OID_analysis.utils.analysis import ( # noqa: E402 from OID_analysis.utils.analysis import ( # noqa: E402
compute_force_oid, compute_force_oid as compute_oid, compute_force_oid,
standardize, reconstruct_oid_modes, standardize, reconstruct_oid_modes,
) )

View File

@ -35,7 +35,7 @@ try:
HAS_SKLEARN = True HAS_SKLEARN = True
except ImportError: except ImportError:
HAS_SKLEARN = False HAS_SKLEARN = False
print("WARNING: sklearn not available. Install: pip install scikit-learn") # sklearn unavailable — comparison will be skipped
SCENES = ["steady_cloak", "karman_re100", SCENES = ["steady_cloak", "karman_re100",

View File

@ -1,9 +1,16 @@
"""Save robustness results and write comprehensive report.""" """Save robustness results.
WARNING: This file contains hardcoded numerical results from a previous run.
It is a one-shot results-saver. If the pipeline is re-run with different data
or parameters, this file MUST be manually updated or replaced by
robustness_analysis.py which generates robustness_results.json dynamically.
"""
import json, os, sys import json, os, sys
_REPO = "/home/frank14f/DynamisLab" _REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
sys.path.insert(0, os.path.join(_REPO, "src")) sys.path.insert(0, _REPO)
from OID_analysis.configs import DATA_DIR from OID_analysis.configs import DATA_DIR
# Hardcoded results from ~2026-06-22 run. Update if pipeline re-runs.
results = { results = {
"rank_sensitivity": { "rank_sensitivity": {
"steady_cloak": {"r6": -0.4865, "r8": -0.7764, "r10": -0.7631, "r12": -0.7261, "r16": -0.6756}, "steady_cloak": {"r6": -0.4865, "r8": -0.7764, "r10": -0.7631, "r12": -0.7261, "r16": -0.6756},
@ -37,4 +44,4 @@ out_dir = os.path.join(DATA_DIR, "derived", "robustness")
os.makedirs(out_dir, exist_ok=True) os.makedirs(out_dir, exist_ok=True)
with open(os.path.join(out_dir, "robustness_results.json"), "w") as f: with open(os.path.join(out_dir, "robustness_results.json"), "w") as f:
json.dump(results, f, indent=2) json.dump(results, f, indent=2)
print("Saved.") print("Saved robustness_results.json (hardcoded — update manually if re-running pipeline).")

View File

@ -74,6 +74,26 @@ SCENES["pinball_baseline"] = {
"u0": U0, "u0": U0,
} }
# -- Pure Pinball (illusion positions) ---------------------------------------
SCENES["pinball_baseline_illusion"] = {
"scene_id": "pinball_baseline_illusion",
"re_code": 100,
"nu": 0.004,
"has_disturbance": False,
"sample_interval": 800,
"action_scale": 8.0,
"action_bias": (0.0, -2.0, 2.0),
"source": "open_loop",
"n_objects_env": 6,
"obs_slice": (0, 12),
"sensor_x": 30.0,
"pinball_front_x": 19.0,
"pinball_rear_x": 20.3,
"target_type": "periodic",
"s_dim": 12,
"u0": U0,
}
# -- Disturbance Only (Karman inflow) ---------------------------------------- # -- Disturbance Only (Karman inflow) ----------------------------------------
SCENES["disturbance_only"] = { SCENES["disturbance_only"] = {
"scene_id": "disturbance_only", "scene_id": "disturbance_only",
@ -244,6 +264,8 @@ def data_dir_for_scene(scene_name: str) -> str:
return os.path.join(DATA_DIR, "steady_cloak", "empty_channel") return os.path.join(DATA_DIR, "steady_cloak", "empty_channel")
elif sid == "pinball_baseline": elif sid == "pinball_baseline":
return os.path.join(DATA_DIR, "steady_cloak", "pinball_baseline") return os.path.join(DATA_DIR, "steady_cloak", "pinball_baseline")
elif sid == "pinball_baseline_illusion":
return os.path.join(DATA_DIR, "steady_cloak", "pinball_baseline_illusion")
elif sid == "steady_cloak": elif sid == "steady_cloak":
return os.path.join(DATA_DIR, "steady_cloak", "steady_cloak") return os.path.join(DATA_DIR, "steady_cloak", "steady_cloak")
# Karman group: separate dirs for q_in, q_blk, q_ctl # Karman group: separate dirs for q_in, q_blk, q_ctl

View File

@ -171,7 +171,7 @@ def collect_single(scene_name: str, device_id: int, n_steps: int) -> dict:
# ---- Target signals (needed for s_dim=14 illusion) ---- # ---- Target signals (needed for s_dim=14 illusion) ----
target_states = None target_states = None
target_harmonics = None target_harmonics = None
if cfg_sid == "illusion": if cfg["scene_id"] == "illusion":
target_path = os.path.join(out_dir, "target.npz") target_path = os.path.join(out_dir, "target.npz")
harm_path = os.path.join(out_dir, "target_harmonics.json") harm_path = os.path.join(out_dir, "target_harmonics.json")
if os.path.isfile(target_path) and os.path.isfile(harm_path): if os.path.isfile(target_path) and os.path.isfile(harm_path):
@ -248,9 +248,9 @@ def collect_single(scene_name: str, device_id: int, n_steps: int) -> dict:
# Compute similarity # Compute similarity
conv_len = cfg.get("conv_len", CONV_LEN_DEFAULT) conv_len = cfg.get("conv_len", CONV_LEN_DEFAULT)
if target_states is not None: if target_states is not None:
if cfg_sid == "karman": if "karman" in cfg["scene_id"]:
sim = compute_similarity(target_states, sens_arr, conv_len) sim = compute_similarity(target_states, sens_arr, conv_len)
elif cfg_sid == "illusion": elif cfg["scene_id"] == "illusion":
# For illusion, target_states[:, 2:8] has the sensor references # For illusion, target_states[:, 2:8] has the sensor references
target_sensors = target_states[:, 2:8] if target_states.shape[1] >= 8 else target_states target_sensors = target_states[:, 2:8] if target_states.shape[1] >= 8 else target_states
sim = compute_similarity(target_sensors, sens_arr, conv_len) sim = compute_similarity(target_sensors, sens_arr, conv_len)

View File

@ -1,8 +1,12 @@
# OID_analysis/scripts/compute_delta_fields.py # OID_analysis/scripts/compute_delta_fields.py
""" """
Compute Delta_q_blk and Delta_q_ctl from collected fields. DEPRECATED Phase 0 draft. Always SKIPPED at runtime due to filename collision.
Compute zone statistics. This file is superseded by analysis/phase1_correction_pod.py which handles the full
Gate check: does Delta_q_ctl have clear structure? correction-field computation, POD, and saves delta_q_blk/delta_q_ctl.
Kept for reference only. Do NOT use for pipeline runs.
"""
# This file is intentionally non-functional. See phase1_correction_pod.py for
# the canonical correction-field computation.
Usage: Usage:
python3 src/OID_analysis/scripts/compute_delta_fields.py python3 src/OID_analysis/scripts/compute_delta_fields.py