-
Notifications
You must be signed in to change notification settings - Fork 16
2025 Supply Curves Update #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bsergi
wants to merge
31
commits into
main
Choose a base branch
from
bs/supply_curves
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
4940d6a
a few hourlize bug fixes
bsergi 15695b8
remove old crs parameter
bsergi 3dd92b8
add script to automate copying of reV data to ReEDS Supply_Curve_Data…
bsergi 27bfc08
integrate reV folder copying into hourlize run
bsergi b019cf0
address datetime index as bytes bug
bsergi 25ae346
remove some settings that are no longer used
bsergi 59bc345
get cases from rev_paths file, remove cases.json files
bsergi 1439453
additional bug fixes
bsergi 89ef12c
add option to select for ATB technology with geothermal
bsergi dd4cc43
add atb_scenario to EGS config
bsergi 15c9d66
add option to exclude techs when running hourlize
bsergi fe13e4b
updated rev_paths file
bsergi 24241ca
updated supply curves with hourlize
bsergi 8fcd354
new exogenous capacity and prescribed builds (temporary--will be remo…
bsergi c51499d
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi c2dfe47
save mean_resource_temp for EGS
bsergi c2467bf
remove existing_capacity references
bsergi e337efc
updated supply curve files
bsergi ab5a9a7
add function to check status of hourlize runs
bsergi debbc5e
skip runs with 'none' listed for original rev folder
bsergi e2dbdd6
track original rev folder and date updated in config
bsergi a55adef
add back cf to egs
bsergi 6b7ad1b
supply curve metadata update
bsergi be3b446
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi 267961a
Merge branch 'main' into bs/supply_curves
bsergi fdfe393
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi 6a1bd16
add script to generate supply curve maps for docs
bsergi 7a3db49
Merge remote-tracking branch 'origin/main' into bs/supply_curves
bsergi cdf8f16
Merge branch 'main' into bs/supply_curves
bsergi 50186a6
move supply_curve_plots.py into plotting_scripts folder; add presenta…
bsergi 8e57156
Merge branch 'bs/supply_curves' of github.com:ReEDS-Model/ReEDS into …
bsergi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is very handy! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| ''' | ||
| 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(): | ||
| for tech in ['upv', 'wind-ons', 'wind-ofs']: | ||
| print(f"plotting supply curve for {tech}") | ||
|
|
||
| fig, axs = plt.subplots( | ||
| 2, 2, figsize=(13, 10.5), | ||
| gridspec_kw={'hspace': 0.08, 'wspace': 0.04}, | ||
| ) | ||
| panels = [ | ||
| ('open', 'capacity', 'Open access'), | ||
| ('reference', 'capacity', 'Reference access'), | ||
| ('limited', 'capacity', 'Limited access'), | ||
| ('open', 'cf', ''), | ||
| ] | ||
|
|
||
| for ax, (access, column, title) in zip(axs.flat, 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] | ||
|
|
||
| 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 | ||
| ) | ||
| 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.', | ||
| ) | ||
| args = parser.parse_args() | ||
|
|
||
| try: | ||
| if args.mode == 'docs': | ||
| plot_docs() | ||
| else: | ||
| plot_presentation() | ||
| except Exception: | ||
| print(traceback.format_exc()) | ||
| raise | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| """ | ||
| Copy reV supply curve source folders to the shared ReEDS supply curve directory. | ||
|
|
||
| Source: original_rev_folder (from rev_paths.csv) | ||
| Destination: /kfs2/shared-projects/reeds/Supply_Curve_Data/{sc_path}/reV/{rev_case} | ||
|
|
||
| Usage: | ||
| python copy_rev_folders.py | ||
| python copy_rev_folders.py --tech wind-ons upv | ||
| python copy_rev_folders.py --sc_path ONSHORE/2025_08_31_NewSites | ||
| python copy_rev_folders.py --overwrite # skip overwrite prompts | ||
| """ | ||
| import argparse | ||
| import os | ||
| import subprocess | ||
| import time | ||
|
|
||
| import pandas as pd | ||
|
|
||
|
|
||
| DEST_BASE = '/kfs2/shared-projects/reeds/Supply_Curve_Data' | ||
| DEFAULT_CSV = os.path.join( | ||
| os.path.dirname(os.path.abspath(__file__)), | ||
| '..', 'inputs', 'supply_curve', 'rev_paths.csv', | ||
| ) | ||
|
|
||
|
|
||
| def main(rev_paths_csv, techs=None, sc_paths=None, overwrite=False): | ||
| t0 = time.perf_counter() | ||
| # load rev paths file | ||
| df = pd.read_csv(rev_paths_csv) | ||
|
|
||
| # subset runs as specified | ||
| if techs: | ||
| df = df.loc[df['tech'].isin(techs)] | ||
| if sc_paths: | ||
| df = df.loc[df['sc_path'].isin(sc_paths)] | ||
| if df.empty: | ||
| print('No rows match the given filters.') | ||
| return | ||
|
|
||
| # iterate over rows to run | ||
| for _, row in df.iterrows(): | ||
| src = row['original_rev_folder'] | ||
| label = f"{row['tech']} / {row['access_case']}" | ||
|
|
||
| if pd.isna(src) or str(src).strip() == '' or str(src) == 'none': | ||
| print(f'[SKIP] {label}: original_rev_folder not specified.') | ||
| continue | ||
|
|
||
| src = str(src).strip() | ||
| if not os.path.isabs(src): | ||
| print(f'[SKIP] {label}: source path is not absolute: {src!r}') | ||
| continue | ||
|
|
||
| if not os.path.exists(src): | ||
| print(f'[SKIP] {label}: source does not exist: {src}') | ||
| continue | ||
|
|
||
| dst = os.path.join(DEST_BASE, row['sc_path'], 'reV', row['rev_case']) | ||
|
|
||
| print(f'\n[{label}]') | ||
| print(f' src: {src}') | ||
| print(f' dst: {dst}') | ||
|
|
||
| # check if folder exists and follow overwrite procedure | ||
| if os.path.exists(dst): | ||
| if overwrite: | ||
| print(' Destination exists — overwriting (--overwrite).') | ||
| else: | ||
| answer = input(' Destination already exists. Overwrite? [y/N] ').strip().lower() | ||
| if answer != 'y': | ||
| print(' Skipped.') | ||
| continue | ||
|
|
||
| # copy folder using rysnc | ||
| os.makedirs(dst, exist_ok=True) | ||
| t0_row = time.perf_counter() | ||
| print(' Copying...') | ||
| subprocess.run( | ||
| ['rsync', '-a', '--progress', src.rstrip('/') + '/', dst], | ||
| check=True, | ||
| ) | ||
| elapsed_row = time.perf_counter() - t0_row | ||
| print(f' Done. ({elapsed_row:.1f}s)') | ||
|
|
||
| elapsed = time.perf_counter() - t0 | ||
| print(f'\nTotal time: {elapsed:.1f}s') | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
|
|
||
| # command line arguments | ||
| parser = argparse.ArgumentParser(description=__doc__) | ||
| parser.add_argument( | ||
| '--csv', default=DEFAULT_CSV, | ||
| help='Path to rev_paths.csv (default: inputs/supply_curve/rev_paths.csv)', | ||
| ) | ||
| parser.add_argument( | ||
| '--techs', '-t', nargs='+', metavar='TECH', | ||
| help='Filter by one or more techs. E.g. --tech wind-ons upv', | ||
| ) | ||
| parser.add_argument( | ||
| '--sc_paths', nargs='+', metavar='SC_PATH', | ||
| help='Filter by one or more sc_paths. E.g. --sc_path ONSHORE/2025_08_31_NewSites', | ||
| ) | ||
| parser.add_argument( | ||
| '--overwrite', '-o', action='store_true', | ||
| help='Force overwrite of existing destinations without prompting', | ||
| ) | ||
| args = parser.parse_args() | ||
|
|
||
| main(args.csv, args.techs, args.sc_paths, args.overwrite) |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.