Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 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
e248912
uppercase NEUE
abdelrahman-ayad Jun 1, 2026
fc1e33f
update _stress_metric extraction
abdelrahman-ayad Jun 1, 2026
977536e
update NEUE keywords
abdelrahman-ayad Jun 1, 2026
ae1b613
always include NEUE reporting
abdelrahman-ayad Jun 1, 2026
a99df3a
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad Jun 1, 2026
79db702
revert default metric to EUE to match main
abdelrahman-ayad Jun 2, 2026
ce7c0d5
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad Jun 2, 2026
7babd28
Revert "uppercase NEUE"
abdelrahman-ayad Jun 4, 2026
02d9679
update switches and description
abdelrahman-ayad Jun 5, 2026
a4e643f
addressing PB's comments.
abdelrahman-ayad Jun 5, 2026
0a9b73f
address review comments
abdelrahman-ayad Jun 5, 2026
035c4a8
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad Jun 5, 2026
dc9694c
addressing comments; changing LOLE to LOLH
abdelrahman-ayad Jun 14, 2026
42bbf6c
remove LOLE from loop
abdelrahman-ayad Jun 14, 2026
41e2ffd
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad Jun 15, 2026
690d4d4
fix switches parsing
abdelrahman-ayad Jun 16, 2026
84c33b1
revert NEUE to neue
abdelrahman-ayad Jun 17, 2026
cbca500
minor formatting
abdelrahman-ayad Jun 17, 2026
9e885c4
Merge branch 'aa/multi_metrics' of github.com:ReEDS-Model/ReEDS into …
abdelrahman-ayad Jun 17, 2026
bd0d0ad
revert shoulder_periods changes: use EUE for LOLH
abdelrahman-ayad Jun 17, 2026
a42b6a0
remove EUE from switches list
abdelrahman-ayad Jun 17, 2026
98c1240
revert NEUE to neue
abdelrahman-ayad Jun 17, 2026
e88a1c8
Merge branch 'main' into aa/multi_metrics
abdelrahman-ayad Jun 17, 2026
0a0d986
initial implementation of outage duration
abdelrahman-ayad Jun 17, 2026
360cda4
add `OutageDuration` and `OutageMagnitude` metrics
abdelrahman-ayad Jun 17, 2026
704a0b1
add metrics to `cases.csv` and extend validation
abdelrahman-ayad Jun 17, 2026
047caf2
extend stress_metric_units dict
abdelrahman-ayad Jun 17, 2026
3afcdac
minor change
abdelrahman-ayad Jun 17, 2026
3c74b66
add LOLE
abdelrahman-ayad Jun 18, 2026
a0e0c0c
add LOLE
abdelrahman-ayad Jun 18, 2026
8e539ab
restore EUE for shoulder_periods calculation
abdelrahman-ayad Jun 19, 2026
ef566e2
fix prm updates for non-NEUE
abdelrahman-ayad Jun 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
10 changes: 8 additions & 2 deletions cases.csv
Original file line number Diff line number Diff line change
Expand Up @@ -263,14 +263,20 @@ 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 (supported options are: NEUE, LOLH)",N/A,NEUE,
GSw_PRM_StressThresholdLOLH,LOLH threshold [hours/year] above which to re-solve the latest model year with new stress periods; formulated as HierarchyLevel_LOLH_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; LOLH is loss of load event-hours per year [event-h/year]; 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_2.4_sum,
GSw_PRM_StressThresholdLOLE,LOLE threshold [event-days/year] above which to re-solve the latest model year with new stress periods; formulated as HierarchyLevel_LOLEdays_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; LOLEdays is loss of load event-days per year (a day is counted if at least one hour has a shortfall) [event-day/year]; 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_0.1_max,

@patrickbrown4 patrickbrown4 Jun 18, 2026

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.

I've seen different definitions used in different sources, but at least in some places, "LOLE" is taken to mean "events" and LOLD as "event-days". So if the units used here are "event-days", then it might be clearer to label it as LOLD.

Here's the figure I'm thinking of, from https://doi.org/10.1109/PMAPS53380.2022.9810615:

image

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_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; NEUEppm is normalized expected unserved energy in parts per million [ppm]; 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_sum,
GSw_PRM_StressThresholdOutageDuration,Outage duration; formulated as HierarchyLevel_OutageDurationHours_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; OutageDurationHours is the max outage duration in hours; PeriodAggMethod is 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_10000_max,

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.

  1. 10000 hours is an extremely long event. I think it'd be most convenient to set the defaults to values in the range of what's come up in the literature review. If I'm interpreting correctly, the values include 8 hours for NWPCC, 12 hours for ERCOT, and 18 hours for ISONE. So how about 12 hours?
  2. Just to keep the switch name shorter, you could change it to GSw_PRM_StressThresholdDuration.
Suggested change
GSw_PRM_StressThresholdOutageDuration,Outage duration; formulated as HierarchyLevel_OutageDurationHours_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; OutageDurationHours is the max outage duration in hours; PeriodAggMethod is 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_10000_max,
GSw_PRM_StressThresholdDuration,Outage duration; formulated as HierarchyLevel_OutageDurationHours_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; OutageDurationHours is the max outage duration in hours; PeriodAggMethod is 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_12_max,

GSw_PRM_StressThresholdOutageMagnitude,Outage magnitude; formulated as HierarchyLevel_OutageMagnitudeMW_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; OutageMagnitudeMW is the max outage magnitude in MW; PeriodAggMethod 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_0.1_max,
GSw_PRM_StressThresholdNormalizedOutageMagnitude,Normalized outage magnitude; formulated as HierarchyLevel_NormalizedOutageMagnitude_PeriodAggMethod where HierarchyLevel is a column in hierarchy.csv; NormalizedOutageMagnitude is the max outage normalized magnitude (ratio of the maxmimum load) ; PeriodAggMethod is 'max' over the hours in each period (only used in period selection) (see README.md for detailed notes),N/A,transgrp_10_max,
Comment on lines +278 to +279

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.

  1. I can't remember how much we discussed this, but in the same vein as the earlier discussion on the EUE metric, it'd be hard to apply a single magnitude threshold in units of MW across different transgrps (with very different peak loads) and over time. In the same way that we supply and enforce the PRM as a percent (even if some reasons think of it as MW), it seems clearest to stick with the normalized approach here. So I think we could drop GSw_PRM_StressThresholdOutageMagnitude and only keeping the normalized version.
  2. Just to keep the switch name shorter, you could drop 'Normalized' from the switch name. So just keep a single switch, GSw_PRM_StressThresholdMagnitude, with the functionality of the current GSw_PRM_StressThresholdNormalizedOutageMagnitude switch.
  3. It's unclear what units are being used for GSw_PRM_StressThresholdNormalizedOutageMagnitude if the value is 10 (the description says it's a ratio). From your review, it looks like thresholds range from 3% in ISONE and NWPCC to 20% in Tri-state and 25% in ERCOT. It will be good to do a sweep of the values, but for now, I would use something between 3% and 25%.
  4. But I would use fractional units in the switch (in keeping with the related switches), so transgrp_0.03_max if you go with the ISONE/NWPCC number.

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
weatheryear = sw.GSw_HourlyWeatherYears.split('_')[0]
metrics = [
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 @@ -717,7 +717,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
25 changes: 15 additions & 10 deletions reeds/reedsplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,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 @@ -4127,7 +4127,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 All @@ -4143,7 +4145,7 @@ def plot_stressperiod_evolution(
pd.concat(dictin_neue, names=['year','iteration'])
.xs(level,0,'level')
.xs(metric,0,'metric')
.NEUE_ppm.unstack('region')
.NEUE.unstack('region')
)
### Load stress periods for labels
dfstress = get_stressperiods(case)
Expand Down Expand Up @@ -4251,8 +4253,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 @@ -4314,10 +4317,10 @@ def map_neue(
else:
_iteration = iteration
neue = reeds.io.read_output(case, f'neue_{year}i{_iteration}.csv')
neue = neue.loc[neue.metric==metric].set_index(['level','region']).NEUE_ppm
neue = neue.loc[neue.metric==metric].set_index(['level','region']).NEUE
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 @@ -6186,7 +6189,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 @@ -6647,7 +6651,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