National Scale Example Model¶
This example consists of two possible power supply technologies, a power demand at two nodes, the possibility for battery storage at one of the nodes, and a transmission technology linking the two.
The diagram below gives an overview:
We distinguish between model configuration (the options provided to Calliope to do its work) and the model definition (your representation of a physical system in YAML).
Model configuration¶
The model configuration file model.yaml
is the place to tell Calliope about how to interpret the model definition and how to build and solve your model.
It does not contain much data, but the scaffolding with which to construct and run your model.
config:
init:
name: National-scale example model
# What version of Calliope this model is intended for
calliope_version: 0.7.0
time_subset: ["2005-01-01", "2005-01-05"] # Subset of timesteps
broadcast_param_data: true # allow single indexed parameter data entries to be broadcast across all index items, if there are multiple entries.
build:
ensure_feasibility: true # Switches on the "unmet demand" constraint
mode: plan # Choices: plan, operate
solve:
solver: cbc
zero_threshold: 1e-10 # Any value coming out of the backend that is smaller than this (due to floating point errors, probably) will be set to zero
Model definition¶
Referencing tabular data¶
As of Calliope v0.7.0 it is possible to load tabular data completely separately from the YAML model definition.
To do this we reference data tables under the data_tables
key:
data_tables:
time_varying_parameters:
data: data_tables/time_varying_params.csv
rows: timesteps
columns: [comment, nodes, techs, parameters]
drop: comment
cost_parameters:
data: data_tables/costs.csv
rows: techs
columns: [parameters, comment]
drop: comment
add_dims:
costs: monetary
In the Calliope national scale example model, we load both timeseries and cost data from file. As an example, the data in the cost CSV file looks like this:
parameters | cost_flow_cap | cost_storage_cap | cost_area_use | cost_source_cap | cost_flow_in | cost_flow_out |
---|---|---|---|---|---|---|
comment | USD per kW | USD per kWh storage capacity | USD per m2 | USD per kW | USD per kWh | USD per kWh |
ccgt | 750.000000 | nan | nan | nan | 0.020000 | nan |
csp | 1000.000000 | 50.000000 | 200.000000 | 200.000000 | nan | 0.002000 |
You'll notice that in each row there is reference to a technology, and in each column to a cost parameter and a comment on the units being used.
Therefore, we reference techs
in our data table rows, and parameters
and comment
in our data table columns.
The comment
information is metadata that we don't need in our Calliope model object, so we drop it on loading the table.
Since all the data refers to the one cost class monetary
, we don't add that information in the CSV file, but instead add it on as a dimension when loading the file.
Where there is no data for that combination of technology and cost parameter, the value is Not-a-Number (NaN) and this combination will be ignored on loading the table.
Info
You can read more about loading data from file in our dedicated tutorial.
Indexed parameters¶
Before we dive into the technologies and nodes in the model, we have defined some parameters that are independent of both of these:
parameters:
objective_cost_weights:
data: 1
index: monetary
dims: costs
# `bigM` sets the scale of unmet demand, which cannot be too high, otherwise the optimisation will not converge
bigM: 1e6
cost_interest_rate:
data: 0.10
index: monetary
dims: costs
Neither of these parameters is strictly necessary to define.
They have defaults assigned to them (see the model definition schema in the reference
section of the documentation).
However, we have included them in here as examples.
objective_cost_weights
can be used to weight different cost classes in the objective function
(e.g., if we had co2_emissions
as well as monetary
costs).
bigM
(see "Big M method" on Wikipedia) is used to formulate certain types of constraints and should be a large number,
but not so large that it causes numerical trouble.
bigM
is dimensionless, while objective_cost_weights
is indexed over the costs
dimension.
You will see this same parameter
definition structure elsewhere in the model definition as we index certain parameters over other dimensions.
Supply technologies¶
The example model defines two power supply technologies.
The first is ccgt
(combined-cycle gas turbine), which serves as an example of a simple technology with an infinite source.
Its only constraints are the cost of built capacity (flow_cap
) and a constraint on its maximum built capacity.
The definition of this technology in the example model's configuration looks as follows
ccgt:
name: "Combined cycle gas turbine"
color: "#E37A72"
base_tech: supply
carrier_out: power
flow_out_eff: 0.5
flow_cap_max: 40000 # kW
flow_cap_max_systemwide: 100000 # kW
flow_ramping: 0.8
lifetime: 25
There are a few things to note.
First, ccgt
defines essential information:
a name, a color (given as an HTML color code, for later visualisation), its base_tech, supply
, and its carrier_out, power
.
It has set itself up as a power supply technology.
This is followed by the definition of parameters to use to constrain the technology's contribution to the system and costs.
Note
There are technically no restrictions on the units used in model definitions. Usually, the units will be kW and kWh, alongside a currency like USD or EUR for costs. There is nothing preventing the use of other units, but yt is the responsibility of the modeler to ensure that units are correct and consistent.
The second technology is csp
(concentrating solar power), and serves as an example of a complex supply technology making use of:
- a finite source based on time series data
- inbuilt storage
- plant-internal losses (
parasitic_eff
)
This definition in the example model's configuration is more verbose:
csp:
name: "Concentrating solar power"
color: "#F9CF22"
base_tech: supply
carrier_out: power
source_unit: per_area
include_storage: True
storage_cap_max: 614033
flow_cap_per_storage_cap_max: 1
storage_loss: 0.002
flow_out_eff: 0.4
flow_out_parasitic_eff: 0.9
area_use_max: .inf
flow_cap_max: 10000
lifetime: 25
Again, csp
has the definitions for name, color, base_tech, and carrier_out.
Its constraining parameters are more numerous, it defines:
- a maximum storage capacity (
storage_cap_max
) - an hourly storage loss rate (
storage_loss
), - a constraint that flow capacity can be no greater than storage capacity (
flow_cap_per_storage_cap_max
).
It also defines a carrier conversion efficiency of 0.4 and a parasitic efficiency of 0.9 (i.e., an internal loss of 0.1). Finally, the source collector area and the installed carrier conversion capacity are constrained to a maximum.
The costs are more numerous as well, and include monetary costs for all relevant components along the conversion from source to carrier (power):
- storage capacity
- source collector area
- source conversion capacity
- carrier conversion capacity
- variable operational and maintenance costs
Storage technologies¶
The second location allows a limited amount of battery storage to be deployed to better balance the system.
This technology is defined as follows:
battery:
name: "Battery storage"
color: "#3B61E3"
base_tech: storage
carrier_in: power
carrier_out: power
flow_cap_max: 1000 # kW
storage_cap_max: .inf
flow_cap_per_storage_cap_max: 4
# 0.95 * 0.95 = 0.9025 round trip efficiency
flow_out_eff: 0.95
flow_in_eff: 0.95
storage_loss: 0 # No loss over time assumed
lifetime: 25
The constraints give a maximum installed generation capacity for battery storage.
This is combined with a maximum ratio of flow capacity to storage capacity (flow_cap_per_storage_cap_max
),
which effectively limits the storage capacity.
The ratio is the charge/discharge rate / storage capacity (a.k.a the battery reservoir
).
In the case of a storage technology, flow_in_eff
applies on charging and flow_out_eff
on discharging.
In addition, storage technologies can lose stored carrier over time - in this case, we set this loss to zero.
Other technologies¶
Three more technologies are needed for a simple model.
First, a definition of power demand:
Power demand is a technology like any other. We will associate an actual demand time series with the demand technology at each node separately.
What remains to set up is a simple transmission technology. Transmission technologies look different to other technologies, as they link the carrier at one location to the carrier at another:
region1_to_region2:
from: region1
to: region2
name: "AC power transmission"
color: "#8465A9"
base_tech: transmission
carrier_in: power
carrier_out: power
flow_out_eff: 0.85
lifetime: 25
flow_cap_max: 10000
region1_to_region1_1:
from: region1
to: region1_1
template: free_transmission
region1_to_region1_2:
from: region1
to: region1_2
template: free_transmission
region1_to_region1_3:
from: region1
to: region1_3
template: free_transmission
ac_transmission
has an efficiency of 0.85, so a loss during transmission of 0.15, as well as some cost definitions.
free_transmission
allows local power transmission from any of the csp facilities to the nearest location.
As the name suggests, it applies no cost or efficiency losses to this transmission.
Interlude: inheriting from templates¶
We can see that those technologies which rely on free_transmission
inherit a lot of this information from elsewhere in the model definition.
free_transmission
is defined in templates
, which makes it inheritable.
Templates allow us to avoid excessive repetition in our model definition.
Technologies and nodes can inherit from anything defined in templates
.
items in templates
can also inherit from each other, so you can create inheritance chains.
The free_transmission
template looks like this:
templates:
free_transmission:
name: "Local power transmission"
color: "#6783E3"
carrier_in: power
carrier_out: power
base_tech: transmission
Nodes¶
In order to translate the model requirements shown in this section's introduction into a model definition, five nodes are used: region1
, region2
, region1_1
, region1_2
, and region1_3
.
The technologies are set up at these nodes as follows:
Locations and their technologies in the example model
Let's now look at the first location definition:
region1:
latitude: 40
longitude: -2
techs:
demand_power:
ccgt:
flow_cap_max: 30000 # increased to ensure no unmet_demand in first timestep
There are several things to note here:
- The node specifies a dictionary of technologies that it allows (
techs
), with each key of the dictionary referring to the name of technologies defined in ourtechs.yaml
file. The technologies listed here must have been defined under thetechs
key. - It also overrides some options for both
demand_power
andccgt
. Forccgt
, it simply sets a node-specific maximum capacity constraint. Fordemand_power
, the options set here are related to reading the demand time series from a CSV file. CSV is a simple text-based format that stores tables by comma-separated rows. Note that we did not define anysink
option in the definition of thedemand_power
technology. Instead, this is done directly via a node-specific override. For this node, the filedemand-1.csv
is loaded and the columndemand
is taken (the text after the colon). If no column is specified, Calliope will assume that the column name matches the location nameregion1
. - Coordinates are defined by latitude and longitude, which will be used to calculate distance of transmission lines (unless we specify otherwise later on). They can also be used for geospatial visualisations.
The remaining nodes look similar:
region2:
latitude: 40
longitude: -8
techs:
demand_power:
battery:
region1_1:
template: csp_regions
latitude: 41
longitude: -2
region1_2:
template: csp_regions
latitude: 39
longitude: -1
region1_3:
template: csp_regions
latitude: 39
longitude: -2
region2
is very similar to region1
, except that it does not include the ccgt
technology.
The three region1-
locations are defined together using the template csp_regions
, except for their geospatial coordinates.
They allow only the csp
technology, this allows us to model three possible sites for CSP plants.