feat(SR): complete article-grade symbolic regression evidence
Freeze the contract-audited discovery, closed-loop validation, robustness, plotting, and manuscript evidence so the SR section is reproducible and ready for paper development. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+245
-72
@@ -1,81 +1,254 @@
|
||||
# SR_analysis: Symbolic Regression for DRL Flow Control
|
||||
# SR analysis: agent entry point
|
||||
|
||||
Extracts interpretable control laws (obs -> act) from DRL-trained PPO policies
|
||||
for the fluidic pinball using PySR symbolic regression. Validates all formulas
|
||||
in CFD closed-loop and produces publication-quality figures.
|
||||
This directory contains the active symbolic-regression analysis for extracting compact control laws from the legacy PPO policies of the fluidic pinball.
|
||||
|
||||
## Pipeline
|
||||
**Start here, then read `PIPELINE.md`.** The active scientific workflow has exactly three entry points:
|
||||
|
||||
```
|
||||
stage_1_infer.py -> stage_2_fit.py -> stage_3_validate.py -> stage_4_analyze.py
|
||||
(PPO data) (PySR formula) (CFD closed-loop) (paper figures)
|
||||
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 current article evidence is indexed in `results/README.md`. The manuscript-ready SR section is `../../docs/JFM_WYQ/SR_Draft.md`.
|
||||
|
||||
## Scientific question
|
||||
|
||||
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 selection chain is therefore:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
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 article scope
|
||||
|
||||
Two objectives are fitted separately:
|
||||
|
||||
- **Kármán cloaking:** `karman_re50`, `karman_re100`, `karman_re200`, `karman_re400`.
|
||||
- **Illusion:** `illusion_0.75L`, `illusion_1L`, `illusion_1.5L`.
|
||||
|
||||
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.
|
||||
|
||||
## Verification
|
||||
|
||||
At the 2026-07-21 plotting-package revision, the SR contract suite contains 88 passing tests. Run from the repository root:
|
||||
|
||||
```bash
|
||||
# Generate PPO inference data
|
||||
conda run -n pycuda_3_10 python stage_1_infer.py --scene karman_re100 --device 2
|
||||
|
||||
# Fit symbolic formula
|
||||
conda run -n sr_env python stage_2_fit.py --scenes illusion_0.75L,illusion_1L --mode joint --deep
|
||||
|
||||
# Validate in CFD
|
||||
conda run -n pycuda_3_10 python stage_3_validate.py \
|
||||
--scene illusion_1L --device 2 --mode pysr \
|
||||
--formula-front results/formulas/illusion_joint_front.json \
|
||||
--formula-top results/formulas/illusion_joint_top.json
|
||||
|
||||
# Generate figures
|
||||
conda run -n pycuda_3_10 python stage_4_analyze.py
|
||||
PYTHONPATH=src conda run -n sr_env python -m pytest \
|
||||
src/SR_analysis/tests tests/test_stage_3_validate.py -q
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
SR_analysis/
|
||||
stage_1_infer.py # PPO inference (all scenes)
|
||||
stage_2_fit.py # PySR symbolic regression fitting
|
||||
stage_3_validate.py # CFD closed-loop validation
|
||||
stage_4_analyze.py # Publication figure generation
|
||||
configs.py # All scene definitions (19 scenes)
|
||||
scene_registry.json # Canonical results registry
|
||||
utils/ # Shared library (features, CFD, fitting)
|
||||
data/ # Runtime .npz data per scene
|
||||
results/
|
||||
formulas/ # Canonical formula JSONs
|
||||
validations/ # CFD validation outputs
|
||||
figures/ # Publication-quality PNG/PDF
|
||||
FIGURE_INDEX.md # Figure catalog with captions
|
||||
README.md # Formula + validation index
|
||||
docs/
|
||||
SR_analysis_report.md # Full analysis report
|
||||
illusion_joint_formula_analysis.md
|
||||
PIPELINE.md # Detailed reproduction guide
|
||||
literature_note.md # Paper writing + literature positioning
|
||||
old/ # Archived historical files
|
||||
```
|
||||
|
||||
## Key Results
|
||||
|
||||
| Scene | Formula | CFD Similarity |
|
||||
|-------|---------|:---:|
|
||||
| Karman cross-Re (joint) | alpha_F = daF_dt - 14.95*mu*Cl_tot | avg 0.847 |
|
||||
| Illusion joint (0.75L+1L) | alpha_F = Cd_tot - Cd_err - 5.43 + 0.01*(du_a_dt+u_a) | 0.978/0.970 |
|
||||
| Vortex lamb (Karman formula) | Karman joint, zero retraining | 0.949 (exceeds PPO) |
|
||||
|
||||
## Environments
|
||||
|
||||
- `pycuda_3_10`: CFD + DRL model loading + visualization (stages 1, 3, 4)
|
||||
- `sr_env`: PySR symbolic regression (stage 2)
|
||||
- GPU: device 2 recommended
|
||||
|
||||
## Documentation
|
||||
|
||||
| File | Content |
|
||||
|------|---------|
|
||||
| `PIPELINE.md` | Full reproduction guide with all commands |
|
||||
| `docs/SR_analysis_report.md` | Complete methodology + results + discussion |
|
||||
| `results/figures/FIGURE_INDEX.md` | All figures with paper-ready captions |
|
||||
| `literature_note.md` | Literature positioning + writing guidance |
|
||||
| `results/README.md` | Formula + validation file index |
|
||||
See `PIPELINE.md` for reproducible commands and `results/README.md` for the exact evidence chain.
|
||||
|
||||
Reference in New Issue
Block a user