# OID_analysis — Observable-Inferred Decomposition for Fluidic Pinball

Identifies which correction-field structures the DRL controller modulates, ranked by cross-correlation with force and signature observables (not by POD energy).

## Quick Start

```bash
# Read first:   PIPELINE.md           pipeline overview, scene table, conventions
# Deep dive:    OID_knowledge.md      rules, results table, bug history
# Tasks:        OID_notes.md          open items, handover
# Conclusions:  Final_Conclusions.md  six key questions answered

# Run (from repo root):
PYTHONPATH="src:$PYTHONPATH" conda run -n sr_env python3 \
  src/OID_analysis/analysis/run_full_analysis.py --scene karman_re100 --force
```

## File Map

```
src/OID_analysis/
├── PIPELINE.md              ← START HERE — overview, scene table, conventions
├── OID_knowledge.md          hard rules, full results, bugs
├── OID_notes.md              task tracking, open items
├── Final_Conclusions.md      six key questions answered
├── scene_registry.json       machine-readable scene index + canonical values
├── configs.py                single source of truth: 13 scene definitions
│
├── utils/                    core library (CPU, no GPU dependency)
│   ├── analysis.py           POD, force-OID, sig-OID, PCD, zone stats
│   └── cfd_interface.py      re-exports from CCD_analysis
│
├── scripts/                  GPU data collection (pycuda_3_10 env)
│   ├── collect_empty_channel.py / collect_pinball_baseline.py
│   ├── collect_karman_blk.py / collect_disturbance_only.py
│   ├── collect_controlled.py / collect_steady_cloak.py
│   ├── collect_illusion_qblk.py / collect_target_cylinder.py
│   ├── collect_all_data.py     batch orchestrator
│   └── replay_full_fields.py   full-field PPO replay
│
├── analysis/                 CPU analysis pipeline (sr_env)
│   ├── phase1_correction_pod.py → phase7_whitebox.py   (7 phases)
│   ├── robustness_analysis.py / steady_reanalysis.py
│   ├── compile_master_table.py / make_figures.py
│   └── run_full_analysis.py     batch runner
│
├── data/                     raw collected data (NOT committed)
│   ├── steady_cloak/         q_in, q_blk, q_ctl
│   ├── karman_cloak/         q_in, q_blk, q_ctl
│   ├── illusion/             q_ctl (3 diameters)
│   ├── target_cylinder/      reference targets
│   └── derived/              all computed results + 7 figures
│
├── papers/                   reference papers
│   ├── Sch12.md              OID original paper
│   └── Li22b.md              pinball state estimation paper
├── docs/
│   └── sch12_code_mapping.md Sch12 formula → code traceability
├── tests/                    unit tests (7/7 pass)
└── archive/                  deprecated files
```

## Core Results (one table)

| Finding | Key Value | Confidence |
|---------|-----------|------------|
| Force-sig monotonic separation | +0.763 → -0.034 → -0.082 → -0.495 → -0.932 | High |
| OID beats POD (force prediction) | R²=0.44-0.75 (OID) vs -2.4~0.42 (POD) | High |
| OID beats POD (sig prediction) | R²=0.32-0.66 (OID) vs -0.16~0.06 (POD) | High |
| Action orthogonal to force+sig | |overlap|<0.33 across all scenes | Confirmed |
| Steady cloak RMS reduction | 99.4% | High |
| Li22b cross-map | modes 0-5 diagonal 0.81-0.98 | Verified |
| SR validation | OID z1 ↔ Cl_tot r=-0.82 | Verified |

Full numbers: `data/derived/master/master_table.json` · `scene_registry.json`

## Pitfalls

1. OID operates on **Δq_ctl = q_ctl − q_blk**, not raw q_ctl.
2. **force-OID and sig-OID reported separately** — divergence is a mechanism result.
3. **Illusion q_blk uses separate geometry** (pinball_x=19/20.3, sensor_x=30).
4. Fields stored at **full 1280×512**; ROI mask applied only at analysis stage.
5. GPU: Karman on device 1, steady/illusion on device 3.
6. Conda: `pycuda_3_10` for GPU, `sr_env` for CPU analysis.
7. "2U" in model name = S_DIM=14, NOT 2× velocity.
