acud¶
acud is a lightweight capacity expansion, economic dispatch and unit commitment simulation tool written in Python, which uses csv and Excel files as input and output data format. It is an optimisation-based calculation engine that leverages multiple state-of-art data handling Python packages including pandas and xarray, powered by open source (e.g. glpk, cbc) or commercial (e.g. cplex, gurobi) solvers.
User guide¶
Overview¶
The optimisations underlying the acud simulations are defined as a Linear Programming (LP) or Mixed-Integer Linear Programming (MIP) problem, depending on the desired level of accuracy and complexity. acud is able to handle multiple time resolutions, producing both chronological and load duration curve-based results.
Features¶
- Capacity expansion
- Minimum and maximum power for each unit
- Generation unit derating
- Power plant ramping limits
- Minimum up/down times
- Curtailment
- Detailed hydro modelling, including hydro cascades
- Pumped storage
- Non-dispatchable units (e.g. wind, solar, run-of-river, etc.)
- Start-up, ramping and no-load costs
- Net transfer capacity based network modelling
- Constraints on the targets for renewables and/or CO2 emissions
Output¶
- Timing, location and type of new capacity built
- Nodal energy prices
- Scheduled generation
- Generating unit starts and stops
- Fuel consumption
- Emissions
- Interconnector flows
- Storage volumes, water releases and spillages
- Pumped energy
- Unserved energy
Formulation¶
A partial formulation of the chronological MT stage mathematical optimization problem can be found below.
Installation¶
We strongly recommend using a dedicated conda environment to install acud.
Install the package with pip:
$ pip install git+[acud git repository url here]
Input preparation¶
The acud simulation input data is specified through a set of text files which can be grouped as follows:
- configuration yaml files
- content csv files
Configuration yaml files¶
Referred to in short as yml files, these are two YAML-format files:
- run configuration yml file, and
- model configuration yml file
which jointly define the model outline.
The model yml file specifies the more “structural” data whereas the run yml file contains information related to the analysis to be performed (e.g. which solver to use or the time horizon to be considered). The split of data between run and model configuration data is somewhat arbitrary, the purpose of this split being to ease the reuse of information contained in the model configuration file. In this sense, there is a certain hierarchy between the two config files, with the run file at the top level. Indeed, the run yml file can be thought of as the trigger file: it is the only file that needs to be directly specified when invoking an acud command (the model configuration file is invoked internally through the acud code using the model entry of the run configuration file).
The yml files themselves do store some of the values applied in the acud simulation, e.g. discount rate or VOLL, but most of their content is made up of references to other files (mostly csv files) where the data is actually stored.
yml files store nested mappings of key-value pairs, where values can be either single values, lists of values or further key-value pairs. Mappings are nested through indentation, e.g.
timeseries:
generator:
derating:
format: ymdp
files:
COAL: input/derating_COAL.csv
In the example above the key-value pair COAL: input/derating_COAL.csv is a value to the files key which in turn together with the format key-value pair is a value to the derating key, and so on.
IMPORTANT: use space NOT tab for indentation to ensure correct yaml file parsing.
In these notes we refer to the most inner entry of nesting mappings using a “flattened” dot-based notation, e.g. COAL files entry in the example above would be represented like this
timeseries.generator.derating.files.COAL: input/derating_COAL.csv
Within a given map nesting level, the order in which the entries are written in the configuration files is not relevant but it is probably best to follow a certain convention about it.
Below we provide a commented version of the run configuration file. As YAML allows comments (after #), the text below is valid config file content.
name: basecase_run # run name, can be different from model name
model: model.yml # name of (and path to) file with model configuration data
default: default.yml # name of (and path to) file with parameter default values
time:
startperiod: 2012-03-01 00:00 # use this datetime format
endperiod: 2012-03-31 23:00 # last period included in modelling horizon
stepsize: 24 # number of hours in optimization step
blocks: 3 # placeholder, currently not in use
output:
format: csv # only format currently supported
path: solution # results destination, will be created if it doesn't exist
drypath: dry # dry run output destination, will be created if it doesn't exist
settings:
mode: quantity # placeholder, currently not in use
phase: MT # LT, MT or ST
solver: glpk # CBC or glpk
cat: Integer # Linear or Integer solution for integer variables
Similarly, a commented version of a sample model configuration file follows.
name: basecase # model name
components:
bus:
file: input/buses.csv
referencenode: GB # if no bus specified for generators, assume they are connected to this bus
branch:
file: input/branches.csv
generator:
file: input/gens.csv
fuel: # can be empty, but needs to be included for the fuel timeseries input specified below to be processed
timeseries: # this information further qualifies the component instances created based on the components entries above
generator:
derating: # this entry could also be a time invariant parameter, in which case there would be no need for a timeseries entry
format: ymdp
files: # as the shape is ymdp, each file contains information referring to a single component instance
COAL: input/derating_COAL.csv
OCGT: input/derating_OCGT.csv
CCGT: input/derating_CCGT.csv
OIL: input/derating_OIL.csv
NUCLEAR: input/derating_NUCLEAR.csv
OTHER: input/derating_OTHER.csv
WIND: input/derating_WIND.csv
PS: input/derating_PS.csv
units:
format: dtname
datetimeformat: '%d/%m/%Y' # as in input data file, the internal format is different
files: # can be a list of multiple files which will overwrite the configuration derived from the component table entries
- input/units_WIND.csv
fuel:
price:
format: dtname
datetimeformat: '%d/%m/%Y'
files:
- input/fuels.csv
bus:
load:
format: ymdp
files:
ES: input/load.csv
scalars: # these are values that are not indexed neither by datetime nor by component instance name
discountrate: 0
voll: 5000
pricedumpenergy: 5000
loadescalator: 1
branchescalator: 1
yaml templates¶
Configuration yaml files are a key ingredient of an acud input dataset. They contain a number of fields grouped by sections and subsections, and can be easily created and updated using the simplest of text editors. However, some complication arise when dealing with configuration files:
- they must abide to the [YAML file format](http://yaml.org/) e.g. regarding indentation
- they involve a long and nested list of required and optional fields.
YAML file templates tackle these two complications. They are well formatted (i.e correct indentation and markup) and contain placeholders for all available fields -whether optional or required- with descriptive comments attached.
Let RUN_CONFIG be an existing yaml file at the case folder location where you want to create new yaml files (note that for the purpose of automatically creating a template-based yaml file, RUN_CONFIG does not need to be a properly built acud run configuration file).
To create a draft run config file from an acud template, use the following command:
ad dry RUN_CONFIG --run
Similarly, for a model or a default file:
ad dry RUN_CONFIG --model
ad dry RUN_CONFIG --default
You can also create multiple templates simultaneously:
ad dry RUN_CONFIG --run --model --default
ad dry RUN_CONFIG --run --model
ad dry RUN_CONFIG --run --default
and so on.
This command will create a file called, respectively, run.yml, model.yml and default.yml at the location where RUN_CONFIG is stored. If there is already a file called run.yml, model.yml or default.yml at the destination folder it will not be overwritten. Instead, the template-based yaml files will be renamed as run(1).yml, run(2).yml and so on. Extracts of the run, model and default templates look, respectively, like this:
# RUN CONFIGURATION
name: <run name>
model: <model yaml file> # Relative path to model configuration yaml file
#default: <default yaml file> # Relative path to user-defined default yaml file that overrides built-in defaults
time:
startperiod: <YYYY-MM-DD hh:mm> # Starting hour of simulation horizon
endperiod: <YYYY-MM-DD hh:mm> # Last hour of simulation horizon
# stepsize: [int] # Number of hours in optimization step
# blocks: [int] # Number of blocks applied in load duration curve approximation
# snapshots:
# file: <snapshots csv filename> # Full filename to snapshots specification
# datetimeformat: <Python datetime format> # Pattern used when parsing datetime field, see http://strftime.org/ for syntax reference
output:
path: <solution folder> # will be created if it doesn't exist
drypath: <dry run output folder> # will be created if it doesn't exist
xtrapath: <extrapolated solution folder> # will be created if it doesn't exist
# format: [csv] # File format of reported solution
# scenario: [scenario name] # Label for data handling
# out_lp: [0 or 1] # Switch to output text file with problem formulation in CPLEX LP format
# out_mps: [0 or 1] # Switch to output text file with problem formulation in MPS format
# MODEL CONFIGURATION
name: <model name>
components:
bus:
file: <filepath> # Table file location
referencenode: <string> # System wide energy price is set to nodal price at bus reference
generator:
file: <filepath> # Table file location
datetimeformat: <Python datetime format> # Pattern used when parsing date from and date to field, see http://strftime.org/ for syntax reference
# branch:
# file: <filepath> # Table file location
#
# fuel:
# file: <filepath> # Table file location
scalars:
# discountrate: [float] # Yearly rate to discount cash flows in objective function of capacity expansion problem
# thermalfirm: [0 <= float <= 1] # Firmness factor of thermal generating units in capacity expansion problem
# SOLVE OPTIONS
solve:
mode: quantity # price, quantity
phase: MT # LT, MT
solver: coin # coin, glpk, xpress, gurobi
cat: Integer # Integer, Binary or Continuous
scenario: Base
allow_use: 1 # allow unserved energy
allow_dump: 1 # allow dump energy
include_ramps: 1 # consider max ramp up limits
include_msl: 1 # consider min stable level
include_no_load_costs: 1 # consider no load costs
include_start_costs: 1 # consider start costs
epgap: 0.0001 # mipgap tolerance termination
sec: 7200
# TIME OPTIONS
time:
stepsize: 24
blocks: 3
# OUTPUT OPTIONS
output:
verbose: 0 # amount of progress info printed
out_csv: 1 # write csv files
Composing the yaml file is then just a matter of editing the placeholders in the template and saving changes. Note that only the default.yml is ready to use as provided; in this case the file does not include placeholders but rather built-in default values. The run.yml and model.yml need further editing by replacing the placeholder included in the template following the field code described below:
- <item> denotes that user-defined input is required, i.e. acud provides no default value for this entry.
- [item] denotes that a default value is available for this entry, i.e. if you do not provide a value for this entry then acud will apply a default value during the simulation.
- Commented out entries are optional entries; when uncommented during the template modification, these entries need to be further edited by replacing <item> or [item] placeholders with the appropriate value.
Content csv files¶
Content files are a variable number of csv files containing the bulk of the input data. There are two types of csv files:
- table files
- time series files
Non-data rows can also be included in csv files, regardless of their type. Rows starting with a # character will be ignored by the acud computations.
IMPORTANT: the acud code is case sensitive so upper and lower cases of component instance and parameter names need to match.
Table files¶
Table files lists the instances of the different components included in the model. There should be one table file per component type contained in the model. The first columns shows the name of the instance, the rest of the columns store various parameters, which will vary depending on the component type.
Component instance parameters can be either numerical, denoting measures of quantifiable metrics, or categorical, representing relationships. To illustrate, generators have numerical parameters such as heat rate or max capacity, and categorical parameters such as bus (to which it connects) or fuel (burned).
When acud reads the input data it starts with the table files. Reading through these files it creates the different component instances that comprise the model, populating their parameters either with provided or default values.
acud input processing then moves on to time series files which further qualify the information provided through the table files.
Time series files¶
Time series files come in two (for now) shapes:
- dtname
- ymdp
You need to specify the shape of the time series files through the format entry found in the model configuration yml file, e.g. like this:
bus.load.format: ymdp
or
fuel.price.format: dtname
In csv files with dtname shape the first column contains datetime values and the header for this column is “datetime”. The rest of the columns to the right store parameter values, with each column containing the values of a single component instance. The names of these component instance are stored as headers of the value columns. To avoid faulty datetime parsing it is best to explicitly specify the datetime format through the entry:
timeseries.<component type>.<parameter>.datetimeformat
csv files with ymdp shape store year, month and day values in the left columns. Each of the remaining columns contain the parameter values, with each column storing values for the same period (of different days). Periods are shown as column headers. csv files with ymdp shape do not include any component instance name information, which means that each csv files contains timeseries data corresponding to a single component instance.
In principle most if not all parameters can be made to hold time series. However the mathematical optimisation problem formulation assumes that only a given subset of parameters are time dependent, with all other parameters being time invariant.
The time dependent parameters in the optimization problem formulation are as follows.
For generators:
- max capacity
- max build
- cincr (incremental costs)
- units
- derating
- bid
- bid escalator
For buses:
- load
For fuels:
- price
All other parameters not listed above will be handled as time invariant in the optimization problem formulation. When a time series is specified in the simulation input data for a time invariant parameter, the value of the time series at the start of the modelling horizon will be assigned to such parameter.
Input validation¶
acud input data validation functionality runs two types of input data checks:
- yaml (files) validation
- csv (files) validation
yaml validation covers both run and model configuration files and runs checks such as:
- Can the run and model configuration yaml files be found?
- Do the configuration yaml files include all required fields
- Are field values provided of the right type and within allowed values?
csv validation performs the following checks on input csv files:
- Structural checks - ensure that there are no empty rows, no blank headers, etc.
- Content checks - ensure that the values have the correct types (“string”, “number”, etc.), that their values are allowed (“datetime format must be either dtname or ymdp”), and that they respect the constraints (“forced outage must be a number greater than 0”).
Basic usage¶
From the command line, change the current directory to the case folder you want to inspect:
cd my_case_folder
Validate yaml configuration files only:
ad validate RUN
where RUN stands for the name of the run configuration yaml file (including the file extension, e.g. run_base_case.yml).
Run the yaml validation and display the name of the configuration files that were inspected:
ad validate RUN --verbose
Run both yaml and csv validations:
ad validate RUN --all
or just:
ad validate RUN -a
Again, display the names of the inspected input data files:
ad validate RUN --all --verbose
Built-in schema files contain the input data validation rules applied for both yaml and csv files, e.g. whether a field is required or not, a field´s name, type, allowed values, etc.
List the built-in schema files:
ad schema -l ACME
ACME above stands for just any string (but you do need to provide one).
Display a built-in schema specification, e.g. for generators:
ad schema generator
If you find the schema difficult to read on screen you can write it to a file for easier inspection like this: ad schema generator > check_schema.txt
This will write a text file named check_schema.txt into your current directory.
List all available acud commands and a brief description of each one of them:
ad --help
Get help about the new validation commands:
ad validate --help
or:
ad schema --help
Important usage notes¶
Datetime formats¶
run yaml configuration files includes fields startperiod and endperiod expecting datetime values. There is only one datetime format allowed to specify these fields in the run configuration yaml file:
%Y-%m-%d %H:%M
This is a slightly modified version of the ISO8601 standard datetime format: we drop the seconds, the time zone and replace the ‘T’ character separating date and time with a blank space. This means that in the run configuration yaml file January, 2, 2018 at 11pm looks like this:
2018-01-02 23:00
On the other hand, multiple datetime formats are allowed in the timeseries csv files. These formats need to be specified by the user in the corresponding timeseries datetimeformat field included in the model configuration yaml file.
Datetime column position¶
Timeseries csv files with dtname format MUST include the datetime field in the leftmost column.
Implementation¶
Most of the heavylifting of the acud input data validation is performed by two mature and well maintained third-party Python packages, namely Cerberus and goodtables-py. Cerberus is a lightweight, extensible data validation library for Python. goodtables-py is a Python framework to validate tabular data.
More information about these packages can be found at http://docs.python-cerberus.org/en/stable/ and https://github.com/frictionlessdata/goodtables-py, respectively. For additional information on table schemas also check https://frictionlessdata.io/specs/table-schema.
Simulation timeline¶
A typical acud simulation timeline is a sequence of contiguous hours between the start and the end simulation datetimes, both included. For sizeable models with an extended timeline, this can lead to very long runtimes (hours) and massive hardrive memory consumption. A workaround for this is to run acud simulations with a snapshots-based timeline.
Snapshots-based simulation timeline¶
When running a simulation through a snapshots-based timeline, , you can specify a set of (non-contiguous) datetimes at which the optimization should be run. If required, these snapshots-based simulation results can then be extrapolated, assigning the nearest hourly results to non-computed datetimes (e.g. the extrapolated result of a non-computed datetime happening at 7a.m. will be the last computed result at 7 a.m.).
Snapshots are specified by:
- Listing snapshots in a csv file with a single field called datetime, and
- Referencing this csv file in a
time.snapshots.file
entry in the run configuration yml file.
Note that you also need to provide the date format in the time.snapshots.datetimeformat entry to ensure that the snapshot dates and times are correctly interpreted by acud. An extract of the time section of a run yml file including snapshots-based timeline specification is shown below.
time:
startperiod: 2015-01-01 00:00
endperiod: 2018-12-31 23:00
stepsize: 24
blocks: 3
snapshots:
file: csv/snapshots.csv
datetimeformat: '%d/%m/%Y'
To further illustrate, these are the first lines of an example snapshots csv file. Note that the dates are non-contiguous.
datetime
01/01/2018
03/01/2018
10/01/2018
20/01/2018
Snapshots override start and end datetime specifications. If no snapshots specification is provided in the run config yml file, the simulation timeline will consist of the sequence of contiguous hours between the start and the end datetime, both included.
After completing a snapshots-based simulation, you can extrapolate the sparse timeline results
to obtain a dense timeline solution using the xtra
command, e.g. like this:
ad xtra run.yml
Command reference¶
The ad
command is the primary interface for managing
acud simulations.
ACUD(1) User Commands ACUD(1) Usage: ad [OPTIONS] COMMAND [ARGS]... acud: capacity expansion, unit commitment and dispatch simulation engine Options: --version Display version. --help Show this message and exit. Commands: dry Dry run model. run Run model simulation. schema Display input data schemas. validate Validate input data. xtra Extrapolate solution.
acud provides several commands for data handling and execution of power market simulations.
The links on this page provide help for each command.
You can also access help from the command line with the
--help
flag:
ad run --help
TIP: You can abbreviate many frequently used command options that
are preceded by 2 dashes (--
) to just 1 dash and the first
letter of the option. So --list
and -n
are the same.
Execution commands¶
Execution of acud simulations is managed through the following commands:
ad run¶
ACUD(1) User Commands ACUD(1) Usage: ad run [OPTIONS] RUN_CONFIG Execute the given RUN_CONFIG run configuration file. Options: --no-xtra Skip solution extrapolation. --debug Print debug information when encountering errors. --pdb If used together with --debug, drop into interactive debugger on encountering errors. --profile Run through cProfile. --profile_filename TEXT Filename to save profile to if enabled --profile. --help Show this message and exit.
ad xtra¶
ACUD(1) User Commands ACUD(1) Usage: ad xtra [OPTIONS] RUN_CONFIG Post-process solution to extrapolate results as required. Options: --debug Print debug information when encountering errors. --pdb If used together with --debug, drop into interactive debugger on encountering errors. --profile Run through cProfile. --profile_filename TEXT Filename to save profile to if enabled --profile. --help Show this message and exit.
Data commands¶
acud input data handling commands include:
ad dry¶
ACUD(1) User Commands ACUD(1) Usage: ad dry [OPTIONS] RUN_CONFIG Dry run the given RUN_CONFIG run configuration file. Options: --default Copy built-in default file into current directory. --run Copy run template file into current directory. --model Copy model template file into current directory. --help Show this message and exit.
ad schema¶
ACUD(1) User Commands ACUD(1) Usage: ad schema [OPTIONS] SCHEMAS Display input data schema. SCHEMAS is the name of the schema to be displayed, e.g. ad schema generator To list the available schemas, pass the -l flag followed by any string as SCHEMAS (it does not need to be a valid schema name) like this: ad schema -l acme Options: -l Display list of available schemas. --help Show this message and exit.
ad validate¶
ACUD(1) User Commands ACUD(1) Usage: ad validate [OPTIONS] RUN Validate the given run and model configuration files. Options: -a, --all Run complete validation, including csv files. --verbose Display verbose output. --debug Print debug information when encountering errors. --pdb If used together with --debug, drop into interactive debugger on encountering errors. --profile Run through cProfile. --profile_filename TEXT Filename to save profile to if enabled --profile. --help Show this message and exit.
Developer guide¶
Unit testing¶
The acud developer distribution includes basic pytest-based unit testing. To run these unit tests you first need to install pytest either via conda:
conda install pytest
or pip:
pip install pytest
Once pytest is installed, set the test folder as current directory:
cd test
To run all available pytest unit test:
py.test -v
or
python -m pytest -v
To run a specific unit test:
py.test test_api.py -v
or
python -m pytest test_cli.py -v
Note that passing the validate test included in the unit test suite means that the validation process completed successfully, not that the validation tests passed. To review the validation test results, run the validate command separately through the command line or via the acud Python api.
License¶
acud is released under the MIT license with the following terms:
Copyright (c) 2014-2018, Guillermo Lozano Branger. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Dependencies¶
versioneer.py is Public Domain.