Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5f40e60
minimal example on how to call CVAR in run_pras.jl
abdelrahman-ayad Apr 21, 2026
4a867e6
minor fix to `get_params`
abdelrahman-ayad Apr 24, 2026
b11b588
generalize eue methods to stress metrics
abdelrahman-ayad May 4, 2026
42f38c5
update stress metrics in cases.csv
abdelrahman-ayad May 4, 2026
62e0be2
add validation checks for switches
abdelrahman-ayad May 4, 2026
71dd317
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad May 4, 2026
926d6d8
fix a bug when searching for the switch
abdelrahman-ayad May 4, 2026
fc03be8
generalize check for stressThresholdMetrics
abdelrahman-ayad May 4, 2026
d67e237
minor comment edit
abdelrahman-ayad May 4, 2026
064828b
comment stress_periods debugging code
abdelrahman-ayad May 5, 2026
c2c9cc5
refactor stress_periods; get_shoulder periods uses capacity only (not…
abdelrahman-ayad May 19, 2026
52bdfdd
remove debugging csv output
abdelrahman-ayad May 19, 2026
b632dad
minor fix
abdelrahman-ayad May 19, 2026
558e384
warning and error messages for `stressThresholdMetricSwitches`
abdelrahman-ayad May 19, 2026
37703fe
comment debugging lines
abdelrahman-ayad May 19, 2026
f246fd2
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad May 19, 2026
50fae67
update get_pras_stress_metric call
abdelrahman-ayad May 19, 2026
10f7ba5
replace ReEDS_Augur by handoff dir name
abdelrahman-ayad May 19, 2026
b5c0384
minor fix
abdelrahman-ayad May 20, 2026
a0c7959
minor fixes
abdelrahman-ayad May 20, 2026
767547e
keep EUE as default metric in cases.csv
abdelrahman-ayad May 20, 2026
435dcdb
update switches logic
abdelrahman-ayad May 20, 2026
4e054d6
remove error if switch is not specified
abdelrahman-ayad May 20, 2026
0280c95
remove CVAR info
abdelrahman-ayad May 20, 2026
5ea585a
untrack cases_multi and srun_template
abdelrahman-ayad May 20, 2026
2e74fae
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad May 20, 2026
40fffa5
update dir from augur_data to PRAS
abdelrahman-ayad May 22, 2026
4070ea7
`reeds_data` instead of `PRAS` folder
abdelrahman-ayad May 22, 2026
987bc0e
USE PRAS NEUE calculations
abdelrahman-ayad May 23, 2026
aab0a08
fix a bug in get_pras_stress_metric not getting NEUE values
abdelrahman-ayad May 23, 2026
cc52dd8
remove debug statements
abdelrahman-ayad May 26, 2026
1aa6e04
minor PRAS print change
abdelrahman-ayad May 26, 2026
5e1271d
update NEUE switch name
abdelrahman-ayad May 28, 2026
041985b
change default `GSw_PRM_StressThresholdMetrics` to NEUE
abdelrahman-ayad May 29, 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
7 changes: 5 additions & 2 deletions cases.csv
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,17 @@ GSw_PRM_NetImportLimit,Turn on (1) or off (0) the eq_firm_transfer_limit constra
GSw_PRM_NetImportLimitScen,/-delimited list of {year}_{max percent import OR 'hist' for historical percent OR 'histmax' for max historical percent across all regions} values to use in eq_firm_transfer_limit,N/A,2031_hist/2050_100,
GSw_PRM_scenario,"column of inputs/reserves/prm_annual.csv from which to draw the PRM (""nerc"" means the annual values from the 2024 NERC LTRA; ""static"" means the 2024 values from the same source); or a float (like 0.12) which gets applied as a fraction to all regions in all years (0.12 means 12%)",(static|nerc|ramp2025_20by50|^\d*\.?\d+$),0.12,
GSw_PRM_StressIncrement,How many stress periods to add per iteration,int,2,
GSw_PRM_StressIterateMax,Max number of times to iterate on a given solve year to achieve GSw_PRM_StressThreshold when using stress periods (0 means don't iterate; 1 means 1 extra ReEDS run; etc),int,5,
GSw_PRM_StressIterateMax,"Max number of times to iterate on a given solve year to achieve adequacy stress levels (e.g., GSw_PRM_StressThresholdNEUE) when using stress periods (0 means don't iterate; 1 means 1 extra ReEDS run; etc)",int,5,
GSw_PRM_StressLoadAggMethod,How to aggregate load for stress periods within the chunks specified by GSw_HourlyChunkLengthStress (only used if GSw_HourlyChunkAggMethod=mean; otherwise GSw_HourlyChunkAggMethod is used),mean; max,max,
GSw_PRM_StressModel,Model used to identify stress periods: pras or a string starting with 'user' which specifies a file at inputs/temporal/stressperiods_{GSw_PRM_StressModel}.csv,N/A,pras,
GSw_PRM_StressOutages,Whether to apply the availability factor (forced + scheduled outages) during stress periods,0; 1,1,
GSw_PRM_StressSeedLoadLevel,Region hierarchy level at which to include peak coincident load days as seeded stress periods (or False to ignore peaks),false; False; FALSE; r; nercr; transreg; transgrp; cendiv; st; interconnect; country; usda_region; ccreg,transgrp,
GSw_PRM_StressSeedMinRElevel,Region hierarchy level at which to include minimum wind and solar capacity factor days as seeded stress periods (or False to ignore min-wind/solar CF days),false; False; FALSE; r; nercr; transreg; transgrp; cendiv; st; interconnect; country; usda_region; ccreg,interconnect,
GSw_PRM_StressStorageCutoff,"How to select ""shoulder"" stress periods giving storage time to recharge before/after high-unserved-energy periods. Two-part switch separated by _. The first argument is ""EUE"" or ""capacity"" or ""absolute"". If ""EUE"" the second argument specifies a PRAS storage headspace / EUE threshold [fraction]; if ""cap"" it specifies a headspace / storage capacity threshold [fraction]; if ""abs"" it specifies absolute number of periods before/after [integer]. Turned off if set to ""off"".",N/A,EUE_0.1,
GSw_PRM_StressThreshold,/-delimited list of annual NEUE level [ppm] above which to re-solve the latest model year with new stress periods; formulated as HierarchyLevel_NEUEppm_StressMetric_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; NEUEppm is normalized expected unserved energy in parts per million; StressMetric is EUE or NEUE (only used in period selection); PeriodAggMethod is 'sum' or 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_1_EUE_sum,
GSw_PRM_StressThresholdMetrics,/-delimited list of metrics for identifying stress periods,N/A,NEUE,
GSw_PRM_StressThresholdLOLE,LOLE threshold above which to re-solve the latest model year with new stress periods; formulated as HierarchyLevel_nLOLE_StressMetric_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; nLOLE is number of loss of load events; StressMetric is LOLE; PeriodAggMethod is 'sum' or 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_36_LOLE_sum,
GSw_PRM_StressThresholdEUE,/Annual EUE level [MWh] threshold above which to re-solve the latest model year with new stress periods; formulated as HierarchyLevel_EUE_StressMetric_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; EUE is expected unserved energy; StressMetric EUE (only used in period selection); PeriodAggMethod is 'sum' or 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_10000_EUE_sum,
GSw_PRM_StressThresholdNEUE,/Annual NEUE level [ppm] threshold above which to re-solve the latest model year with new stress periods; formulated as HierarchyLevel_NEUEppm_StressMetric_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; NEUEppm is normalized expected unserved energy in parts per million; StressMetric is EUE or NEUE (only used in period selection); PeriodAggMethod is 'sum' or 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_1_NEUE_sum,
GSw_PRM_UpdateFraction,Fraction to add to the PRM if a region fails RA threshold (only used if GSw_PRM_UpdateMethod = 1),float,0.02,
GSw_PRM_UpdateMethod,Option to update PRM: (0) no update; (1) static update set by GSw_PRM_UpdateFraction; (2) dynamic update informed by PRAS; (3) dynamic update but only after all new stress periods have been added,0; 1; 2; 3,0,
GSw_PRMTRADE_level,hierarchy level within which to allow PRM trading,r; nercr; transreg; transgrp; cendiv; st; interconnect; country; usda_region,country,
Expand Down
11 changes: 7 additions & 4 deletions postprocessing/compare_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,7 @@ def two_bars(dfplot, basecase, colors, ax, col=0, ypad=0.02):

#%%### SCOE, NEUE
try:
neue_threshold = float(sw.GSw_PRM_StressThreshold.split('_')[1])
neue_threshold = float(sw.GSw_PRM_StressThresholdNEUE.split('_')[1])
width = 9 + len(cases)*0.5
plt.close()
f,ax = plt.subplots(
Expand Down Expand Up @@ -1549,9 +1549,9 @@ def two_bars(dfplot, basecase, colors, ax, col=0, ypad=0.02):

#%% Regional NEUE
try:
neue_threshold = float(sw.GSw_PRM_StressThreshold.split('_')[1])
neue_threshold = float(sw.GSw_PRM_StressThresholdNEUE.split('_')[1])
dfmap = reeds.io.get_dfmap(cases[basecase])
level = sw.GSw_PRM_StressThreshold.split('_')[0]
level = sw.GSw_PRM_StressThresholdNEUE.split('_')[0]
regions = dfmap[level].loc[hierarchy[basecase][level].unique()].bounds.minx.sort_values().index
_nrows, _ncols, _coords = reeds.plots.get_coordinates(regions, ncols=6)
labelcoords = {
Expand Down Expand Up @@ -2500,7 +2500,10 @@ def two_bars(dfplot, basecase, colors, ax, col=0, ypad=0.02):


#%%### Copy some premade single-case plots
level = dictin_sw[basecase]['GSw_PRM_StressThreshold'].split('_')[0]
# Use first stress metric level
## TODO: add a check for choosing level if there are multiple stress metrics
stress_metrics = dictin_sw[basecase]['GSw_PRM_StressThresholdMetrics'].split('/')
level = dictin_sw[basecase][f'GSw_PRM_StressThreshold{stress_metrics[0]}'].split('_')[0]
wide = 1 if len(hierarchy[basecase]['transreg'].unique()) > 6 else 0
metrics = [
'cap',
Expand Down
4 changes: 3 additions & 1 deletion postprocessing/single_case_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,9 @@
print(traceback.format_exc())

try:
level, threshold, _, metric = sw['GSw_PRM_StressThreshold'].split('/')[0].split('_')
_first_metric = sw['GSw_PRM_StressThresholdMetrics'].split('/')[0].upper()
_parts = sw[f'GSw_PRM_StressThreshold{_first_metric}'].split('_')
level, threshold, metric = _parts[0], _parts[1], _parts[2]
plt.close()
f,ax = reedsplots.plot_stressperiod_evolution(
case=case, level=level, metric=metric)
Expand Down
21 changes: 13 additions & 8 deletions reeds/reedsplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ def plot_diff(
ymax = max(ax[0].get_ylim()[1], ax[1].get_ylim()[1])
ymin = min(ax[0].get_ylim()[0], ax[1].get_ylim()[0])
if val == 'NEUE (ppm)':
neue_threshold = float(sw.GSw_PRM_StressThreshold.split('_')[1])
neue_threshold = float(sw.GSw_PRM_StressThresholdNEUE.split('_')[1])
ymax = max(ymax, 10, neue_threshold*1.05)
ax[0].axhline(neue_threshold, c='C7', ls='--', lw=0.75)
ax[1].axhline(neue_threshold, c='C7', ls='--', lw=0.75)
Expand Down Expand Up @@ -4137,7 +4137,9 @@ def plot_stressperiod_evolution(
"""Plot NEUE by year and stress period iteration"""
### Parse inputs
sw = reeds.io.get_switches(case)
_level, _threshold, _, _metric = sw['GSw_PRM_StressThreshold'].split('/')[0].split('_')
_first_metric = sw['GSw_PRM_StressThresholdMetrics'].split('/')[0].upper()
_parts = sw[f'GSw_PRM_StressThreshold{_first_metric}'].split('_')
_level, _threshold, _metric = _parts[0], _parts[1], _parts[2]
level = _level if level is None else level
threshold = float(_threshold) if threshold is None else threshold
metric = _metric if metric is None else metric
Expand Down Expand Up @@ -4261,8 +4263,9 @@ def plot_neue_bylevel(
norm = {'sum':1, 'max':1e-4}
ylabel = {'sum': 'Sum of NEUE [ppm]', 'max':'Max NEUE [%]'}
thresholds = {
i.split('_')[0]: float(i.split('_')[1])
for i in sw.GSw_PRM_StressThreshold.split('/')
sw[f'GSw_PRM_StressThreshold{m.upper()}'].split('_')[0]:
float(sw[f'GSw_PRM_StressThreshold{m.upper()}'].split('_')[1])
for m in sw.GSw_PRM_StressThresholdMetrics.split('/')
}
### Plot it
plt.close()
Expand Down Expand Up @@ -4326,8 +4329,8 @@ def map_neue(
neue = reeds.io.read_output(case, f'neue_{year}i{_iteration}.csv')
neue = neue.loc[neue.metric==metric].set_index(['level','region']).NEUE_ppm
sw = reeds.io.get_switches(case)
neue_threshold = float(sw.GSw_PRM_StressThreshold.split('_')[1])
neue_threshold_level = sw.GSw_PRM_StressThreshold.split('_')[0]
neue_threshold = float(sw.GSw_PRM_StressThresholdNEUE.split('_')[1])
neue_threshold_level = sw.GSw_PRM_StressThresholdNEUE.split('_')[0]

### Set up plot
levels = ['interconnect','nercr','transreg','transgrp','st','r']
Expand Down Expand Up @@ -6195,7 +6198,8 @@ def map_stressors(
dfmap[k] = v.to_crs(crs)

### Derived inputs
criterion = sw.GSw_PRM_StressThreshold.split('/')[0]
_first_metric = sw.GSw_PRM_StressThresholdMetrics.split('/')[0].upper()
criterion = sw[f'GSw_PRM_StressThreshold{_first_metric}']
level = criterion.split('_')[0]
regions = hierarchy[level].unique()
region2rs = {
Expand Down Expand Up @@ -6656,7 +6660,8 @@ def map_prm(case, tmin=2023, cmap=cmocean.cm.rain, scale=3, fontsize=7, vmax=Non

### Plot it
nrows, ncols, coords = plots.get_coordinates(year2iteration.index, aspect=1.8)
level = sw.GSw_PRM_StressThreshold.split('_')[0]
_first_metric = sw.GSw_PRM_StressThresholdMetrics.split('/')[0].upper()
level = sw[f'GSw_PRM_StressThreshold{_first_metric}'].split('_')[0]
plt.close()
f,ax = plt.subplots(
nrows, ncols, figsize=(ncols*scale, nrows*scale*0.8), sharex=True, sharey=True,
Expand Down
6 changes: 3 additions & 3 deletions reeds/resource_adequacy/run_pras.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,9 @@ function run_pras(pras_system_path::String, args::Dict)
results = Dict{String,Any}(zip(keys(resultspec), results_tuple))

#%% Print some results for the entire modeled region to show it worked
@info "$(PRAS.LOLE(results["short"])) event-h"
@info "$(PRAS.EUE(results["short"])) MWh"
@info "NEUE = $(1e6 * PRAS.EUE(results["short"]).eue.estimate / sum(sys.regions.load)) ppm"
@info "$(PRAS.LOLE(results["short"]))"
@info "$(PRAS.EUE(results["short"]))"
@info "$(PRAS.NEUE(results["short"]))"

## Filter out DC regions used for VSC HVDC transmission
regions = [r for r in sys.regions.names if !(occursin("|", r))]
Expand Down
Loading
Loading