Skip to content

[PSH] Update PSH Supply Curves for Site-Level Processing - #184

Merged
jvcarag merged 34 commits into
mainfrom
vc/UnitLevelPSHSC
Oct 14, 2026
Merged

jvcarag merged 34 commits into
mainfrom
vc/UnitLevelPSHSC

Conversation

@jvcarag

@jvcarag jvcarag commented Aug 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR updates the pumped-storage hydropower (PSH) supply curve input files with the latest (5th-generation) PSH resource and cost data as described at https://www.nlr.gov/gis/psh-supply-curves.

PSH input files are now stored at site-level spatial resolution, and input processing procedures are modified to aggregate the site-level data up to the spatial resolution of each corresponding ReEDS run. In effect, PSH supply curves are now processed using the same procedures as those used for other RSC technologies such as upv, wind-ons, and wind-ofs. The old PSH supply curves (pre-binned at the old 134-zone model resolution) are removed due to their incompatibility with the new input processing procedures which require the data at site-level resolution.

The new PSH supply curve input files also reflect new site exclusion scenarios labeled "Reference", "Open", and "Limited" that are more consistent with wind and solar resource availability scenarios. "Open" is most similar to earlier PSH scenarios including existing reservoir sites (wExist) and sites overlapping with ephemeral streams (wEph). "Limited" is a new case with more stringent PSH siting restrictions from the "Reference" case. Below is a comparison of the new binned supply curves for 8-hr storage duration PSH vs the old binned supply curves - the old default 12hr_ref scenario is also included for comparison between old and new defaults:

line_PSH_SC_old_vs_new_z132

Technical details

Site-Level PSH Supply Curve Input Files:
PSH supply curve capacity and capital cost input files are now stored in a single, site-level spatial resolution input file (previously separated and at z132-resolution), using the latitude/longitude coordinates of the lower reservoir as the location of the powerhouse and its corresponding generating capacity potential. The coordinates of each site's paired upper reservoir are also provided in the input files, available only for the purpose of post-ReEDS mapping. Interconnection and transmission costs are appended to the PSH supply curve using each site's lower reservoir latitude/longitude coordinates to map to the nearest (Euclidean distance) reV site in inputs/supply_curve/interconnection_land.h5. Mapping with latitude/longitude coordinates instead of sc_point_gid mapping ensures PSH supply curves stay compatible with any future updates to the reV sites in the model.

PSH Supply Curve Scenarios:
To align more closely with siting scenarios for other resources (solar and wind), PSH site exclusion scenarios are now consolidated into 3 distinct scenarios: limited, reference, and open. Below are the exclusion layers included in each of the 3 scenarios:

  • open: urbanized/developed areas, existing waterbodies, 100yr flood plains, various federal, state, and local protected areas and conservations, glaciers, snow/ice, and wetland ecosystems, and airports/airpads/helipads
  • reference: all "open" exclusions [plus] ephemeral streams, critical habitats for endangered species, railways/pipelines/roads (incl. 30m buffer), and national wetlands
  • limited: all "reference" exclusions [plus] agricultural lands, mature forests on federal lands, building footprints, and tribal areas (reservation and off reservation trust land)
    This change also simplifies the combinations of PSH supply curves and reduces file count in inputs/supply_curve,

Below are the new unbinned open, reference, and limited PSH supply curves for 8-, 10-, and 12-hr PSH storage durations:
line_PSH_SC_raw

Implementation notes

Input Files:

  • Add new site-level PSH supply curve files and remove old vintages of BA-level PSH supply curve files
  • Update inputs/storage/PSH_supply_curves_durations.csv with entries for new PSH supply curve files
  • cases.csv: update options for pshsupplycurve switch, add numbins_psh switch for controlling PSH supply curve bin number, and set 8-hr Reference case as default for pshsupplycurve
  • Update inputs/supply_curve/dollaryear.csv with entry for new PSH supply curve files
    Input Processing
  • runfiles.csv: remove old psh_supply_curves_{capacity|cost}.csv entries and add new supplycurve_psh.csv entry
  • writesupplycurves.py: update procedures in agg_supplycurve() function for assembling/aggregating supply curves for use with site-level PSH supply curves.
    • New procedure clips pre-binned supply curve values at $4000/kW [2004$] to improve binning resolution at the low-cost end
  • io.py: add nearest-point mapping of interconnection costs to PSH supply curve to assemble_supplycurve() function

Additional changes

  • b_inputs.gms: remove unit adjustment for pumped-hydro supply curve costs, as new input files are already stored at $/MW
  • recf.csv: remove deprecated copy argument from pd.concat() calls
  • reeds2.py: add new ReEDS result and associated preset function to calculate and display cumulative capacity additions by technology and model year

Switches added/removed/changed

  • pshsupplycurve: updated Choices to reflect new exclusion scenarios
  • numbins_psh: added new switch to control number of PSH supply curve bins
  • numbins_{upv|windons}: updated Description to reflect current default setting

Issues resolved

Issue #174

Known incompatibilities

Note that while available generating capacity for PSH in ReEDS does account for frictional head losses in the conveyance system, the round-trip efficiency for PSH still uses a generic value that does not account for these losses, which are site-specific. Future work will explore ways to better account for efficiency reductions from frictional losses, either by incorporating site-level efficiencies into supply curve data or calculating a reasonable standard efficiency adjustment.

Relevant sources or documentation

Validation, testing, and comparison report(s)

Old vs New Default PSH Supply Curve Comparison

A comparison of the USA_Defaults case using the old 12-hr Reference PSH supply curve on the main branch vs this PR branch which uses the new default 8-hr Reference PSH supply curve was conducted. Below are the capacity, generation, and system cost results comparison:

image Screenshot 2026-09-28 at 11 15 04 AM Screenshot 2026-09-28 at 11 17 24 AM

comparison_default_mainv-vs-branch.zip

The less resource-available, lower-duration 8-hr Reference PSH supply curve used as the new default result in a 1.2 GW reduction of PSH deployment by 2050 (25.5 -> 24.3 GW) in favor of Battery, also displacing Gas-CT and wind capacity/generation with Gas-CC/CCS and Solar.

High PSH Deployment Scenario

The new reference case only deploys an additional 3.5 GW PSH from 2025-2050 for a national total of ~23GW PSH storage capacity by 2050. To better understand the effects of the new supply curve and updated exclusion layer scenarios on PSH deployment, provided below are the PSH capacity deployment results [GW] of a "high PSH deployment" ReEDS scenario:
New PSH Capacity deployed from 2025-2050 [GW]:
bokeh_plot
Screenshot 2026-10-05 at 9 49 02 AM
New PSH Capacity deployed from 2025-2050 [GW]:
bokeh_plot (1)
Screenshot 2026-10-05 at 9 53 05 AMScreenshot 2026-10-05 at 9 53 28 AMScreenshot 2026-10-05 at 9 53 52 AMScreenshot 2026-10-05 at 9 54 39 AM

high_PSH_deployment_scenario_plots.zip

This scenario assumes favorable cost and performance metrics for solar and unfavorable metrics for li-ion battery technologies, as well as a linear reduction of PSH capital cost to 50% by 2050 to simulate a case that encourages high deployment of PSH capacity across CONUS. The 8-hr reference case deploys up to 83 GW PSH by 2050, with 47 GW deploying in CA, 10 GW in AZ, and 7 GW in NV.

Checklist for author

Details to double-check

  • Charge code provided to reviewers
  • Included comparison reports for appropriate test cases
  • Documentation updated if necessary
  • If input data added/modified:
    • Dollar year recorded and converted to 2004$ for GAMS
    • Units are specified
    • Preprocessing steps have been documented and committed in ReEDS_Input_Processing PR21
  • Code formatting standardized
  • Reusable functions used where possible instead of copy/pasted code

General information to guide review

  • Zero impact on results of default case
  • No large data file(s) added/modified
  • No substantive impact on runtime for full-US reference case
  • No substantive impact on folder size for full-US reference case
  • No change to process flow (runreeds.py, reeds/core/solve/solve.py)
  • No change to code organization
  • No change to package requirements (environment.yml or Project.toml)

Tag points of contact here if you would like additional review of the relevant parts of the model

jvcarag and others added 7 commits July 29, 2026 16:37
* Add new open-siting 10-hr supply curve at lat/lon resolution
* Update writesupplycurves.py to process new SC data using same procedures as wind/solar
* reeds/io.py: add nearest-point mapping for PSH to assemble_supplycurve() function
* Add regional tech class assignment procedures to hourlize/resource.py
* runfiles.csv: add PSH supply curve entry and remove old PSH supply curve capacity/cost entries
* cases.csv: temporarily remove `pshsupplycurve` switch options
* inputs/supply_curve/dollaryear.csv: add PSH supply curve entry
Future PSH supply curves will be stored at $/MW, consistent with all other tech supply curve costs processed by the agg_supplycurve function in writesupplycurves.py
@github-actions github-actions Bot added the docs label Sep 23, 2026
Comment thread hourlize/resource.py
- remove old PSH supply curve entries from inputs/storage/PSH_supply_curves_durations.csv and inputs/supply_curve/dollaryear.csv
- fix descriptions of options for numbins_{upv|windons} in cases.csv
- remove lines appending ReEDS root path to PATH variable in reeds/io.py (added for this PR but no longer needed)
- add new bokeh result for calculating cumulative new capacity by model year

@stuartcohen8 stuartcohen8 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be good to have someone else take a look at the input processing scripts in case there are any code improvements there. Otherwise just some minor comments to help improve clarity.

Comment thread inputs/storage/PSH_supply_curves_durations.csv
Comment thread inputs/storage/PSH_supply_curves_durations.csv Outdated
Comment thread inputs/supply_curve/README.md Outdated
Comment thread inputs/supply_curve/README.md Outdated
Comment thread postprocessing/bokehpivot/reeds2.py
@stuartcohen8

Copy link
Copy Markdown

Per our conversation, it could also be good to include a before/after results comparison for a scenario setup with at least a few GW of new PSH deployment.

@jvcarag
jvcarag requested a review from kodiobika October 2, 2026 23:03
@jvcarag
jvcarag requested a review from stuartcohen8 October 7, 2026 18:41
@jvcarag jvcarag mentioned this pull request Oct 7, 2026
24 tasks

@kodiobika kodiobika left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this! It's really nice to have site-level resolution for PSH. Overall looks great, just some small things. Happy to approve once those are addressed, but if you're up for it, there are two final checks I'd recommend to make sure nothing unrelated to PSH is impacted by the code changes:

  • Run this branch and main with PSH disabled and make sure the results are unchanged
  • Re-run hourlize for the non-PSH techs and make sure the generated inputs are unchanged (but @mmowers would have a better sense of how impactful your hourlize changes are, so I'd defer to him on that)

Comment thread helpers/runstatus.py
Comment thread inputs/supply_curve/README.md Outdated
Comment thread reeds/io.py Outdated
Comment thread reeds/io.py Outdated
Comment thread reeds/io.py Outdated
Comment thread reeds/input_processing/writesupplycurves.py Outdated
Comment thread reeds/input_processing/writesupplycurves.py Outdated
Comment thread reeds/input_processing/writesupplycurves.py Outdated
 - `io.py`: update boolean logic for psh for brevity and `if psh:` conditional logic to be more clear
 - `writesupplycurves.py`: update conditional logic to be more clear, employ underscore convention for unused formula output
 - `inputs/supply_curve/README.md`: condense sentences for brevity
@jvcarag

jvcarag commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for doing this! It's really nice to have site-level resolution for PSH. Overall looks great, just some small things. Happy to approve once those are addressed, but if you're up for it, there are two final checks I'd recommend to make sure nothing unrelated to PSH is impacted by the code changes:

  • Run this branch and main with PSH disabled and make sure the results are unchanged
  • Re-run hourlize for the non-PSH techs and make sure the generated inputs are unchanged (but @mmowers would have a better sense of how impactful your hourlize changes are, so I'd defer to him on that)

Thanks for the review Kodi! I've addressed all you suggestions and appreciate their point of brevity and clarity.

Prior to merging I'll be sure to run those final checks to ensure no unintentional changes are happening.

@patrickbrown4 patrickbrown4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Vincent, it's great to get these in the same format!

Would you mind running the MARICTNYNJPAOH_Offshore case in cases_test.csv just to make sure it still works after the reeds.io.assemble_supplycurve() changes?

The runtime difference is also surprisingly large, which makes me wonder if the main branch and PR branch were in sync. Would you mind rerunning the USA_defaults test again once you've caught them both up?

Comment thread cases.csv Outdated
Comment thread cases.csv Outdated
Comment thread inputs/supply_curve/PSH_supply_curves_capacity_10hr_ref_apr2025.csv Outdated
Comment thread reeds/input_processing/writesupplycurves.py Outdated
Comment thread reeds/io.py Outdated
@jvcarag

jvcarag commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for doing this! It's really nice to have site-level resolution for PSH. Overall looks great, just some small things. Happy to approve once those are addressed, but if you're up for it, there are two final checks I'd recommend to make sure nothing unrelated to PSH is impacted by the code changes:

  • Run this branch and main with PSH disabled and make sure the results are unchanged
  • Re-run hourlize for the non-PSH techs and make sure the generated inputs are unchanged (but @mmowers would have a better sense of how impactful your hourlize changes are, so I'd defer to him on that)

Confirmed by testing both main and branch Pacific test case where GSw_Storage == 0 that there are no changes to model results besides an inconsequentially-small difference in generation. Below shows the difference to national Generation [TWh] between the results of the branch run vs main run:
Screenshot 2026-10-09 at 4 57 26 PM

- `writesupplycurves.py`: added annotation for agg_supplycurve() function to include type hints and unit specification
- `cases.csv`: removed options for numbins_{windons|upv} switches
- `io.py`: update "psh" boolean in assemble_supplycurve() function
@jvcarag

jvcarag commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks Vincent, it's great to get these in the same format!

Would you mind running the MARICTNYNJPAOH_Offshore case in cases_test.csv just to make sure it still works after the reeds.io.assemble_supplycurve() changes?

The runtime difference is also surprisingly large, which makes me wonder if the main branch and PR branch were in sync. Would you mind rerunning the USA_defaults test again once you've caught them both up?

Thanks for the review @patrickbrown4 - I've addressed the suggested changes you left. Regarding the runtime difference, you were correct in that main and PR branch were out of sync. I've updated the plot in the PR with the new comparison of synced branches.

The requested MARICTNYNJPAOH_Offshore test case is currently running - I will update you once it completes.

@jvcarag

jvcarag commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

Testing found that the MARICTNYNJPAOH_Offshore test case is broken in the main branch, likely from recent updates to the offshore wind supply curves in PR #183

For the purposes of this PR this test case will be ignored, and the PR is ready to merge.

@stuartcohen8 stuartcohen8 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code-formulation is good. It might be good to post a downloadable html version of the state-wise deployment bar chart for the high deployment scenario. There are too many similar colors to reliably map those results to specific states.

@jvcarag
jvcarag merged commit eb75a6b into main Oct 14, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants