Stress metrics extension#124
Draft
abdelrahman-ayad wants to merge 93 commits into
Draft
Conversation
…get_longest_events()
…end of timeseries
…tify new stress periods
…t_eue_events(); silence map_outagerate_new_stressperiods() if empty
…ull failures in plot_eue_events()
| if ( | ||
| (int(sw.GSw_PRM_UpdateMethod) == 0) | ||
| or (len(new_stressperiods_write) and (int(sw.GSw_PRM_UpdateMethod) == 3)) | ||
| or not any(failed[c].name == 'NEUE' for c in failed) |
Contributor
There was a problem hiding this comment.
We still want to allow GSw_PRM_UpdateMethod = 1 (fixed PRM increment controlled by GSw_PRM_UpdateFraction) to work regardless of the RA metric chosen, so I think it'd be best to:
- Drop the conditional here (done on pb/multimetric)
- Add a check to
runreeds.check_compatibility()that raises an error ifint(sw.GSw_PRM_UpdateMethod) in [2, 3]and'neue' not in sw.GSw_PRM_StressThresholdMetrics.lower().split('/')
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the Resource Adequacy (RA) multi-metrics framework by adding new “stress metrics” (Duration, Depth, LOLD, LOLE), updates the stress-period iteration logic to use per-metric threshold switches, and updates downstream plotting/postprocessing to consume the new ra_metrics_*.csv outputs.
Changes:
- Add new RA metric computations and outputs (
ra_metrics_*.csv,eue_events_*.csv) and update stress period selection to support multiple metric types. - Update switch compatibility/validation and switch definitions (
GSw_PRM_StressThresholdMetrics+ per-metric threshold switches). - Update plotting and postprocessing to read the new RA metric outputs and remove the legacy NEUE-only pipeline.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| runreeds.py | Validates metric selection and enforces NEUE requirement for PRM update methods 1–3. |
| reeds/resource_adequacy/stress_periods.py | Implements new RA metrics, stress-period selection by metric, and PRM-update behavior for multi-metric failures. |
| reeds/resource_adequacy/run_pras.jl | Updates PRAS logging to report LOLE/EUE/NEUE in a standardized way. |
| reeds/resource_adequacy/ra_calcs.py | Updates debugging defaults and diagnostic plotting invocation flow. |
| reeds/resource_adequacy/diagnostic_plots.py | Adds reading/plotting support for newly generated new_stress_periods.csv. |
| reeds/reedsplots.py | Updates RA plotting to use ra_metrics_*.csv and adds EUE event plotting. |
| postprocessing/single_case_plots.py | Switches single-case plotting to RA-metrics plots and adds EUE event plots. |
| postprocessing/compare_cases.py | Switches comparison report ingestion from neue_*.csv to ra_metrics_*.csv. |
| postprocessing/bokehpivot/reports/templates/reeds2/standard_report_expanded.py | Removes legacy NEUE entry from the expanded standard report. |
| postprocessing/bokehpivot/reeds2.py | Removes the legacy “Resource adequacy” (neue.csv) dataset registration. |
| docs/source/figs/docs/ra-flowcharts.png | Updates RA flowchart diagram (LFS pointer changed). |
| cases.csv | Replaces legacy stress threshold switch with per-metric switches and documents new metrics. |
| cases_test.csv | Adds/updates a test case configuration for multi-metric stress thresholds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1044
to
+1046
| for outage_type in vmax: | ||
| savename = f'map-outage_{outage_type}_{aggfunc}-{t}i{iteration}.png' | ||
| plt.close() |
Comment on lines
+4352
to
+4353
| neue = reeds.io.read_output(case, f'ra_metrics_{year}i{_iteration}.csv') | ||
| neue = neue.loc[neue.metric==metric].set_index(['level','region']).NEUE |
Comment on lines
4238
to
4242
| year2iteration = ( | ||
| pd.DataFrame([ | ||
| os.path.basename(i).strip('neue_.csv').split('i') | ||
| for i in sorted(glob(os.path.join(case, 'outputs', 'neue_*.csv'))) | ||
| os.path.basename(i).strip('ra_metrics.csv').split('i') | ||
| for i in sorted(glob(os.path.join(case, 'outputs', 'ra_metrics_*.csv'))) | ||
| ], columns=['year','iteration']).astype(int) |
Comment on lines
6756
to
6760
| year2iteration = ( | ||
| pd.DataFrame([ | ||
| os.path.basename(i).strip('neue_.csv').split('i') | ||
| for i in sorted(glob(os.path.join(case, 'outputs', 'neue_*.csv'))) | ||
| os.path.basename(i).strip('ra_metrics.csv').split('i') | ||
| for i in sorted(glob(os.path.join(case, 'outputs', 'ra_metrics_*.csv'))) | ||
| ], columns=['year','iteration']).astype(int) |
Comment on lines
+158
to
+165
| match norm: | ||
| case 'peak': | ||
| peak_eue = dfeue_agg.max() / dfload_agg.max() | ||
| case 'hourly': | ||
| peak_eue = (dfeue_agg / dfload_agg).max() | ||
| case 'absolute': | ||
| peak_eue = dfeue_agg.max() | ||
| return peak_eue |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Duration,Depth,LOLD, andLOLE.GSw_PRM_StressThresholdMetricsalongside the existing metrics (NEUE,LOLH).of the LOLE Resource Adequacy Metric
Technical details
Implementation notes
calc_ra_metrics()after reading PRAS outputs.DurationandDepthderive from the hourly EUE timeseries via two helper functions:calc_max_duration(dfeue_agg)— length of the longest consecutive run of hours with EUE above thresholdcalc_peak_eue(dfeue_agg, dfload_agg, norm='peak')— peak hourly EUE normalized by peak loadLOLDandLOLEuse the PRAS_LOLEhourly columns (same source asLOLH):LOLD(calc_lold) — a day is counted as an event-day if at least one hour has LOLE > 0LOLE(calc_lole) — number of loss-of-load events, where an event is a contiguous run of hours with LOLE > 0GSw_PRM_StressThresholdOutageMagnitude(a raw-MW magnitude threshold) was dropped in favor of keeping only the normalizedDepthmetric, since an absolute-MW threshold isn't comparable across transgrps of very different sizes (same reasoning as the existing EUE-vs-NEUE tradeoff).GSw_PRM_StressThresholdEUEwas also removed as a standalone switch; its role is now split betweenDurationandDepth.update_prm()(used whenGSw_PRM_UpdateMethodis 1, 2, or 3) still assumed the pre-multi-metric shape of the failed-criteria data and would crash (KeyError) as soon as any threshold failed. It's now updated to correctly select NEUE-based failures from the new multi-metric structure — since the PRM update math is inherently NEUE/ppm-based — and to no-op (leave the PRM unchanged) when NEUE didn't fail even though another metric did. Added a companion check inrunreeds.check_compatibility()that raises a clear error ifGSw_PRM_UpdateMethodis 1-3 butNEUEisn't included inGSw_PRM_StressThresholdMetrics.New stress metric switches
DurationGSw_PRM_StressThresholdDurationtransgrp_12: threshold at 12 hours, pertransgrpDepthGSw_PRM_StressThresholdDepthtransgrp_0.1: threshold at 0.1 (10% of peak load), pertransgrpLOLDGSw_PRM_StressThresholdLOLDtransgrp_0.1: threshold at 0.1 event-days/year, pertransgrpLOLEGSw_PRM_StressThresholdLOLEtransgrp_0.1: threshold at 0.1 events/year, pertransgrpValidation, testing, and comparison report(s)
Checklist for author
Details to double-check
General information to guide review
Did you use LLM tools (chatbot or copilot) in the preparation of this PR? If so, describe how
update_prm()uncovered during that review (see Implementation notes).