Skip to content

Fix data pipeline bugs and write GOOD 2.x format - #2

Open
headisbagent wants to merge 5 commits into
mainfrom
v2-pipeline-fixes
Open

headisbagent wants to merge 5 commits into
mainfrom
v2-pipeline-fixes

Conversation

@headisbagent

@headisbagent headisbagent commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes the data problems found in the September 2026 GOOD model review, fixes several pipeline bugs, and makes the pipeline write GOOD 2.x format (ucdavis/good_model#3). The notebooks are replaced by one command, python build.py, which validates every output graph with GOOD. CI checks that the committed data can be rebuilt from Data/US/Raw (numbers must match to their last written digit).

Data fixes (from the model review)

  • Wind profiles had 25 values per day (D1). table_4-39_onshore.csv has an index column, so long_wide()'s iloc[:, 6:] started each day at "Day Of Month". Hour columns are now selected by name everywhere. The resulting wind profiles are identical to those in Grant 2/20/2026: Fixed onshore wind data #1, which fixed the same problem by editing the CSV; this change works with either version of the file.
  • Hydro profiles were never used and were one hour short (D2). Assets used "REGION:hydro:" and profiles "REGION:hydro", and iloc[:, 3:] dropped Hour_0. One profile_key() now names every profile, and hydro uses its monthly capacity factors as a daily energy budget.
  • New wind and solar capex was 1,000x too low (D5): $/kW / 1e6. It is now $/MW, with Table 4-16 fixed O&M and EPA's 9.78% capital charge rate. Range: $929–2,193/kW.
  • Storage had no duration or efficiency (D3). Existing batteries use plant-level durations from EIA-860 2021 Schedule 3-4 (added to Raw/; median 2.0 h, 63 of 102 matched). New batteries use EPA Table 4-35.
  • Transmission was lossless. Lines now carry EPA's 2.8% (WECC) and 2.4% losses, and the two directions of a path share a corridor.

Pipeline bugs found along the way

  • Missouri's RPS applied to nothing: 'Missouri': 'MO ' had a trailing space. 495 assets now match rps_MO.
  • Results were not reproducible: fill-in fuel and VOM costs used unseeded np.random.choice. The build now uses a seeded generator.
  • Offshore wind, biomass and landfill gas were not flagged renewable.
  • All existing wind and solar in a region used the first resource class's profile. They now use a capacity-weighted average of the region's classes.
  • Nuclear dispatch cost included fixed O&M and was rescaled to $21.2/MWh. It is now fuel plus variable O&M: mean $6.8/MWh. This moves nuclear down the dispatch order; please review.
  • pandas 3 breaks the old code. It crashes in renewable_transmission_cost, ffill(inplace=True) on a column becomes a no-op, and groupby().apply() offsets shift. The new code gives the same output on pandas 2.3 and 3.0.

Structure

  • build.py replaces Raw_Data.ipynb, Graph.ipynb, Aggregation.ipynb and process_data.py. It writes Data/US/Processed/ and GOOD graphs to Outputs/: the US, nine interconnect regions, and an aggregated California example.
  • good.graph and good.aggregate replace src/graph.py and the old aggregator.
  • plants.json and combined_assets.json are removed; nothing produced or read them.
  • metadata.json records units and every assumed parameter with its source.

Unchanged

Existing capacity is identical (1,135,501 MW, the same 18,993 units). Coal, gas and oil mean dispatch costs are unchanged. 22 zero-MW wind cost classes are no longer written as candidate sites.

Needs team review

Test plan

  • pytest -q: 21 tests pass on pandas 2.3 and 3.0. They cover the parsing fixes on synthetic tables and checks on the committed data, including GOOD validation of the full US graph.
  • python build.py --check: a fresh build matches the committed files on pandas 2.3 and 3.0.
  • python build.py: all 11 graphs pass GOOD validation.
  • Team review of the items above.

🤖 Generated with Claude Code

headisbagent and others added 5 commits September 28, 2026 16:16
Fixes the data problems found in the September 2026 GOOD model review:
- Wind profiles had 25 values per day: table_4-39_onshore.csv carries an
  index column, so iloc-based slicing started each day at "Day Of Month".
  Hour columns are now selected by name (load, solar and hydro too), which
  also keeps results unchanged under pandas 3.
- Hydro profiles dropped Hour_0 and were never attached to plants (asset
  key "REGION:hydro:" vs profile key "REGION:hydro"). One profile_key()
  now names every profile, and hydro uses the monthly capacity factors as a
  daily energy budget.
- New wind and solar capex was $/kW divided by 1e6; it is now $/MW (x1e3)
  with Table 4-16 fixed O&M and EPA's 9.78% capital charge rate.
- Storage gets durations and efficiencies: existing batteries from EIA-860
  2021 Schedule 3-4 (added to Raw/, fleet median 2 h otherwise), new
  batteries from EPA Table 4-35.
- Lines carry EPA inter-regional losses and share corridors.

Also fixes problems found in the pipeline itself:
- Missouri's state code was "MO " (trailing space), so rps_MO matched no
  assets.
- Offshore wind, biomass and landfill gas were not flagged renewable.
- Existing wind and solar all took the first resource class's profile; they
  now use a capacity-weighted average of the region's classes.
- Nuclear dispatch cost included fixed O&M and was rescaled to $21.2/MWh;
  it is now fuel plus variable O&M (mean $6.8/MWh).
- Fill-in costs were sampled with an unseeded np.random; a seeded Generator
  makes builds reproducible.
- ffill(inplace=True) on column selections becomes a no-op under pandas 3;
  replaced with assignment.

Outputs use GOOD 2.x units (MW, MWh, $/MWh, $/MW, kg/MWh), classes (wind
and solar are curtailable Producers, loads are positive MW) and declarative
policy filters. Every assumed value is in PARAMETERS with its source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build.py rebuilds Data/US/Processed and writes GOOD graphs to Outputs/
(the US, nine interconnect regions and an aggregated California example)
in one command, validating each graph against GOOD's input schema.
"python build.py --check" rebuilds into a temporary folder and fails if the
result differs from the committed files.

Removes Raw_Data.ipynb, Graph.ipynb, Aggregation.ipynb and process_data.py,
which build.py replaces, and src/graph.py, src/inputs/aggregate.py,
src/reload.py and src/progress_bar.py, which good.graph and good.aggregate
replace. Outputs/ now also ignores gzipped graphs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Built with "python build.py" (seed 0). Existing capacity is unchanged
(1,135,501 MW across the same 18,993 units). All 868 profiles have 8,760
values; wind profiles match those in PR #1. 22 zero-capacity wind cost
classes are no longer written as candidate sites. Removes plants.json and
combined_assets.json, which nothing produced or read, and adds
metadata.json with units and sourced parameters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tests cover the parsing fixes on synthetic tables (index columns, row
order, hour columns, profile keys, state codes, cost units, seeded
filling, line losses) and check the committed data: 8,760-value per-unit
profiles, resolved profile references, state codes, MW and $/MW ranges,
capacity against NEEDS, storage, policies, and GOOD validation of the full
US graph. CI runs them and "python build.py --check". The README documents
the build, outputs, units, sources and the assumptions that need review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's rebuild check failed on three weighted-average wind profiles: the
weights were applied with a matrix product, which BLAS computes in a
different order on Linux (OpenBLAS) and macOS (Accelerate), and seven
values landed on the other side of a 5th-decimal rounding boundary. The
average now uses elementwise operations, and "build.py --check" accepts
numbers that differ only in their last written digit. Regenerated the three
profiles (seven values change by 1e-5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant