Core changes: - New phase-state features (PHASE_STATE_KEYS, ILLUSION_PHASE_KEYS) with obs dynamics - Derivative and absolute output modes (output_mode="deriv"|"absolute") - predict_v23_deriv() with integration support for closed-loop - Offline multi-step rollout evaluator (eval_rollout.py) Key results: - Illusion 0.75L/1L: phase-state+error-state+abs achieves 0.974/0.958 closed-loop with zero action history features — proving the new route works - Karman re100: phase-state+abs reaches 0.699 (vs 0.901 with action history) - 1.5L confirmed as bang-bang regime (R2=0.12 for linear SINDy) - Feature ablation: 6-dim phase-state outperforms 16-dim full-lag in closed-loop Documentation: - docs/SR_analysis_results.md: comprehensive analysis report - docs/HANDOVER_SR_ANALYSIS.md: handover notes for next coder - 6 figures in docs/figures/SR_analysis/ - Updated README.md, sindy_sr_notes.md, sindy_sr_knowledge.md - Updated configs.py with generalization scenes Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .. | ||
| compare | ||
| configs/legacy | ||
| data | ||
| scripts | ||
| sindy | ||
| utils | ||
| validate | ||
| configs.py | ||
| pysr.md | ||
| README.md | ||
| sindy_sr_knoeledge.md | ||
| sindy_sr_knowledge.md | ||
| sindy_sr_notes.md | ||
SR_analysis: Unified SINDy-SR Analysis Pipeline
Overview
This directory consolidates the SINDy-and-symbolic-regression analysis pipeline
for the DynamisLab fluidic pinball project. It replaces the old
src/analysis_crossre/ and src/analysis_cloak/ directories with a unified
structure.
The pipeline fits sparse interpretable control laws (obs -> act) for all
cloak and illusion scenes, using dimensionless physical features,
G-equivariant structural constraints, and STLSQ threshold grids.
For background, see:
sindy_sr_notes.md-- execution plan and task trackingsindy_sr_knowledge.md-- confirmed facts and known pitfalls../../docs/SR_analysis_results.md-- comprehensive results report
Directory Structure
SR_analysis/
configs.py # Unified scene metadata (all 10+ scenes)
configs/
legacy/ # Legacy CFD configs
utils/
__init__.py # Selective exports (no pycuda dependency)
feature_builder.py # Dimensionless features + G-operator + phase-state features
sindy_fitter.py # STLSQ + feature matrices + derivative/absolute modes
cfd_interface.py # LegacyCelerisLab wrapper (requires pycuda_3_10)
g_operator.py # Equivariance diagnostics
data/
karman/ # Karman cloak: karman_re50/100/200/400
steady/ # Steady cloak
illusion/ # Illusion: illusion_0.75L/1L/1.5L
vortex/ # Vortex cloak
scripts/
infer_karman.py # Inference: LegacyCFD + PPO -> controlled.npz
infer_illusion.py # Inference for illusion scenes
infer_vortex.py # Inference for vortex scenes
sindy/
run_all_v2.py # Unified SINDy fitting (supports --deriv, --phase, --output-mode etc.)
run_pysr.py # Restricted PySR symbolic regression
wrap_joint.py # Joint model -> wrapped format for validator
compare_v2.py # Cross-scene comparison report
karman/illusion/vortex/ # SINDy output JSONs
validate/
run_closed_loop.py # Karman closed-loop validator (v23/deriv/abs modes)
run_closed_loop_illusion.py # Illusion closed-loop validator
eval_rollout.py # Offline multi-step rollout evaluation
results/ # Validation result JSONs
compare/
support_overlap.py # Support set comparison
shared_core.py # Shared core detection
Key Design Decisions
1. Scene Metadata Driven
All scene parameters defined once in configs.py.
2. Feature Levels
| Level | Features | Dim | Description |
|---|---|---|---|
| Static | u_m, u_a, u_c, v_a, Cd_tot, Cd_rear, Cl_tot, Cl_diff | 8 | Current-step only |
| Phase-state | u_a, du_a/dt, Cl_tot, dCl_tot/dt, Cd_tot, Cd_rear | 6 | Oscillation phase + rate |
| Illusion-phase | Phase-state + Cd_err, Cl_err, dCd_err/dt, dCl_err/dt | 10 | Phase + error-state |
| Karman-expanded | Phase-state + u_m, u_c, v_a, Cl_diff | 10 | Phase + supplementary |
| Full-lag | Static + lag-1 | 16 | Full temporal context |
3. Output Modes
- deriv: predict
d(alpha)/dt, thenalpha(t) = alpha(t-1) + dt_c * dalpha/dt - absolute: predict
alpha(t)directly (no integration drift)
4. G-Equivariant Structure (v23)
Front(t) = f_front(x(t)) # no bias, odd under G
Top(t) = f_rear(x(t)) # with bias
Bottom(t) = -f_rear(G[x(t)]) # shared-head
Current Best Results (2026-06-15)
Illusion — New Route: Phase-state + Error-state + Absolute Action
| Scene | Closed-loop | % of PPO | Action history? | Features |
|---|---|---|---|---|
| 0.75L | 0.974 | 100.2% | No | ILLUSION_PHASE (10dim) |
| 1L | 0.958 | 98.5% | No | ILLUSION_PHASE (10dim) |
| 1.5L | N/A | — | No | Bang-bang regime |
Karman re100 — Ablation
| Config | Feat | Output | R2 | Closed-loop | Note |
|---|---|---|---|---|---|
| old v23 (a_lag) | 14+3 | alpha | 0.996 | 0.901 | Baseline |
| Phase->abs | 6 | alpha | 0.965 | 0.699 | Best new route |
| Phase->deriv | 6 | dalpha/dt | 0.837 | 0.656 | |
| Phase+mu->abs | 9 | alpha | 0.979 | 0.700 | mu helps cross-Re |
| Expanded->abs | 10 | alpha | 0.980 | 0.580 | Overfitting |
Commands
All from repo root (/home/frank14f/DynamisLab).
SINDy Fitting
# Illusion phase-state + absolute (recommended for 0.75L/1L)
conda run -n pycuda_3_10 python src/SR_analysis/sindy/run_all_v2.py \
--scenes illusion_0.75L,illusion_1L --deriv --phase --output-mode absolute
# Karman phase-state + absolute
conda run -n pycuda_3_10 python src/SR_analysis/sindy/run_all_v2.py \
--scenes karman_re100 --deriv --phase --output-mode absolute
# Karman expanded (10 dim)
conda run -n pycuda_3_10 python src/SR_analysis/sindy/run_all_v2.py \
--scenes karman_re100 --deriv --karman-expand --output-mode absolute
# Karman with mu modulation
conda run -n pycuda_3_10 python src/SR_analysis/sindy/run_all_v2.py \
--scenes karman_re100 --deriv --karman-mu --output-mode absolute
# Old-style (v2, with action history)
conda run -n pycuda_3_10 python src/SR_analysis/sindy/run_all_v2.py \
--scenes karman_re50,karman_re100 --joint
Closed-loop Validation
# Karman with absolute action
conda run -n pycuda_3_10 python src/SR_analysis/validate/run_closed_loop.py \
--scene karman_re100 --device 0 --steps 200 --mode abs \
--sindy-results src/SR_analysis/sindy/karman/sindy_results_deriv.json
# Karman old v23
conda run -n pycuda_3_10 python src/SR_analysis/validate/run_closed_loop.py \
--scene karman_re100 --device 0 --steps 200 --mode v23 \
--sindy-results src/SR_analysis/sindy/karman/sindy_joint_wrapped.json
# Illusion with absolute action
conda run -n pycuda_3_10 python src/SR_analysis/validate/run_closed_loop_illusion.py \
--scene illusion_1L --device 0 --steps 320 \
--sindy-results src/SR_analysis/sindy/illusion/sindy_results_deriv.json
PySR Symbolic Regression
conda run -n sr_env python src/SR_analysis/sindy/run_pysr.py --scene illusion_1L
Offline Rollout Evaluation
python3 src/SR_analysis/validate/eval_rollout.py \
--sindy-results src/SR_analysis/sindy/karman/sindy_results_deriv.json \
--scene karman_re100
Important Reminders
controlled.npzactions are normalized [-1,1] — must convert via(norm * scale + bias) * u0- FIFO bias ≠ DRL action bias for Illusion: FIFO=[0, -0.01, 0.01], decode=[0, -0.02, 0.02]
- "2U" in model name = S_DIM=14 (not 2x velocity), u0 always 0.01
- SAMPLE_INTERVAL: 0.75L=400, 1L=600, 1.5L/Karman=800
- Closed-loop steps auto-set: S=400→320, S=600→214, S=800→160
- One-step R² high ≠ closed-loop good — always validate
- For phase-state features, always pass
sensors_raw/forces_rawto enable derivative computation