Skip to content

System Element Modeling Overview

This spec describes the physical components of a hydrothermal power system as modeled by Cobre: what each element represents, its decision variables, how it connects to other elements, and its role in the optimization objective. It serves as the conceptual foundation between the SDDP algorithm description and the full LP formulation — the reader should understand what is being optimized before seeing how the constraints are assembled.

Reading order: SDDP algorithmthis specLP formulationequipment formulations

For variable naming conventions and index sets, see notation conventions.

All decision variables in Cobre use rate units: electrical quantities in MW, hydraulic flows in m³/s. Storage (hm³) is inherently an absolute quantity. The block duration τk\tau_k [hours] enters the LP as an external multiplier — it appears in the objective function coefficients and in the water balance conversion factor, but not in the variable bounds or constraint matrix.

This is a deliberate design decision with consequences across the formulation:

AspectConsequence
Objective functionAll cost terms are scaled by τk\tau_k: the coefficient for a $100/MWh thermal is τk×100\tau_k \times 100
Variable boundsBlock-invariant — a 500 MW capacity bound is the same regardless of block duration
Constraint matrixClean coefficients: load balance has ±1, production function uses ρ\rho [MW/(m³/s)] directly
DualsLoad balance dual πb,k\pi_{b,k} has units $/MW. To obtain the marginal cost (CMO) in $/MWh, divide by τk\tau_k
Cut coefficientsUnaffected — coupling state variables (storage in hm³, AR lags in m³/s) are independent of this choice

Why not absolute units (MWh, hm³ per block)? The alternative — internalizing τk\tau_k into the variables — was evaluated and rejected for three reasons:

  1. FPHA incompatibility: The FPHA hyperplane gγ0+γvvavg+γqq+γssg \leq \gamma_0 + \gamma_v \cdot v^{avg} + \gamma_q \cdot q + \gamma_s \cdot s relates instantaneous rates to storage level. Converting to absolute units does not eliminate τk\tau_k from the FPHA constant term, and introduces a 106/360027810^6/3600 \approx 278 scaling factor on flow coefficients.

  2. Constraint matrix quality: With rate units, the constraint matrix (excluding the objective row) spans ~3 orders of magnitude (ρ0.05\rho \approx 0.0555, η0.95\eta \approx 0.951.01.0, conversion factors ~0.010.0133). Absolute units inflate this to ~5 orders via the 278 factor in FPHA rows. A tighter constraint matrix improves simplex pivot stability.

  3. Block-varying bounds: Absolute units make every variable bound depend on τk\tau_k (Gˉτk\bar{G} \cdot \tau_k instead of Gˉ\bar{G}), complicating LP construction and making the LP structure vary with block configuration.

The objective row does carry large coefficients — up to τk×cdef730×10,000=7.3×106\tau_k \times c^{def} \approx 730 \times 10{,}000 = 7.3 \times 10^6 for deep deficit in monthly problems. Modern LP solvers handle objective scaling effectively through internal prescaling, and this is where the scaling challenge is most tractable.

A hydrothermal power system in Cobre consists of interconnected physical elements that work together to meet electricity demand at minimum cost under inflow uncertainty:

System element overview — buses, a hydro plant with its reservoir (inflow in), a thermal plant, an NCS (wind/solar) source, a transmission line between buses, a demand draw (d) off each bus, and a deficit slack (δ, dashed) backstopping unserved load. Key flow variables are labelled (f line flow, q hydro turbined, g thermal, gⁿᶜ NCS, δ deficit, d demand).

Bus 1Bus 2inflow aReservoir vₕHydro q (turbined)Thermal gNCS (wind / solar) gⁿᶜDemand dDemand dDeficit slack δ aq → gggⁿᶜ line flow f± (η losses)dd δ (unserved)

The optimizer determines generation and flow decisions at each stage to minimize total expected cost (thermal generation + deficit penalties + regularization costs) while respecting physical constraints and preparing for uncertain future inflows.

Most entity types may enter service or be decommissioned partway through the horizon, so that planning studies can represent new plants coming online and aging units retiring. An entity carries an optional commissioning window defined by two stage indices, entry_stage_id and exit_stage_id. The window is half-open: the entity is active at stage tt when

entry_stage_idt<exit_stage_id\text{entry\_stage\_id} \leq t < \text{exit\_stage\_id}

so the entry stage is inclusive and the exit stage is exclusive — the entity is gone from its exit stage onward. A null entry_stage_id means “active from the first stage”; a null exit_stage_id means “never decommissioned”. The default for an entity that sets neither is to be active at every stage.

This window applies uniformly to transmission lines, thermal plants, non-controllable sources, pumping stations, and contracts (and, for generation, to hydro plants). Outside its window an entity contributes nothing to the dispatch: its decision columns are present in the LP but pinned to zero, so it injects no power, withdraws no power, and consumes no resource. Decommissioning is symmetric to commissioning — both are expressed by the same two fields.

Two element-specific lifecycle mechanisms layer on top of this generic window:

  • Hydro dead-volume filling (§5) — a hydro plant may exist but be unable to generate while its reservoir is still filling toward the dead volume; this is a distinct commissioning state with its own per-stage storage floors, not just a presence gate.
  • Anticipated thermals (§4) — a commitment column is opened only when its delivery stage falls inside the study horizon, an additional horizon predicate beyond the entry/exit window.

A bus represents a node in the power network where electrical energy balance must be maintained. The granularity is user-defined: a bus may represent a large regional subsystem, a single substation, or any aggregation level in between. The model scales from a handful of buses to hundreds or thousands without structural changes.

VariableUnitsDescription
δb,k,s\delta_{b,k,s}MWLoad deficit (unserved energy) at bus bb, block kk, segment ss
ϵb,k\epsilon_{b,k}MWExcess generation at bus bb, block kk

Each bus serves as the energy balance node where:

  • Inflows: Generation from hydro plants, thermal plants, and import contracts connected to the bus
  • Outflows: Demand, export contracts, pumping station consumption, and transmission to other buses
ParameterUnitsDescription
Db,kD_{b,k}MWLoad demand at bus bb, block kk
cb,sdefc^{def}_{b,s}$/MWhDeficit cost (value of unserved energy), segment ss
cbexcc^{exc}_b$/MWhExcess generation penalty (regularization)
dˉb,s\bar{d}_{b,s}MWDeficit segment depth
kKτk[bBsSbcb,sdefδb,k,s+bBcbexcϵb,k]\sum_{k \in \mathcal{K}} \tau_k \left[ \sum_{b \in \mathcal{B}} \sum_{s \in \mathcal{S}_b} c^{def}_{b,s} \cdot \delta_{b,k,s} + \sum_{b \in \mathcal{B}} c^{exc}_b \cdot \epsilon_{b,k} \right]
  • Deficit cost: Very high penalty ($1,000–10,000/MWh) representing value of lost load
  • Excess cost: Small regularization term to eliminate spurious slack generation

For each bus bb and block kk, the load balance constraint enforces:

(generation at b)+(imports)(exports)(pumping)+sδb,k,sϵb,k=Db,k\text{(generation at } b\text{)} + \text{(imports)} - \text{(exports)} - \text{(pumping)} + \sum_{s} \delta_{b,k,s} - \epsilon_{b,k} = D_{b,k}

For the assembled constraint, see LP formulation.

A transmission line represents the interconnection between two buses, allowing power transfer subject to capacity limits and transmission losses. Lines are bidirectional.

VariableUnitsDescription
fl,k+f^+_{l,k}MWDirect flow on line ll (source → target), block kk
fl,kf^-_{l,k}MWReverse flow on line ll (target → source), block kk

Each line connects exactly two buses:

  • Source bus: Exports fl,k+f^+_{l,k}, receives ηlfl,k\eta_l \cdot f^-_{l,k}
  • Target bus: Receives ηlfl,k+\eta_l \cdot f^+_{l,k}, exports fl,kf^-_{l,k}
ParameterUnitsDescription
Fˉl+\bar{F}^+_lMWCapacity limit (direct direction); may vary by stage via exchange factors
Fˉl\bar{F}^-_lMWCapacity limit (reverse direction); may vary by stage via exchange factors
ηl\eta_lTransmission efficiency: ηl=1losses/100\eta_l = 1 - \text{losses}/100
clexchc^{exch}_l$/MWhExchange cost (regularization)
kKτklLclexch(fl,k++fl,k)\sum_{k \in \mathcal{K}} \tau_k \sum_{l \in \mathcal{L}} c^{exch}_l \cdot (f^+_{l,k} + f^-_{l,k})

The exchange cost is a regularization term (typically $0.01–1.00/MWh) that prevents degenerate solutions with unnecessary power circulation and guides the solver toward physically meaningful flow patterns.

Capacity bounds:

0fl,k+Fˉl+,0fl,kFˉl0 \leq f^+_{l,k} \leq \bar{F}^+_l, \quad 0 \leq f^-_{l,k} \leq \bar{F}^-_l

Load balance contribution at source bus: fl,k++ηlfl,k-f^+_{l,k} + \eta_l \cdot f^-_{l,k}

For detailed constraints, see equipment formulations.

A thermal plant represents dispatchable generation using fuel (natural gas, coal, oil, biomass, nuclear). Thermal plants have fuel costs modeled with piecewise-linear cost curves.

VariableUnitsDescription
gj,k,sg_{j,k,s}MWGeneration at thermal plant jj, block kk, cost segment ss

The total generation is gj,k=sgj,k,sg_{j,k} = \sum_s g_{j,k,s}.

  • Bus connection: Each thermal plant connects to exactly one bus, contributing to its energy balance
  • No cascade coupling: Unlike hydro plants, thermals are independent of each other
ParameterUnitsDescription
Gˉj\bar{G}_j, Gj\underline{G}_jMWGeneration bounds (capacity, minimum stable load)
cj,sthc^{th}_{j,s}$/MWhMarginal cost for segment ss (fuel + O&M)
gˉj,s\bar{g}_{j,s}MWSegment ss capacity
kKτkjTscj,sthgj,k,s\sum_{k \in \mathcal{K}} \tau_k \sum_{j \in \mathcal{T}} \sum_{s} c^{th}_{j,s} \cdot g_{j,k,s}

Thermal costs represent actual operating expenses ($50–500/MWh depending on fuel type) and constitute the primary controllable cost in the objective function.

Segment bounds (cost curve linearization): 0gj,k,sgˉj,s0 \leq g_{j,k,s} \leq \bar{g}_{j,s} for all ss.

Total generation bounds: Gjsgj,k,sGˉj\underline{G}_j \leq \sum_s g_{j,k,s} \leq \bar{G}_j

For detailed constraints, see equipment formulations.

A thermal plant may be flagged as anticipated by attaching a per-plant lead K1K \geq 1. The physical motivation is fuel-ordering lead time: LNG (originally Gás Natural Liquefeito) terminals, long-haul coal contracts and similar arrangements require the committed dispatch quantity to be locked KK stages before the energy is physically delivered. Anticipated thermals therefore split the per-stage thermal decision into two coupled variables — the commitment, made at the decision stage tt, and the delivered generation, which is forced to match the matured commitment at the delivery stage t+Kt + K.

The lead is encoded as an integer plant-specific parameter Ki1K_i \geq 1 (lead_stages on the plant entity). A plant with Ki=1K_i = 1 commits one stage ahead; a plant with Ki=3K_i = 3 commits three stages ahead. Plants without the anticipation flag use the standard thermal model from the preceding subsections.

Each anticipated plant ii carries a ring-buffer pipeline of KiK_i pending commitments through the Bellman recursion alongside hydro storage and inflow lags. Anticipated thermals are the only non-hydro elements with state variables in the SDDP formulation.

State variableSlotMeaning at the start of stage tt
x0,i,tax^{\mathrm{a}}_{0,i,t}0Commitment maturing this stage — sets the delivered generation at tt
x1,i,tax^{\mathrm{a}}_{1,i,t}1Commitment placed at tKi+1t - K_i + 1, scheduled to deliver at t+1t + 1
\vdots\vdots
xKi1,i,tax^{\mathrm{a}}_{K_i - 1,i,t}Ki1K_i - 1Most-recent commitment, written at t1t - 1, scheduled to deliver at t+Ki1t + K_i - 1

The state vector reserves Kmax=maxiKiK_{\max} = \max_i K_i slots per plant for layout uniformity across stages; slots beyond KiK_i are padded to zero by an LP equality and carry no information.

At each stage tt the plant exposes a commitment column dtid^i_t on the LP. Its bounds replicate the generation bounds of the delivery stage t+Kit + K_i:

dti{[Gi(t+Ki), Gˉi(t+Ki)]t+Ki<T{0}t+KiT(presolved out)d^i_t \in \begin{cases} [\,\underline{G}_i(t + K_i),\ \bar{G}_i(t + K_i)\,] & t + K_i < T \\ \{\,0\,\} & t + K_i \geq T \quad \text{(presolved out)} \end{cases}

The horizon predicate t+Ki<Tt + K_i < T guarantees the commitment is only opened when there is a delivery stage inside the study horizon; commitments whose delivery would fall outside TT are pinned to zero.

The fishing constraint binds the per-block generation of plant ii to the matured commitment in slot 0 at every stage t[0,T1]t \in [0, T - 1]:

bhbgi,b,t  =  Htx0,i,ta\sum_{b} h_b \cdot g_{i,b,t} \;=\; H_t \cdot x^{\mathrm{a}}_{0, i, t}

where hbh_b is the duration of block bb and Ht=bhbH_t = \sum_b h_b is the total stage hours. The fishing row is active at every stage, including the pre-horizon stages where slot 0 is fed by the seeded past_anticipated_commitments (see below) rather than by an LP-decided did^i.

Column bounds pin each slot to its incoming value, and a separate decoupled state-out column writes the LP commitment dtid^i_t into the post-shift slot Ki1K_i - 1 for the next stage. The decoupling prevents a write into slot 0 from overlapping a read in the same stage, which is what makes the fishing-at-every-stage predicate safe even at Ki=1K_i = 1.

Because anticipated dispatch carries state across stages, plant ii must be primed with KiK_i pre-horizon commitments — the values that were committed at the negative stages Ki,,1-K_i, \ldots, -1 and are scheduled to mature at stages 0,,Ki10, \ldots, K_i - 1. These live in initial_conditions.past_anticipated_commitments[i].values_mw, an array of exactly KiK_i entries with values_mw[k] carrying the commitment that delivers at study stage kk. The values must satisfy the plant’s generation bounds; both the bounds-check and the array-length check are enforced by the semantic validator. An empty list is the default for studies with no anticipated plants.

The seed enters the LP via the slot-0 fishing constraint at stages 0,,Ki10, \ldots, K_i - 1: at t=0t = 0 the LP reads values_mw[0] out of slot 0; the ring-buffer shift then moves values_mw[1] into slot 0 for stage 11; and so on. From stage KiK_i onward, slot 0 carries the LP-decided commitment dtKiid^i_{t - K_i}.

Anticipation costs are charged at the decision stage but discounted to the delivery stage in the same way a real-world option is priced. The objective coefficient on dtid^i_t is

obj[dti]  =  ci(t+Ki)Ht+Kidt+KiNPV\mathrm{obj}\bigl[\,d^i_t\,\bigr] \;=\; c_i(t + K_i) \cdot H_{t + K_i} \cdot d^{\mathrm{NPV}}_{t + K_i}

where ci()c_i(\cdot) is the unit cost in $/MWh, Ht+KiH_{t + K_i} is the total hours at the delivery stage, and dt+KiNPVd^{\mathrm{NPV}}_{t + K_i} is the cumulative NPV discount factor at the delivery stage. The per-block thermal column cost is zeroed at delivery stages for anticipated plants so the same energy is not double-priced once via the commitment and once via the per-block dispatch.

Benders cuts propagate the marginal value of the matured commitment back through the ring buffer. The reduced cost of the pinned slot-0 column at stage t+1t + 1 is the partial Qt+1/x0,i,t+1a\partial Q_{t+1} / \partial x^{\mathrm{a}}_{0, i, t+1} and is non-zero only when the fishing constraint has bound the LP there. The cut-row builder remaps this coefficient to the predecessor’s commitment column (for Ki=1K_i = 1) or to the predecessor’s outgoing-state slot one step deeper into the ring buffer (for Ki2K_i \geq 2), so the subgradient ultimately lands on the original did^i decision regardless of how many stages have elapsed between commitment and delivery.

Hydro plants are the central elements of the SDDP formulation because:

  1. Reservoir storage creates temporal coupling (water saved today is available tomorrow)
  2. Inflows are stochastic (uncertain future rainfall/snowmelt)
  3. The water value (opportunity cost of using water now vs. saving it) emerges from the optimization

A hydro plant converts the potential energy of stored water into electricity. Each plant has a reservoir (storage), turbines (conversion), and spillways (excess water release). Hydro plants are typically arranged in cascades where upstream releases become downstream inflows.

Cobre distinguishes two hydro plant subsets based on their operational state:

SubsetSymbolDescription
OperatingHop\mathcal{H}^{op}Plants that can generate electricity; subject to generation constraints
FillingHfill\mathcal{H}^{fill}New plants under commissioning, filling dead volume; no generation

Most plants are in Hop\mathcal{H}^{op}. Filling hydros have per-stage target-storage floors instead of generation constraints. Some plants have negligible storage capacity (run-of-river) and must pass all inflows through turbines and spillways within the same stage.

VariableUnitsDescription
vhv_hhm³End-of-stage reservoir storage (state variable)
ah,a_{h,\ell}m³/sAR lag \ell for inflow model (state variable, see note below)
qh,kq_{h,k}m³/sTurbined flow (through generators), block kk
sh,ks_{h,k}m³/sSpillage (released without generation), block kk
uh,ku_{h,k}m³/sDiversion flow (bypassed to separate channel), block kk
eh,ke_{h,k}m³/sEvaporation (see note below), block kk
rh,kr_{h,k}m³/sWater withdrawal (see note below), block kk
gh,kg_{h,k}MWHydro generation, block kk
oh,ko_{h,k}m³/sTotal outflow: oh,k=qh,k+sh,ko_{h,k} = q_{h,k} + s_{h,k} (downstream channel flow)

State variables (vhv_h and ah,a_{h,\ell}) link stages through the Bellman recursion. The storage vhv_h tracks reservoir volume and is a true decision variable within each stage (the optimizer chooses its end-of-stage value). The AR lags ah,a_{h,\ell} carry inflow history for the PAR(p) model: they are state variables in the SDDP sense (passed between stages and subject to Benders cuts), but are fixed at the beginning of each stage to the realized inflow values — they are not free for the optimizer to choose. All other variables are control variables determined within each stage.

  • Bus connection: Each hydro plant connects to one bus for energy delivery
  • Cascade topology: Upstream plants’ outflows (q+s+uq + s + u) become downstream plants’ inflows, with optional water travel time delay
  • Diversion targets: Some plants can divert water to a separate downstream plant (not the immediate cascade successor), bounded by Uˉh\bar{U}_h
  • Pumping stations: May receive pumped water (increasing storage) or supply water to pumps (decreasing storage)
ParameterUnitsDescription
Vˉh\bar{V}_h, Vh\underline{V}_hhm³Storage bounds (useful volume)
Qˉh\bar{Q}_h, Qh\underline{Q}_hm³/sTurbined flow bounds (machine limits)
Oˉh\bar{O}_h, Oh\underline{O}_hm³/sOutflow bounds (environmental flow, flood control)
Gˉh\bar{G}_h, Gh\underline{G}_hMWGeneration bounds (user-defined, not derived from flow)
Uˉh\bar{U}_hm³/sMaximum diversion flow
ρh\rho_hMW/(m³/s)Productivity (constant model)
γ0m,γvm,γqm,γsm\gamma^m_0, \gamma^m_v, \gamma^m_q, \gamma^m_sFPHA hyperplane coefficients for plane mm
aha_hm³/sIncremental inflow (stochastic, from PAR model)
v^h\hat{v}_h, a^h,\hat{a}_{h,\ell}hm³, m³/sIncoming state (from previous stage)

The reservoir dynamics account for all water flows in and out of the plant:

TermDirectionDescription
v^h\hat{v}_hInitialIncoming storage from previous stage
aha_hInflowIncremental inflow (lateral catchment, stochastic)
iUh(qi+si+ui)\sum_{i \in \mathcal{U}_h}(q_i + s_i + u_i)InflowUpstream cascade outflows (with travel time delay)
i:div=hui\sum_{i:\text{div}=h} u_iInflowDiverted water received from other plants
j:dest=hpj\sum_{j:\text{dest}=h} p_jInflowPumped water received from pumping stations
qh+sh+uhq_h + s_h + u_hOutflowTurbined + spillage + diversion (released downstream)
ehe_hOutflowEvaporation (reservoir surface loss; can be negative for net precipitation)
rhr_hOutflowWater withdrawal (consumptive use, removed from system)
j:src=hpj\sum_{j:\text{src}=h} p_jOutflowPumped water extracted by pumping stations

Cobre supports three models for converting turbined flow to electrical generation, in increasing order of complexity:

  1. Constant Productivity: gh,k=ρhqh,kg_{h,k} = \rho_h \cdot q_{h,k} — simple linear relationship with fixed ρh\rho_h [MW/(m³/s)], suitable for plants with stable head.

  2. Linearized Head (simulation-only): Adjusts productivity based on head variation with storage level. Requires hydro geometry data (Volume-Height-Area curve). This model is excluded from training because the bilinear term (q×vavgq \times v^{avg}) requires re-fixing vavgv^{avg} between iterations, changing the LP and breaking SDDP convergence guarantees. See hydro production models §3.

  3. FPHA (Função de Produção Hidrelétrica Aproximada): Piecewise-linear approximation via hyperplanes that captures head variation with storage level and accounts for tailrace effects from spillage. Each plane mm:

gh,kγ0m+γvmvhavg+γqmqh,k+γsmsh,kg_{h,k} \leq \gamma_0^m + \gamma_v^m \cdot v^{avg}_h + \gamma_q^m \cdot q_{h,k} + \gamma_s^m \cdot s_{h,k}

The production model can vary by stage or season per hydro.

For the complete FPHA formulation and model comparison, see hydro production models.

Several hydro constraints are enforced as soft constraints with slack variables and penalties:

ConstraintMeaningSlack Variable
vhVhv_h \geq \underline{V}_hMinimum storage (dead volume)σhv\sigma^{v-}_{h}
qh,kQhq_{h,k} \geq \underline{Q}_hMinimum turbined flow (equipment limits)σh,kq\sigma^{q-}_{h,k}
oh,kOho_{h,k} \geq \underline{O}_hMinimum outflow (environmental flow)σh,ko\sigma^{o-}_{h,k}
oh,kOˉho_{h,k} \leq \bar{O}_hMaximum outflow (flood control)σh,ko+\sigma^{o+}_{h,k}
gh,kGhg_{h,k} \geq \underline{G}_hMinimum generation (grid services)σh,kg\sigma^{g-}_{h,k}
eh,ke_{h,k} feasibleEvaporation within physical limitsσh,ke±\sigma^{e\pm}_{h,k}
rh,kr_{h,k} metWater withdrawal commitmentσh,kr\sigma^{r}_{h,k}
vhVttargetv_h \geq V^{\text{target}}_t (filling floor)Per-stage filling target during commissioningσhfill\sigma^{fill}_{h}

Soft constraints allow the optimizer to violate bounds when physically necessary (e.g., drought conditions preventing minimum outflow), with high penalty costs signaling undesirable operation. Maximum storage (Vˉh\bar{V}_h) is a hard physical limit — excess water is handled by emergency spillage, not a slack variable. For the penalty priority ordering and cost magnitudes, see Penalty System. For the complete constraint formulations, see equipment formulations.

Cobre models the commissioning of new hydro plants with a filling period ([start_stage_id, entry_stage_id)) during which the reservoir accumulates water to reach the dead volume (Vh\underline{V}_h). During this period:

  • The hydro has no generation: qh,k=0q_{h,k} = 0, gh,k=0g_{h,k} = 0 (hard constraint)
  • Natural inflow flows freely through the ordinary water balance — there is no retention or impound cap diverting inflow to storage
  • Storage is allowed below Vh\underline{V}_h (the operating min-storage slack is inactive)
  • Outflow is limited to spillage (turbines not operational), with the outflow_violation_below slack if environmental flow cannot be met
  • A per-stage filling floor vhVttargetv_h \geq V^{\text{target}}_t requires the reservoir to stay on a minimum-accumulation schedule set by filling_min_rate_m3s. The floor ramps up to Vh\underline{V}_h at the last filling stage; its slack σhfill\sigma^{fill}_h is priced below deficit (a fill schedule is not defended as hard as load serving)

When the plant enters service at entry_stage_id, the ordinary soft minimum-storage floor takes over. For the per-stage floor trajectory and the penalty ordering, see Penalty System.

kKτkhH[chspillsh,k+chfphaqh,k+chdivuh,k]+(slack penalties)\sum_{k \in \mathcal{K}} \tau_k \sum_{h \in \mathcal{H}} \left[ c^{spill}_h \cdot s_{h,k} + c^{fpha}_h \cdot q_{h,k} + c^{div}_h \cdot u_{h,k} \right] + \text{(slack penalties)}
  • Spillage cost: Small regularization ($0.001–0.01 per m³/s·h) to prefer turbining over spilling
  • FPHA turbined cost: Regularization applied only to hydros using the FPHA production model. Must be > spillage_cost for the same plant to prevent interior FPHA solutions. See Penalty System.
  • Diversion cost: Small regularization, typically higher than spillage (water leaves main cascade)
  • Slack penalties: High costs for constraint violations — storage below dead volume, outflow violations, generation violations, evaporation violations, water withdrawal shortfall. See Penalty System for the full penalty taxonomy and priority ordering.
  • No generation cost: Hydro generation has zero marginal fuel cost — its “cost” is the opportunity cost of depleting storage, captured through the value function Vt+1(vh)V_{t+1}(v_h)

Water balance (reservoir dynamics):

vh=v^h+ζ[ah+kwknet_flowsh,k]v_h = \hat{v}_h + \zeta \cdot \left[ a_h + \sum_{k} w_k \cdot \text{net\_flows}_{h,k} \right]

where net_flowsh,k\text{net\_flows}_{h,k} includes all inflow and outflow terms listed above.

AR lag pinning (inflow history): ah,=a^h,a_{h,\ell} = \hat{a}_{h,\ell} for all {1,,Ph}\ell \in \{1, \ldots, P_h\}, enforced by equal column bounds (not a constraint row)

Outflow definition: oh,k=qh,k+sh,ko_{h,k} = q_{h,k} + s_{h,k}

Generation constraint (depends on production model):

  • Constant productivity: gh,k=ρhqh,kg_{h,k} = \rho_h \cdot q_{h,k}
  • FPHA: gh,kγ0m+γvmvhavg+γqmqh,k+γsmsh,kg_{h,k} \leq \gamma_0^m + \gamma_v^m \cdot v_h^{avg} + \gamma_q^m \cdot q_{h,k} + \gamma_s^m \cdot s_{h,k} for each plane mm

For the fully assembled constraints, see LP formulation.

A non-controllable source represents intermittent generation (wind farms, solar plants, small run-of-river hydros, etc.) whose available output depends on external conditions (weather, river flow) rather than dispatch decisions. The solver receives a stochastic availability value per scenario from the scenario pipeline, and can only curtail generation below that availability — it cannot dispatch upward beyond what nature provides.

Non-controllable sources have near-zero marginal cost. The cost of curtailing available generation is a regularization penalty (Category 3 in the Penalty System), analogous to spillage_cost for hydros — curtailment discards available “free” energy.

A per-source flag χr{curtailable,must-run}\chi_r \in \{\text{curtailable}, \text{must-run}\} selects between two LP behaviours for the realized availability ArA_r:

  • Curtailable (default): the generation column has bounds [0,Ar][0, A_r], the LP is free to curtail any amount below ArA_r, and curtailment is regularised by curtailment_cost. This is the standard model for stand-alone wind and solar plants where ramping down is physically feasible and economically justified by the regularisation cost.
  • Must-run: the generation column is pinned to the realized availability, gr,knc=Arg^{nc}_{r,k} = A_r, by setting both lower and upper bounds to ArA_r on every scenario. The curtailment penalty is unused because the curtailment slack is zero by construction. This model is required when the scenario pipeline feeds the LP with an aggregate that has already been pre-netted from demand by the upstream model — for example, NEWAVE-derived geracao_usinas_nao_simuladas totals over PCH, PCT, EOL, UFV, and MMGD: those have already been subtracted from MERC upstream, so allowing the LP to curtail them double-discounts the must-run contribution and produces a cheaper hydrothermal dispatch than the reference model. On the bundled deterministic 1983 case, leaving the aggregates curtailable gives ≈ 18 % of total NCS supply curtailed, a ≈ +15 % hydro-dispatch swing, and ≈ −23 % spillage versus NEWAVE; pinning them as must-run restores parity while keeping per-source observability in the simulation outputs.

The pin is applied per scenario by overwriting the upper and lower bounds on the NCS column with ArA_r before each stage solve. The availability ratio α=clamp(μ+ση,0,1)\alpha = \mathrm{clamp}(\mu + \sigma \cdot \eta,\,0,\,1) and the per-(stage, block) shape factor multiply the installed capacity exactly as in the curtailable case — only the lower bound differs.

Non-controllable sources follow the generic commissioning window (§1, Entity Commissioning Windows), controlled by entry_stage_id and exit_stage_id:

StateConditionLP Variables
non_existingBefore entry_stage_idPinned to zero
operatingentry_stage_idt<exit_stage_id\text{entry\_stage\_id} \leq t < \text{exit\_stage\_id}generation, curtailment (derived)
decommissionedAt or after exit_stage_idPinned to zero
VariableUnitsDescription
gr,kncg^{nc}_{r,k}MWGeneration at non-controllable source rr, block kk

Curtailment is not a separate LP decision variable — it is derived as κr,k=Argr,knc\kappa_{r,k} = A_{r} - g^{nc}_{r,k}, where ArA_r is the stochastic available generation for the current (stage, scenario). The implementation may equivalently formulate curtailment as a reward for dispatching (negative cost on gr,kncg^{nc}_{r,k}) rather than a penalty on (Argr,knc)(A_r - g^{nc}_{r,k}); either is valid. For must-run sources, κr,k0\kappa_{r,k} \equiv 0 by construction (the lower bound on the generation column equals ArA_r), so the regularisation term contributes zero to the objective regardless of how it is signed.

  • Bus connection: Each source connects to exactly one bus, contributing generation to its energy balance
ParameterUnitsDescription
Gˉr\bar{G}_rMWInstalled capacity (hard physical upper bound)
ArA_rMWAvailable generation for current (stage, scenario), from scenario pipeline. Bounded by [0,Gˉr][0, \bar{G}_r]
crcurtc^{curt}_r$/MWhCurtailment cost (regularization penalty)
kKτkrRcrcurt(Argr,knc)\sum_{k \in \mathcal{K}} \tau_k \sum_{r \in \mathcal{R}} c^{curt}_r \cdot (A_r - g^{nc}_{r,k})

The curtailment cost is a small regularization term ($0.001–0.01/MWh) that incentivizes the solver to use all available generation before curtailing.

Generation bounds (hard constraints, no slack variables):

gr,knc{[0, Ar]if χr=curtailable[Ar, Ar]if χr=must-rung^{nc}_{r,k} \in \begin{cases} [\,0,\ A_r\,] & \text{if } \chi_r = \text{curtailable} \\ [\,A_r,\ A_r\,] & \text{if } \chi_r = \text{must-run} \end{cases}

Load balance contribution at connected bus: +gr,knc+g^{nc}_{r,k} (generation injected).

For detailed constraints, see equipment formulations.

A pumping station transfers water from one reservoir (source) to another (destination), consuming electrical power in the process. Pumping enables elevation transfer, basin transfer, and storage arbitrage (pumping during low-demand periods, generating during high-demand).

VariableUnitsDescription
pj,kp_{j,k}m³/sPumped water flow at station jj, block kk
  • Source hydro: Water is withdrawn from this reservoir
  • Destination hydro: Water is added to this reservoir
  • Bus connection: Pumping consumes power at the connected bus
ParameterUnitsDescription
Pj\underline{P}_jm³/sMinimum pumped flow
Pˉj\bar{P}_jm³/sMaximum pumped flow
γj\gamma_jMW/(m³/s)Power consumption rate

Flow bounds: Pjpj,kPˉj\underline{P}_j \leq p_{j,k} \leq \bar{P}_j

Water balance impact: Source hydro: pj,k-p_{j,k} (water removed); Destination hydro: +pj,k+p_{j,k} (water added).

Load balance impact at connected bus: γjpj,k-\gamma_j \cdot p_{j,k} (power consumed).

For detailed constraints, see equipment formulations.

Contracts represent agreements to buy (import) or sell (export) electricity with external systems outside the modeled region, providing flexibility during shortages and revenue opportunity for surplus.

Each contract is unidirectional: it is either an import contract or an export contract, identified by a type field.

VariableUnitsDescription
χc,k\chi_{c,k}MWDispatched power for contract cc, block kk

Each contract connects to exactly one bus, contributing to its energy balance:

  • Import contracts (cCimpc \in \mathcal{C}^{imp}): Add χc,k\chi_{c,k} to the bus (power entering the system)
  • Export contracts (cCexpc \in \mathcal{C}^{exp}): Remove χc,k\chi_{c,k} from the bus (power leaving the system)
ParameterUnitsDescription
Cc\underline{C}_c, Cˉc\bar{C}_cMWMinimum and maximum contract dispatch limits
ccctrc^{ctr}_c$/MWhContract price: positive for imports (cost), negative for exports (revenue)
kKτkcCccctrχc,k\sum_{k \in \mathcal{K}} \tau_k \sum_{c \in \mathcal{C}} c^{ctr}_c \cdot \chi_{c,k}

Because import prices are positive and export prices are negative, this single summation naturally adds import costs and subtracts export revenue.

Capacity bounds: Ccχc,kCˉc\underline{C}_c \leq \chi_{c,k} \leq \bar{C}_c. A non-zero lower bound Cc\underline{C}_c acts as a hard take-or-pay floor — the LP must dispatch at least that quantity at the contract price. Contracts are stateless and honor the generic commissioning window (§1).

For detailed constraints, see equipment formulations.

9. Summary: Physical Elements to LP Components

Section titled “9. Summary: Physical Elements to LP Components”

The following table maps each physical system element to its LP representation:

Physical ElementState VariablesControl VariablesKey ConstraintsObjective Role
Busδb,k,s\delta_{b,k,s}, ϵb,k\epsilon_{b,k}Load balanceDeficit penalty (high), Excess penalty (low)
Transmission Linefl,k+f^+_{l,k}, fl,kf^-_{l,k}Capacity boundsExchange cost (regularization)
Thermal Plantgj,k,sg_{j,k,s}Generation bounds, Segment limitsFuel cost
Thermal (anticipated)xs,i,tax^{\mathrm{a}}_{s,i,t}dtid^i_t, gj,k,sg_{j,k,s}Ring-buffer slot pinning + fishing equalityCommitment cost discounted to delivery stage
Hydro Plantvhv_h, ah,a_{h,\ell}qh,kq_{h,k}, sh,ks_{h,k}, uh,ku_{h,k}, gh,kg_{h,k}Water balance, Generation functionSpillage/diversion cost (regularization)
Non-Controllablegr,kncg^{nc}_{r,k}Availability boundCurtailment penalty (regularization)
Pumping Stationpj,kp_{j,k}Flow bounds (min/max)None (cost via energy consumption)
Contractχc,k\chi_{c,k}Dispatch bounds (min/max)Import cost or Export revenue

Key insight: The hydro storage variables vhv_h, the AR lag variables ah,a_{h,\ell}, and the anticipated-thermal ring-buffer slots xs,i,tax^{\mathrm{a}}_{s,i,t} are the state variables that link stages through the Bellman recursion. All other elements contribute control variables that are determined within each stage. This structure enables SDDP’s decomposition: the stage subproblem optimizes all control variables given the incoming state, and Benders cuts approximate the future cost as a function of the outgoing state.