Skip to content

LOLD Implementation - #108

Open
akrivi wants to merge 12 commits into
mainfrom
al/LOLD
Open

LOLD Implementation#108
akrivi wants to merge 12 commits into
mainfrom
al/LOLD

Conversation

@akrivi

@akrivi akrivi commented May 11, 2026

Copy link
Copy Markdown
Collaborator

This PR:

  • Implements the Loss of Load Days (LOLD) metric as defined in [1]
  • Adds a new documentation page: "Interpreting Resource Adequacy Metrics"

Mathematical formulation

We define the Loss of Load Days (LOLD) metric as:

$$ \mathrm{LOLD} = \mathbb{E}\left[\sum_{d} I_{d,s}\right] $$

where:

$$ I_{d,s} = \begin{cases} 1 & \text{if } \exists t \in {T}(d) \text{ such that } \sum_r S_{r,t,s} > 0 \\ 0 & \text{otherwise} \end{cases} $$

and

  • $r$ indexes regions in the system
  • $t$ indexes timestamps
  • $d$ indexes calendar days
  • $s$ indexes Monte Carlo samples
  • $S_{r,t,s}$ is the shortfall in region $r$, time $t$, sample $s$
  • ${T}(d)$ is the set of all time periods belonging to day $d$

We note that LOLD is not naturally defined at a single timestamp, since it aggregates over all time periods within a day. As a result, additional computation is needed compared to LOLE, namely:

  1. grouping time periods by calendar day
  2. aggregating within each day

Benchmarks

Complexity wise, the system wide and full-horizon LOLD scales with total simulation size, while the day-specifc queries scale only with the size of the selected day.

We also provide below a comparison of the benchmarks between LOLD and LOLE:
Screenshot 2026-03-23 at 23 07 27

References:
[1] G. Stephen et al., "Clarifying the Interpretation and Use of the LOLE Resource Adequacy Metric," 2022 17th International Conference on Probabilistic Methods Applied to Power Systems (PMAPS), Manchester, United Kingdom, 2022, pp. 1-4, doi: 10.1109/PMAPS53380.2022.9810615.

@akrivi akrivi changed the title Al/lold LOLD Implementation May 11, 2026
@codecov-commenter

codecov-commenter commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.05941% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.52%. Comparing base (f49c56e) to head (30ae683).

Files with missing lines Patch % Lines
PRASCore.jl/src/Results/ShortfallSamples.jl 92.30% 3 Missing ⚠️
PRASCore.jl/src/Results/utils.jl 90.32% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #108      +/-   ##
==========================================
+ Coverage   84.14%   84.52%   +0.38%     
==========================================
  Files          45       45              
  Lines        2491     2592     +101     
==========================================
+ Hits         2096     2191      +95     
- Misses        395      401       +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread PRAS.jl/examples/pras_adequacy_metrics.jl
Comment thread PRAS.jl/examples/pras_adequacy_metrics.jl
Comment thread PRAS.jl/examples/pras_walkthrough.jl Outdated
Comment thread PRASCore.jl/test/Simulations/runtests.jl

@abdelrahman-ayad abdelrahman-ayad left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Excellent work Akrivi! I left a couple of very minor comments. Can we also include metrics tests in the test/Results/metrics.jl ?

Comment thread docs/make.jl
using PRASCapacityCredits
using Literate

ENV["GKSwstype"] = "100" # Prevent GR from opening gksqt GUI

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need this?

Comment thread docs/make.jl
sitename = "PRAS",
format = Documenter.HTML(
prettyurls = true,
prettyurls = haskey(ENV, "GITHUB_ACTIONS"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need this?

# `StorageEnergySamples` result specifications instead.


# ## Export Aggregate Results

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm unsure if we need this here, and would favor the results db/event viewer which will come soon, mainly because we don't expose how this can be read back in or develop tools for down stream analysis with this output.

@@ -0,0 +1,144 @@
# # Interpreting Resource Adequacy Metrics

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm wondering if this is an extension to PRAS walkthrough, please give me your thoughts! Can you also include the CVAR here if we go ahead with this? Also will be nice to link this to the docs/resourceadequacy.md page.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually let's keep this here, bring CVAR in. Call this "Multi metric resource adequacy analyses with PRAS"

# multiple complementary metrics should be considered together to understand
# the frequency, distribution and severity of shortfall events.
# ([NERC (2018)](https://www.nerc.com/globalassets/who-we-are/standing-committees/rstc/pawg/probabilistic_adequacy_and_measures_report.pdf),
# [EPRI](https://www.epri.com/research/products/3002027833),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it appropriate to cite ESIG report as well - https://www.esig.energy/reports-briefs/new-resource-adequacy-criteria/?

end No newline at end of file
end

"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's move this to below NEUE please

timeunits, powerunits, energyunits, unitsymbol

import PRASCore.Results: EUE, LOLE, NEUE, ShortfallResult, ShortfallSamplesResult, AbstractShortfallResult, Result
import PRASCore.Results: EUE, LOLE, NEUE, LOLD, ShortfallResult, ShortfallSamplesResult, AbstractShortfallResult, Result

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you split this into separate lines like the other imports here?

return size(shortfall.shortfall,3)
end

const _lold_warned = Ref(false)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think I'd rather have this passed in as a variable to get_lold_result from the write() function and being tracked there, than this global variable for the function, as this will be set to true once, and then won't be displayed if used in loop (like in the REPL)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants