refactor(SR): freeze compact legacy evidence package

Archive excluded experiments and superseded outputs so the active tree exposes only the auditable Kármán and Illusion workflow while preserving scientific provenance.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Frank14f
2026-08-06 22:16:53 +08:00
co-authored by Cursor
parent b702fb7300
commit 7323a235f4
576 changed files with 462 additions and 953 deletions
+34 -234
View File
@@ -1,254 +1,54 @@
# SR analysis: agent entry point
# SR analysis
This directory contains the active symbolic-regression analysis for extracting compact control laws from the legacy PPO policies of the fluidic pinball.
## Authority and scope
**Start here, then read `PIPELINE.md`.** The active scientific workflow has exactly three entry points:
This directory is the frozen symbolic-regression evidence package for the LegacyCelerisLab fluidic pinball. The active scientific scope is Kármán-cloak and Illusion PPO data collection, symbolic discovery/refit, closed-loop CFD validation, sampled duration/generalization extensions, term deletion/scaling, and canonical publication export. The disturbance-free `steady` scene remains only as the calibration used to interpret the Kármán rear constant.
1. `stage_1_infer.py` — collect run-scoped PPO trajectories.
2. `stage_2_fit.py` — discover and refit symbolic structures.
3. `stage_3_validate.py` — evaluate formulas in closed-loop CFD with the legacy DTW metric.
The authoritative evidence index is `results/README.md`; execution details are in `PIPELINE.md`. Material under `archive/` is historical, excluded, or non-authoritative.
The current article evidence is indexed in `results/README.md`. The manuscript-ready SR section is `../../docs/JFM_WYQ/SR_Draft.md`.
## Three-stage workflow
## Scientific question
1. `stage_1_infer.py`: collect immutable, run-scoped Legacy PPO trajectories for trained Kármán and Illusion scenes.
2. `stage_2_fit.py`: perform broad per-case discovery, within-objective joint discovery, and fixed-topology all-data coefficient refit.
3. `stage_3_validate.py`: deploy PPO, symbolic, uncontrolled, or constant policies in serial Legacy CFD and evaluate the exact legacy DTW contract.
SR is not used to maximize imitation of PPO actions. It is used to determine whether successful PPO control contains a compact, symmetric and physically interpretable feedback structure that remains effective when deployed in CFD.
The acceptance chain is data and wiring checks → offline discovery/Pareto diagnostics → frozen topology and coefficient refit → finite closed-loop CFD → 200-step acceptance → 400-step duration and sampled unseen-condition checks → term deletion/scaling. Offline R² helps discover structure; it does not accept a controller. Averages never override a non-finite or prematurely terminated case.
The selection chain is therefore:
## Scientific contracts
```text
PPO trajectories
-> broad per-case variable/topology discovery using R² and Pareto fronts
-> within-objective joint topology discovery
-> fixed-topology coefficient refit using all accepted rows
-> short and standard closed-loop CFD screening using legacy DTW
-> term-deletion and coefficient-scaling tests
-> physical interpretation and explicit limitations
```
- **Solver/model/norm:** Stage 1 and Stage 3 use LegacyCelerisLab and the frozen legacy PPO models. Runtime PPO observations use the scene's frozen `data/karman/**/norm.json` or `data/illusion/**/norm.json`; PPO inference defaults to CPU while PyCUDA owns the CFD GPU.
- **Native order:** bodies/actions are `front, upper, lower`; forces are front, upper, lower with `(x,y)` components; sensors are upper, centre, lower with `(u_x,u_y)` components. `checks/order_contract.py` is the runtime gate.
- **Causal alignment:** Stage 2 uses `causal_post_state_to_next_action`: recorded post-state `i` predicts action `i+1`. Warm-up and lag construction are trajectory-local and splits do not cross trajectories.
- **Action units:** formulas output `alpha = omega/U0`. PPO normalized actions are decoded with the scene scale and bias before fitting; Stage 3 converts formula outputs back to `omega` for CFD.
- **Mapped-shared deployment:** the canonical architecture is `alpha_F=(h_F(x)-h_F(Gx))/2`, `alpha_U=h_R(x)`, `alpha_L=-h_R(Gx)`. This imposes exact reflection symmetry; it is not a claim that PPO training was equivariant. Three independent heads are diagnostic only.
- **Metric:** `legacy_dtw_v1_abs_n_unclipped`, reported as `legacy_reference_cycle_vs_last_recorded_cycle`, is the exact acceptance metric. Its fitted circular lag is part of the historical comparison algorithm, not a physical delay.
- **Names:** Kármán scene `re_code` uses reference length `2D`, so `Re_D=re_code/2`. Illusion labels such as `1L` are historical: the stored `target_diameter` value is passed to `add_cylinder` as a radius and must not be silently relabelled as a physical diameter.
R² is a discovery diagnostic. It is not the acceptance criterion. Closed-loop stability and DTW decide whether a candidate is useful; deletion and scaling tests decide whether its terms are necessary.
## Current claim and evidence chain
## Current article scope
Accepted training data are `data/runs/article-joint-data-karman-20260718` (Re-code 50/100/200/400) and `data/runs/article-joint-data-illusion-20260718` (0.75L/1L/1.5L). Formula discovery, refits, accepted and rejected CFD, 400-step duration, sampled unseen points, deletion/scaling, steady calibration, and plotting are retained under `results/runs/article-*` and `results/runs/article2-*` because their manifests and parent paths are provenance dependencies.
Two objectives are fitted separately:
The Kármán evidence supports a controller dominated by persistent rear counter-rotation, with secondary rear-lift feedback and weak tested front feedback. The steady sweep calibrates the rear constant's magnitude; it is not a third fitting objective. The Illusion result is a finite symmetric numerical family, but its terms are partly replaceable and it does not establish explicit target tracking. Neither result proves global symbolic optimality, causal flow mechanism, universal high-Re behavior, or distribution-wide generalization; Article2 supports only the explicitly sampled conditions.
- **Kármán cloaking:** `karman_re50`, `karman_re100`, `karman_re200`, `karman_re400`.
- **Illusion:** `illusion_0.75L`, `illusion_1L`, `illusion_1.5L`.
## Active package map
Kármán and Illusion are never pooled into one fit. The fitted evidence is limited to these seven training scenes. The coefficient-frozen 2026-07-20 extension tests additional Reynolds-number and target-size points, but those points did not participate in fitting or model selection. Vortex, V5 and historical figures remain outside the current article evidence.
Seven new 200-step PPO trajectories were collected in:
- `data/runs/article-joint-data-karman-20260718/`
- `data/runs/article-joint-data-illusion-20260718/`
All seven passed exact recorded-state policy replay. The accepted data inventory is:
- `results/runs/article-joint-data-audit-20260718/data_inventory.json`
Historical and round-one assets are retained, but are not silently pooled with the article data. The old `round1-legacy-v2-20260716-*` formulas are diagnostic only because they predate the final force-order contract.
## Non-negotiable contracts
### Native order
The canonical body, force and action order is:
```text
front, upper, lower
```
Sensors are ordered upper, centre, lower. Verify runtime binding with `checks/order_contract.py` before collecting data after any CFD change.
### Alignment
The article workflow uses:
```text
causal_post_state_to_next_action
```
Recorded post-state `i` predicts action `i+1`. Each trajectory is built independently so lag features and contiguous splits never cross trajectory boundaries.
### Action definition
Formula outputs are dimensionless cylinder surface velocities:
\[
\alpha_i = \omega_i/U_0.
\]
Normalized PPO actions are decoded with the scene action scale and bias before fitting.
### Exact reflection symmetry
The article candidate uses mapped-shared deployment:
\[
\alpha_F(x)=\frac{h_F(x)-h_F(Gx)}{2},\qquad
\alpha_U(x)=h_R(x),\qquad
\alpha_L(x)=-h_R(Gx).
\]
The front projection is exactly odd. The lower action is generated from the shared upper law. Three-head-independent fitting exists only as a PPO-structure diagnostic and is not the final physical architecture.
Fit augmentation and deployment architecture are separate choices:
- `--fit-augmentation none|G`
- `--deployment-architecture mapped_shared|three_head_independent`
Hard G symmetry is a deliberate physical symmetrization; it is not presented as a property that the legacy PPO was trained to satisfy.
### Metric
The closed-loop metric is:
```text
legacy_dtw_v1_abs_n_unclipped
```
Its exact window is named:
```text
legacy_reference_cycle_vs_last_recorded_cycle
```
There are not separate “full” and “tail” DTW algorithms. Lag is part of the legacy comparison procedure and is not interpreted as a physical observation/control delay.
## Physical labels and units
The Kármán scene names contain the historical code Reynolds label `re_code`, defined with reference length `2D`; the cylinder-diameter Reynolds number is therefore \(Re_D=\texttt{re\_code}/2\). The Illusion names `0.75L`, `1L` and `1.5L` are legacy target-size labels: the stored `target_diameter` value is passed to `LegacyCelerisLab.add_cylinder` as a radius. Paper text must not silently reinterpret these labels as physical diameters.
SR uses dimensionless velocities and force coefficients, not the clipped PPO observation. Rear symmetry coordinates are half-sums and half-differences, for example
\[
C_{d,\mathrm{rear},s}=\frac{C_{d,U}+C_{d,L}}{2},\qquad
C_{d,\mathrm{rear},a}=\frac{C_{d,U}-C_{d,L}}{2},
\]
with the same convention for rear lift.
## Feature strategy
Broad discovery starts from complete, dimensionless variable representations:
- `raw_complete`: six velocity components and six cylinder-force components.
- `symmetry`: symmetric/antisymmetric velocity and force coordinates.
- `physics_reduced`: compact diagnostics only; it is not the starting point for article discovery.
Illusion comparisons use non-overlapping profiles:
- `actual_only`
- `target_only`
- `actual_plus_target`
- `actual_plus_error`
Target/error derivatives or other temporal features are added only after static variables are shown insufficient. Cross-correlation is never used to select a lag.
## Current results
### Kármán joint candidate
\[
\alpha_F=\operatorname{odd}\!\left[-0.381391\,C_{d,\mathrm{rear},a}\right],
\]
\[
\alpha_U=1.307782\,C_{l,\mathrm{rear},s}-3.431209,
\qquad
\alpha_L=-\alpha_U(Gx).
\]
Standard 200-step legacy DTW:
- Re50: `0.9543`
- Re100: `0.9427`
- Re200: `0.8560`
- Re400: `0.7827`
Deletion tests support the ordering:
```text
rear constant > rear lift feedback > front drag-asymmetry feedback
```
This is consistent with the physical hypothesis that persistent rear counter-rotation provides the principal downstream velocity-deficit compensation. The SR evidence ranks controller terms but does not establish the spatial momentum correction or causality; those claims require OID/CCD. The law is not uniformly strong at Re400 and must not be called universal.
### Illusion joint numerical candidate
\[
\alpha_F=\operatorname{odd}\!\left[-1.826604\,C_{d,\mathrm{rear},a}+2.064493\,C_{l,F}\right],
\]
\[
\alpha_U=1.254440\,C_{d,\mathrm{rear},a}-1.528074\,C_{l,F},
\qquad
\alpha_L=-\alpha_U(Gx).
\]
Standard 200-step legacy DTW:
- 0.75L: `0.8749`
- 1.0L: `0.9217`
- 1.5L: `0.8306`
Scaling tests show that the `Cl_F` terms dominate action magnitude; the `Cd_rear,a` terms are weaker and partly replaceable. Every one-term deletion remained stable, so the current expression is not a unique mechanism law. Target/error variables were available but were not selected stably by low-complexity static joint discovery. This is a numerical joint reference, not proof of explicit target tracking.
## What can and cannot be claimed
Supported:
- A complete, reproducible discovery-to-CFD-to-ablation workflow.
- Strong Kármán evidence for dominant rear counter-rotation and secondary rear lift feedback.
- A symmetric Illusion joint family that remains finite across all three trained target-size labels.
- R² and formula appearance alone are insufficient predictors of closed-loop value.
Not supported:
- Global symbolic optimality or uniqueness.
- A universal Kármán law at Re400.
- An explicit target-tracking mechanism for Illusion.
- Necessity of every Illusion term.
- Physical delay inferred from DTW lag or cross-correlation.
- Distribution-wide or universal generalization. The Article2 extension supports only finite pointwise deployment at its explicitly sampled unseen conditions.
## Directory map
```text
SR_analysis/
├── README.md # this agent entry point
├── PIPELINE.md # exact method, commands and design decisions
├── configs.py # scene and action contracts
├── stage_1_infer.py # PPO data collection
├── stage_2_fit.py # discovery and fixed-topology refit
├── stage_3_validate.py # closed-loop CFD and legacy DTW
├── checks/ # pre-fit physical/wiring gates
├── diagnostics/ # diagnostic-only analyses
├── utils/ # feature, G, formula, data and provenance contracts
├── tests/ # SR CPU contract tests
├── results/README.md # evidence index and result status
├── tools/ # integrity audit; audit is not scientific promotion
├── experiments/v5/ # excluded experimental pipeline
└── archive/ # inactive Stage 4 and historical guides
```
`old/`, `archive/`, `experiments/v5/`, historical formula directories and old reports are context only. They are not authoritative sources for article numbers.
## Environments and resource discipline
- Stage 1, policy replay and Stage 3: `pycuda_3_10`; PPO inference defaults to CPU so physical GPU 2 remains dedicated to the PyCUDA CFD context.
- Stage 2/PySR and coefficient refit: `sr_env`.
- CFD uses physical GPU 2 and is strictly serial.
- When `CUDA_VISIBLE_DEVICES=2`, the process uses logical device `0`; provenance records both visibility and GPU UUID rather than mislabelling the physical ordinal.
- Every run ID is immutable; failed telemetry is retained.
- Root: `configs.py`, the three stages, this README, and `PIPELINE.md`.
- `checks/`: order and policy-replay gates.
- `utils/`: active data, feature, symmetry, metric, formula, CFD, and provenance contracts.
- `tools/`: canonical plotting/export tools (`prepare_plotting_data.py`, `telemetry_to_csv.py`, both SR plotting modules, and `export_flow_comparison.py`).
- `tests/`: CPU contract tests.
- `data/`: frozen Kármán/Illusion norms, steady calibration data, and the two accepted article data runs.
- `results/`: the evidence index and provenance-dependent `article-*`/`article2-*` families.
- `archive/`: excluded experiments, diagnostics, old run families, superseded flat surfaces, and historical code/docs. Archive paths may be non-executable.
## Verification
At the 2026-07-21 plotting-package revision, the SR contract suite contains 88 passing tests. Run from the repository root:
From the repository root:
```bash
PYTHONPATH=src conda run -n sr_env python -m pytest \
src/SR_analysis/tests tests/test_stage_3_validate.py -q
PYTHONPATH=src conda run -n sr_env python -m pytest src/SR_analysis/tests -q
python3 -m compileall -q src/SR_analysis/configs.py src/SR_analysis/stage_1_infer.py src/SR_analysis/stage_2_fit.py src/SR_analysis/stage_3_validate.py src/SR_analysis/utils src/SR_analysis/checks src/SR_analysis/tools
git diff --check -- src/SR_analysis
```
See `PIPELINE.md` for reproducible commands and `results/README.md` for the exact evidence chain.
No GPU CFD is part of this verification.