From ca8ee5f238ee58eaaf48027ad026c35784f76d4d Mon Sep 17 00:00:00 2001 From: Frank14f <1515444314@qq.com> Date: Thu, 16 Jul 2026 22:03:20 +0800 Subject: [PATCH] chore(SR): freeze legacy SR_analysis snapshot before contract repair Create pre-fix baseline with: - Manifest recording ignored NPZ hashes, model inventory, env versions - Plan file for long-term SR Legacy Pipeline execution - Snapshot of current stage_1_infer, PIPELINE, STAGE_1_INFER, results/README This commit preserves the frozen historical state before Stage 1-3 contract repair begins. All canonical results are marked historical_frozen; no formula or validation data will be overwritten during round 1. Round 1 scope: legacy Karman (code Re 50/100/200/400) + Illusion (0.75L/1L). V5, Vortex, unseen-Re, erase, 1.5L, and paper figures excluded. Co-authored-by: Cursor --- src/SR_analysis/PIPELINE.md | 2 +- src/SR_analysis/STAGE_1_INFER.md | 6 +- src/SR_analysis/results/README.md | 2 +- .../results/runs/pre_fix_manifest.json | 105 ++++++++++++ .../sr_legacy_pipeline_bf1c2e74.plan.md | 162 ++++++++++++++++++ src/SR_analysis/stage_1_infer.py | 16 +- 6 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 src/SR_analysis/results/runs/pre_fix_manifest.json create mode 100644 src/SR_analysis/sr_legacy_pipeline_bf1c2e74.plan.md diff --git a/src/SR_analysis/PIPELINE.md b/src/SR_analysis/PIPELINE.md index 71bdb69..0485f76 100644 --- a/src/SR_analysis/PIPELINE.md +++ b/src/SR_analysis/PIPELINE.md @@ -88,7 +88,7 @@ done **Output per scene** (in `data/{scene_id}/{scene_name}/`): - `controlled.npz`: actions [N,3], sensors [N,6], forces [N,6] -- `target.npz`: target sensor signals [FIFO_LEN, 6] +- `target.npz`: target signals [FIFO_LEN, 6] for Karman/Vortex; **8 columns for Illusion** = [cyl_fx,cyl_fy, s0_ux,s0_uy, s1_ux,s1_uy, s2_ux,s2_uy] — extract sensors with `target[:, 2:8]` - `norm.json`: normalization factors - `result.json`: similarity + reward summary - `target_harmonics.json` (Illusion only): FFT harmonics for force reconstruction diff --git a/src/SR_analysis/STAGE_1_INFER.md b/src/SR_analysis/STAGE_1_INFER.md index 7386ec9..921439f 100644 --- a/src/SR_analysis/STAGE_1_INFER.md +++ b/src/SR_analysis/STAGE_1_INFER.md @@ -23,7 +23,11 @@ actions in controlled.npz are normalized [-1,+1]. Physical omega = (action*scale ## Per-Scene Notes - **Karman**: 7 objects, obs_slice=(2,14), action_bias=[0,-4,4], s_dim=12 -- **Illusion**: 6 objects, obs_slice=(0,12), action_bias=[0,-2,2], s_dim=14, FIFO bias=[0,-U0,U0] differs from DRL bias +- **Illusion**: 6 objects, obs_slice=(0,12), action_bias=[0,-2,2], s_dim=14, FIFO bias=[0,-U0,U0] differs from DRL bias. + **target.npz format**: 8 columns = [cyl_fx, cyl_fy, s0_ux, s0_uy, s1_ux, s1_uy, s2_ux, s2_uy]. + Consumers must use `target[:, 2:8]` to extract the 6 pure-sensor channels. + (Historical: stage_1_infer.py had a `[:, :6]` write bug that omitted s2; fixed 2026-07-14. + On-disk files were regenerated with gen_illusion_target.py and are correct.) - **Vortex**: 6 objects, MAX_STEPS=150, action_scale=4, vortex added after DDF checkpoint ## Expected Similarities diff --git a/src/SR_analysis/results/README.md b/src/SR_analysis/results/README.md index 6911419..574c3bd 100644 --- a/src/SR_analysis/results/README.md +++ b/src/SR_analysis/results/README.md @@ -54,7 +54,7 @@ |------|---------| | `data/karman/karman_re{50,100,200,400}/controlled.npz` | PPO actions, sensors, forces | | `data/illusion/illusion_{0.5L..2L}/controlled.npz` | PPO data (trained diameters only) | -| `data/illusion/illusion_{0.5L..2L}/target.npz` | Target sensor signals | +| `data/illusion/illusion_{0.5L..2L}/target.npz` | Target signals (8 columns: [cyl_fx,cyl_fy, s0_ux,s0_uy, s1_ux,s1_uy, s2_ux,s2_uy]; use `[:, 2:8]` for pure sensor channels) | | `data/illusion/illusion_{0.5L..2L}/target_harmonics.json` | FFT harmonics | | `data/vortex/vortex_{lamb,taylor}/controlled.npz` | Vortex PPO data | diff --git a/src/SR_analysis/results/runs/pre_fix_manifest.json b/src/SR_analysis/results/runs/pre_fix_manifest.json new file mode 100644 index 0000000..a68bee5 --- /dev/null +++ b/src/SR_analysis/results/runs/pre_fix_manifest.json @@ -0,0 +1,105 @@ +{ + "schema_version": "sr_legacy_manifest_v1", + "snapshot_id": "pre_fix_round1", + "created_at_utc": "2026-07-16T14:00:00Z", + "status": "historical_frozen", + "pipeline": "legacy_karman_illusion", + "purpose": "Baseline snapshot before Stage1-3 contract repair. All results and data are canonical from previous sessions; do NOT overwrite.", + "git_commit": "4feac49f1cc32925cbac9c2f24a5beaaba74b796", + "git_branch": "main", + "git_upstream": "origin/main", + "git_ahead_behind": "+0/-0", + "git_dirty": true, + "worktree_notes": "SR_analysis has 4 modified tracked files (PIPELINE.md, STAGE_1_INFER.md, results/README.md, stage_1_infer.py). Other modules (LegacyCelerisLab, drl_pinball) also modified but excluded from this SR snapshot scope. Untracked V5 files (bridge_v5.py, stage_2_fit_v5.py, data/v5/, results/formulas_v5/) excluded.", + "environment": { + "pycuda_3_10": { + "python": "3.10.13", + "numpy": "1.26.4", + "torch": "2.5.1+cu124", + "sympy": "1.13.1", + "stable_baselines3": "2.4.0", + "cuda_available": "check at runtime (sandbox may differ)", + "platform": "Linux-6.8.0-124-generic-x86_64" + }, + "sr_env": { + "python": "3.10.20", + "numpy": "2.2.6", + "sympy": "1.14.0" + }, + "gpu": "device 2 recommended; verify with nvidia-smi -i 2 at runtime" + }, + "ignored_npz_count": 46, + "ignored_npz": [ + {"path": "src/SR_analysis/data/illusion/illusion_0.5L/target.npz", "size_bytes": 8940, "sha256": "ab0832bf6418afa8b4ba9c9527c3c2fde2628b76e4d6513f8f5ebba08c00e868"}, + {"path": "src/SR_analysis/data/illusion/illusion_0.6L/target.npz", "size_bytes": 8940, "sha256": "e6e4dd001c8ca2a6c5a481983e762f5caf74f61a13c7e93bdad8010fe758f12f"}, + {"path": "src/SR_analysis/data/illusion/illusion_0.75L/controlled.npz", "size_bytes": 14616, "sha256": "f4e88a26ce5cb2121a40f4c098fa5f3151ba0ea1c1c0e2d6a6e1cf58f6f01499"}, + {"path": "src/SR_analysis/data/illusion/illusion_0.75L/target.npz", "size_bytes": 8940, "sha256": "c96e23010f2f11f4a6a46c571acbd9ccb2f80464a5242cb02dcf62df512d0f4a"}, + {"path": "src/SR_analysis/data/illusion/illusion_0.8L/target.npz", "size_bytes": 8940, "sha256": "8eca70a94aa937fb59a1e6121b6a2d1603ff48eac4be227c2cb46fb4b5c17d1d"}, + {"path": "src/SR_analysis/data/illusion/illusion_1.2L/target.npz", "size_bytes": 8940, "sha256": "ba5236e029658cf9e5b1ee0db9af2353e4da0b5a5d405cef5fd4a49e64cc2656"}, + {"path": "src/SR_analysis/data/illusion/illusion_1.5L/controlled.npz", "size_bytes": 14616, "sha256": "78b13c41c2e9913d3b18fb0c457e6c6a778ac8e7c8afebfa3e0a1811a10712a5"}, + {"path": "src/SR_analysis/data/illusion/illusion_1.5L/target.npz", "size_bytes": 8940, "sha256": "69c7885632247848c47b5b1405bca5b5e3c7d1cf922994c03f41484e7fae945f"}, + {"path": "src/SR_analysis/data/illusion/illusion_1L/controlled.npz", "size_bytes": 14616, "sha256": "755dfc4b3ef4e25198c17abfb4eecf6cd98b2351b5183557ca861d04cd9e1599"}, + {"path": "src/SR_analysis/data/illusion/illusion_1L/target.npz", "size_bytes": 8940, "sha256": "33c0034102b14b3495e2ec3944a4d788cb01f7833fc438f4a8302b8caf15038e"}, + {"path": "src/SR_analysis/data/illusion/illusion_2L/target.npz", "size_bytes": 8940, "sha256": "b4d553bb11f088bb31c85137a401551a1c575984eeb56d4ce8df175c5d1b2009"}, + {"path": "src/SR_analysis/data/karman/karman_re100/controlled.npz", "size_bytes": 13804, "sha256": "efd8eaab807dfbaafd741e202f543a7654ed95b201df3a2246e9a8eaf3ed62b6"}, + {"path": "src/SR_analysis/data/karman/karman_re100/target.npz", "size_bytes": 3880, "sha256": "c50dd977de325d603246c8a5b2dcc8972a57a255a46bece69688963dc15a18a8"}, + {"path": "src/SR_analysis/data/karman/karman_re100/uncontrolled.npz", "size_bytes": 10112, "sha256": "e1ca266ee8e18c8019eeab839ca4e7e73b7609d6adf95c1cb94b7333a8e55c8d"}, + {"path": "src/SR_analysis/data/karman/karman_re200/controlled.npz", "size_bytes": 13804, "sha256": "ec7f38dc3a3ee0fce55ffa1e6463a7c6a0c2d0bf00b6d98850da07e65282240e"}, + {"path": "src/SR_analysis/data/karman/karman_re200/target.npz", "size_bytes": 3880, "sha256": "140a0794de258bc8bcf21bd99e0bbbcaad1093c1734a8e9a453faa3ea65cb40f"}, + {"path": "src/SR_analysis/data/karman/karman_re200/uncontrolled.npz", "size_bytes": 10112, "sha256": "0bbd318ce1e27ece0ebf10d6adf6291987bd201474e413eedf572bd2f2541756"}, + {"path": "src/SR_analysis/data/karman/karman_re400/controlled.npz", "size_bytes": 18042, "sha256": "d88141a9299d0092ff82c48e5436c8f1f27f7490ff35abf22f6cda62cfe89453"}, + {"path": "src/SR_analysis/data/karman/karman_re400/target.npz", "size_bytes": 3880, "sha256": "c63869234ebf87145bd1bbe5212356885944a22cc92ccfa78931a04ca70c86cb"}, + {"path": "src/SR_analysis/data/karman/karman_re400/uncontrolled.npz", "size_bytes": 15150, "sha256": "7b9250af15e1c8ed1507468474ca35aef4eaae2cee086b1289ef9f1f663db098"}, + {"path": "src/SR_analysis/data/karman/karman_re50/controlled.npz", "size_bytes": 13804, "sha256": "302bca1d677e1cd82634e5eece612f6a183213d29e7f03f3b5abe42f5bdff2e2"}, + {"path": "src/SR_analysis/data/karman/karman_re50/target.npz", "size_bytes": 3880, "sha256": "5c4f646e7b10861e5578f7b678364434d0ca75497e02e01eb356b958206ee3fa"}, + {"path": "src/SR_analysis/data/karman/karman_re50/uncontrolled.npz", "size_bytes": 10112, "sha256": "b8be401ccb6c2e0ca745a81e02bcf6e8ef02917038d4537e9946ad20ba0c3512"}, + {"path": "src/SR_analysis/data/vortex/vortex_lamb/controlled.npz", "size_bytes": 9758, "sha256": "b6e7e4c9c30daabd126762483d3f5f63641242aedb6df4905e58126e5e38a5f6"}, + {"path": "src/SR_analysis/data/vortex/vortex_lamb/target.npz", "size_bytes": 3880, "sha256": "7ca30bd783776d52b2297c3fffe2598614bebfe7cefa43f2ef35e1b1e9302b2b"}, + {"path": "src/SR_analysis/data/vortex/vortex_taylor/controlled.npz", "size_bytes": 9758, "sha256": "4c912c96fd33ee19c3bc93bcb92d8a68e04f8f01c496a71434c61866a8d0da25"}, + {"path": "src/SR_analysis/data/vortex/vortex_taylor/target.npz", "size_bytes": 3880, "sha256": "e98045241935e157230e6fcbcc50a1fcd868a24b1b9e4f9d1da8a22397e050c3"}, + {"path": "src/SR_analysis/data/steady/steady/controlled.npz", "size_bytes": 12758, "sha256": "98fe6ff3c1e90684238681758a47ce3f48818c4503c1bde2606d4c4bcdb7a3ae"}, + {"path": "src/SR_analysis/data/steady/steady/target.npz", "size_bytes": 3880, "sha256": "c4eac1e1cfacb9b6a0e2f4d374ea3926e5e39af6c736eeb1fa1fd0f64c239f45"}, + {"path": "src/SR_analysis/data/steady/steady_data.npz", "size_bytes": 16902, "sha256": "fedf4f2216e5ff2c7b1a0becf27de975c2e22a2a4a7d360fc1c7cd22c86c8c6c"}, + {"path": "src/SR_analysis/data/v5/ill_075L_sc/controlled.npz", "size_bytes": 19913, "sha256": "57e1675c866adcc272c81294aea4d1fdfce43a3a6f10cd3e8bbae602c64b5132"}, + {"path": "src/SR_analysis/data/v5/ill_075L_sc/target.npz", "size_bytes": 4704, "sha256": "06ac9d58563f58883b8d88f78810bdfc3a8eab98d88d44e00ba68efe72fbc350"}, + {"path": "src/SR_analysis/data/v5/ill_15L_sc/controlled.npz", "size_bytes": 19207, "sha256": "937c3d082227288ca1e3c2ecfca1cbdb3c5431602c4ea8dba78ec2efc8b52264"}, + {"path": "src/SR_analysis/data/v5/ill_15L_sc/target.npz", "size_bytes": 4713, "sha256": "3d851db7f57c82a61bbbb6320de4fe3fded4264743e824285de081c84f6380ac"}, + {"path": "src/SR_analysis/data/v5/ill_1L_sc/controlled.npz", "size_bytes": 19106, "sha256": "ff59ba323da500b21c4f84b8bed4f85fdb1839eabf9ce72b94bbe39445b112ab"}, + {"path": "src/SR_analysis/data/v5/ill_1L_sc/target.npz", "size_bytes": 4709, "sha256": "f6999035db270b0b82d1be89b39857b08b1e7c0e89d038fb8d77fcce26f1d585"}, + {"path": "src/SR_analysis/data/v5/ill_2L_sc/controlled.npz", "size_bytes": 19792, "sha256": "29823406aa3502c31d2af268067dc647f4a312aaeacc8928c588e4253e96ab24"}, + {"path": "src/SR_analysis/data/v5/ill_2L_sc/target.npz", "size_bytes": 4715, "sha256": "5ceb8245bfed5500900ccd130ebd30fde4f01f2cf17a750253d6bc29703c3a16"}, + {"path": "src/SR_analysis/data/v5/kar_d075_sc/controlled.npz", "size_bytes": 20587, "sha256": "f9a01654d1afebcb7ced4c7f3b91f8720f9e14e75bf91ce1faf366f1d1b62328"}, + {"path": "src/SR_analysis/data/v5/kar_d075_sc/target.npz", "size_bytes": 3521, "sha256": "db8b07109ae6c0463f4b3e33aec4c9fd51448ce27b5bcb3d7ac5c16143d2bdfa"}, + {"path": "src/SR_analysis/data/v5/kar_d15_sc/controlled.npz", "size_bytes": 20518, "sha256": "1a5d3e0a82e48dd964ae91e37e9f85e0c5bce38f6614e3ed16e452caaf90c5cd"}, + {"path": "src/SR_analysis/data/v5/kar_d15_sc/target.npz", "size_bytes": 3533, "sha256": "cb606d3fd511afffb3e3bbc3d22a4ef6f2806d442b2d31c216968c440f61e680"}, + {"path": "src/SR_analysis/data/v5/kar_d2_sc/controlled.npz", "size_bytes": 20493, "sha256": "46edfb1e596f8daa1afc5b72e81c38295a45408dac72b89c2ab21b6748fb1f4e"}, + {"path": "src/SR_analysis/data/v5/kar_d2_sc/target.npz", "size_bytes": 3540, "sha256": "2c081891d2981d5c211258e37d6d877c9a255aa2689ab8ac9120b9fc2eadfeec"}, + {"path": "src/SR_analysis/data/v5/kar_re100_sc/controlled.npz", "size_bytes": 20588, "sha256": "bb020692afa1770982fbb67e8fd67f65fe9c8f8e70a43a7ff4b5bea4a964cd94"}, + {"path": "src/SR_analysis/data/v5/kar_re100_sc/target.npz", "size_bytes": 3536, "sha256": "e8c2ea5456b8bbb321d4f24b0e9170819c7cb4309497825e2bbd01657a7a0535"} + ], + "legacy_models": [ + {"name": "d1a3o12_re50.zip", "path": "models/old/d1a3o12_re50.zip", "size_bytes": 154169, "sha256": "dfd2163b0bf89115303015b010aa5ad5fe95b8f4bd81176a356714a1984445f4"}, + {"name": "d1a3o12_re100.zip", "path": "models/old/d1a3o12_re100.zip", "size_bytes": 154169, "sha256": "148240c1dcb8b11d8e5a0a9e991f6874c4e799c9744707bf0fb32a8efeb0468d"}, + {"name": "d1a3o12_re200.zip", "path": "models/old/d1a3o12_re200.zip", "size_bytes": 154169, "sha256": "62ceb682fbfcff1119e049d306d3ac05144b780f166c2835d7d01ca719ffad11"}, + {"name": "d1a3o12_re400.zip", "path": "models/old/d1a3o12_re400.zip", "size_bytes": 154169, "sha256": "e251240ed1179290345f0331f7e014abb74429ec517039fe5836f5f070352617"}, + {"name": "vortex_lamb.zip", "path": "models/old/vortex_lamb.zip", "size_bytes": 155424, "sha256": "69f2a863b08d2313a46523a5cda8ecc3b988b98cef5a7b67f0cae0b2fc9d6e62"}, + {"name": "vortex_taylor.zip", "path": "models/old/vortex_taylor.zip", "size_bytes": 155543, "sha256": "58882721900f1eb0779f64aea0a2e233d307a94b640b9aaf33efa036db3c79e3"}, + {"name": "imit_075L_1U.zip", "path": "models/250525/d1a3o12_250525_imit_075L_1U.zip", "size_bytes": 154176, "sha256": "661afbb11d5229d1f6a10b8d2e44809adc432aae4d97fde78eabf67b68ec39c0"}, + {"name": "imit_1L_1U.zip", "path": "models/250525/d1a3o12_250525_imit_1L_1U.zip", "size_bytes": 154176, "sha256": "637a6a2e9972dd189aff5f64761d12dd79854ae7201dedab994d3bf6b9c7d95e"}, + {"name": "imit_075L_2U.zip", "path": "models/250525/d1a3o14_250525_imit_075L_2U.zip", "size_bytes": 157326, "sha256": "7681d1b3aa24c401100c53bf5f010d64e9b156a5e32b9157df4c4fe7f3567d6e"}, + {"name": "imit_1L_2U.zip", "path": "models/250525/d1a3o14_250525_imit_1L_2U.zip", "size_bytes": 157326, "sha256": "835d116f839cac051648fe3c8bbdde45433e8a8bd290f24fffb80dcb16139bfa"}, + {"name": "imit_15L_2U.zip", "path": "models/250525/d1a3o14_250525_imit_15L_2U.zip", "size_bytes": 157326, "sha256": "3e115a36d4365cfc70994c9307053aa44d9c3ded8c4312f636520b62862be9b6"} + ], + "canonical_results_status": "historical_frozen", + "canonical_numeric_conflicts": [ + "scene_registry.json: illusion_0.75L similarity=0.982194947, results/README.md: writes 0.978", + "scene_registry.json: illusion_1L similarity=0.958060958, results/README.md writes 0.970", + "karman_joint_front: fitted expression includes 0.385*daB_dt; README and PIPELINE show simplified deployment form without it" + ], + "excluded_from_snapshot": { + "v5_data": "src/SR_analysis/data/v5/ (untracked, not in legacy round 1 scope)", + "v5_formulas": "src/SR_analysis/results/formulas_v5/ (untracked, not in legacy round 1 scope)", + "v5_scripts": ["src/SR_analysis/bridge_v5.py", "src/SR_analysis/stage_2_fit_v5.py"], + "other_modules": "drl_pinball and LegacyCelerisLab modifications excluded from this SR snapshot" + } +} diff --git a/src/SR_analysis/sr_legacy_pipeline_bf1c2e74.plan.md b/src/SR_analysis/sr_legacy_pipeline_bf1c2e74.plan.md new file mode 100644 index 0000000..f09c5e2 --- /dev/null +++ b/src/SR_analysis/sr_legacy_pipeline_bf1c2e74.plan.md @@ -0,0 +1,162 @@ +--- +name: SR Legacy Pipeline +overview: 冻结当前 legacy 证据后,修复并版本化 Kármán 与 Illusion 的 Stage 1–3 数据、特征、公式和闭环契约;第一轮只在四个 Kármán 训练 Re 与 Illusion 0.75L/1L 上完成端到端复现并暂停复核。DTW 闭环是公式选择的最终判据,离线指标仅用于排查时序错位、共线性和部署不一致。 +todos: + - id: snapshot-baseline + content: 创建 SR 专用 Git 快照并记录 ignored 数据、模型和环境资产清单 + status: pending + - id: freeze-contracts + content: 统一 legacy 场景、layout、无量纲化、G 映射和 DTW 契约 + status: pending + - id: repair-stage1 + content: 修复并版本化 Kármán/Illusion Stage 1 数据与因果时序 + status: pending + - id: unify-features + content: 实现 Stage 2/3 共用的 stateful 特征和导数计算 + status: pending + - id: repair-stage2 + content: 实现可复现的 joint front/rear PySR 拟合与公式 schema + status: pending + - id: repair-stage3 + content: 实现公式/G 部署、versioned DTW 与完整 validation provenance + status: pending + - id: run-round1 + content: 在指定 Conda 环境和 GPU 2 完成第一轮 legacy Stage 1–3 复跑 + status: pending + - id: review-candidates + content: 审计历史与 candidate 结果并暂停等待 canonical 晋升决定 + status: pending +isProject: false +--- + +# SR Legacy 端到端完善计划 + +## 范围与原则 + +- 主体系冻结为 legacy;V5、erase、unseen-Re、Vortex、1.5L、论文绘图均不进入第一轮验收。 +- CFD、PPO 推理与闭环统一使用 `pycuda_3_10` 和 GPU 2;PySR/SINDy 使用 `sr_env`。 +- 所有新数据、公式和 validation 先写入带 `run_id` 的 staging 目录,不覆盖现有 [`data/`](src/SR_analysis/data/) 与 [`results/`](src/SR_analysis/results/) canonical 文件。 +- 离线拟合的 \(R^2\)、MAE 等只作为数据/模型诊断;公式取舍以 legacy DTW 闭环结果为最终标准。legacy DTW 固定为独立版本,不混用 V5 的 target-amplitude normalization。 +- observation、action、force 均使用实际物理无量纲量;明确 legacy action 是圆柱表面切向速度,统一定义 \(\alpha=u_{wall}/U_0\)。 +- G 映射作为结构约束:front 为 odd channel,upper/lower 交换并反号;新公式必须记录 rear shared-head 的 anchor 和镜像构造。 + +```mermaid +flowchart LR + snapshot["Git快照与资产清单"] --> contracts["冻结数据和物理契约"] + contracts --> infer["Stage1 PPO推理"] + infer --> fit["Stage2 PySR拟合"] + fit --> deploy["Stage3 CFD闭环"] + deploy --> review["结果审计与人工复核"] + review -->|"通过后"| promote["晋升canonical"] + review -->|"不通过"| diagnose["时序或公式诊断"] +``` + +## 第一阶段:冻结当前状态与建立可回滚基线 + +- 按用户选择先创建一个专用 Git 快照提交;提交前按 Git 协议核对完整 status、diff 和近期提交,只纳入当前 SR 工作及明确相关文件,不混入其他模块的无关改动。 +- 记录当前 commit、工作树状态、Conda/Python/PySR/Julia/CUDA/GPU 信息,以及 legacy 模型最终解析路径。 +- 为 ignored 的 NPZ 和 PPO 模型生成只读资产清单:路径、大小、SHA-256、NPZ keys/shape/dtype。Git 快照本身不能恢复 ignored 数据,因此第一轮脚本必须禁止覆盖这些文件;资产清单用于检测意外变化。 +- 将现有 [`scene_registry.json`](src/SR_analysis/scene_registry.json)、[`results/README.md`](src/SR_analysis/results/README.md)、formula 和 validation 标记为 `historical_frozen`,不立即判断 0.978/0.970 与 0.982/0.958 哪组为最终 canonical。 + +## 第二阶段:冻结跨 Stage 的唯一契约 + +### 场景与数据契约 + +- 在 [`configs.py`](src/SR_analysis/configs.py) 集中定义 Kármán/Illusion 的:几何、目标位置、`Re_code` 与 `Re_D`、SI、\(dt_c=SI/(D/U_0)=SI/2000\)、动作 decoder、FIFO 初始动作、sensor/force/action layout、target slices。 +- 保持 legacy 物理定义与数值:`Re_code=2Re_D`;论文输出可以转换成 `Re_D`,文件名和模型名继续保留 code Re。 +- 明确 Illusion target 契约为 `[target_fx,target_fy, six_sensor_channels]`,传感器比较使用 `[:,2:8]`,策略目标力使用 `[:,0:2]`。 +- 先核对真实 native body order,不直接交换历史 NPZ 列;新数据写显式 layout metadata,内部统一使用 `front/upper/lower`,旧 `top/bottom` 名称通过兼容映射读取。 + +### 物理特征与 G 映射 + +- 收敛 [`feature_builder.py`](src/SR_analysis/utils/feature_builder.py) 与 [`g_operator.py`](src/SR_analysis/utils/g_operator.py) 的重复实现,使所有 Stage 调用同一个 G 和无量纲化入口。 +- 增加 `G(G(x))=x`、target drag even/target lift odd、rear shared-head equivariance 测试。 +- 缺失 required feature 时默认报错,禁止再由 `build_feature_matrix` 静默补零;仅历史兼容读取可显式选择零填充。 + +### legacy DTW + +- 在 [`cfd_interface.py`](src/SR_analysis/utils/cfd_interface.py) 中固定 scene-specific metric:`legacy_dtw_v1_abs_n_unclipped`,明确 lag channel、target slice、window、无幅值归一化、无 clipping。 +- 文档明确 legacy 与 V5 DTW 不直接混用;第一轮不改变历史算法。 + +## 第三阶段:修复 Stage 1 并隔离运行产物 + +- 修改 [`stage_1_infer.py`](src/SR_analysis/stage_1_infer.py) 使路径不依赖 cwd,配置 dry-run 能在不启动 CUDA 时完成模型、target、norm 和输出路径检查。 +- 修复 Illusion 的目标位置配置、target force 索引和 `controlled.npz` 中 `target_forces` 缺失;首步 observation、target harmonic phase 与已验证 legacy 测试保持一致。 +- 明确数据采集时序并写入 metadata:哪个 observation 是 action 执行前或执行后、target phase index、action command index。先以旧推理循环和 legacy test 为事实依据,不凭数组同名假设对齐。 +- 新 NPZ 同时保存 schema/version、layout、SI、\(dt_c\)、normalization source、model hash 和 alignment;保留旧 key alias 只用于兼容。 +- Stage 1 只写 `data/runs//...`;没有显式 promotion 时拒绝覆盖历史数据。 + +## 第四阶段:让离线与在线特征严格一致 + +- 建立 stateful feature state,统一保存 previous observation、previous target force、previous actions 和 \(dt_c\)。 +- 在真实 legacy 数据上比较两种主要 alignment:当前同行 \(X_t\to a_t\) 与按控制循环推导的 \(X_t\to a_{t+1}\)。这一步是契约审计,不用较高 \(R^2\) 自动决定正确性;最终采用与 PPO 决策时刻一致的因果定义。 +- 对同一 trajectory 验证:Stage 2 批量计算与 Stage 3 逐步计算的每个 required feature 数值一致;包含 `du_a_dt`、`dCl_tot_dt`、`dCd_err_dt` 和 action derivative。 +- 将 alignment、导数定义和丢弃的初始样本数写入 formula metadata,避免未来再次产生“拟合公式与部署公式语义不同”。 + +## 第五阶段:修复 Stage 2 的双头拟合与公式记录 + +- 修改 [`stage_2_fit.py`](src/SR_analysis/stage_2_fit.py),使 per-scene 和 joint 都生成: + - front head; + - rear shared head;另一个 rear action 由 Stage 3 通过 G 构造。 +- 统一 formula JSON schema,兼容读取旧 `feature_names/feature_keys` 与 `best_sympy`,新写出至少包含:training scenes、feature order/definitions、fitted expression、deployment expression、role/anchor、G version、data hashes、alignment、\(dt_c\)、PySR seed/operators/complexity、in-sample diagnostics。 +- 固定 PySR seed并提供极短 smoke 参数;候选公式写入 `results/runs//formulas/`,不覆盖现有 formula。 +- 对 Kármán 同时保留: + - fitted expression; + - 人工物理审计后的 deployment expression,例如删除部署时恒零/共线产生的 `daB_dt` 项。 + 二者必须分别带 hash,禁止用一个公式的 DTW 给另一个公式背书。 +- SINDy/STLSQ 第一轮只作为内部筛选诊断:检查 feature 共线、lag 与支持稳定性,不作为闭环候选的自动裁决,也不写成正文核心方法。 + +## 第六阶段:修复 Stage 3 的真实部署 + +- 修改 [`stage_3_validate.py`](src/SR_analysis/stage_3_validate.py),使用统一 formula loader:有 symbolic expression 时直接编译,只有明确 linear schema 时才读取 coefficient;禁止缺 coefficient 时默认为全零。 +- 使用与 Stage 2 完全相同的 stateful feature builder 和 \(dt_c\),并按 formula metadata 构造 front 与 G-mirrored rear actions。 +- Kármán和 Illusion 共享部署核心,只在 target-force/reference 和环境 builder 上分支。 +- validation 文件按 scene、mode、formula hash 和 SI 独立命名,异常必须返回非零;不再让 PPO、SR、uncontrolled 或不同 SI 相互覆盖。 +- 每个结果记录:formula/data/model hash、Git SHA、环境、scene config、metric version、n_steps、full/tail DTW、per-channel DTW、action range、NaN/Inf、termination reason 和原始 telemetry 路径。 + +## 第七阶段:分层运行与第一轮验收 + +### 无 GPU 与短 smoke + +- 先运行 config/NPZ/formula schema、G、DTW fixture、batch-vs-step feature equivalence 测试。 +- 在 `sr_env` 中用 Kármán Re100 小样本、极少 iterations 验证 PySR/Julia 启动、front/rear 双输出和 Stage 3 可读性。 +- 在 `pycuda_3_10` 中确认 GPU 2 可用,再做 Kármán Re100 与 Illusion 1L 的最短 wiring smoke;短跑只检查 finite/actions/schema,不用 DTW 判断控制效果。 + +### 完整第一轮 + +按以下顺序运行,单场失败即停止批量扩展: + +1. Kármán Re100 Stage 1→2→3; +2. Illusion 1L Stage 1→2→3; +3. Kármán code Re 50/100/200/400 joint fit 与闭环; +4. Illusion 0.75L+1L joint fit 与各自闭环。 + +验收条件: + +- Stage 1 数据、Stage 2 formula 和 Stage 3 telemetry 均有完整 provenance; +- required features 无静默零填充,批量/在线特征一致,G 测试通过; +- 每个 formula 实际部署 expression 与 validation 中的 hash 一致; +- CFD 无 NaN/Inf 或动作异常; +- legacy DTW 可与历史结果并列比较。若结果改变,不以“必须复现旧数字”强行通过,而是通过 telemetry 定位是 target 修复、alignment 修复、导数修复还是公式变化造成; +- 第一轮结束后只生成审计报告和 candidate registry,不自动修改 canonical [`scene_registry.json`](src/SR_analysis/scene_registry.json)。到此暂停,请用户复核后再决定晋升或继续机制分析。 + +## 后续阶段:第一轮复核后再启动 + +### 机制与公式项价值 + +- Kármán:uncontrolled、constant rear、front-only、full fitted law、reduced deployment law,比较总 DTW、ux/uy、drag/lift、控制功率。 +- Illusion:target-force feedforward-only、feedback-only、error-only、phase hybrid、front-only、rear-only;重点检验当前 joint front 化简为 `target_Cd + phase term` 后是否只是周期轨道上的等价表示。 +- 做受限 lag cross-correlation、coherence/cross-spectrum、delay embedding 和 target/observed quadrature phase;候选仍由 CFD DTW 裁决。 +- 检查 Illusion PPO 与公式的完整 G-equivariance,特别是 `target_Cd` 为 even 而 front action 应为 odd 的结构冲突。 + +### 泛化与扩展 + +- 流程稳定后再补 unseen-Re;随后恢复 Kármán law 到 Lamb/Taylor 的专用 Vortex validator。 +- 重采 1.5L trajectory,分析高频/phase-state 边界;不把 lagged-action 平凡解标为 canonical。 +- 最后再引入 V5 数据、生成论文图、同步 README/registry/报告和写作。 + +## 文档与长期维护 + +- 更新 [`README.md`](src/SR_analysis/README.md)、[`PIPELINE.md`](src/SR_analysis/PIPELINE.md) 与 Stage 文档,使命令、环境、GPU、schema 和实际代码一致。 +- `scene_registry` 只索引 artifact ID/path/hash/run ID;formula 和 validation JSON 各自保存原始数值。README 与后续图表从 registry 自动生成,避免手工重复 0.978/0.970 等数字。 +- 在 SR 根目录最终保存这份长期计划,并在每轮完成后更新状态、风险和下一验收点。 \ No newline at end of file diff --git a/src/SR_analysis/stage_1_infer.py b/src/SR_analysis/stage_1_infer.py index 696dce2..e990297 100644 --- a/src/SR_analysis/stage_1_infer.py +++ b/src/SR_analysis/stage_1_infer.py @@ -168,6 +168,12 @@ def gen_target_states_at(t, harmonics): def infer_illusion(scene_name: str, device_id: int, out_dir: str, n_steps: int, target_only: bool) -> dict: + """Run PPO inference for illusion scene. + + Output target.npz layout (8 columns): + [cyl_fx, cyl_fy, s0_ux, s0_uy, s1_ux, s1_uy, s2_ux, s2_uy] + Consumers should use target[:, 2:8] for pure sensor signals. + """ cfg = get_scene(scene_name) nu, u0, si, l0 = cfg["nu"], cfg["u0"], cfg["sample_interval"], 20.0 action_scale, action_bias = cfg["action_scale"], np.array(cfg["action_bias"]) @@ -195,12 +201,20 @@ def infer_illusion(scene_name: str, device_id: int, out_dir: str, n_steps: int, warmup = int(4 * nx / u0) ff.run(warmup, np.zeros(4, dtype=DATA_TYPE)) + # Target layout: 8 columns = [cyl_fx,cyl_fy,s0_ux,s0_uy,s1_ux,s1_uy,s2_ux,s2_uy] + # obs comes from: 1 target cylinder + 3 sensors added to FlowField target_states = [] for _ in range(FIFO_LEN): ff.run(si, np.zeros(4, dtype=DATA_TYPE)) target_states.append(ff.obs.copy()[0:8]) target_arr = np.array(target_states, dtype=np.float32) - np.savez(os.path.join(out_dir, "target.npz"), target_states=target_arr[:, :6]) + # BUGFIX (2026-07-14): was target_arr[:, :6] which omitted s2 (bottom sensor) and + # mixed cylinder force (col0-1) with sensor channels. The 8-column layout is the + # canonical format — consumers use target[:, 2:8] to extract the 6 pure-sensor + # channels. Historical note: the old gen_illusion_target.py already wrote 8 columns, + # so on-disk files were correct via that path, but re-running this script would + # overwrite them with truncated data. + np.savez(os.path.join(out_dir, "target.npz"), target_states=target_arr[:, :]) harmonics = analyze_harmonics(target_arr, n_harmonics=5) json.dump(harmonics, open(os.path.join(out_dir, "target_harmonics.json"), "w"), indent=2)