Unit Commitment: Electrical Power Generation

Objective and Prerequisites

Major electric power companies around the world utilize mathematical optimization to manage the flow of energy across their electrical grids. In this example, you’ll discover the power of mathematical optimization in addressing a common energy industry problem: electrical power generation. We’ll show you how to figure out the optimal set of power stations to turn on in order to satisfy anticipated power demand over a 24-hour time horizon.

This model is example 15 from the fifth edition of Model Building in Mathematical Programming by H. Paul Williams on pages 270 – 271 and 325 – 326.

This example is at the intermediate level, where we assume that you know Python and the Gurobi Python API and that you have some knowledge of building mathematical optimization models.

This document is cloned from the Gurobi webpage where you can find many other case studies.


Problem Description

In this problem, power generation units are grouped into three distinct types, with different characteristics for each type (power output, cost per megawatt hour, startup cost, etc.). A unit can be on or off, with a startup cost associated with transitioning from off to on, and power output that can fall anywhere between a specified minimum and maximum value when the unit is on. A 24-hour time horizon is divided into 5 discrete time periods, each with an expected total power demand. The model decides which units to turn on, and when, in order to satisfy demand for each time period. The model also captures a reserve requirement, where the selected power plants must be capable of increasing their output, while still respecting their maximum output, in order to cope with the situation where actual demand exceeds predicted demand.

A set of generators is available to satisfy power demand for the following day. Anticipated demand is as follows:

Time Period Demand (megawatts)
12 pm to 6 am 15000
6 am to 9 am 30000
9 am to 3 pm 25000
3 pm to 6 pm 40000
6 pm to 12 pm 27000

Generators are grouped into three types, with the following minimum and maximum output for each type (when they are on):

Type Number available Minimum output (MW) Maximum output (MW)
0 12 850 2000
1 10 1250 1750
2 5 1500 4000

There are costs associated with using a generator: a cost per hour when the generator is on (and generating its minimum output), a cost per megawatt hour above its minimum, and a startup cost for turning a generator on:

Type Cost per hour (when on) Cost per MWh above minimum Startup cost
0 $\$1000$ $\$2.00$ $\$2000$
1 $\$2600$ $\$1.30$ $\$1000$
2 $\$3000$ $\$3.00$ $\$500$

Generators must meet predicted demand, but they must also have sufficient reserve capacity to be able to cope with the situation where actual demand exceeds predicted demand. For this model, the set of selected generators must be able to produce as much as 115% of predicted demand.

Which generators should be committed to meeting anticipated demand in order to minimize total cost?


Model Formulation

Sets and Indices

$t \in \text{Types}=\{0,1,2\}$: Types of generators.

$p \in \text{Periods}=\{0,1,2,3,4\}$: Time periods.

Parameters

$\text{period_hours}_p \in \mathbb{N}^+$: Number of hours in each time period.

$\text{generators}_t \in \mathbb{N}^+$: Number of generators of type $t$.

$\text{demand}_p \in \mathbb{R}^+$: Total power demand for time period $p$.

$\text{start0} \in \mathbb{N}^+$: Number of generators that are on at the beginning of the time horizon (and available in time period 0 without paying a startup cost).

$\text{min_output}_t \in \mathbb{R}^+$: Minimum output for generator type $t$ (when on).

$\text{max_output}_t \in \mathbb{R}^+$: Maximum output for generator type $t$.

$\text{base_cost}_t \in \mathbb{R}^+$: Minimum operating cost (per hour) for a generator of type $t$.

$\text{per_mw_cost}_t \in \mathbb{R}^+$: Cost to generate one additional MW (per hour) for a generator of type $t$.

$\text{startup_cost}_t \in \mathbb{R}^+$: Startup cost for generator of type $t$.

Decision Variables

...

Objective Function

  • Cost: Minimize the cost (in USD) to satisfy the predicted electricity demand.

...

Constraints

  • Available generators: Number of generators used must be less than or equal to the number available.

...

  • Demand: Total power generated across all generator types must meet anticipated demand for each time period $p$.

...

  • Min/max generation: Power generation must respect generator min/max values.

...

  • Reserve: Selected generators must be able to satisfy demand that is as much as 15% above the prediction.

...

  • Startup: Establish relationship between number of active generators and number of startups (use $start0$ for period before the time horizon starts)

...


Python Implementation

We import the Gurobi Python Module and other Python libraries. With Gurobi 9.1.1, a pip installation of the product will automatically include a size-limited (2000 variables, 2000 linear constraints, and 200 quadratic constraints) license that should work in a Docker container, which is used by Google Colab.

In [2]:
%pip install -i https://pypi.gurobi.com gurobipy
Looking in indexes: https://pypi.gurobi.com
Requirement already satisfied: gurobipy in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (9.1.1)
WARNING: You are using pip version 20.2.3; however, version 21.0.1 is available.
You should consider upgrading via the '/usr/local/bin/python3 -m pip install --upgrade pip' command.
Note: you may need to restart the kernel to use updated packages.
In [3]:
import numpy as np
import pandas as pd

import gurobipy as gp
from gurobipy import GRB

Input Data

We define all the input data of the model.

In [4]:
# Parameters

ntypes = 3
nperiods = 5
maxstart0 = 5

generators = [12, 10, 5]
period_hours = [6, 3, 6, 3, 6]
demand = [15000, 30000, 25000, 40000, 27000]
min_load = [850, 1250, 1500]
max_load = [2000, 1750, 4000]
base_cost = [1000, 2600, 3000]
per_mw_cost = [2, 1.3, 3]
startup_cost = [2000, 1000, 500]

Model Deployment

We create a model and the variables.

In [ ]:
 

Next we insert the constraints:

The number of active generators can't exceed the number of generators.

In [5]:
# Generator count

Total power output for a generator type depends on the number of generators of that type that are active.

In [6]:
# Respect minimum and maximum output per generator type

Total output for each time period must meet predicted demand.

In [7]:
# Meet demand

Selected generators must be able to cope with an excess of demand.

In [8]:
# Provide sufficient reserve capacity

Connect the decision variables that capture active generators with the startups.

In [9]:
# Startup constraint

Objective: minimize total cost. Cost consists of three components: the cost for running active generation units, the cost to generate power beyond the minimum for each unit, and the cost to start up generation units.

In [10]:
# Objective: minimize total cost

Next, we start the optimization and Gurobi finds the optimal solution.

In [11]:
model.write('junk.lp')
model.optimize()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-e04621004afb> in <module>
----> 1 model.write('junk.lp')
      2 model.optimize()

NameError: name 'model' is not defined

Analysis

The anticipated demand for electricity over the 24-hour time window can be met for a total cost of $\$1,002,540$. The detailed plan for each time period is as follows.

Unit Commitments

The following table shows the number of generators of each type that are active in each time period in the optimal solution:

In [ ]:
 

The following shows the number of generators of each type that must be started in each time period to achieve this plan (recall that the model assumes that 5 are available at the beginning of the time horizon):

In [ ]:
startups = pd.DataFrame(columns=range(nperiods), index=rows, data=0.0)

Task 2

Two hydroelectric generators are also available, each with a fixed power output (when on):

Hydro plant Output (MW)
A 900
B 1400

The costs associated with using a hydro plant are slightly different. There's an hourly cost, but it is much smaller than the hourly cost of a thermal generator. The real cost for a hydroelectric plant comes from depletion of the water in the reservoir, which happens at different rates for the two units. The reservoir must be replenished before the end of the time horizon by pumping water into it, which consumes electricity. A hydroelectric plant also has a startup cost.

Hydro plant Cost per hour (when on) Startup cost Reservoir depth reduction (m/hr)
A \$90 \$1500 0.31
B \$150 \$1200 0.47

Pumping water into the reservoir consumes electricity at a rate of 3000 MWh of electricity per meter of height. The height of the reservoir at the end of the time horizon must be equal to the height at the beginning.

Generators must meet predicted demand, but they must also have sufficient reserve capacity to be able to cope with the situation where actual demand exceeds predicted demand. For this model, the set of selected thermal generators plus the set of hydro generators must be able to produce as much as 115% of predicted demand.

Which generators should be committed to meet anticipated demand in order to minimize total cost?


References

H. Paul Williams, Model Building in Mathematical Programming, fifth edition.

Copyright © 2020 Gurobi Optimization, LLC

In [ ]: