The decarbonisation of energy systems is one of the main challenges of our century. Finding the optimal technological mix to achieve that goal is a major concern for policy and decision makers alike. These problems are known as energy system planning and sizing and are often tackled by Mixed Integer Linear Programming (MILP). In order to solve them, one first has to encode the problem using a modeling environment. The modeling tool reads the problem and converts the information into an equivalent intermediate representation understandable by a solver. The solver then takes the intermediate representation as input, solves it and returns a solution.

In previous work (Berger et al.) we highlighted the fact that energy system planning and sizing problems very often possess a time dimension and a natural block decomposable structure where, for example, each technology can be seen as a block. Exploiting this structure has several advantages, including simplifying model encoding, enabling model re-use and facilitating the use of structure-exploiting solution algorithms, among others. Although a couple of solvers can take advantage of such structure, comparatively few modelling environments can handle and exploit it consistently from problem encoding to problem solving. This effectively limits the ability of practitioners to do so. In short, the modeler needed to possess the following attributes,

- be
, in order to guarantee an easy access to everyone and promote transparency,**open-source** - be
, to ensure an easy deployment,**stand-alone** - support the encoding of
,**any MILP** - allow
to be exposed and exploited,*any hierarchical block structure* - facilitate the encoding and construction of
**time-indexed models,** - make it easy to
and**re-use**components and models,**combine** - and, interfacing with
and**commercial**, including structure-exploiting ones**open-source solvers**

Based on these specifications, we developed a new modeling language and associated tool called the Graph-Based Optimization Modeling Language (GBOML). GBOML implements a hierarchical hypergraph abstraction of optimization problems. It provides language constructs to represent such hierarchical structure and facilitate the encoding of time-indexed models. More precisely, structured MILPs are encoded as * Graphs* made-up of

*and*

**nodes***where each*

**hyperedges***can itself be composed of*

**node***and*

**sub-nodes***. Each*

**sub-hyperedges***has its own*

**node***,*

**parameters***,*

**variables***and*

**constraints***. Each*

**objectives***has its own set*

**hyperedge***and*

**parameters***that link several*

**constraints***from different*

**variables***. The language combines the expressiveness of algebraic modeling languages making the expression of any mixed integer linear problem possible, with features of object-oriented modeling in order to facilitate problem formulation and model re-use.*

**nodes**The GBOML parser, developed in Python, is open-source (MIT licence) and depends solely on Numpy, Scipy and PLY (three very stable libraries). It turns GBOML input files into hierarchical graph data structures representing optimization models. The GBOML parser takes advantage of the structure by using it to speed up model generation, expose problem structure to specialised solvers and simplify post-processing. The associated tool provides both a command-line interface and a Python API. It interfaces with a variety of open-source and commercial solvers, including structure-exploiting ones. GBOML has recently been published in the Journal of Open Source Software.

## Example

To illustrate how problems are encoded in GBOML, we consider the problem of finding the optimal capacity of solar panels and battery storage to install in order to satisfy a known electricity demand profile for every hour of the year. In this toy example, we have two nodes, the solar panels and a battery, and one hyperedge, the power balance. The problem can be encoded in GBOML as,

#TIMEHORIZON

T = 8760; // planning horizon (hours)#NODE SOLAR_PV

#PARAMETERS

capex = 600; // annualised capital expenditure per unit capacity

capacity_factor = import « pv_gen.csv »; // normalised generation profile

#VARIABLES

internal: capacity; // capacity of solar PV plant

external: power[T]; // power output of solar PV plant

#CONSTRAINTS

capacity >= 0;

power[t] >= 0;

power[t] <= capacity_factor[t] * capacity;

#OBJECTIVES

min: capex * capacity;#NODE BATTERY

#PARAMETERS

capex = 150; // annualised capital expenditure per unit capacity

#VARIABLES

internal: capacity; // energy capacity of battery storage system

internal: energy[T]; // energy stored in battery storage system

external: power[T]; // power flow in/out of battery storage system

#CONSTRAINTS

capacity >= 0;

energy[t] >= 0;

energy[t] <= capacity;

energy[t+1] == energy[t] + power[t];

#OBJECTIVES

min: capex * capacity;#HYPEREDGE POWER_BALANCE

#PARAMETERS

electrical_load = import « electrical_load.csv »;

#CONSTRAINTS

SOLAR_PV.power[t] == electrical_load[t] + BATTERY.power[t];

You can try this example on google colab.

## Leave A Comment