GTEP is an open source software package implemented using Python/pyomo for generation and transmission expansion planning (GTEP) in power systems. GTEP includes a mixed-integer linear programming (MILP) model that considers both the long term investment decisions and the hourly unit commitment decisions. Several algorithms including Benders decomposition, nested Benders decomposition, are implemented.
The models and algorithms of GTEP are based on Lara et al (2018), Li et al (2021), and Li et al (2021).
We are given different types of existing and known generating units and the generating units' nameplate (maximum) capacity; expected lifetime; fixed and variable operating costs; fixed and variable start-up cost; cost for extending their lifetimes; emission factor and carbon tax, if applicable; fuel price, if applicable; and operating characteristics such as ramp-up/ramp-down rates, operating limits, contribution to spinning and quick start fraction for thermal generators, and capacity factor for renewable generators. Also given are existing and candidate transmission lines between any of the two neighboring buses. The susceptance, distance, and capacity of each transmission line are known. We use DC power flow equations to calculate the power flow in each transmission line. These equations are built based on Kirchhoff's voltage and current laws.
With the above input data, the proposed GTEP model is to decide: a) when and where to install new generators, storage units and transmission lines; b) when to retire generators and storage units; c) whether or not to extend the life of the generators that reached their expected lifetime; d) unit commitment of the thermal generators during the representative days; e) power generation of the generator clusters and power flows through the transmission lines. The objective is to minimize the overall cost including operating, investment, and environmental costs (e.g., carbon tax and renewable generation quota).
CPLEX has to be installed to run the Bender algorithm. Installation instructions can be found here
The required python package can be found in requirements.txt. To install on linux, type
pip install -r requirements.txt
In order to solve with a given algorithm, run the following line of code in run.py
from gtep import *
newinstance = GTEP(repn_day_method="input", time_limit=100000, tee=True, algo="fullspace", clustering_algorithm = "kmeans", num_repn_days=15, time_horizon=5, formulation="improved")
newinstance.solve_model()
newinstance.write_gtep_results()The options can be given as arguments of GTEP.
The descriptions and default values of each option can be found in the following table.
| Argument | Default | Domain | Description |
|---|---|---|---|
| region | "ERCOT" | In(["ERCOT"]) | The region where the GTEP model is solved, currently only support ERCOT |
| time_horizon | 5 | In(list(range(1,21))) | planning horizon of the GTEP model (from 1 to 20) |
| num_repn_days | 10 | PositiveInt | The number of representative days to be used for the GTEP model |
| formulation | "improved" | In(["improved", "hull", "standard"]) | formulation for the transmission expansion |
| algo | "benders" | In(["benders", "nested_benders", "fullspace"]) | solution algorithm |
| clustering_algorithm | "kmeans" | In(["kmeans", "kmedoid", "kmeans_exact", "kmedoid_exact"]) | cluster algorithm |
| max_extreme_day | 8 | PositiveInt | max number of extreme days added |
| extreme_day_method | "load_shedding_cost" | In(["highest_cost_infeasible", "highest_cost", "load_shedding_cost", "kmedoid_exact"]) | extreme day selection method |
| repn_day_method | "input" | In(["input", "cost"]) | representative day selection method |
| print_level | 3 | In([0, 1, 2,3,4]) | print level of log |
| solver | "cplex" | In(["cplex", "gurobi", "cbc"]) | solver |
| time_limit | 36000 | PositiveFloat | Time limit (seconds, default=36000) |
| benders_mip_gap | 5e-3 | PositiveFloat | relative optimality gap for benders decomposition |
| nested_benders_iter_limit | 100 | PositiveInt | iteration limit for nested Benders |
| nested_benders_relax_integrality_forward | 1 | In([0,1]) | whether to relax integrality in the nested bender forward pass |
| nested_benders_rel_gap | 0.01 | PositiveFloat | relative optimality gap for nested Benders |
| threads | 1 | PositiveInt | number of threads |
| solver_options | bool | options passed to the solver | |
| tee | False | bool | Stream solver output to terminal. |
| write_gtep_results | True | bool | Boolean varaible whether to write gtep results to a csv file |
| logger | idaeslog.getLogger(__name__) | The logger object or name to use for reporting. |
Given is a geographical region with existing and potential generating units and transmissions lines. The problem consists in making capacity expansion decisions for both generation and transmission while considering the unit commitment and power flow constraints at the operational level.
- For the existing generators we consider: (a) coal: steam turbine (coal-st-old); (b) natural gas: boiler plants with steam turbine (ng-st-old), combustion turbine (ng-ct-old), and combined-cycle (ng-cc-old); (c) nuclear: steam turbine (nuc-st-old); (d) solar: photo-voltaic (pv-old); (e) wind: wind turbine (wind-old).
- For the potential generators we consider: (a) coal: without (coal-new) and with carbon capture (coal-ccs-new); (b) natural gas: combustion turbine (ng-ct-new), combined-cycle without (ng-cc-new) and with carbon capture (ng-cc-ccs-new); (c) nuclear: steam turbine (nuc-st-new); (d) solar: photo-voltaic (pv- new) and concentrated solar power (csp-new); (e) wind: wind turbine (wind-new).
Also known are: the generating units' nameplate (maximum) capacity; expected lifetime; fixed and variable operating costs; fixed and variable start-up cost; cost for extending their lifetimes; emission factor and carbon tax, if applicable; fuel price, if applicable; and operating characteristics such as ramp-up/ramp-down rates, operating limits, contribution to spinning and quick start fraction for thermal generators, and capacity factor for renewable generators.
For the case of existing generators, their age at the beginning of the study horizon and location are also known. For the case of potential generators, the capital cost and the maximum yearly installation of each generation technology are also given. Also given is a set of potential storage units, with specified technology (e.g., lithium ion, lead-acid, and flow batteries), capital cost, power rating, rated energy capacity, charge and discharge efficiency, and storage lifetime. Additionally, the projected load demand is given for each location.
We assume that the generators using the same type of technology are homogeneous, i.e., their design parameters are identical. For example, all the coal-st-old generators have the same parameters, which can be obtained by performing aggregation on the existing generators that use coal steam turbines. Note that although the renewable generators of the same technology have the same design parameters under our assumption, they can have different capacity factors depending on the weather conditions of the region in which they are installed.
Given are existing and candidate transmission lines between any of the two neighboring buses. The susceptance, distance, and capacity of each transmission line are known. For the existing transmission lines, we assume that they will not reach their life expectancy during the planning horizon, i.e., we do not consider the retirement of transmission lines. For the candidate transmission lines, the capital cost of each transmission line is known.
We use DC power flow equations to calculate the power flow in each transmission line. These equations are built based on Kirchhoff's voltage and current laws.
The GTEP model integrates unit commitment decisions to evaluate the hourly operation requirements. Given that the planning horizon of the GTEP problem can be as long as 10 to 30 years, solving the long-term planning problem with operating decisions in every hour of the planning horizon is intractable. Therefore, a simplification is needed to make the problem solvable, while representing the hourly fluctuations of the load and renewable profiles. We use representative days approach for time representation.

GTEP is typically performed on large scale power systems which consists of thousands of buses, such as ERCOT, SPP, PJM, MISO, etc. In most cases, it is intractable for GTEP to model each bus. To reduce the spatial complexity of the problem. The area of interest is divided into several regions that have similar climate (e.g., wind speed and solar incidence over time), and load profiles. As we describe in the generation representation subsection, all the generators using the same technology have the same parameters. On the other hand, for the renewable generators, the capacity factors are dependent on the location at which they are installed. We assume that the capacity factors of the renewable generators in the same region are the same.
We assume that all the generators and loads are located at the center of each region. Since each region is treated as one bus in the power flow model, we only consider the tielines between two neighboring regions. We assume that the two ends of each tieline are the centers of the two regions it connects. All the tielines are assumed to have the same voltage, susceptance, and capacity. An example of the proposed spatial representation approach is shown in the figure below. The ERCOT region is divided into five regions, Panhandle, Northeast, West, South, and Coast. The center of each region is specified as one of the cities in the region. The existing transmission lines are represented as solid lines while the candidate transmission lines are represented as dashed lines. Each region has generator clusters corresponding to different technologies. The aggregation of the generating units is a simplification of the problem that may yield suboptimal solution compared with modeling each generator individually. Such simplification is necessary to make the problem tractable. In order to obtain a feasible solution to the real physical system, i.e., the unit commitment decisions of each generator, one could perform a disaggregation heuristics on the aggregated solution. We will leave developing these heuristics as future work.
With the above input data, spatial and temporal representations, the proposed GTEP model is to decide: a) when and where to install new generators, storage units and transmission lines; b) when to retire generators and storage units; c) whether or not to extend the life of the generators that reached their expected lifetime; d) unit commitment of the thermal generators during the representative days; e) power generations of the generator clusters and power flows through the transmission lines. The objective is to minimize the overall cost including operating, investment, and environmental costs (e.g., carbon tax and renewable generation quota).
| Set notation | definition | Example |
|---|---|---|
| m.r | regions | ['Northeast', 'West', 'Coastal', 'South', 'Panhandle'] |
| m.i | generators | ['coal-st-old1', 'ng-ct-old', 'ng-cc-old', 'ng-st-old', 'pv-old', 'wind-old', 'wind-new', 'pv-new', 'csp-new', 'coal-igcc-new', 'coal-igcc-ccs-new', 'ng-cc-new', 'ng-cc-ccs-new', 'ng-ct-new','nuc-st-old','nuc-st-new'] |
| m.th | thermal generators | ['coal-st-old1', 'coal-igcc-new', 'coal-igcc-ccs-new','ng-ct-old', 'ng-cc-old', 'ng-st-old', 'ng-cc-new', 'ng-cc-ccs-new','ng-ct-new','nuc-st-old', 'nuc-st-new'] |
| m.rn | renewable generators | ['pv-old', 'pv-new', 'csp-new', 'wind-old', 'wind-new'] |
| m.co | coal-based generators | ['coal-st-old1', 'coal-igcc-new', 'coal-igcc-ccs-new'] |
| m.ng | natural gas (NG) generators | ['ng-ct-old', 'ng-cc-old', 'ng-st-old', 'ng-cc-new', 'ng-cc-ccs-new', 'ng-ct-new'] |
| m.nu | nuclear generators | ['nuc-st-old', 'nuc-st-new'] |
| m.pv | solar photovoltaic generators | ['pv-old', 'pv-new'] |
| m.csp | concentrated solar panels | ['csp-new'] |
| m.wi | wind turbines | ['wind-old', 'wind-new'] |
| m.old | subset of existing generators | ['coal-st-old1', 'ng-ct-old', 'ng-cc-old', 'ng-st-old', 'pv-old','wind-old','nuc-st-old'] |
| m.new | subset of potential generators | ['wind-new', 'pv-new', 'csp-new', 'coal-igcc-new','coal-igcc-ccs-new', 'ng-cc-new', 'ng-cc-ccs-new', 'ng-ct-new','nuc-st-new'] |
| m.rold | subset of existing renewable generators | ['pv-old', 'wind-old'] |
| m.rnew | subset of potential renewable generators | ['wind-new', 'pv-new', 'csp-new'] |
| m.told | subset of existing thermal generators | ['coal-st-old1', 'ng-ct-old', 'ng-cc-old', 'ng-st-old','nuc-st-old'] |
| m.tnew | subset of potential thermal generators | ['coal-igcc-new', 'coal-igcc-ccs-new', 'ng-cc-new','ng-cc-ccs-new', 'ng-ct-new','nuc-st-new'] |
| m.j | clusters of potential storage unit | ['Li_ion', 'Lead_acid', 'Flow'] |
| m.d | set of representative days | RangeSet(15) |
| m.hours | set of subperiods within the days | RangeSet(24) |
| m.t | set of time periods | RangeSet(15) |
| m.l | set of transmission lines | RangeSet(nlines) |
| m.l_old | set of existing transmission lines | |
| m.l_new | set of prospective transmission lines | |
| m.stage | set of stages in the scenario tree | RangeSet(stages) |
| Parameter notation | Definition |
|---|---|
| m.L | load demand in region r in sub-period s of representative day d of year t (MW) |
| m.n_d | weight of representative day d |
| m.L_max | peak load in year t (MW) |
| m.cf | capacity factor of renewable generation cluster i in region r at sub-period s, of representative day d of r year t (fraction of the nameplate capacity) |
| m.Qg_np | generator nameplate capacity (MW) |
| m.Ng_max | max number of generators in cluster i of region r |
| m.Qinst_UB | Yearly upper bound on installation capacity by generator type |
| m.LT | expected lifetime of generation cluster i (years) |
| m.Tremain | remaining time until the end of the time horizon at year t (years) |
| m.Ng_r | number of generators in cluster i of region r that achieved their expected lifetime |
| m.q_v | capacity value of generation cluster i (fraction of the nameplate capacity) |
| m.Pg_min | minimum operating output of a generator in cluster i ∈ ITH (fraction of the nameplate capacity) |
| m.Ru_max | maximum ramp-up rate for cluster i ∈ ITH (fraction of nameplate capacity) |
| m.Rd_max | maximum ramp-down rate for cluster i ∈ ITH (fraction of nameplate capacity) |
| m.f_start | fuel usage at startup (MMbtu/MW) |
| m.C_start | fixed startup cost for generator cluster i ($/MW) |
| m.frac_spin | maximum fraction of nameplate capacity of each generator that can contribute to spinning reserves (fraction of nameplate capacity) |
| m.frac_Qstart | maximum fraction of nameplate capacity of each generator that can contribute to quick-start reserves (fraction of nameplate capacity) |
| m.t_loss | transmission loss factor between region r and region r ̸= r (%/miles) |
| m.t_up | transmission line capacity |
| m.dist | distance between region r and region r′ ̸= r (miles) |
| m.if_ | discount factor for year t |
| m.ED | energy demand during year t (MWh) |
| m.Rmin | system's minimum reserve margin for year t (fraction of the peak load) |
| m.hr | heat rate of generator cluster i (MMBtu/MWh) |
| m.P_fuel | price of fuel for generator cluster i in year t ($/MMBtu) |
| m.EF_CO2 | full lifecycle CO2 emission factor for generator cluster i (kgCO2/MMBtu) |
| m.FOC | fixed operating cost of generator cluster i ($/MW) |
| m.VOC | variable O&M cost of generator cluster i ($/MWh) |
| m.CCm | capital cost multiplier of generator cluster i (unitless) |
| m.DIC | discounted investment cost of generator cluster i in year t ($/MW) |
| m.TIC | investment cost of tranmission line l ($) |
| m.LEC | life extension cost for generator cluster i (fraction of the investment cost of corresponding new generator) |
| m.PEN | penalty for not meeting renewable energy quota target during year t ($/MWh) |
| m.PENc | penalty for curtailment during year t ($/MWh) |
| m.tx_CO2 | carbon tax in year t ($/kg CO2) |
| m.susceptance | susceptance of transmission line l [Siemenns] |
| m.line_capacity | capacity of transmission line l (MW) |
| m.RES_min | minimum renewable energy production requirement during year t (fraction of annual energy demand) |
| m.hs | duration of sub-period s (hours) |
| m.ir | interest rate |
| m.storage_inv_cost | investment cost of storage unit of type j in year t [$/MW] |
| m.P_min_charge | min power storage charge for unit j [MW] |
| m.P_max_charge | max power storage charge for unit j [MW] |
| m.P_min_discharge | min power storage discharge for unit j [MW] |
| m.P_max_discharge | max power storage discharge for unit j [MW] |
| m.min_storage_cap | min storage capacity for unit j [MWh] |
| m.max_storage_cap | max storage capacity for unit j [MWh] |
| m.eff_rate_charge | efficiency rate to charge energy in storage unit j |
| m.eff_rate_discharge | efficiency rate to discharge energy in storage unit j |
| m.storage_lifetime | storage lifetime (years) |
| Variable notation | definition |
|---|---|
| b.P | power output of generation cluster i in region r during sub-period s of representative day d of year t (MW) |
| b.cu | curtailment slack generation in region r during sub-period s of representative day d of year t (MW) |
| b.RES_def | decit from renewable energy quota target during year t (MWh) |
| b.P_flow | power transfer from region r to region r̸=r during sub-period s of representative day d of year t (MW) |
| b.d_P_flow_plus | nonnegative variable, power flow from the sending end of transmission line l, s(l), to the receiving end of line l, r(l) during sub-period s of representative day d of year t (MW) |
| b.d_P_flow_minus | nonnegative variable, power flow from the receiving end of transmission line l, r(l), to the sending end of line l, s(l) during sub-period s of representative day d of year t (MW) |
| b.Q_spin | spinning reserve capacity of generation cluster i in region r during sub-period s of representative day d of year t (MW) |
| b.Q_Qstart | quick-start capacity reserve of generation cluster i in region r during sub-period s of representative day d of year t (MW) |
| b.ngr_rn | number of generators that retire in cluster i ∈ IRN of region r in year t (continuous relaxation) |
| b.nge_rn | number of generators that had their life extended in cluster i ∈ IRN of region r in year t (continuous relaxation) |
| b.ngb_rn | number of generators that are built in cluster i ∈ IRN of region r in year t (continuous relaxation) |
| b.ngo_rn | number of generators that are operational in cluster i ∈ IRN of region r in year t (continuous r relaxation) |
| b.ngr_th | number of generators that retire in cluster i ∈ ITH of region r in year t (integer variable) |
| b.nge_th | number of generators that had their life extended in cluster i ∈ ITH of region r in year t (integer r variable) |
| b.ngb_th | number of generators that are built in cluster i ∈ ITH of region r in year t (integer variable) r |
| b.ngo_th | number of generators that are operational in cluster i ∈ ITH of region r in year t (integer variable) |
| b.u | number of thermal generators ON in cluster i ∈ Ir of region r during sub-period s of representative day d of year t (integer variable) |
| b.su | number of generators starting up in cluster i during sub-period s of representative day d in year t (integer variable) |
| b.sd | number of generators shutting down in cluster i during sub-period s of representative day d in year t (integer variable) |
| b.p_charged | power charged into storage in region r, day d, hour h, year t [MW] |
| b.p_discharged | power discharged into storage in region r, day d, hour h, year t [MW] |
| b.p_storage_level | ending state of charge of storage in region r, day d, hour h, year t [MWh] |
| b.p_storage_level_end_hour | ending state of charge of storage in region r, day d, hour h, year t [MWh] |
| b.nsb | Number of storage units of type j installed in region r, year t (relaxed to continuous) |
| b.nso | Number of storage units of type j operational in region r, year t (relaxed to continuous) |
| b.nsr | Number of storage units of type j retired in region r, year t (relaxed to continuous) |
| b.ntb | Whether new transmission line l is built in time period t |
| b.nte | whether transmission line l exist in time period t |
| b.theta | voltage angle at region r during sub-period s of representative day d of year t |
| b.d_theta_plus | nonnegative variable, angle difference between the angles at sending end and receiving end of transmission line l during sub-period s of representative day d of year t (MW) |
| b.d_theta_minus | nonnegative variable, angle difference between the angles at receiving end and sending end of transmission line l during sub-period s of representative day d of year t (MW) |
| b.d_theta_1 | disaggregated variable in the hull formulation, angle difference between the angles at sending end and receiving end of transmission line l during sub-period s of representative day d of year t (MW) if the transmission line l exists in year t |
| b.d_theta_2 | disaggregated variable in the hull formulation, angle difference between the angles at sending end and receiving end of transmission line l during sub-period s of representative day d of year t (MW) if the transmission line l does not exist in year t |