Power Systems and Capacity Expansion


Lecture 14

October 21, 2024

Questions?

Poll Everywhere QR Code

Text: VSRIKRISH to 22333

URL: https://pollev.com/vsrikrish

See Results

Electric Power System Decision Problems

Overview of Electric Power Systems

Power Systems Schematic

Source: Wikipedia

Decisions Problems for Power Systems

Decision Problems for Power Systems by Time Scale

Adapted from Perez-Arriaga, Ignacio J., Hugh Rudnick, and Michel Rivier (2009)

Electricity Generation by Source

Electricity Generation in 2022 by Source

Source: U.S. Energy Information Administration

Generating Capacity Expansion

Capacity Expansion

Capacity expansion involves adding resources to generate or transmit electricity to meet anticipated demand (load) in the future.

Typical objective: Minimize cost

But other constraints may apply, e.g. reducing CO2 emissions or increasing fuel diversity.

Simple Capacity Expansion Example

Plant Types

In general, we have many fuel options:

  • Gas (combined cycle or simple cycle);
  • Coal;
  • Nuclear;
  • Renewables (wind, solar, hydro, geothermal)

Simplified Example: Generators

Code
gens = DataFrame(CSV.File("data/capacity_expansion/generators.csv"))
gens_display = rename(gens, Symbol.([:Generator, :"Fixed Cost (\\\$)", :"Variable Cost (\\\$/MW)"]))
markdown_table(gens_display[1:end-2, :])
Generator Fixed Cost ($) Variable Cost ($/MW)
Geothermal 450000 0
Coal 220000 21
NG CCGT 82000 25
NG CT 65000 35

Simplified Example: Demand

Code
NY_demand = DataFrame(CSV.File("data/capacity_expansion/2020_hourly_load_NY.csv"))
rename!(NY_demand, :"Time Stamp" => :Date)
demand = NY_demand[:, [:Date, :C]]
rename!(demand, :C => :Demand)
@df demand plot(:Date, :Demand, xlabel="Date", ylabel="Demand (MWh)", label=:false, xrot=45, bottom_margin=15mm)
plot!(size=(1200, 500))
Figure 1: Demand for 2020 in NYISO Zone C

Load Duration Curves

The chronological demand curve makes it hard to understand what levels of load occur with lower or greater frequency.

Instead, we can sort demand from high to low, which creates a load duration curve.

Simplified Example: Load Duration Curve

Code
plot(sort(demand.Demand, rev=true), linewidth=3, label=:false)
xaxis!("Hours")
yaxis!("Demand (MWh)")
plot!(size=(1200, 450))
Figure 2: Load Duration Curve for 2020 in NYISO Zone C

Simplified Example: Load Duration Curve

Code
hline!([2400], color=:red, linewidth=3, label=false)
annotate!(2000, 2500, text("Peak Load", :red, :right, 20))
hline!([1500], color=:brown, linewidth=3, label=false)
annotate!(4000, 2000, text("Shoulder Load", :brown, :left, 20))
annotate!(2000, 1400, text("Base Load", :blue, :right, 20))
Figure 3: Load Duration Curve for 2020 in NYISO Zone C

Capacity Expansion: Goal

We want to find the installed capacity of each technology that meets demand at all hours at minimal total cost.

Although…

  • For some hours with extreme load, is it necessarily worth it to build new generation to meet those peaks?
  • Instead, assign a high cost \(NSECost\) to non-served energy (NSE). In this case, let’s set \(NSECost = \$9000\)/MWh

Decision Variables

What are our variables?

Variable Meaning
\(x_g\) installed capacity (MW) from each generator type \(g \in \mathcal{G}\)
\(y_{g,t}\) production (MWh) from each generator type \(g\) in hour \(t \in \mathcal{T}\)
\(NSE_t\) non-served energy (MWh) in hour \(t \in \mathcal{T}\)

Capacity Expansion Objective

\[ \begin{align} \min_{x, y, NSE} Z &= {\color{red}\text{investment cost} } + {\color{blue}\text{operating cost} } \\ &= {\color{red} \sum_{g \in \mathcal{G}} \times \text{FixedCost}_g x_g} + \\ & \qquad{\color{blue} \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \text{VarCost}_g \times y_{g,t} + \sum_{t \in \mathcal{T}} \text{NSECost} \times NSE_t} \end{align} \]

What Are Our Constraints?

Capacity Expansion Constraints

  • Demand: Sum of generated energy and non-served energy must equal demand \(d_t\).
  • Capacity: Generator types cannot produce more electricity than their installed capacity.
  • Non-negativity: All decision variables must be non-negative.

Problem Formulation

\[ \begin{align} \min_{x, y, NSE} \quad & \sum_{g \in \mathcal{G}} \text{FixedCost}_g \times x_g + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \text{VarCost}_g \times y_{g,t} & \\ & \quad + \sum_{t \in \mathcal{T}} \text{NSECost} \times NSE_t & \\[0.5em] \text {subject to:} \quad & \sum_{g \in \mathcal{G}} y_{g,t} + NSE_t \geq d_t \qquad \forall t \in \mathcal{T} \\[0.5em] & y_{g,t} \leq x_g \qquad \qquad \qquad\qquad \forall g \in {G}, \forall t \in \mathcal{T} \\[0.5em] & x_g, y_{g,t}, NSE_t \geq 0 \qquad \qquad \forall g \in {G}, \forall t \in \mathcal{T} \end{align} \]

Capacity Expansion is an LP

  • Linearity: costs assumed to scale linearly;
  • Divisible: we model total installed capacity, not number of individual generator units
  • Certainty: no uncertainty about renewables.

Real problems can get much more complex, particularly if we try to model making decisions under renewable or load uncertainty.

Capacity Expansion Example Solution

Code
# define sets
G = 1:nrow(gens[1:end-2, :])
T = 1:nrow(demand)
NSECost = 9000

gencap = Model(HiGHS.Optimizer)
# define variables
@variables(gencap, begin
    x[g in G] >= 0
    y[g in G, t in T] >= 0
    NSE[t in T] >= 0
end)
@objective(gencap, Min, 
    sum(gens[G, :FixedCost] .* x) + sum(gens[G, :VarCost] .* sum(y[:, t] for t in T)) + NSECost * sum(NSE)
)
@constraint(gencap, load[t in T], sum(y[:, t]) + NSE[t] >= demand.Demand[t])
@constraint(gencap, availability[g in G, t in T], y[g, t] <= x[g])
optimize!(gencap)
Resource Installed (MW) Percent (%) Generation (GWh) Percent (%)
Geothermal -0.0 -0.0 0.0 0.0
Coal 0.0 0.0 -0.0 -0.0
NG CCGT 2016.9 72.5 15157.7 98.1
NG CT 733.0 26.4 292.2 1.9
NSE 31.2 1.1 0.1 0.0

When Might Generators Operate?

Code
p = areaplot(value.(y).data', 
    label=permutedims(gens.Plant), 
    xlabel = "Hour", 
    ylabel ="Generated Electricity (MWh)", 
    color_palette=:seaborn_colorblind,
    grid=:false,
    legend = :bottomleft)
ylims!(p, (0, 3200))
plot!(p, size=(1200, 500))
Figure 4: Results of Generating Capacity Expansion Example

How Often Is There Non-Served Energy?

\(\text{NSE}\) is non-zero for 7 hours and a total of 94 MWh.

Why do we think there is any NSE given the high NSE Cost?

What Does This Problem Neglect?

  1. Discrete decisions: is a plant on or off (this is called unit commitment)?
  2. Intertemporal constraints: Power plants can’t just “ramp” from producing low levels of power to high levels of power; there are real engineering limits.
  3. Transmission: We can generate all the power we want, but what if we can’t get it to where the demand is
  4. Retirements: We might have existing generators that we want to retire (“brownfield” scenarios).

What About Renewables?

Renewables make this problem more complicated because their capacity is variable:

  • resource availability not constant across time;
  • need to consider a capacity factor.

How would this change our existing capacity expansion formulation?

Renewable Variability Impact

This will change the capacity constraint from \[y_{g,t} \leq x_g \qquad \forall g \in {G}, \forall t \in \mathcal{T}\] to \[y_{g,t} \leq x_g \times c_{g,t} \qquad \forall g \in {G}, \forall t \in \mathcal{T}\] where \(c_{g,t}\) is the capacity factor in time period \(t\) for generator type \(g\).

Implementing Constraints in JuMP

I recommend using vector notation in JuMP to specify these constraints, e.g. for capacity:

# define sets
G = 1:num_gen # num_gen is the number of generators
T = 1:num_times # number of time periods

c = ... # G x T matrix of capacity factors  
@variable(..., x[g in G] >= 0) # installed capacity
@variable(..., y[g in G, t in T] >= 0) # generated power
@constraint(..., capacity[g in G, t in T], 
    y[g,t] <= x[g] * c[g,t]) # capacity constraint

Key Takeaways

Key Takeaways

  • Capacity Expansion is a foundational power systems decision problem.
  • Is an LP with some basic assumptions.
  • We looked at a “greenfield” example: no existing plants.
  • Decision problem becomes more complex with renewables (HW4) or “brownfield” (expanding existing fleet, possibly with retirements).

Upcoming Schedule

Next Classes

Wednesday: Economic Dispatch

Next Week: Managing Air Pollution

Assessments

  • HW4 assigned today (on LP/power systems), due on 10/31 at 9pm.