Complete implementation of Observable-Inferred Decomposition (OID) for the fluidic pinball project. Covers Phases 0-7 for all 5 scenes (steady cloak, Karman cloak, illusion 0.75L/1.0L/1.5L). Key deliverables: - Full analysis pipeline: configs, utils, 11 collection scripts, 7 phase scripts, robustness analysis, figure generator, batch runner - Data collected: 500 snapshots per scene, separate illusion-position q_blk - 7 publication-quality figures: force-sig overlap, rank sensitivity, OID vs POD comparison, tau_c sensitivity, POD energy, steady metrics, white-box chain - Comprehensive report at docs/OID_analysis_results.md (292 lines) - Handover document at docs/OID_handover.md - Updated knowledge base and notes with all Phase 2 results Core finding: force-relevant and signature-relevant correction structures systematically separate across control tasks (steady: +0.763 -> Karman: -0.034 -> illusion: -0.082 to -0.932), with OID consistently outperforming POD. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .. | ||
| analysis | ||
| data | ||
| scripts | ||
| utils | ||
| configs.py | ||
| Final_Conclusions.md | ||
| OID_knowledge.md | ||
| OID_notes.md | ||
| README.md | ||
| Sch12.md | ||
OID_analysis: Observable-Inferred Decomposition for Fluidic Pinball Control
What this directory does
This directory implements an OID (Observable-Inferred Decomposition) pipeline for analyzing which flow structures the DRL controller actually modulates in the fluidic pinball experiments. OID ranks modes by cross-correlation with a chosen observable (force, sensor error), rather than by fluctuation energy (POD).
The three companion documents:
OID_knowledge.md-- confirmed facts, hard rules, critical caveats, current resultsOID_notes.md-- execution plan, task tracking, handover notes- This file (README.md) -- engineering entry point, how to run
Critical reading order for new agent:
docs/OID_analysis_results.md-- full project report (start here)- README.md (this file) -- understand scope and how to run
OID_knowledge.md-- know the rules, the results, and pitfallsOID_notes.md-- understand what's left to do
Current scope (as of 2026-06-22)
All 5 scenes analyzed end-to-end:
| Scene | Type | Source | Status |
|---|---|---|---|
| steady_cloak | Open-loop constant rotation (rear=+-5.1U0) | Collected | Full Phases 1-7 |
| karman_re100 | PPO (d1a3o12_re100) | Replayed from CCD | Full Phases 1-7 |
| illusion_0.75L | PPO (d1a3o14_075L_2U_400S) | Replayed from CCD | Full Phases 1-7 |
| illusion_1.0L | PPO (d1a3o14_1L_2U_600S) | Replayed from CCD | Full Phases 1-7 |
| illusion_1.5L | PPO (d1a3o14_15L_2U) | Replayed from CCD | Full Phases 1-7 |
Fixed scope notes (inherited from SR/CCD):
- All illusion models use u0=0.01, nu=0.004 (standard defaults from config_flowfield.json)
- "2U" in model name means S_DIM=14 (2 extra target force observations), NOT 2x velocity
- SAMPLE_INTERVAL depends on target diameter: 0.75L=400, 1.0L=600, 1.5L=800
- Illusion q_blk was collected separately from cloak-position q_blk (different geometry)
Directory structure
src/OID_analysis/
configs.py # Unified scene metadata (12 scene definitions)
utils/
cfd_interface.py # Re-exports CCD's proven CFD interface
analysis.py # CPU-only: POD, OID, PCD, zone statistics, comparison
scripts/
collect_*.py # Data collection scripts (GPU, pycuda_3_10)
replay_*.py # Field replay + verification
compute_delta_fields.py # Phase 0 draft
analysis/
phase*.py # Analysis scripts Phases 1-7 (CPU, sr_env)
robustness_analysis.py # Rank/tau_c/window/zone robustness
steady_reanalysis.py # Steady cloak suppression metrics
compile_master_table.py # Cross-scene comparison
make_figures.py # Generate 7 figures
run_full_analysis.py # Batch pipeline runner
data/
configs/legacy/ # Legacy CFD configs (symlinked)
steady_cloak/ # Baseline + controlled fields
karman_cloak/ # Baseline + controlled fields
illusion/ # PPO controlled fields
target_cylinder/ # Reference targets
derived/ # All analysis results + figures
OID_knowledge.md # Knowledge base
OID_notes.md # Task tracking
Final_Conclusions.md # Six-question conclusions
Sch12.md # OID reference paper
docs/
OID_analysis_results.md # Full project report (7 figures, 292 lines)
How to run
All commands from repo root (/home/frank14f/DynamisLab).
Data collection (GPU, pycuda_3_10)
# Steady group:
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_empty_channel.py --device 3 --steps 200
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_pinball_baseline.py --device 3 --steps 500
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_steady_cloak.py --device 3 --steps 500 --omega-rear 5.1
# Karman group:
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_disturbance_only.py --device 1 --steps 500
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_karman_blk.py --device 1 --steps 500
# Illusion q_blk (important: separate geometry from cloak):
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_illusion_qblk.py --device 3 --steps 500
# PPO field replay (from CCD checkpoints):
conda run -n pycuda_3_10 python src/OID_analysis/scripts/replay_full_fields.py --scene karman_re100 --device 1
conda run -n pycuda_3_10 python src/OID_analysis/scripts/replay_full_fields.py --scene illusion_1.0L --device 3
# Target cylinders:
conda run -n pycuda_3_10 python src/OID_analysis/scripts/collect_target_cylinder.py --diameter 1.0 --device 3 --steps 500
Analysis (CPU only, sr_env)
# Full pipeline for one scene:
cd /home/frank14f/DynamisLab
PYTHONPATH="src:$PYTHONPATH" conda run -n sr_env python3 src/OID_analysis/analysis/run_full_analysis.py --scene karman_re100
# Robustness analysis:
PYTHONPATH="src:$PYTHONPATH" conda run -n sr_env python3 src/OID_analysis/analysis/robustness_analysis.py
# Generate figures:
PYTHONPATH="src:$PYTHONPATH" conda run -n pycuda_3_10 python3 src/OID_analysis/analysis/make_figures.py
# Cross-scene table:
PYTHONPATH="src:$PYTHONPATH" conda run -n sr_env python3 src/OID_analysis/analysis/compile_master_table.py
Replay verification
conda run -n pycuda_3_10 python src/OID_analysis/scripts/replay_verify.py --scene karman_re100 --device 1
Key results
| Finding | Evidence | Confidence |
|---|---|---|
| Force-sig structures systematically separate across tasks | Monotonic trend: +0.763 -> -0.034 -> -0.082 -> -0.495 -> -0.932 | High (rank-stable for 4/5 scenes) |
| OID beats POD for force prediction | OID R2=0.435-0.750 vs POD R2=-2.4 to 0.418 | High |
| OID beats POD for signature prediction | OID R2=0.315-0.661 vs POD R2=-0.16 to 0.06 | High |
| OID coordinates != control state | force-OID->act R2=0.225 vs obs->act R2=0.956 | Confirmed (expected design) |
| Steady cloak suppresses 99.4% of RMS fluctuation | Full-field RMS reduction | High |
Common pitfalls (read these before making changes)
- Always use model name as single source of truth. "2U" = S_DIM=14, NOT 2x velocity. u0 is ALWAYS 0.01.
- NEVER use nu_from_re() for illusion models. Only valid for standard S_DIM=12 cases.
- Distinguish action_bias from preset_action. They are DIFFERENT. action_bias is for DRL scaling; preset_action is for FIFO warmup.
- context.push()/pop() around every run() call. Mandatory for multi-step loops.
- Fresh GPU per PPO scene. GPU state contamination degrades similarity. Minimum 4NX/U0 steps separation between scenes on the same GPU.
- No field cropping. All fields must be full 1280x512 resolution.
- Three-field decomposition is MANDATORY. OID operates on Delta-q_ctl = q_ctl - q_blk, NOT on raw q_ctl.
- OID identifies directions within the chosen POD subspace. It CANNOT recover structures truncated by POD rank reduction.
Delivered files (non-data)
These files should be committed to the repository:
Code (src/OID_analysis/):
configs.py,utils/cfd_interface.py,utils/analysis.pyscripts/(11 collection + 3 replay scripts)analysis/(7 phase scripts + robustness + figures + batch runner)OID_knowledge.md,OID_notes.md,Final_Conclusions.md
Report (docs/):
docs/OID_analysis_results.md
Large data files (NOT committed -- see .gitignore):
- All
.npzindata/ - All
.npyindata/derived/ - All
.pngindata/derived/figures/