Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
4940d6a
a few hourlize bug fixes
bsergi Aug 4, 2026
15695b8
remove old crs parameter
bsergi Aug 4, 2026
3dd92b8
add script to automate copying of reV data to ReEDS Supply_Curve_Data…
bsergi Aug 4, 2026
27bfc08
integrate reV folder copying into hourlize run
bsergi Aug 4, 2026
b019cf0
address datetime index as bytes bug
bsergi Aug 4, 2026
25ae346
remove some settings that are no longer used
bsergi Aug 4, 2026
59bc345
get cases from rev_paths file, remove cases.json files
bsergi Aug 4, 2026
1439453
additional bug fixes
bsergi Aug 5, 2026
89ef12c
add option to select for ATB technology with geothermal
bsergi Aug 5, 2026
dd4cc43
add atb_scenario to EGS config
bsergi Aug 5, 2026
15c9d66
add option to exclude techs when running hourlize
bsergi Aug 5, 2026
fe13e4b
updated rev_paths file
bsergi Aug 5, 2026
24241ca
updated supply curves with hourlize
bsergi Aug 5, 2026
8fcd354
new exogenous capacity and prescribed builds (temporary--will be remo…
bsergi Aug 5, 2026
c51499d
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Aug 7, 2026
c2dfe47
save mean_resource_temp for EGS
bsergi Aug 7, 2026
c2467bf
remove existing_capacity references
bsergi Aug 7, 2026
e337efc
updated supply curve files
bsergi Aug 7, 2026
ab5a9a7
add function to check status of hourlize runs
bsergi Aug 7, 2026
debbc5e
skip runs with 'none' listed for original rev folder
bsergi Aug 7, 2026
e2dbdd6
track original rev folder and date updated in config
bsergi Aug 7, 2026
a55adef
add back cf to egs
bsergi Aug 13, 2026
6b7ad1b
supply curve metadata update
bsergi Aug 13, 2026
be3b446
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Aug 13, 2026
267961a
Merge branch 'main' into bs/supply_curves
bsergi Aug 17, 2026
fdfe393
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Aug 18, 2026
6a1bd16
add script to generate supply curve maps for docs
bsergi Aug 18, 2026
7a3db49
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Aug 18, 2026
cdf8f16
Merge branch 'main' into bs/supply_curves
bsergi Aug 18, 2026
50186a6
move supply_curve_plots.py into plotting_scripts folder; add presenta…
bsergi Aug 18, 2026
8e57156
Merge branch 'bs/supply_curves' of github.com:ReEDS-Model/ReEDS into …
bsergi Aug 18, 2026
d8dd87d
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Aug 27, 2026
a6752e0
add egs plot
bsergi Aug 27, 2026
3cf9af7
hourlize README update
bsergi Aug 27, 2026
424844b
add tech filtering for docs plots
bsergi Sep 2, 2026
916d1f2
finish techs argument to map plots
bsergi Sep 2, 2026
2dd3db5
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Sep 3, 2026
cc9b803
update EGS supply curve map and table
bsergi Sep 4, 2026
fa88756
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Sep 4, 2026
b7b672c
remove stale config entries and update the hourlize README
bsergi Sep 4, 2026
3f8c585
A few more README edits
bsergi Sep 4, 2026
08199c5
add and use spatial.site2poly_buffer()
patrickbrown4 Sep 9, 2026
e1cc112
add input_diff_plots.plot_sc_diffs()
patrickbrown4 Sep 9, 2026
30ebfe9
input_diff_plots.py: add support for wind-ofs
patrickbrown4 Sep 11, 2026
3f7fabe
input_diff_plots.py: adapt plot_cf_diff() for site-level CF profiles
patrickbrown4 Sep 11, 2026
68d46e6
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Sep 17, 2026
3f09f06
add helper function for collecting Zenodo input files
bsergi Sep 17, 2026
74745ef
remove dead code from mode check in run_hourlize.py
bsergi Sep 17, 2026
c89d18d
plot AC capacity for UPV
bsergi Sep 17, 2026
fc77c3c
update UPV supply curve map to use AC capacity
bsergi Sep 17, 2026
91fd2c3
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Sep 17, 2026
fd33421
Merge branch 'bs/supply_curves' of github.com:ReEDS-Model/ReEDS into …
bsergi Sep 17, 2026
27ada0d
update wind-ofs zenodo record id and checksums
bsergi Sep 17, 2026
babca9d
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi Sep 21, 2026
990227a
prompt user before recopying original reV folders
bsergi Sep 22, 2026
45213b8
use original reV supply curve file before copying for column checking
bsergi Sep 22, 2026
d318186
remove geothermal table
bsergi Sep 22, 2026
dd610ce
remove unused subtract_exog argument
bsergi Sep 22, 2026
e74a977
ensure copy_to_shared is false by default
bsergi Sep 22, 2026
158994c
Merge branch 'main' into bs/supply_curves
bsergi Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/source/figs/docs/supplycurve-egs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/source/figs/docs/supplycurve-upv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/source/figs/docs/supplycurve-wind-ofs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/source/figs/docs/supplycurve-wind-ons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions docs/source/figs/docs/supplycurve-windofs.png

This file was deleted.

3 changes: 0 additions & 3 deletions docs/source/figs/docs/supplycurve-windons.png

This file was deleted.

47 changes: 14 additions & 33 deletions docs/source/model_documentation.md

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.

We should probably recreate Fig29. for EGS technical potential since the supply curve is updated? Or since reV supply curves for geohydro are forthcoming so we could update it for both technologies together later.

@bsergi bsergi Aug 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point. I took a first pass at recreating the EGS portion and got the following:

supplycurve-egs

The map looks pretty different from what's in the docs, and the total supply curve capacity here (~13 TW) is lower than the ~17 GW of near-field + deep EGS listed in Table 6. This might be because the original map shows the full technical potential whereas this one shows what goes into ReEDS after picking the best resources at each depth. Do you know if that's the case or if something else if going on here?

As for hydrothermal I think we might consider dropping that figure for now since it isn't supported by the model and then adding it back in once we get the updated reV data.

Original file line number Diff line number Diff line change
Expand Up @@ -886,48 +886,29 @@ The hydrothermal potential included in the base supply curve comprises only iden
- EGS sites are geothermal resources that have sufficient temperature but lack the natural permeability, in situ fluids, or both, to be hydrothermal systems.
Developing these sites with water injection wells could create engineered geothermal reservoirs appropriate for harvesting heat.

EGS is further separated into near-field EGS and deep EGS based on proximity to known hydrothermal features.
Near-field EGS represents additional geothermal resource available near hydrothermal fields that have been identified.
EGS is further separated into near-field EGS and deep EGS.
Near-field EGS represents geothermal resource available near hydrothermal fields that have been identified.
Deep EGS represents available geothermal resource not tied to existing hydrothermal sites and at depths below 3.5 km.

Geothermal in ReEDS represents geothermal power production with a representative plant size up to 100 megawatts electric (MW<sub>e</sub>).
Geothermal in ReEDS represents geothermal power production with a representative plant size up to 50 megawatts electric (MW<sub>e</sub>).
Geothermal resource classes are defined by reservoir temperature ranges, which are closely linked to the cost of a plant normalized by generation capacity.
Energy conversion processes, including binary and flash cycles, are linked to reservoir temperature and are specified by resource class.
Plants with reservoir temperatures \<200°C (Class 7--10) use a binary cycle, which uses a heat exchanger and secondary working fluid with a lower boiling point to drive a turbine.
All other reservoir temperatures assume a turbine is driven directly by working fluid from the geothermal wells.
These assumptions are aligned with those in the 2024 ATB.

{numref}`technical-resource-potential` lists the technical resource potential for the different geothermal categories.

```{table} Technical Resource Potential (GW)
:name: technical-resource-potential
| **Resource Class** | Reservoir Temperature **(°C)** | **Hydrothermal** | **Near-Field EGS** | **Deep EGS** |
|:------------------:|:------------------------------:|:----------------:|:------------------:|:------------:|
| Class 1 | \> 325 | \- | 0.2 | 7.3 |
| Class 2 | 300–325 | 2.2 | 0.2 | 35 |
| Class 3 | 275–300 | 1.2 | 0.1 | 177 |
| Class 4 | 250–275 | 0.7 | 0.1 | 1696 |
| Class 5 | 225–250 | 0.2 | 0.1 | 4633 |
| Class 6 | 200–225 | 0.9 | 0.2 | 6467 |
| Class 7 | 175–200 | 12 | 0.3 | 3234 |
| Class 8 | 150–175 | 342 | 0.3 | \- |
| Class 9 | 125–150 | 2823 | 0.03 | \- |
| Class 10 | \<125 | 699 | \- | \- |
| Total | | 3881 | 1.4 | 16249 |
```

```{figure} figs/docs/geothermal-resource-availability.png
:name: figure-geothermal-resource-availability

Resource availability for hydrothermal (left) and deep EGS (right) for the CONUS.
```{figure} figs/docs/supplycurve-egs.png
:name: figure-supplycurve-egs

Resource availability for deep EGS.
```

The default geothermal resource assumptions allow for hydrothermal sites.
Identified hydrothermal resources are based on the U.S. Geological Survey's 2008 geothermal resource assessment.
The undiscovered portion of the hydrothermal resource is limited by a discovery rate defined as part of the GeoVision Study {cite}`doeGeoVisionHarnessingHeat2019`.
Existing exogenous hydrothermal capacity is treated as already discovered; the discovery rate applies to the remaining resource available for new investment.
Prescribed builds retain this discovery treatment, with first-bin resource added only as needed to keep the prescriptions feasible.
The geothermal supply curves are based on the analysis described by {cite}`augustineGeoVisionAnalysisSupporting2019` and are shown in {numref}`figure-geothermal-resource-availability`.
The geothermal supply curves are based on the analysis described by {cite}`augustineGeoVisionAnalysisSupporting2019`.
The hydrothermal and near-field EGS resource potential is derived from the U.S. Geological Survey's 2008 geothermal resource assessment {cite}`williamsReviewMethodsApplied2008a`, whereas the deep EGS resource potential is based on an update of the EGS potential from the Massachusetts Institute of Technology {cite}`testerFutureGeothermalEnergy2006`.
As with other technologies, geothermal cost and performance projections are from the ATB {cite}`nrel2024AnnualTechnology2024`.
Default geothermal capacity representation in ReEDS is categorized by depth and is based on reV analysis {cite}`pinchukpaulDevelopmentGeothermalModule2023`, which estimates potential and site-based levelized cost of energy (LCOE) based on resource assessment at various depths, development constraints, land use characteristics, and grid infrastructure (spur line transmission) costs.
Expand Down Expand Up @@ -1041,16 +1022,16 @@ Capacity factors for wind plants coming online from 2010 through 2023 are taken
Available land-based wind resources and site-specific cost and performance are based on {cite}`lopezRenewableEnergyTechnical2025`, using outputs of the reV model {cite}`maclaurinRenewableEnergyPotential2021`.
The Reference Access case includes more than 49,000 potential wind sites, totaling more than 9,400 gigawatts (GW).
Limited Access and Open Access supply curves are also available.
Available resource for the three access cases and associated average capacity factors are shown in {numref}`figure-supplycurve-windons`.
Available resource for the three access cases and associated average capacity factors are shown in {numref}`figure-supplycurve-wind-ons`.
In ReEDS, each wind site is characterized with a supply curve cost, which comprises transmission spur line and reinforcement upgrade costs as well as site-specific capital cost adjustments based on region, land cost, and site capacity (to account for economies of scale).
See the [Interzonal Transmission](#interzonal-transmission) section for more discussion of the interconnection supply curves for accessing the wind resource.

The individual wind sites are grouped into 10 resource classes based on *k*-means clustering of average annual capacity factors.
Distinct wind generation profiles are represented in ReEDS for each region and class, based on capacity-weighted averages of all sites of that region and class.
Sites are also grouped into a flexible number of supply curve cost bins in ReEDS, with 10 bins used by default for each ReEDS region and class.

```{figure} figs/docs/supplycurve-windons.png
:name: figure-supplycurve-windons
```{figure} figs/docs/supplycurve-wind-ons.png
:name: figure-supplycurve-wind-ons

Land-based wind resource availability and capacity factor for the three siting scenarios included in ReEDS.
```
Expand All @@ -1074,11 +1055,11 @@ The offshore technology selection is made using the Offshore Wind Cost Model, wh
See also {cite}`lopezRenewableEnergyTechnical2025` for more information on the development of the resource supply curves.

Resource availability varies across different siting access cases: The Reference Access case has 4,064 sites totaling 2.97 terawatts (TW), the Open Access case has 4,524 sites totaling 3.534 TW, and the Limited Access case with 3,166 sites totals 2.212 TW.
Modeled site-level capacity factor and resource availability are shown in {numref}`figure-supplycurve-windofs`.
Modeled site-level capacity factor and resource availability are shown in {numref}`figure-supplycurve-wind-ofs`.
Additional details regarding offshore wind resource modeling can be found in {cite}`lopezRenewableEnergyTechnical2025`.

```{figure} figs/docs/supplycurve-windofs.png
:name: figure-supplycurve-windofs
```{figure} figs/docs/supplycurve-wind-ofs.png
:name: figure-supplycurve-wind-ofs

Offshore wind resource availability by siting access case for the CONUS
```
Expand Down
186 changes: 186 additions & 0 deletions docs/source/plotting_scripts/supply_curve_plots.py

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.

This is very handy!

Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
'''
Generates maps of the supply curves capacity.
Can be used to re-create documentation figures or to generate a summary
figure for a presentation.
'''

import sys
import numpy as np
import pandas as pd
from pathlib import Path
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import patheffects as pe
import geopandas as gpd
import shapely
import argparse
import traceback
import cmocean

reeds_path = Path(__file__).resolve().parents[3]
sys.path.append(str(reeds_path))
import reeds
from reeds import plots
from postprocessing import input_plots

plots.plotparams()

savepath = reeds_path / 'docs' / 'source' / 'figs' / 'docs'
savepath.mkdir(parents=True, exist_ok=True)

def saveit(savename, fig=None):
outpath = savepath / (savename.lower().replace(' ', '-') + '.png')
(fig or plt.gcf()).savefig(outpath, bbox_inches='tight')
print(outpath)


def add_capacity_total(ax, df, fontsize=14):
ax.annotate(
f'{df.capacity.sum() / 1e6:.0f} TW', (0.08, 0.10),
xycoords='axes fraction', ha='left', va='bottom', fontsize=fontsize, zorder=1e8,
)


def plot_docs(techs):
for tech in techs:
print(f"plotting supply curve for {tech}")

if tech == 'egs':
panels = [
('reference', 'capacity', 'Reference access'),
]
fig, ax = plt.subplots(figsize=(6.5, 5.25))
axes = [ax]
else:
panels = [
('open', 'capacity', 'Open access'),
('reference', 'capacity', 'Reference access'),
('limited', 'capacity', 'Limited access'),
('open', 'cf', ''),
]
fig, axs = plt.subplots(
2, 2, figsize=(13, 10.5),
gridspec_kw={'hspace': 0.08, 'wspace': 0.04},
)
axes = axs.flat

for ax, (access, column, title) in zip(axes, panels):
f, ax, df, col = next(input_plots.map_supplycurves(
access=access,
tech=tech,
cols_out=column,
draw_stats=False,
title=title,
title_fontsize=16,
title_fontweight='bold',
cbar_ticklabel_fontsize=12,
cbar_title_fontsize=14,
cbar_labelpad=2.6,
f=fig,
ax=ax,
))
if col == 'capacity':
add_capacity_total(ax, df)
if col == 'cf':
capacity_factor_cbar_ax = fig.axes[-2]

# dividing line settings for capacity factor plot (not used for egs)
if tech != 'egs':
capacity_factor_ax = axs[1, 1]
separator = {'color': '0.55', 'lw': 1.5, 'clip_on': False, 'zorder': 1e9}
capacity_factor_ax.plot([0, 1], [1, 1], transform=capacity_factor_ax.transAxes, **separator)
capacity_factor_position = capacity_factor_ax.get_position()
fig.canvas.draw()
caption_bottom = min(
text.get_window_extent(fig.canvas.get_renderer())
.transformed(fig.transFigure.inverted()).y0
for text in capacity_factor_cbar_ax.texts
)
# draw dividing line
fig.add_artist(mpl.lines.Line2D(
[capacity_factor_position.x0, capacity_factor_position.x0],
[caption_bottom - 0.005, capacity_factor_position.y1],
transform=fig.transFigure, **separator,
))

saveit(f"supplycurve {tech}", fig=fig)
plt.close(fig)


def plot_presentation():
access_cases = ['open', 'reference', 'limited']
technologies = {
'upv': 'Utility-scale PV',
'wind-ons': 'Land-based wind',
}
row_labels = ['Open\naccess', 'Reference\naccess', 'Limited\naccess']

fig = plt.figure(figsize=(6.5, 5.6))
grid = fig.add_gridspec(
4, 2, height_ratios=[1, 1, 1, 0.06],
left=0.16, right=0.98, bottom=0.09, top=0.94,
hspace=0.08, wspace=0.06,
)
map_axes = np.empty((len(access_cases), len(technologies)), dtype=object)

for col, (tech, tech_label) in enumerate(technologies.items()):
colorbar_mappable = None
for row, (access, row_label) in enumerate(zip(access_cases, row_labels)):
ax = fig.add_subplot(grid[row, col])
map_axes[row, col] = ax
f, ax, df, _ = next(input_plots.map_supplycurves(
access=access,
tech=tech,
cols_out='capacity',
draw_colorbar=False,
draw_stats=False,
f=fig,
ax=ax,
))
add_capacity_total(ax, df, fontsize=12)
if row == 0:
ax.set_title(tech_label, fontsize=12, fontweight='bold', pad=2)
if col == 0:
ax.annotate(
row_label, (-0.08, 0.5), xycoords='axes fraction',
ha='right', va='center', fontsize=10, clip_on=False,
)
colorbar_mappable = ax.collections[-1]

colorbar_ax = fig.add_subplot(grid[-1, col])
colorbar = fig.colorbar(colorbar_mappable, cax=colorbar_ax, orientation='horizontal')
colorbar.ax.xaxis.set_major_formatter(
mpl.ticker.FuncFormatter(lambda value, _: f'{value / 1e3:g}')
)
colorbar.ax.tick_params(labelsize=9, pad=1)
colorbar.set_label('Capacity [GW]', fontsize=10, fontweight='bold', labelpad=2)

saveit('supplycurve-capacity-summary', fig=fig)
plt.close(fig)


def main():
parser = argparse.ArgumentParser(description='Generate supply-curve availability maps.')
parser.add_argument(
'--mode', choices=['docs', 'presentation'], default='docs',
help='Plot layout to generate.',
)
parser.add_argument(
'--techs', '-t', nargs='+',
choices=['upv', 'wind-ons', 'wind-ofs', 'egs'],
default=['upv', 'wind-ons', 'wind-ofs', 'egs'],
help='Optional tech filter(s) for docs plots, e.g. --techs upv wind-ons')
args = parser.parse_args()

try:
if args.mode == 'docs':
plot_docs(args.techs)
else:
plot_presentation()
except Exception:
print(traceback.format_exc())
raise


if __name__ == '__main__':
main()
Loading
Loading