class: center, middle .title[Unit Commitment]
.subtitle[BEE 4750/5750]
.subtitle[Environmental Systems Analysis, Fall 2022]
.author[Vivek Srikrishnan]
.date[October 19, 2022] --- name: toc class: left # Outline
1. Project Updates 2. Questions? 3. Unit Commitment 4. Unit Commitment Worked Example --- name: poll-answer layout: true class: left # Poll
.left-column[{{content}} URL: [https://pollev.com/vsrikrish](https://pollev.com/vsrikrish) Text: **VSRIKRISH** to 22333, then message] .right-column[.center[]] --- name: questions template: poll-answer ***Any questions?*** --- layout: false # Last Class
* Mixed Integer Programming * Network Problems and Waste Allocation --- class: left # Power Systems Decision Problems
.center[] .center[.cite[Adapted from Perez-Arriaga, Ignacio J., Hugh Rudnick, and Michel Rivier (2009).]] --- class: left # Economic Dispatch
$$ \begin{alignat}{3} & \min\_{y\_{g,t}} && \sum\_g VarCost\_g \times \sum\_t y\_{g,t} && \notag\\\\ & \text{subject to:} && && \notag\\\\ & && \sum\_g y\_{g,t} = d\_t && \forall t \in T \\\\ & && y\_{g,t} \leq P^{\text{max}}\_g && \forall g \in G, t \in T \\\\ & && y\_{g,t} \geq P^{\text{min}}\_g && \forall g \in G, t \in T \\\\ & && y\_{g,t+1} - y\_{g, t} \leq R\_g && \forall g \in G, t \in T \\\\ & && y\_{g,t} - y\_{g, t+1} \leq R\_g && \forall g \in G, t \in T \end{alignat} $$ --- class: left # Missing from Economic Dispatch
* Startup Costs * Minimum up/down times --- class: left # Unit Commitment
**Unit commitment** extends economic dispatch by also considering whether generating units should be *committed*, or scheduled to be online. So: * Given the load profile for the decision period; * Given a set of units available We want to schedule units to meet demand at lowest cost. --- name: questions template: poll-answer ***What are our new decision variables?*** --- class: left # Unit Commitment Decision Variables
| Variable | Definition | |:-------------:|:------------------------------------------------------ | | $y_{g,t}$ | power generated by generator $g$ (MWh) | | $c_{g,t}$ | commitment status of thermal generator $g$ at time $t$ | | $start_{g,t}$ | startup decision of thermal generator $g$ at time $t$ | | $shut_{g,t}$ | shutdown decision of thermal generator $g$ at time $t$ | -- **Note**: $c\_{g,t}$, $start\_{g,t}$, and $shut\_{g,t}$ are all *binary* variables, so this will be a mixed-integer LP! --- class: left # Unit Commitment Objective
$$ \begin{aligned} &\min \textcolor{blue}{generation\ cost} + \textcolor{red}{startup\ costs}\\\\ \Rightarrow &\min \color{blue} \sum\_{g \in G, t \in T} VarCost\_{g} \times y\_{g,t} \color{black} + \\\\ & \quad \color{red} \sum\_{g \in {G\_{thermal}}, T \in T} StartCost\_g \times start\_{g,t} \end{aligned} $$ --- class: left # Unit Commitment Constraints: Part 1
$$ \begin{alignat}{2} & \sum\_g y\_{g,t} = d\_t && \quad \forall t \in T\\\\ & y\_{g,t} \leq P^{\text{max}}\_g \times c\_{g,t} && \quad \forall g \in G, t \in T \\\\ & y\_{g,t} \geq P^{\text{min}}\_g \times c\_{g,t} && \quad \forall g \in G, t \in T \end{alignat} $$ --- class: left # Unit Commitment Constraints: Part 2
$$ \begin{alignat}{2} &c\_{g,t} \geq \sum\_{s = t - MinUp\_g}^t start\_{g,s} & \quad \forall g \in G\_\text{thermal}, t \in T \\\\ & 1 - c\_{g,t} \geq \sum\_{s = t - MinDown\_g}^t shut\_{g,s} & \quad \forall g \in G\_\text{thermal}, t \in T\\\\ & c\_{g, t+1} - c\_{g, t} = start\_{g, t+1} - shut\_{g, t+1} & \quad \forall g \in G\_\text{thermal}, t \in T \\\\ & c\_{g, t} = 1 & \quad \forall g \notin G\_\text{thermal} \end{alignat} $$ --- class: left # Unit Commitment Ramp Constraints
How do we deal with ramp constraints? **Key issue**: if we start a generator, we jump from generating 0 MW to at least $P^\text{min}_g$ MW. .left-column[This could violate the ramp limit $R_g$!] /private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/jl_X2yGR3/build/ramping-aux.svg .right-column[.center[]] --- class: left # Unit Commitment Ramp Constraints
**Solution**: Introduce a new variable, $y^\text{aux}_{g,t}$, which is the generation above the minimum (if commited): $$ y^\text{aux}\_{g,t} = y\_{g,t} - \left(P^\text{min}\_g \times c\_{g,t}\right) $$ .center[] --- class: left # Unit Commitment Constraints: Part 3
$$ \begin{alignat}{2} & y^\text{aux}\_{g,t} = y\_{g,t} - \left(P^\text{min}\_g \times c\_{g,t}\right) && \quad \forall g \in G\_\text{thermal}, t \in T \\\\ & y^\text{aux}\_{g,t+1} - y^\text{aux}\_{g, t} \leq R\_g && \quad \forall g \in G\_\text{thermal}, t \in T \\\\ & y^\text{aux}\_{g,t} - y^\text{aux}\_{g, t+1} \leq R\_g && \quad \forall g \in G\_\text{thermal}, t \in T \end{alignat} $$ --- class: left # Example: Generator Data
| Type | $P^{\text{min}}$ (MW) | $P^{\text{max}}$ (MW) | $VarCost$ ($/MWh) | $R$ (MW) | $MinUp$ (hr) | $MinDown$ (hr) | $StartUpCost$ ($) | | ----------------:| ---------------------:| ---------------------:| -----------------:| --------:| ------------:| --------------:| -----------------:| | Hydro | 0 | 1000 | 0 | 1000 | – | – | – | | Wind | 0 | 800 | 0 | 800 | – | – | – | | Solar | 0 | 700 | 0 | 700 | – | – | – | | Nuclear | 200 | 1000 | 2 | 100 | 24 | 24 | 500000 | | Natural Gas CCGT | 200 | 600 | 23 | 250 | 6 | 6 | 30000 | | Natural Gas CT | 60 | 300 | 39 | 300 | 1 | 1 | 8000 | --- class: left # Example: Demand and Capacity Factors
/private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/jl_X2yGR3/build/uc-example-windcf.svg .left-column[] .right-column[] --- class: left # Unit Commitment Implementation
```julia using JuMP using Cbc using DataFrames # load data demand = [1725, 1596, 1476, 1408, 1530, 1714, 1820, 1973, 2081, 2202, 2105, 2065, 2045, 2195, 2309, 2390, 2486, 2515, 2075, 2006, 1956, 1902, 1865, 1820] wind_cf = [0.58, 0.57, 0.55, 0.28, 0.14, 0.21, 0.03, 0.04, 0.01, 0.04, 0.04, 0.01, 0.04, 0.04, 0.01, 0.01, 0.01, 0.13, 0.30, 0.45, 0.44, 0.57, 0.55, 0.58] solar_cf = [0, 0, 0, 0, 0, 0, 0.20, 0.57, 0.80, 0.93, 0.99, 0.99, 0.85, 0.99, 0.95, 0.81, 0.55, 0.12, 0, 0, 0, 0, 0, 0] hydro_cf = 0.65 ``` --- class: left # Unit Commitment Implementation
```julia generators = ["hydro", "wind", "solar", "nuclear", "ccgt", "ct"] ramp = [1000, 800, 700, 100, 200, 300] p_min = [0, 0, 0, 200, 200, 60] p_max = [1000, 800, 700, 1000, 600, 300] varom = [0, 0, 0, 2, 23, 39] startcost = [0, 0, 0, 500000, 30000, 8000] minup = [0, 0, 0, 24, 6, 1] mindown = [0, 0, 0, 24, 6, 1] ``` --- class: left # Unit Commitment Implementation
```julia h = length(demand) T = 1:h G = 1:length(generators) Gthermal = 4:6 uc = Model(Cbc.Optimizer) @variable(uc, y[g in G, t in T] >= 0) # generation @variable(uc, c[g in Gthermal, t in T], Bin) # commitment @variable(uc, start[g in Gthermal, t in T], Bin) # startup @variable(uc, stop[g in Gthermal, t in T], Bin) # shutdown @variable(uc, yaux[g in Gthermal, t in T] >= 0) # aux generation @objective(uc, Min, sum(varom .* sum(y[:, t] for t in T)) + sum(startcost[Gthermal] .* sum(start[:, t] for t in T))) ``` --- class: left # Unit Commitment Implementation
```julia @constraint(uc, load[t in T], sum(y[:, t]) == demand[t]) @constraint(uc, pmax[g in Gthermal, t in T], y[g, t] <= p_max[g] * c[g, t]) @constraint(uc, hydromax[t in T], y[1, t] <= hydro_cf * p_max[1]) @constraint(uc, windmax[t in T], y[2, t] <= wind_cf[t] * p_max[2]) @constraint(uc, solarmax[t in T], y[3, t] <= solar_cf[t] * p_max[3]) @constraint(uc, pmin[g in Gthermal, t in T], y[g, t] >= p_min[g] * c[g, t]) ``` --- # Unit Commitment Implementation
```julia @constraint(uc, startup[g in Gthermal, t in T], c[g, t] >= sum(start[g, s] for s in intersect(T, (t - minup[g]):t))) @constraint(uc, shutdown[g in Gthermal, t in T], 1 - c[g, t] >= sum(stop[g, s] for s in intersect(T, (t - mindown[g]):t))) @constraint(uc, commit[g in Gthermal, t in 1:(h-1)], c[g, t+1] - c[g, t] == start[g, t+1] - stop[g, t+1]) @constraint(uc, aux[g in Gthermal, t in T], yaux[g, t] == y[g, t] - (p_min[g]) * c[g, t]) @constraint(uc, rampup[g in Gthermal, t in 1:(h-1)], yaux[g, t + 1] - yaux[g, t] <= ramp[g]) @constraint(uc, rampdown[g in Gthermal, t in 1:(h-1)], yaux[g, t] - yaux[g, t + 1] <= ramp[g]) ``` --- # Unit Commitment Solution
```julia set_silent(uc) optimize!(uc) objective_value(uc) ``` ``` 143582.0 ``` --- # Unit Commitment Solution
``` "/private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/jl_X2yGR3/build/unit-commitment-stacked.svg" ``` .center[] --- class: left # Unit Commitment Results
.center[] --- class: left # Key Takeaways
* Unit commitment involves telling generating units whether to operate or not in a given time period. * Decision-making about turning plants on and off turns this into a mixed integer program and introduces new constraints for thermal plants, which can cause curtailment of renewable generation. * We looked at a *very* simple example: UC can get very complicated with many plants, renewable uncertainty, and transmission constraints. --- class: left # Next Class
* Air Pollution Models * Optimization using Simulation Models