# Reproduce (Track B)

Re-runs legacy PPO models on the **new CelerisLab** solver (v0.5.1) and
compares against SR_analysis reference data to quantify solver differences.

## Quick Start

```bash
# Phase 2: Open-loop target-signal validation (isolates CFD diffs)
conda run -n pycuda_3_10 python src/drl_pinball/reproduce/phase2_open_loop.py --device 2 --scene karman

# Phase 3: DRL inference with legacy-compatible config
conda run -n pycuda_3_10 python src/drl_pinball/reproduce/phase3_reproduce.py --device 2 --scene karman

# Run both phases:
bash src/drl_pinball/reproduce/run_all_reproduce_tests.sh 2
```

## Directory

```
reproduce/
├── README.md                          # This file
├── REPRODUCE_KNOWLEDGE.md             # Comprehensive knowledge base (bugs, API diffs, findings)
├── core/
│   ├── action_wrapper.py              # Action EMA + omega conversion (sign-corrected)
│   ├── obs_normalizer.py              # Norm computation (exact legacy formulas)
│   ├── dtw_metrics.py                 # DTW similarity + harmonics analysis
│   ├── open_loop_validator.py         # Phase 2: compare new CFD targets vs legacy ref
│   └── drl_comparator.py              # Phase 3: compare DRL output vs SR_analysis ref
├── configs/
│   ├── scene_params.py                # All scene parameter definitions
│   └── model_inventory.py             # PPO model registry + loading
├── phase2_open_loop.py                # Open-loop target validation (5 scenes)
├── phase3_reproduce.py                # DRL inference with legacy-compat config
├── run_all_cases.py                   # (Legacy) old reproduce runner — superseded by phase3
├── run_illusion_vortex.py             # (Legacy) old illusion/vortex runner — superseded
├── run_all_reproduce_tests.sh         # Sequential launcher
└── output/
    ├── phase2_validation/             # Phase 2 comparison results
    └── phase3/                        # Phase 3 DRL inference results
```

## Config

The legacy-compatible config at `configs/config_lbm_pinball_legacy_compat.json`
uses **regularized inlet** with `regularized_neq_damp: 1.0`, matching the legacy
NBB (Non-Equilibrium Bounce-Back) formula: `f = feq_target + (f_neb - feq_neb)`.

This is the primary fix over the original `config_lbm_pinball.json` (which used
`zou_he_local` inlet, a fundamentally different numerical scheme).

## Key Results

| Scene | Legacy DTW | New CFD DTW (old) | New CFD DTW (fixed) |
|-------|:----------:|:-----------------:|:-------------------:|
| Karman Re100 | 0.975 | 0.916 | **0.943** |
| Vortex Lamb | 0.968 | 0.955 | **0.970** |
| Vortex Taylor | 0.996 | 0.979 | **0.994** |

The inlet scheme fix closed most of the gap. The remaining ~3% is attributable
to the ghost-source vs inline BC architectural difference.

## Known Limitations

- **Illusion**: S_DIM=14 with harmonics-derived target forces is more sensitive
  to run-to-run CFD variability than the S_DIM=12 scenes
- **Steady Cloak**: Open-loop, no DRL — DTW comparison not applicable
- **Erase**: Incomplete training, no reference for comparison
