Resiliency Mathematical Formulation
This page specifies the two optimization problems used by the resiliency module:
(B) Baseline annual economic dispatch on fixed capacities (with demand charges).
(O) Per-hour outage economic dispatch (slack + penalty).
Resiliency metrics are derived from the family of solutions to (O). The narrative usage guide is in Resiliency Evaluation.
1. Sets
Symbol |
Description |
|---|---|
\(\mathcal{T} = \lbrace 1, \ldots, N_T \rbrace\) |
Hours of the baseline horizon (default \(N_T = 8760\)). |
\(\mathcal{M} = \lbrace 1, \ldots, 12 \rbrace\) |
Calendar months (used by demand-charge billing). |
\(\mathcal{T}_m \subset \mathcal{T}\) |
Hours belonging to month \(m\). |
\(\mathcal{T}^{out}_h\) |
Outage horizon anchored at hour \(h\): \(\lbrace h, h+1, \ldots, h + \Delta^{out} + \Delta^{rec} - 1 \rbrace\), clipped to \(\mathcal{T}\). |
\(\mathcal{S}\) |
Storage technologies. |
\(\mathcal{W}\) |
Wind plants. |
\(\mathcal{K}\) |
Solar PV plants. |
\(\mathcal{B}\) |
Balancing (thermal) units, indexed by |
\(\mathcal{N}, \mathcal{O}, \mathcal{R}\) |
Must-run sources: nuclear, other renewables, hydro (each treated as a single aggregate stream driven by a time series). |
\(\mathcal{B}^{out}, \mathcal{W}^{out}, \mathcal{K}^{out}, \mathcal{S}^{out}, \mathcal{I}^{out}, \mathcal{N}^{out}, \mathcal{O}^{out}, \mathcal{R}^{out}\) |
Subsets selected for outage / de-rating in a given |
2. Parameters
2.1 Designed capacities (fixed)
Symbol |
Description |
Source |
|---|---|---|
\(Cap^{B}_{b}\) |
Capacity of balancing unit \(b\) (MW). |
|
\(Cap^{W}_{w}, Cap^{K}_{k}\) |
Designed wind / solar capacities (MW). |
|
\(Cap^{Pch}_{s}, Cap^{Pdis}_{s}\) |
Storage charge / discharge power (MW). |
|
\(Cap^{E}_{s}\) |
Storage energy capacity (MWh). |
Same as above |
\(\overline{P}^{imp}_{t}, \overline{P}^{exp}_{t}\) |
Hourly import / export capacity (MW). |
|
2.2 Time series
Symbol |
Description |
Source |
|---|---|---|
\(D_{t}\) |
Demand at hour \(t\) (MW). |
|
\(A^{W}_{w,t} \in [0,1]\) |
Wind capacity factor. |
|
\(A^{K}_{k,t} \in [0,1]\) |
Solar capacity factor. |
|
\(G^{nuc}_{t}, G^{otre}_{t}, G^{hydro}_{t}\) |
Must-run / scheduled generation (MW). |
|
2.3 Costs
Symbol |
Description |
Source |
|---|---|---|
\(c^{B}_{b}\) |
Variable cost of balancing unit \(b\): \(\mathrm{HeatRate}_b \cdot \mathrm{FuelCost}_b + \mathrm{VOM}_b\) (USD/MWh). |
|
\(c^{imp}_{t}, c^{exp}_{t}\) |
Energy price (USD/MWh). |
|
\(\phi^{var}_{t}\) |
Hourly variable demand-charge tariff (USD/MW). Hourly-varying. |
|
\(\phi^{fix}_{t}\) |
Hourly fixed demand-charge tariff (USD/MW). Constant within each month. |
|
\(c^{vom}_{s}\) |
Storage VOM (USD/MWh). |
|
\(f^{B}_{b}\) |
Fixed O&M of balancing unit \(b\) (USD/kW-yr). |
|
\(f^{W}_{w}\) |
Fixed O&M of wind plant \(w\) (USD/kW-yr). |
|
\(f^{K}_{k}\) |
Fixed O&M of solar plant \(k\) (USD/kW-yr). |
|
\(f^{S}_{s}\) |
Fixed O&M of storage technology \(s\) (USD/kW-yr), applied to power capacity. |
|
\(\alpha_{s} \in [0,1]\) |
Cost-ratio split of storage FOM between charge and discharge sides. |
|
\(M_{kW} = 10^{3}\) |
Unit conversion (MW \(\to\) kW), since FOM parameters are in USD/kW-yr while capacities are in MW. |
constant |
\(H^{yr} = 8760\) |
Hours per year. Used to prorate annual FOM to the outage horizon length in (O). |
constant |
\(\pi^{slack}\) |
Penalty on unserved energy (USD/MWh). Default \(10^{4}\). |
User ( |
\(\pi^{curt}\) |
Penalty on curtailed VRE energy (USD/MWh). Default \(0\) (free curtailment). |
User (kwarg) |
\(\pi^{soc}\) |
Penalty on SOC recovery-target slack (USD/MWh). Default \(10^{3}\). Applies to Problem (O) only. |
User (kwarg) |
2.4 Outage / operational
Symbol |
Description |
|---|---|
\(\Delta^{out}\) |
Outage duration (hours), or per-asset \(\Delta^{out}_{a}\). |
\(\Delta^{rec}\) |
Recovery window (hours), single value or per-storage \(\Delta^{rec}_{s}\). |
\(H^{out}(h)\) |
Length of the outage horizon \(\mathcal{T}^{out}_h\) in hours, after end-of-year clipping: $H^{out}(h) = |
\(\delta_{a,t} \in [0,1]\) |
Time-varying capacity multiplier from outage. Equals the user-defined derating value (default \(0\)) inside the outage window \([h, h + \Delta^{out}_a - 1]\), and equals \(1\) everywhere else, including the entire recovery window \([h + \Delta^{out}, h + \Delta^{out} + \Delta^{rec} - 1]\). Defined for all capacity-bounded assets, including storage charge / discharge bounds. |
\(\delta^{nuc}_{t}, \delta^{otre}_{t}, \delta^{hydro}_{t} \in [0,1]\) |
Same outage / de-rating mechanism applied to the must-run time-series sources (nuclear, other renewables, hydro). The user-supplied factor multiplies the input time series during the outage window; equals \(1\) outside the outage window. |
\(SOC^{min}_{s}\) |
Operational SOC floor (fraction of \(Cap^{E}_{s}\)). |
\(SOC^{rec}_{s}\) |
Required SOC at end of recovery window (fraction of \(Cap^{E}_{s}\)). |
\(SOC^{base}_{s,h}\) |
Baseline SOC trajectory value used as the prior-state boundary \(SOC^{init}_{s}\) at the start of the outage horizon. Sourced from |
\(SOC^{init}_{s}\) |
Initial SOC boundary value at the start of \(\mathcal{T}^{out}_h\), conceptually equal to \(SOC_{s,h-1}\). Used by the storage dynamics equation at \(t = h\). |
3. Variables
Defined for both problems unless noted. All non-negative.
Symbol |
Description |
|---|---|
\(p^{B}_{b,t}\) |
Generation of balancing unit \(b\) (MW). |
\(p^{W}_{w,t}, p^{K}_{k,t}\) |
Dispatched wind / solar (curtailable, MW). |
\(p^{ch}_{s,t}, p^{dis}_{s,t}\) |
Storage charge / discharge power (MW). |
\(SOC_{s,t}\) |
Storage state of charge (MWh). |
\(p^{imp}_{t}, p^{exp}_{t}\) |
Imports / exports (MW). |
\(D^{fix}_{m}, D^{var}_{m}\) |
Monthly demand-charge cost (USD), one per month. Defined as the maximum tariff-weighted import in month \(m\) via section 5.4. Problem (B) only by default. |
\(u_{t}\) |
Unserved-energy slack (MWh). Problem (O) only. |
\(\sigma^{rec}_{s}\) |
SOC recovery-target slack (MWh). Non-negative relaxation of the per-tech end-of-recovery target (section 5.5). Problem (O) only. |
4. Objective Functions
4.1 Problem (B): Baseline annual dispatch
Minimize the total operational cost
with components
Each \(D^{k}_{m}\) (\(k \in \lbrace fix, var \rbrace\)) is the monthly peak of the tariff-weighted imports power, enforced as a linear maximum in section 5.4. Because the tariffs \(\phi^{k}_{t}\) are expressed in USD/MW, the products \(\phi^{k}_{t} \cdot p^{imp}_{t}\) and the variables \(D^{k}_{m}\) are in USD.
Because capacities are fixed parameters in (B), \(Z^{B}_{FOM}\) is a constant
added to the reported objective. It does not influence the optimal
dispatch decisions but is required for an apples-to-apples comparison
with the CEM total system cost. Storage FOM is applied only to the
power components (\(Cap^{Pch}_{s}\), \(Cap^{Pdis}_{s}\)), split by the
per-technology cost ratio \(\alpha_{s}\); there is no energy-side
(\(Cap^{E}_{s}\)) FOM term, mirroring
src/sdom/models/formulations_storage.py::storage_fixed_om_cost_expr_rule.
The factor \(M_{kW}=10^{3}\) converts the FOM parameters (USD/kW-yr) to
USD/MW-yr to match the capacity units (MW).
CAPEX is intentionally excluded from \(Z^{B}\) (capacities are fixed planning outputs from the CEM, so CAPEX is sunk relative to (B)); \(Z^{B}_{FOM}\) is included because annual fixed O&M is incurred whether or not the asset operates and is part of the annual operating cost comparison. Problem (B) does not include outages, so \(\delta_{a,t} \equiv 1\) and \(\delta^{m}_{t} \equiv 1\) for every asset and must-run source; the outage multipliers therefore do not appear in (B).
4.2 Problem (O): Per-hour outage dispatch starting at \(h\)
Minimize the operational cost over the outage horizon
with components
where \(\sigma^{rec}_{s} \ge 0\) is a non-negative slack variable on the SOC recovery target (see section 5.5). The operational SOC floor in section 5.3 remains a hard bound; only the end-of-recovery target is softened.
The annual fixed-O&M aggregate \(Z^{B}_{FOM}\) (section 4.1) is prorated by the outage-horizon fraction \(H^{out}(h) / H^{yr}\) with \(H^{yr} = 8760\). The same per-asset structure is reused (thermal, wind, solar, storage with CostRatio split); imports and exports carry no FOM. Because every capacity in (O) is a fixed parameter, \(Z^{O}_{FOM}(h)\) is a constant added to the objective; it does not influence the optimal dispatch, only the reported \(Z^{O}(h)\) level. End-of-year clipping is honored: \(H^{out}(h) = |\mathcal{T}^{out}_h|\) may be shorter than \(\Delta^{out} + \Delta^{rec}\) when \(h\) is near the end of the year, in which case the prorated FOM scales accordingly.
The default \(\pi^{soc} = 10^{3}\) is intentionally below \(\pi^{slack} = 10^{4}\), so a feasible LP without unserved load is always preferred to one that violates the recovery target. Users can raise \(\pi^{soc} \ge \pi^{slack}\) to invert that preference (the model will then leave load unserved rather than violate the recovery target).
Demand charges and the monthly variables \(D^{fix}_m, D^{var}_m\) are omitted from (O) by default (peak charges are billing-period concepts, not relevant within a sub-day to multi-day window).
5. Constraints
Common to (B) and (O) unless noted. In (B), \(u_{t} \equiv 0\) (no slack).
5.1 Power balance
The power balance equation below applies to both problems. In Problem (B) (baseline, no outages), \(\delta_{a,t} = \delta^{nuc}_{t} = \delta^{otre}_{t} = \delta^{hydro}_{t} \equiv 1\) for every asset \(a\).
5.2 Capacity bounds with de-rating
The bounds below apply to both problems. In Problem (B), \(\delta_{a,t} \equiv 1\) for every asset \(a\), so the multipliers reduce to \(1\) and the bounds collapse to nominal capacity / availability.
5.3 Storage dynamics, charge / discharge bounds
where the prior-state term is
In Problem (B), \(SOC_{s,0}\) is set by the cyclic baseline boundary
(see formulations_storage.soc_balance_rule); in Problem (O), the
boundary parameter \(SOC^{init}_{s}\) is seeded from the baseline
trajectory (section 5.5). Writing the dynamics equation for every
\(t \in \mathcal{T}^{out}_h\) — including the anchor hour \(t = h\) — is
required so that \(p^{ch}_{s,h}\) and \(p^{dis}_{s,h}\) appear in a SOC
balance equation; otherwise the LP would leave the anchor-hour
charge / discharge variables unconstrained by any energy balance,
letting the solver charge or discharge “for free” at \(t = h\) for any
non-outaged storage tech.
In (B) and for any storage tech not selected for outage, \(\delta_{s,t} \equiv 1\) and the bounds reduce to nominal \(Cap^{Pch}_{s}, Cap^{Pdis}_{s}\). In (O), storage may be outaged like any other capacity-bounded asset (section 6.1); during its outage window \(\delta_{s,t} = \rho_{s} \in [0,1]\) (default \(0\)) zeros out both charge and discharge. The SOC dynamics still apply, so SOC remains constant when \(p^{ch}_{s,t} = p^{dis}_{s,t} = 0\).
5.4 Demand-charge linking (Problem (B))
For each month \(m \in \mathcal{M}\) and each tariff type \(k \in \lbrace fix, var \rbrace\):
Since the objective minimizes \(\sum_m (D^{fix}_m + D^{var}_m)\) and \(D^{k}_{m}\) has no upper bound, at the optimum each \(D^{k}_{m}\) equals \(\max_{t \in \mathcal{T}_m} \phi^{k}_{t} \cdot p^{imp}_{t}\), i.e., the monthly peak of the tariff-weighted import. The fixed tariff \(\phi^{fix}_{t}\) is constant within a month, so \(D^{fix}_{m} = \phi^{fix}_{m} \cdot \max_{t \in \mathcal{T}_m} p^{imp}_{t}\) (classic peak-power demand charge). The variable tariff \(\phi^{var}_{t}\) varies hourly, so \(D^{var}_{m}\) captures the time-of-use peak.
5.5 Outage problem coupling (Problem (O), starting at \(h\))
Initial state from the baseline trajectory. The boundary parameter \(SOC^{init}_{s}\) is set to the baseline SOC value at hour \(h\) and is used by the dynamics equation at \(t = h\) (section 5.3) as the prior state \(SOC^{prev}_{s,h}\):
\(SOC^{init}_{s}\) is implemented as a mutable Pyomo Param rather than
as a fixed SOC[s, h] variable. Earlier versions used
SOC[s, h].fix(value) and skipped the dynamics equation at \(t = h\);
under that formulation the charge and discharge variables
\(p^{ch}_{s,h}, p^{dis}_{s,h}\) for non-outaged storage technologies did
not appear in any SOC balance equation, allowing the solver to
dispatch them without an energy-conservation constraint at the anchor
hour. The present formulation closes that gap.
Recovery target at the end of the recovery window (Problem (O) only). In Problem (O), the target is softened by a non-negative slack variable \(\sigma^{rec}_{s} \ge 0\) priced at \(\pi^{soc}\) in the objective (see section 4) so the LP remains feasible when storage cannot fully recharge by the end of its recovery window. In Problem (B), \(\sigma^{rec}_{s} \equiv 0\):
6. Outage Modeling Formalism
6.1 Capacity-bounded assets
For each asset \(a\) in \(\mathcal{B}^{out} \cup \mathcal{W}^{out} \cup \mathcal{K}^{out} \cup \mathcal{S}^{out} \cup \mathcal{I}^{out}\):
where \(\rho_{a} \in [0,1]\) is the user-provided derating factor (default \(\rho_{a} = 0\) for a full outage). Assets not selected for outage have \(\delta_{a,t} \equiv 1\). The multiplier appears as a time-varying upper bound (section 5.2).
6.2 Must-run time-series sources
For each must-run source \(m \in \lbrace \text{nuc}, \text{otre}, \text{hydro} \rbrace\):
These sources are not capacity-bounded variables; their injection is fixed by the input time series. The outage multiplier therefore scales the time-series parameter directly in the power balance (section 5.1) rather than acting as a variable upper bound. Sources not selected for outage have \(\delta^{m}_{t} \equiv 1\).
6.3 Recovery window semantics
The recovery window \([h + \Delta^{out},\; h + \Delta^{out} + \Delta^{rec} - 1]\) is included in the optimization horizon \(\mathcal{T}^{out}_h\) but lies outside every outage window, so \(\delta_{a,t} = 1\) and \(\delta^{m}_{t} = 1\) for all assets and sources there. During recovery the system operates with full capacity and storage devices may charge from any source (thermal, VRE, imports, surplus generation) subject only to their nominal power and energy limits. The only additional constraint that distinguishes recovery from normal operation is the SOC recovery target enforced at the end of each storage device’s recovery window (see section 5.5).
7. Resiliency Metrics
Let \(u_{t}^{*}(h)\) denote the optimal slack of problem (O) anchored at hour \(h\). Let \(\mathcal{H} \subseteq \mathcal{T}\) be the set of evaluated start hours and \(N_{H}\) its cardinality.
7.1 Per-scenario (anchored at \(h\))
7.2 Aggregate
7.3 Probability-weighted expected metrics
Each evaluated anchor hour \(h \in \mathcal{H}\) is assigned an outage-start probability \(P(h)\) and the expected metrics are reported alongside the unweighted statistics in section 7.2:
Partial-evaluation convention (renormalize). When only a subset
\(\mathcal{H} \subsetneq \mathcal{T}\) of anchor hours is evaluated (e.g. an
explicit hours= list passed to evaluate_resiliency), probabilities
are renormalized over the evaluated set so they sum to 1:
Hours with solver_status == "error" are excluded from \(\mathcal{H}\)
before renormalize, mirroring the unweighted statistics in section 7.2.
With uniform \(P(h) = 1 / N_{H}\) the identities \(EUE^{\text{exp}} \equiv \overline{EUE}\) and \(H_{USE}^{\text{exp}} \equiv LOLE\) hold by construction. The keys are surfaced separately so future severity- or arrival-rate-weighted schemes can replace the uniform weight without changing the persisted schema or breaking the existing unweighted metric names.
The empirical distribution \(\lbrace EUE(h) \rbrace_{h \in \mathcal{H}}\) is
exposed via ResiliencyResults and underlies the
histogram / ECDF / exceedance plots described in Resiliency Evaluation.