Two-stage stochastic MILP · CVaR-aware · MEM Resolución SE 400/2025

Optimization under
uncertainty for
industrial energy systems.

STORM is a computational framework that jointly designs the contracting portfolio and behind-the-meter generation and storage for large electricity users in the Argentine Wholesale Market (MEM) — pricing volume, power-adequacy, and tail risk as first-class decisions rather than after-the-fact accounting.

MATER · MATE · MATP PV + BESS sizing 35,040 × Δt = 15 min CVaRα=0.95 Gurobi 11
Case 3 — full year −33.3% vs GUDI
Expected total cost 525.4kUSD / year
First-stage PV hedge 2.29MWp
MIP gap reported 0.00% · 44/44 runs
The framework

A here-and-now portfolio, a wait-and-see dispatch.

STORM is a two-stage stochastic mixed-integer linear program. The first stage locks in monthly contract volumes QEk,m, power-adequacy coverage RPm, and installed capacity CPV, CBESS, PBESS before uncertainty is revealed. The second stage dispatches energy, storage, and demand response per scenario across S realizations of demand, spot price, PV yield, and tariff parameters.

Native demand Dt,s · kW
median 10–90% min–max
Spot energy price λspott,s · USD/MWh
median 10–90% min–max
PV yield Gt,s · kWh/kWp
median 10–90% min–max

Inputs are stochastic objects, not point forecasts. First-stage variables cannot adapt to a particular realization — they must hedge across the full envelope.

The Argentine MEM

User cost is a stack, not a price.

Under Resolución SE 400/2025 the procurement choice reopens for large industrial users. STORM models the cost stack the way the regulator records it — separating energy from power-adequacy, grid services, transport, distribution peaje, and local adders — so contracts and behind-the-meter assets are sized against the exposures they actually hedge.

Approximate cost-stack — large industrial user (Case 3, 1.247 MW peak) CAMMESA DTE settlement components
Energy · 55%
PPAD · 18%
Peaje · 12%
Services · 8%
Local · 7%
Energy — MATER / MATE / spot Power adequacy — MATP / PPAD Distribution peaje Grid services + transport Local tariffs + taxes

MATER

Renewable energy contract. Bilateral MWh from wind, PV, biomass — long duration, profile-fit, counterparty exposure.

MATE

Energy contract with conventional, hydro, or renewable generators. Monthly take-or-pay / deliver-or-pay commitments.

MATP

Power-adequacy hedge tied to CAMMESA peak-hour requirements. Priced per MW of reserved peak, not per MWh.

Spot + PPAD

Residual energy and power settled after contracts and self-supply. PPAD activates only when peak-hour exposure becomes expensive.

Architecture

A scenario fan in, an investment plan out.

Inputs define an uncertainty envelope. First-stage decisions are fixed before uncertainty resolves. Second-stage recourse adapts the operation by scenario. The objective penalizes the conditional tail of OPEX via CVaR.

Inputs

Scenarios & parameters

Dt,sdemand (kWh)
Gt,sPV yield (kWh / kWp)
λspott,sspot price
cP,spotmPPAD adder
γPV, γBESSannualized CAPEX
α, βCVaR settings
First stage · here-and-now

Portfolio & sizing

QEk,mmonthly MATER/MATE volume
RPmMATP / PPAD coverage
CPVPV capacity (kWp)
CBESSBESS energy (kWh)
PBESSBESS power (kW)
∀s : same Q, R, Cnon-anticipativity
Second stage · per scenario

Dispatch & recourse

espott,sspot energy purchase
econk,t,scontract energy allocation
ech, edis, EBESSBESS charge / SOC
dredt,sdemand reduction
rspotPm,sresidual PPAD
δTOPk,m,stake-or-pay slack
Objective

Risk-aware optimum

𝒞CAPEXannualized investment
𝔼[𝒞OPEXs]expected operation cost
β · CVaRαtail-risk penalty
→ STORM-RNβ = 0 · risk-neutral
→ STORM-CVaRβ > 0 · risk-averse
Implementation

Build the program. Solve the fan.

STORM is implemented in Python on top of Gurobi. The first-stage variables are declared outside the scenario loop so non-anticipativity is enforced structurally. The second stage indexes everything by (t, s) over T = 35,040 intervals and S scenarios — solved at root with a reported MIP gap of zero in the headline campaign.

storm / model_milp.py
Gurobi 11
import gurobipy as gp
from gurobipy import GRB
from storm import config as cfg
from storm.scenario_gen import build_scenarios

# 12 scenarios × 35,040 intervals (15-min, 365 d)
scenarios = build_scenarios(
    demand    = load_case("case3"),
    horizon   = cfg.YEAR_HOURS,
    interval  = cfg.DELTA_T,
    n         = 12,
    seed      = 2026,
)

m = gp.Model("storm")

# ── First stage: here-and-now ──
Q_MATER = m.addVars(M, lb=0, name="Q_MATER")
Q_MATE  = m.addVars(M, lb=0, name="Q_MATE")
R_MATP  = m.addVars(M, lb=0, name="R_MATP")
C_PV    = m.addVar(lb=0,  name="C_PV")
C_BESS  = m.addVar(lb=0,  name="C_BESS")
P_BESS  = m.addVar(lb=0,  name="P_BESS")

# ── Second stage: per-scenario recourse ──
e_spot  = m.addVars(T, S, lb=0)
e_con   = m.addVars(K, T, S, lb=0)
E_BESS  = m.addVars(T, S, lb=0)
d_red   = m.addVars(T, S, lb=0)
r_spotP = m.addVars(M, S, lb=0)
y       = m.addVars(T, S, vtype=GRB.BINARY)  # 1 if charging

# Objective: annualized CAPEX + E[OPEX] + β · CVaR_α(OPEX)
capex = γ_PV*C_PV + γ_BESS*C_BESS + γ_P*P_BESS
opex  = (1/S) * gp.quicksum(opex_s[s] for s in S_set)
cvar  = η + (1/((1-α)*S)) * gp.quicksum(ζ[s] for s in S_set)

m.setObjective(capex + opex + β*cvar, GRB.MINIMIZE)
m.optimize()  # MIP gap target 2% · reported 0.00%

CVaR risk-aversion sweep — Case 3

β ∈ [0, 2]
PV @ β=2 3.06+65%
BESS @ β=2 0.40MWh
MATE energy 1.75−16%

Source: full-year Case 3 campaign. Increasing β shifts the first-stage portfolio toward physical hedges (PV, BESS) and reduces MATE energy commitments and MATP coverage.

Interactive explorer

Turn the knobs. See the plan change.

Based on the full-year Case 3 campaign results. Each data point is an exact Gurobi solve; intermediate values are interpolated so you can explore the sensitivity surface continuously.

0.50
RN CVaR
550 USD/kWp
300 700
600 USD/kWh
150 800
56 USD/MWh
45 90
MATER = 59, MATP = 15, PPAD spot = 16. Interpolated between campaign solve points.
Total cost 525.4 kUSD/y
CAPEX 147.7 kUSD/y
OPEX 377.6 kUSD/y

Portfolio mix

PV2.29MWp
BESS0.00MWh
MATE1.98GWh/y
MATER0.00GWh/y
MATP759kW
Spot875MWh/y

Cost split

Physical hedge ratio

Contracts 43% Physical

PV self-consumption + BESS discharge as % of total supply.

Scientific foundation

CAPEX is deterministic. OPEX is a distribution.

The objective has three layers: annualized capital cost on first-stage assets, the expected operating cost across scenarios, and the conditional value-at-risk of the OPEX tail. CAPEX does not affect the ordering of scenarios — only the OPEX distribution enters the tail-risk term.

Eq. 4 · Objective
Annualized cost with CVaR penalty
\min \; \mathcal{C}^{\text{CAPEX}} + \frac{1}{S}\sum_{s \in \mathcal{S}} \mathcal{C}^{\text{OPEX}}_{s} + \beta \cdot \mathrm{CVaR}_{\alpha}

β controls risk aversion. β = 0 yields STORM-RN, the risk-neutral expected-cost optimizer. Larger β shifts the portfolio toward conservative hedges — defining STORM-CVaR.

Eq. 5–6 · CVaR
Tail expectation via auxiliary slacks
\mathrm{CVaR}_{\alpha} = \eta + \frac{1}{(1-\alpha)\,S}\sum_{s \in \mathcal{S}} \zeta_s,\quad \mathcal{C}^{\text{OPEX}}_{s} - \eta \le \zeta_s,\; \zeta_s \ge 0

Rockafellar–Uryasev representation. With α = 0.95 the term penalizes the worst 5% of scenario OPEX outcomes, independent of CAPEX.

Eq. 7 · Energy balance
Site equilibrium per interval, per scenario
e^{\text{spot}}_{t,s} + \sum_{k \in \mathcal{K}^E} e^{\text{con}}_{k,t,s} + e^{\text{PV}}_{t,s} + e^{\text{dis}}_{t,s} + d^{\text{red}}_{t,s} = D_{t,s} + e^{\text{ch}}_{t,s}

Supply from grid spot, MEM contracts, PV self-consumption, BESS discharge, and curtailed demand must equal native load plus charging energy at every (t, s).

Eq. 11, 15 · BESS
State-of-charge dynamics with SOC window
E^{\text{BESS}}_{t,s} = E^{\text{BESS}}_{t-1,s} + \eta^{\text{ch}} e^{\text{ch}}_{t,s} - \tfrac{e^{\text{dis}}_{t,s}}{\eta^{\text{dis}}},\quad \mathrm{SOC}^{\min} C^{\text{BESS}} \le E^{\text{BESS}}_{t,s} \le \mathrm{SOC}^{\max} C^{\text{BESS}}

Storage operating bounds are linear in the first-stage energy capacity. A linear discharge-throughput penalty captures the first-order economic cost of cycling.

Eq. 17–18 · PPAD
Power-adequacy exposure on peak intervals
r^{\text{PPAD}}_{m,s} \ge \frac{e^{\text{grid}}_{t,s}}{\Delta t},\; \forall t \in \mathcal{H}_m,\quad r^{\text{spotP}}_{m,s} \ge r^{\text{PPAD}}_{m,s} - R^{P}_{m}

Chargeable peak power is the maximum grid import during the regulated peak-hour window. MATP coverage absorbs it; the remainder is paid at the residual PPAD rate.

Eq. 8–9 · Take-or-pay
Monthly contract commitment with TOP slack
\sum_{t:\, m(t)=m} e^{\text{con}}_{k,t,s} + \delta^{\text{TOP}}_{k,m,s} \ge Q^{E}_{k,m},\quad \sum_{t:\, m(t)=m} e^{\text{con}}_{k,t,s} \le Q^{E}_{k,m}

Unilateral departure from the monthly commitment is priced at the take-or-pay penalty cTOPk · δTOP. Setting cTOP=0 recovers the pure commitment-cost formulation.

Numerical campaign · Case 3 · 365 days

The joint feasible set wins.

Evaluated on the same 12-scenario fan, STORM beats every single-channel ablation: contracts-only and DER-only are both materially worse than co-optimizing the two. CVaR-aware first-stage decisions trade a modest expected-cost premium for a measurably tighter tail.

Baseline comparison · annual cost

kUSD / year · expected total cost (dark) and empirical CVaR95% (cyan band). Bars drawn from Table II of the paper.

Strategy summary

Strategy E[total] CVaR95 PV BESS
GUDI full service779.7779.90.000.000
Deterministic EV520.7521.71.860.000
STORM-RN (β=0)520.4520.71.860.000
STORM-CVaR (β=0.5)525.4525.62.290.000
Contracts-only626.7626.70.000.000
DER-only551.0551.22.330.000
STORM-CVaR · no deg.525.5525.82.290.006

Costs in kUSD/year. Capacities in MWp (PV) and MWh (BESS). MIP gap = 0% on all non-GUDI runs.

Applications

Where STORM-class decisions live.

The same two-stage structure generalizes well beyond the Case 3 logistics center: any industrial-scale procurement decision exposed to layered regulatory cost stacks and operational uncertainty admits the same framing.

Industrial procurement

Migration analysis from GUDI to GUMA / GUME for users with mixed schedules and seasonal load profiles.

PV + BESS sizing

Joint sizing of behind-the-meter generation and storage against price, demand, and irradiance scenarios.

Contract portfolio design

Optimal monthly volume across MATER, MATE, MATP — with take-or-pay structures explicit in the formulation.

Tail-risk hedging

CVaR-aware first-stage decisions for buyers required to demonstrate cost-stability under regulatory volatility.

Peak-shaving valuation

Quantify when BESS substitutes for MATP power coverage as a function of installed storage cost.

Demand-response programs

Value voluntary load reduction under SE 379/2025 caps against full-year scenario distributions.

Regulatory transition

Side-by-side baseline vs. post-Resolution scenarios — measure migration value beyond aggregate tariff numbers.

Scenario-based planning

Plug in any source of structured uncertainty — hydrology, fuel, FSA transition path — without rewriting the model.

Engagement models

Use STORM as a model, a workflow, or a managed decision service.

STORM can be adopted at different levels of depth: from licensing the optimization model and integrating it with internal tools, to using the team as a technical partner for procurement studies, scenario design, and decision support.

Model licensing

Access to the STORM formulation, scenario structure, data templates, and reproducible optimization workflow for internal studies and recurring analyses.

Python integration

Integration with Python pipelines, notebooks, dashboards, APIs, Gurobi environments, and existing data workflows used by technical teams.

Excel-first deployment

A practical spreadsheet interface for organizations that need structured inputs, auditable assumptions, and exportable results before adopting a full Python stack.

Consulting studies

One-off or periodic studies for contract portfolios, PV+BESS sizing, GUDI/GUMA/GUME migration, PPAD exposure, and CVaR-based risk analysis.

Managed decision support

Scenario updates, model runs, sensitivity analysis, and executive reporting delivered as a recurring analytical service for management teams.

Executive + technical outputs

Decision memos, reproducible notebooks, Excel workbooks, scenario reports, investment recommendations, and technical appendices for auditability.

Engineering optimization under uncertainty.

A two-stage stochastic MILP for procurement and DER sizing under the Argentine MEM normalization process — open implementation, reproducible campaign, anonymized for review.

Paper available on request · preprint coming after peer review.