OATS: Optimisation and Analysis Toolbox for power Systems

_images/logo.png

Optimisation and Analysis Toolbox for power Systems (OATS) is a high-level modelling and simulation tool for power system analysis, developed at the University of Strathclyde.

OATS is a collection of optimisation models and Python scripts for analysis and solution of a range of power system analysis problems.

OATS integrates a modelling language PYOMO for describing optimisation models. Using PYOMO’s high-level representation of sets, variables and parameters the models in OATS are written in a way that are intuitive and easy to understand and extend.

Introduction to OATS

Optimisation and Analysis Toolbox for power Systems (OATS) is a high-level modelling and simulation tool for power system analysis, developed at the University of Strathclyde. OATS is a collection of optimisation models and Python scripts for solving and analysing a range of power system analysis problems. These problems include: load flow, optimal power flow (AC, DC and security constrained) and unit commitment. OATS can be extended to solve more bespoke problems such as balancing markets, multi-period, and stochastic optimsation.

Architecture

The optimisation models in OATS are written in an algebraic modelling language (AML) called PYOMO. An algebraic modelling language provides a convenient interface between an optimisation model and a solver where the problem is eventually solved. OATS also contains a set of Python scripts that handle the flow of information between OATS, PYOMO and a solver.

_images/architecture.png

In OATS the optimisation models are written in PYOMO, the test case data is specified using a spreadsheet. OATS passes user-specified optimisation model, a test case and a set of options to PYOMO. PYOMO creates an instance (a concrete model). The concrete model is then passed onto a solver in the form of a .nl binary file. The solver returns a solution in a binary format .sol that is processed by PYOMO. OATS reads the output and write it in a spreadsheet.

The optimisation problems can be warm-started meaning that a user-specified (or output of another model) is used as an initial guess for gradient-based solvers. This feature is particularly useful for running batch simulations where the speed of convergence of a solution if important.

Citation

Waqquas Bukhsh. (2019, September 5). bukhsh/oats: OATS release (Version v1.0.1). Zenodo. http://doi.org/10.5281/zenodo.3387594.

License

OATS is distributed under the open-source license GNU GPLv3. In simple terms, this is a copyleft license that requires anyone who distributes this code or a derivative work to make the source available under the same terms.

See the license file here for more details.

Installation

OATS

OATS can be installed using pip;

pip install oatspower

The pip installation is most suited to users wishing to solve standard ‘off-the-shelf’ power flow problems without the need for full access to the OATS scripts. The ipopt solver is included in the oatspower package along with the following key dependencies:

OATS can also be installed directly from the source available here.

Installing OATS from the source offers the advantage of full access to customise the OATS scripts. This is recommended for advanced users comfortable with coding (or learning) in pyomo.

Solvers

A solver is required to solve a power systems optimisation problem in OATS. The choice of the problem depends on the type of optimisation problem. The optimisation problems can be broadly classified into the following four main categories:

  • Linear programming (LP)
  • Nonlinear programming (NLP)
  • Mixed-integer programming problem (MILP)
  • Mixed-integer nonlinear programming problem (MINLP)

The following table presents the classification of the traditional optimisation models implemented in OATS and suitable solvers that can be used to solve these problems.

Model Type Solver
DC Optimal Power Flow LP cplex, ipopt, glpk
AC Optimal Power Flow NLP ipopt
DC Security Constrained OPF LP cplex, ipopt, glpk
Unit commitment MILP cplex

NEOS

OATS allow a user to submit the problems to NEOS server. A user can specify neos=True option while calling the function and also can specify the solver to use on the NEOS server by using the option ‘solver’.

For more details on the available solvers on the NEOS server, please follow this link.

Local installation of solvers

Installation of a local solver is recommended for using OATS. This is not only computationally efficient but also allow greater control for specifying options to the solver. The following table provides several open-source and free academic license solvers that can be used with OATS.

Solver name Capability License Reference
glpk LP, MILP Open source [1]
cbc LP, MILP Open source [2]
lp_solve LP, MILP Open source [3]
ipopt LP, NLP Open source [4]
bonmin LP, NLP, MILP, MINLP Open source [5]
couen LP, NLP, MILP Open source [6]
gurobi LP, QP, MILP Free academic license [7]
CPLEX LP, QP, MILP Free academic license [8]

Installation instructions for the CPLEX solver

Academics can get free access to the IBM solver CPLEX. The following instructions will help you to download CPLEX solver directly from IBM academic initiative website:

  1. Go to the IBM academic initiative page using this link.
  2. Register an account with an academic institution-issued email address
  3. After registering and logging into your IBM academic initiative account click on Download vXY.Z under ILOG CPLEX Optimization Studio on this page. .
  4. A new window will open where you can choose a Download option suitable for your operating system (for example IBM ILOG CPLEX Optimization Studio 12.8 for Windows x86-64 Multilingual).

References

[1] “GLPK (GNU linear programming kit),” 2006. [Online]. Available: http://www.gnu.org/software/glpk

[2] J. Forrest and R. Lougee-Heimer, CBC User Guide, ch. Chapter 10, pp. 257–277. [Online]. Available: https://pubsonline.informs.org/doi/abs/10.1287/educ.1053.0020

[3] “lp solve: Documentation 5.52.5,” 2016. [Online]. Available: http://web.mit.edu/lpsolve/doc/

[4] A. WAchter and L. T. Biegler, “On the implementation of an interior-point filter line-search algorithm for large-scale nonlinear programming,” Mathematical Programming, vol. 106, pp. 25–57, 2006.

[5] “bonmin (basic open-source nonlinear mixed integer programming),” 2005. [Online]. Available: https://www.coin-or.org/Bonmin/

[6] P. Belotti, J. Lee et al., “Branching and bounds tightening techniques for non-convex MINLP,” Optimization Methods and Software, vol. 24, no. 4-5, pp. 597–634, 2009. [Online]. Available: https://projects.coinor.org/Couenne

[7] I. Gurobi Optimization, “Gurobi optimizer reference manual,” 2016. [Online]. Available: http://www.gurobi.com

[8] “IBM ILOG CPLEX Optimizer,” http://www01.ibm.com/software/integration/optimization/cplex-optimizer/, Last 2010.

Quick Start

OATS is a powerful power systems optimisation toolbox. OATS include implementation of the following steady-state analysis models:

  • DC/AC load flow problem
  • DC/AC optimal power flow problem
  • Security constrained optimal power flow problem
  • Unit commitment problem

Solving a problem in OATS

import oats
oats.dcopf()

The above command will solve a DC optimal power flow problem on a default 24-bus IEEE reliability test system. A user provide their own network by using the keyword ‘tc’, as shown in an example below.

_images/dcopf0.png
import oats
oats.dcopf(tc='mynetwork.xlsx',)

Other options allow a user to specify solver: either on NEOS server of locally on a machine. The following set of lines solves a DC optimal power flow problem using a local installation of the solver ‘cplex’.

import oats
oats.dclf(tc='mynetwork.xlsx',solver='cplex',neos=False,out=0):
_images/dcopf1.png _images/dcopf2.png

Output

A ‘results.xlsx’ file is produced after an OATS model is solved. This file in created in the directory where the oats in called. The results file has a same data format as the input test case.

_images/results.png

Models

OATS includes implementation of the following steady-state power system optimisation models:

Load flow problem

The load flow problem can be stated as: for a given power network, with known complex power loads, and a set of specifications on power generation and voltages, determine bus voltages, any unspecified generation set point and finally the complex power flow in the network components. Load flow (or power flow) problem forms the core of power system analysis. This problem is at the heart of system planning, operation, contingency analysis and the implementation of real-time monitoring systems.

Load flow analysis is commonly used for following applications:

  • Identify real and reactive power flow
  • Identify proper transformer tap settings
  • Identify transformer and circuit loadings
  • Contingency analysis

The following two tables provide information about the generator and transformers types modelled in OATS.

Generator Types in OATS
1= PV bus
2= Distributed slack bus
3= Reference bus
Transformer Types in OATS
1= 2-winding transformer
2= Tap-changing transformer

Mathematical formulation

The load flow problem in OATS is solved as a constrained OPF problem. The fixed parameters of PV, PQ and Vδ buses are modelled using hard constraints. The detailed mathematical formulation is provided in the following technical note.

Bukhsh, W. (2018). On Solving the Load Flow Problem as an Optimization Problem. Glasgow: University of Strathclyde. [Online] Available: https://pureportal.strath.ac.uk/en/publications/on-solving-the-load-flow-problem-as-an-optimization-problem

Distributed slack

The load flow problem in OATS allow a user to model a distributed slack. The user can specify the number of slack buses in a system by changing the generator type from ’1’ to ’2’.

Tap-changing transformer

OATS allow a user to determine tap setting of the transformers connecting a high voltage bus to a lower voltage bus. The tap-changing transformers can be specified using ’2’ in the type field of the transformers. The target voltage at the lower-voltage side is specified in column VM in the bus sheet. The turn ratios are determined at the high-voltage side of the transformer.

Solving DC and AC load flow problems in OATS

oats.dclf(tc='default', solver='ipopt', neos=True, out=0)

Solves DC load flow problem

ARGUMENTS:

tc (*.xlsx file) - OATS test case. See OATS data format for details

solver (str) - name of a solver. Defualt is ‘ipopt’

neos (bool) - If True, the problem is solved using NEOS otherwise using a localy install solver.

out (bool) - If True, the output is displayed on screen.

oats.aclf(tc='default', solver='ipopt', neos=True, out=0)

Solves AC load flow problem

ARGUMENTS:

tc (*.xlsx file) - OATS test case. See OATS data format for details

solver (str) - name of a solver. Defualt is ‘ipopt’

neos (bool) - If True, the problem is solved using NEOS otherwise using a localy install solver.

out (bool) - If True, the output is displayed on screen.

Optimal power flow problem

Optimal power flow problem (OPF) is a well studied optimization problem in power systems. The objective of OPF is to find a steady state operating point that minimizes the cost of electric power generation while satisfying operating constraints and meeting demand. The problem can be formulated in various ways.

The DCOPF problem is a linear optimisation problem, whereas the ACOPF problem is nonconvex and nonlinear. The ACOPF problem can be formulated using either polar or rectangular coordinates. The current release of OATS provides an implementation in the polar coordinates. The mathematical model of the ACOPF borrowed from [1] is as follows:

_images/opf.png
oats.dcopf(tc='default', solver='ipopt', neos=True, out=0)

Solves DC optimal power flow problem

ARGUMENTS:

tc (*.xlsx file) - OATS test case. See OATS data format for details

solver (str) - name of a solver. Defualt is ‘ipopt’

neos (bool) - If True, the problem is solved using NEOS otherwise using a localy install solver.

out (bool) - If True, the output is displayed on screen.

oats.acopf(tc='default', solver='ipopt', neos=True, out=0)

Solves AC optimal power flow problem

ARGUMENTS:

tc (*.xlsx file) - OATS test case. See OATS data format for details

solver (str) - name of a solver. Defualt is ‘ipopt’

neos (bool) - If True, the problem is solved using NEOS otherwise using a localy install solver.

out (bool) - If True, the output is displayed on screen.

[1] W. A. Bukhsh, A. Grothey, K. I. M. McKinnon and P. A. Trodden, “Local Solutions of the Optimal Power Flow Problem,” in IEEE Transactions on Power Systems, vol. 28, no. 4, pp. 4780-4788, Nov. 2013.(doi: 10.1109/TPWRS.2013.2274577)

Security constrained optimal power flow problem

Secure operation of a power system requires that no breach of operating standards take place following a credible contingency. This is achieved by solving a security-constrained optimal power flow. A DC version of SCOPF is implemented in OATS. A set of credible contingencies can be specified in the test case. The credible contingencies in OATS are outages of single circuits, transformers or generating units.

Mathematical formulation

The mathematical formulation of the SCOPF implemented in OATS takes the following form:

\[\begin{split}\min_{u_c,x_c: \forall c \in \{0\} \cup C} ~~f(u_0,x_0)~~~~~~~~~~~~~~~~~~\\ \text{subject to}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\\ h_c(u_c,x_c)=0,~~~~~~~~~~~~ \forall c \in \{0\} \cup C\\ g_c(u_c,x_c)\le 0,~~~~~~~~~~~~ \forall c \in \{0\} \cup C\\ |u_c-u_0|\le R_c, ~~~~~~~~~~~~~~\forall c \in C~~~~~~~~~~\end{split}\]

where \(C\) is the set of contingencies. OATS allow a user to build the set of contingencies by selecting generators, branches and transformers to be included in the contingency list. The user is referred to the data format section for information regarding selecting a contingency. The equality constraints (\(h_c\)) and inequality constraints (\(g_C\)) are imposed on the set of contingencies \(C\) and on the pre-fault operating state \(\{0\}\). The last constraint is a coupling constraint that couples pre-fault and post-fault state of operation.

SCOPF problem with pre-fault AC and post-fault DC

The traditional implementations of the SCOPF problem model the pre-fault and post-fault operation of a system using DC-model of power flow. OATS allow a user to model the pre-fault operation of a system using AC power flow (hence giving information regarding voltage and reactive power) and post-fault operation using DC equations. The mathematical formulation of such problem is given as follows.

\[\begin{split}\min_{u_c,x_c: \forall c \in \{0\} \cup C} ~~f(u_0,x_0)~~~~~~~~~~~~~~~~~~\\ \text{subject to}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\\ h^{\text{AC}}_0(u_c,x_c)=0,~~~~~~~~~~~~ c \in \{0\}\\ g^{\text{AC}}_0(u_c,x_c)\le 0,~~~~~~~~~~~~ c \in \{0\}\\ h^{\text{DC}}_c(u_c,x_c)=0,~~~~~~~~~~~~ \forall c \in C\\ g^{\text{DC}}_c(u_c,x_c)\le 0,~~~~~~~~~~~~ \forall c \in C\\ |u_c-u_0|\le R_c, ~~~~~~~~~~~\forall c \in C\end{split}\]

As noted above, the AC power flow equations are only used to model the pre-fault operation of a system. The post-fault operation of a system is modelled using DC power flow equations.

Solving SCOPF problems in OATS

oats.scopf(tc='default', solver='ipopt', neos=True, out=0)

Solves security constrained optimal power flow problem

ARGUMENTS:

tc (*.xlsx file) - OATS test case. See OATS data format for details

solver (str) - name of a solver. Defualt is ‘ipopt’

neos (bool) - If True, the problem is solved using NEOS otherwise using a localy install solver.

out (bool) - If True, the output is displayed on screen.

Unit Commitment problem

Unit commitment is the problem of determining the least cost schedule of generating units subject to power balance and network constraints. In OATS, the unit commitment problem is modelled as a mixed integer linear programming problem. The objective function is to minimise the total cost of generation over a given time horizon. The constraints in each step are of power balance, restrictions on ramp rates, zonal net transfer limits and generation limits.

A mathematical formulation of the UC problem

Several mathematical formulations of the unit commitment problem exists in literature. The current release of oats implement a formulation from the following paper:

G. Morales-España, J. M. Latorre and A. Ramos, “Tight and Compact MILP Formulation for the Thermal Unit Commitment Problem,” in IEEE Transactions on Power Systems, vol. 28, no. 4, pp. 4897-4908, Nov. 2013. doi: 10.1109/TPWRS.2013.2251373

Note that the above formulation provides several tight relaxations around minimum start-up (shut-down) times of the thermal generators. These relaxations can easily be implemented in OATS by adopting the current ‘UC.mod’ model file. In case of any issues, the user is encouraged to raise an issue via GitHub page for support.

Solving UC problems in OATS

oats.uc(tc='default', solver='cplex', neos=True, out=0)

Solves unit commitment problem

ARGUMENTS:

tc (*.xlsx file) - OATS test case. See OATS data format for details

solver (str) - name of a solver. Defualt is ‘ipopt’

neos (bool) - If True, the problem is solved using NEOS otherwise using a localy install solver.

out (bool) - If True, the output is displayed on screen.

The following table provides information about the implementation of the steady-state optimisation models in OATS. Note that the selected solver(s) column is not an exhaustive list of solvers. Also, the references column provide links to a selected set of publications where the users can find the mathematical formulation of the models implemented in OATS.

OATS ID Model Classification Selected solver(s) References
DCLF DC load flow LP cplex, glpk [1,2]
DCOPF DC optimal power flow LP cplex, gurobi [3]
SCOPF Security constrained OPF LP cplex, gurobi [4]
ACLF AC load flow NLP ipopt [2,3]
ACOPF AC optimal power flow NLP ipopt [5,6]
UC Unit commitment problem MILP cplex, bonmin [7]

[1] W. Bukhsh, On Solving the Load Flow Problem as an Optimization Problem. Tech. Report, University of Strathclyde, May 2018. [Online]. Available: https://strathprints.strath.ac.uk/64156/

[2] S. Frank and S. Rebennack, “An introduction to optimal power flow: Theory, formulation, and examples,” IIE Transactions, vol. 48, no. 12, pp. 1172–1197, 2016. [Online]. Available: https://doi.org/10.1080/0740817X.2016.1189626

[3] A. J. Wood, Power generation, operation, and control, Third edition ed., 2014.

[4] D. Phan and J. Kalagnanam, “Some efficient optimization methods for solving the security-constrained optimal power flow problem,” IEEE Transactions on Power Systems, vol. 29, no. 2, pp. 863–872, March 2014.

[5] W. Bukhsh, A. Grothey et al., “Local solutions of the optimal power flow problem,” Power Systems, IEEE Transactions on, vol. 28, no. 4, pp. 4780–4788, Nov 2013.

[6] M. B. Cain, R. P. O’Neil, and A. Castillo, “History of optimal power flow and formulations, optimal power flow paper 1,” 2012.

[7] G. Morales-Espana, J. Latorre, and A. Ramos, “Tight and compact MILP formulation for the thermal unit commitment problem,” Power Systems, IEEE Transactions on, vol. 28, no. 4, pp. 4897–4908, Nov 2013.

Data format

OATS uses a spreadsheet format for specifying network, demand and generation data.

OATS also has a test case library where a number of standard IEEE and some real-world test cases are provided. The test case library is available on the OATS GitHub page.

OATS data template

A blank template of OATS data format can be downloaded from this link.

_images/testcase.png

Description of sheets in the OATS data format

Following tables provide information about each sheet of the OATS dataformat.

The parameters required to describe a network in OATS are outlined below. Optional parameters are highlighted by (^);

bus

name bus name. string (can contain letters and/or numbers)
baseKV base voltage (kV)
zone^ zone (positive integer) [1]
VM Voltage Magnitude (p.u.)
VA Voltage angle
VNLB Normal minimum voltage magnitude (p.u.)
VNUB Normal maximum voltage magnitude (p.u.)
VELB Extreme minimum voltage magnitude (p.u.) [2]
VEUB Extreme minimum voltage magnitude (p.u.)

Notes

[1]Zone is used in unit commitment problem to define inter zonal transfer constraints
[2]Extreme values columns are provided as an option for security constrained optimal power flow when relaxed post-fault voltage bounds are desired

demand

name Demand name (string)
busname Bus name [3]
real real power demand (MW)
reactive reactive power demand (MVAr)
stat Status (1- connected, 2-disconnected)
VOLL Value of Lost Load (£/MW)

Notes

[3]Must match a bus name from the bus sheet

branch

name branch name (string)
from_busname from bus name [4]
to_busname to bus name [4]
stat Status (1-connected, 0-disconnected)
r resistance (p.u.)
x reactance (p.u.)
b total line charging susceptance (p.u.)
ShortTermRating MVA rating (short term rating), set to 0 for unlimited [5]
ContinuousRating MVA rating (continuous rating), set to 0 for unlimited
angLB minimum angle difference (degrees) [6]
angUB maximum angle difference (degrees) [6]
contingency^ 1-include in SCOPF contingencies, 0- don’t include
failure_rate^ failure rate over user specified time horizon

Notes

[4](1, 2) Must match a bus name from the bus sheet
[5]The short term rating is used in post fault calculation in SCOPF
[6](1, 2) The voltage angle difference is taken to be unbounded below if angLB < -360 and unbounded above if angUB > 360. If both parameters are zero, it is unconstrained.

transformer

name transformer name (string)
from_busname from bus name [7]
to_busname to bus name [7]
stat Status (1-connected, 0-disconnected)
type^ 1- 2-winding transformer with fixed tap ratios 2- tap-changing transformer
r resistance (p.u.)
x reactance (p.u.)
ShortTermRating MVA rating (short term rating), set to 0 for unlimited [8]
ContinuousRating MVA rating (continuous rating), set to 0 for unlimited
angLB minimum angle difference (degrees) [9]
angUB minimum angle difference (degrees) [9]
PhaseShift^ transformer phase shift angle (degrees), positive => delay
TapRatio^ Transformer turns ratio
TapLB Transformer minimum turns ratio
TapUB Transformer maximum turns ratio
contingency^ 1-include in SCOPF contingencies, 2- don’t include
failure_rate^ failure rate over user specified time horizon

Notes

[7](1, 2) Must match a bus name from the bus sheet
[8]The short term rating is used in post fault calculation in SCOPF
[9](1, 2) The voltage angle difference is taken to be unbounded below if angLB < -360 and unbounded above if angUB > 360. If both parameters are zero, it is unconstrained.

wind

The wind sheet is included to separate variable generation from fixed capacity

busname Bus name [10]
name Wind farm name
stat Status (1-connected, 0-disconnected)
PG Real power output (MW)
QG Reactive power output (MVAr)
PGLB Minimum real power output (MW)
PGUB Maximum power output (MW)
QGLB Minimum Reactive power output (MW)
QGUB Maximum reactive power output (MVAr)
VS Voltage magnitude setpoint (p.u.)
contingency^ 1-include in SCOPF contingencies, 0- don’t include
failure_rate^ failure rate over user specified time horizon

Notes

[10]Must match a bus name from the bus sheet

shunt

busname Bus name [11]
name Shunt name (string)
GL Shunt conductance (MW demanded at V = 1.0 p.u.)
BL Shunt susceptance (MVAr injected at V = 1.0 p.u.)
stat Status (1- connected, 0-disconnected)

Notes

[11]Must match a bus name from the bus sheet

zone

interconnection_ID ID for interconnector between zones
from_zone from zone [12]
to_zone to zone [12]
TransferCapacity(MW) Transfer capacity between ‘from_zone’ and ‘to_zone’

Notes

[12](1, 2) Must match a zone name from the bus sheet

generators

busname Bus name [13]
name Generator name (string)
stat Status (1-connected, 0-disconnected)
PG Real power output (MW)
QG Reactive power output (MVAr)
PGLB Minimum real power output (MW)
PGUB Maximum power output (MW)
QGLB Minimum Reactive power output (MW)
QGUB Maximum reactive power output (MVAr)
VS Voltage magnitude setpoint (p.u.)
RampDown (MW/hr)^ Ramp down rate (MW/hr) [14]
RampUp (MW/hr)^ Ramp up rate (MW/hr) [14]
MinDownTime(hr)^ Minimum down time (hr) [15]
MinupTime(hr)^ Minimum up time (hr) [15]
FuelType^ Coal, Nuke - nuclear, CCGT, OCGT, Unknown
contingency 1-include in SCOPF contingencies, 0- don’t include
startup^ Start up cost (£) [15]
shutdown^ Shut down cost (£) [15]
costc2 Quadratic cost coefficient
costc1 Linear cost coefficient
costc0 Constant cost coefficient
bid^ Bid in balancing mechanism to reduce generation [16]
offer^ Offer in balancing mechanism to increase generation [16]

Notes

[13]Must match a bus name from the bus sheet
[14](1, 2) Ramp rates required for security constrained OPF or unit commitment problems
[15](1, 2, 3, 4) Minimum up/down times, startup and shutdown costs are required in the unit commitment models
[16](1, 2) These parameters are part of the balancing market extension model that is available as an extension to OATS

storage

name Name for the storage device
zone Name of the zone
stat Status
Minoperatingcapacity(MW) Min operating capacity
capacity(MW) Total capacity of the storage
chargingrate(MW/hr) charging rate
dischargingrate(MW/hr) discharging rate
ChargingEfficieny(%) charging efficiency
DischargingEfficieny(%) discharging efficiency
InitialStoredPower(MW) Initial stored energy
FinalStoredPower(MW) Final stored energy at the end of the planning horizon

Filter Matpower2Oats

A Python script is provided that can be used to convert Matpower test-cases into equivalent OATS test-cases. This script is available on the OATS GitHub page.

Extending models in OATS

A salient feature of OATS is its ease of extending a model to define a new class of problem.

No modelling tool is capable of capturing all the extensions in constraint handling, or extension in objective function so it is important to give the user freedom to define their problems.

Knowledge of PYOMO modelling language is required to defined OATS models. The GitHub page of OATS includes a range of models that are extended for specific applications.

Adding variables

Variables in OATS are defined using Pyomo’s ‘Var’ function. For example, real power generation variable in DCOPF model of OATS is defined as follows:

model.pG = Var(model.G, domain= Reals)

The above definition of the variable name ‘pG’ states that it is variable defined on a set of generators ‘G’ and is with the domain of real numbers.

Adding parameters

Parameters in OATS are defined using Pyomo’s ‘Param’ function. The following example shows definition of a parameter:

model.PGmax = Param(model.G, within=NonNegativeReals)

The above definition of a parameter ‘PGmax’ defines a new parameter that belongs to the set of generators ‘G’ and since it is modelling the capacity of a generator it’s domain is defined as a set of non-negative real numbers. OATS will raise an error if a user tries to input a negative value for a generator capacity.

Modifying objective function

The objective function describes the main aim of the model which is either to minimise or maximise. In power systems optimisation problems often the objective function is to minimise the total cost of generation that is required to meet demand. The objective function of DCOPF and ACOPF models in OATS is written as follows:

def objective(model):
    obj = sum(model.c2[g]*(model.baseMVA*model.pG[g])**2+model.c1[g]*model.baseMVA*model.pG[g]+ model.c0[g] for g in model.G)+\
    sum(model.VOLL[d]*(1-model.alpha[d])*model.baseMVA*model.PD[d] for d in model.D)
    return obj

The first part of the objective function is to minimise the cost of generation and the second part of the objective function is to minimise the cost of load shedding. ‘c2’, ‘c1’ and ‘c0’ are the coefficients of the quadratic cost function and ‘VOLL’ represents the value of lost load. ‘g’ represents a generator in ‘model.G’ set of generators. ‘d’ represents a demand in ‘model.D’ set of demands.

The objective function in OATS can be changed by modifying the ‘obj’ variable. For example, if it is desired in the ACOPF model that the voltages deviation from 1 p.u. is penalised then that could be achieved by modifying the objective function in the following way:

def objective(model):
    obj = sum(model.c2[g]*(model.baseMVA*model.pG[g])**2+model.c1[g]*model.baseMVA*model.pG[g]+ model.c0[g] for g in model.G)+\
    sum(model.VOLL[d]*(1-model.alpha[d])*model.baseMVA*model.PD[d] for d in model.D)+\
    model.WV*sum((1-model.v[b])**2 for b in model.B)
    return obj

Note that we have added a penalty in the objective function that penalises the violation of the voltages from 1 p.u. ‘WV’ is a weighting on the voltage deviation part of the objective function. ‘b’ represents a demand in ‘model.B’ set of demands. ‘model.v[b]’ represents the voltage at bus ‘b’.

Adding/Modifying constraints

Constraints in OATS are implemented as function calls for each member of a set. For example, line limits in DCOPF are implemented as follows:

def line_lim1_def(model,l):
    return model.pL[l] <= model.SLmax[l]
def line_lim2_def(model,l):
    return model.pL[l] >= -model.SLmax[l]

The line limit constraints are applied for each member of the set of lines ‘L’. The following code snippet presents an example where the line limits are relaxed by 10%. ‘pL[l]’ represents the active power flow in line ‘l’ and ‘SLmax[l]’ represents the continuous line rating of line ‘l’.

def line_lim1_def(model,l):
    return model.pL[l] <= 1.10*model.SLmax[l]
def line_lim2_def(model,l):
    return model.pL[l] >= -1.10*model.SLmax[l]

Consider a case when the relaxation of 10% is required to be penalised in the objective function. This could be achieved by defining new variables (a variable for each line) that captures line violations up to 10% and then penalises it in the objective function.

The first step is to define new variables as follows:

model.relaxL = Var(model.L, domain= NonNegativeReals)

The line limit constraints are modified as follows:

def line_lim1_def(model,l):
    return model.pL[l] <= model.SLmax[l]+model.relaxL[l]
def line_lim2_def(model,l):
    return model.pL[l] >= model.SLmax[l]-model.relaxL[l]

The line_lim1_def constraint ensures that the active power flow ‘model.pL[l]’ through line ‘l’ is less than or equal to the continuous line rating ‘model.SLmax’ plus the relaxation variable ‘model.relaxL[l]’. The line_lim2_def constraint ensures that the active power flow ‘model.pL[l]’ through line ‘l’ is more than or equal to the continuous line rating ‘model.SLmax’ minus the relaxation variable ‘model.relaxL[l]’.

The variable ‘relaxL’ needs to be bounded so that the line violations are limited to 10%. This can be achieved using the following constraint:

def relaxL_bound(model,l):
    return model.relaxL[l] <= 0.1*model.SLmax[l]

The final step is to penalise variable ‘relaxL’ in the objective function:

The objective function now puts a cost on relaxation of the line power flow constraint, ‘WR’ is the weighting of the cost.

Solving user defined models

A user can solve a new model by called oats function ‘model’. Here is an example of solving DCOPF_BM model:

import oats
oats.model(model='DCOPF_BM')

The DCOPF_BM model is a balancing optimisation model where the objective function is to minimise the cost of redispatching generation from their set points; to balance supply and demand, and/or due to thermal and voltage constraints.

Examples

This section provides a number of examples on extending models in OATS.

Voltage Dependent Loads

The steady-state analysis models implemented in OATS have a constant power model of electricity load. The ACOPF model in OATS can be easily extended to model voltage dependent loads. In this demonstrative examples, a ZIP model of electricity load consists of constant impedance (Z), constant current (I) and constant power (P) load components and are represented by a second-order polynomial in bus voltage magnitude as follows:

\[\begin{split}\begin{align} p^{\text{D}}_d(v_d) &= \text{P}^{\text{D}}_d \left( a^\text{P}_dv_d^2+b^\text{P}_dv_d+c^\text{P}_d\right)\\ q^{\text{D}}_d(v_d) &= \text{Q}^{\text{D}}_d \left(a^\text{Q}_dv_d^2+b^\text{Q}_dv_d+c^\text{Q}_d\right) \end{align}\end{split}\]

where \(a^\text{P}_d, b^\text{P}_d, c^\text{P}_d\) are the active and reactive power coefficients of the quadratic polynomial, respectively. Parameters \(a^\text{P}_d\) represent the relative participation of constant impedance load, \(b^\text{P}_d\) the relative participation of constant load, and \(c^\text{P}_d\) the relative participation of constant power load.

The real and reactive power demand are modelled as parameters in the ACOPF model of OATS (written in PYOMO syntax) on the set of demands D, as follows:

model.PD = Param(model.D, within=Reals)
model.QD = Param(model.D, within=Reals)

In order to model the dependence of electricity demand on voltages, the real and reactive power parameters are modelled as variables pD and qD, as follows.

model.pD  = Var(model.D, within=Reals)
model.qD  = Var(model.D, within=Reals)
model.aPD = Param(model.D, within=NonNegativeReals)
model.bPD = Param(model.D, within=NonNegativeReals)
model.cPD = Param(model.D, within=NonNegativeReals)
model.aQD = Param(model.D, within=NonNegativeReals)
model.bQD = Param(model.D, within=NonNegativeReals)
model.cQD = Param(model.D, within=NonNegativeReals)

The coefficients of the quadratic function are defined as parameters given by the user. Equations (2) are implemented in the ACOPF model of OATS to model the ZIP load as follows:

def real_power_demand(model,d):
  return model.pD[d] == model.PD(model.aPD[d]*model.v[b]**2+model.bPD[d]*model.v[b]+model.cPD[d])

def reactive_power_demand(model,d):
  return model.qD[d] == model.QD(model.aQD[d]*model.v[b]**2+model.bQD[d]*model.v[b]+model.cQD[d])

The implementation of the above model is provided in the GitHub folder containing OATS models extensions.

Modelling Storage in OATS

In the current version of OATS, storage is modelled as part of the unit commitment (UC) problem.

The UC problem is a time-linked problem where the time-periods are coupled via ramp rate constraints. The following power balance equation is imposed for each time period t and for each zone z:

\[\sum_{g \in G} p^{\text{G}}_{g,t} + \sum_{s \in S} \left(p^{\text{Out}}_{s,t}-p^{\text{In}}_{s,t}\right) = \sum_{d \in D}P^{\text{D}}_{d,t}+\sum_{l \in L}p^{\text{L}}_{l,t}\]

where pIn and pOut represents the charging and discharging of energy storage, respectively. The energy storage is modelled using the following equation:

\[p^S_{s,t} =\eta^{D}_s p^{\text{Out}}_{s,t}-\frac{1}{\eta^{C}_s} p^{\text{In}}_{s,t}\]

where \(\eta^{C}_s, \eta^{D}_s\) are the charging and discharging efficiencies of the storage asset s, respectively.

For details about specifying storage data type, see the explanation of fields here. The following command will run the unit commitment model and display results for storage that has been modelled in the network data test.xlsx.

oats.uc(neos=False,solver='cplex', tc = 'test.xlsx')

Optimising Reactive Power Margin

Optimising Transformers Tap Settings