Executed battery-dispatch run over the full 2018-2020 Attachment 2
series (225.9s, 1096 rolling-horizon windows) and committed the
results: outputs/ (dispatch.csv, annual/monthly summaries, summary.json,
four figures), README.md (setup, run instructions, assumptions, the
one-paragraph approach summary) and RESULTS.md (headline numbers,
per-year table, charts, commentary).
The full run surfaced three real issues, all fixed rather than papered
over:
- validate_schedule's soc_within_bounds check used a fixed 1e-6 MWh
tolerance for the "state of charge below zero" case, while its
sibling soc_matches_power_flows check already scales its tolerance
with sqrt(n) for the same reason (CBC's own solver precision
accumulating over a long cumulative sum). Over 52,608 half-hours this
false-failed on a 5.1e-6 MWh solver-noise dip, not a real violation.
Scaled it the same way.
- cli.py's summary printed net_of_opex_gbp under the label "Less fixed
opex", so the terminal output showed the post-opex profit (£193k)
where a reader would expect the opex figure itself (£15k). Split into
two correctly-labelled lines.
- plots.py's monthly revenue chart stacked Market 1 (always negative
here) and Market 2 (always positive) with a single running `bottom`,
which is only correct for same-signed series: Market 2's bar
completely overlapped and painted over Market 1's, hiding the
-£297k Market 1 loss entirely. Now accumulates positive and negative
contributions on separate baselines and marks the net.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>