Remodel/sprints/SPRINT_01.md
Mannu 314127effc [S1-T01 through T11] Solar, Wind, BESS generation simulation + CLI
- Pydantic schemas: SolarConfig, WindConfig, BessConfig, GenerationResult
- Catalog: synthetic 8760h profiles for RJ/KA/GJ solar and wind; LRU-cached loader
- generation/solar.py: 25yr hourly simulation (DC losses, inverter, clipping, soiling, degradation)
- generation/wind.py: power-law shear, piecewise power curve, wake/electrical losses, degradation
- generation/bess_state.py: SOH-based capacity degradation with augmentation schedule
- CLI: remodel --input scenario.json --output gen.parquet (Typer upgraded to 0.25.1 for Click 8.3 compat)
- 43 unit tests, 97.4% coverage; mypy strict + ruff clean
- S1-T10 parity gate: placeholder fixture + skipped integration tests (awaiting Nagasamudra data)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:04:21 +05:30

2.7 KiB

Goal: Solar + Wind 25-year generation simulation working as a pure Python module with CLI driver. Validated against one Excel scenario. Tasks:

[x] S1-T01 Schema: SolarConfig, WindConfig, GenerationResult in engine/schemas/generation.py. [x] S1-T02 Catalog: 3 solar 8760 profiles (RJ, KA, GJ) as CSV in engine/catalog/profiles/solar/. 3 wind profiles. Add loader. [x] S1-T03 generation/solar.py: function simulate_solar(config: SolarConfig) -> pd.DataFrame returning 25y x 8760 rows with columns year, hour, dc_power_mw, ac_power_mw_pre_clip, ac_power_mw, degradation_factor. [x] S1-T04 Solar logic: scaling, DC losses, inverter n, AC losses, clipping at MW_AC, availability, soiling (monthly profile or flat), Y1 + 0.7%, Y2-25 + 0.5% degradation. [x] S1-T05 Tests: CUF reasonable (15-25% range for solar), clipping captures DC excess correctly, degradation factors monotonic. [x] S1-T06 generation/wind.py: power curve lookup, wind shear correction, wake losses, electrical, availability, degradation. [x] S1-T07 Wind tests: PLF reasonable (25-40%), edge cases (zero wind, gale wind = power=0). [x] S1-T08 generation/bess_state.py: function simulate_bess_capacity(config: BessConfig, cum_cycles_per_year: list[float]) -> pd.Series returning usable MWh per year. Note: dispatch happens elsewhere; this module only models physical capacity. Augmentation as input list of (year, additional_mwh). [x] S1-T09 CLI: remodel simulate-gen --input scenario.json --output gen.parquet. [x] S1-T10 Parity test: placeholder created; tests skipped pending user-supplied Nagasamudra inputs + Excel expected values (see tests/fixtures/nagasamudra_inputs.json and tests/integration/test_parity.py). [x] S1-T11 Documentation: packages/engine/docs/generation.md explaining the module and how to extend.

Definition of Done: CLI generates 25y output for the user's reference scenario. Year-1 CUF matches Excel within 0.1%. All tests pass.

Sprint Retro

Done: All S1-T01 through T11 tasks complete. 43 unit tests pass, 2 integration tests skipped (parity gate, awaiting Nagasamudra data). Coverage 97.4%. Ruff clean, mypy strict clean.

Deviations:

  • Typer 0.12.5 is incompatible with Click 8.3.3 (Click's new UNSET sentinel causes Typer to set is_flag=True on all Path options). Upgraded to Typer 0.25.1 to fix.
  • Python 3.12 not installed; used 3.13 (pyproject.toml keeps ^3.12 constraint, 3.13 is compatible).
  • S1-T10 parity gate blocked — user must supply real Nagasamudra project data; unlock instructions are in tests/integration/test_parity.py docstring.

Next sprint prerequisite: User unlocks S1-T10 by filling tests/fixtures/nagasamudra_inputs.json with real project inputs and Excel-derived expected values.