YAML as used in Calliope¶
All model configuration/definition files (with the exception of tabular data files) are in the YAML format, "a human friendly data serialisation standard for all programming languages".
A quick introduction to YAML¶
Configuration for Calliope is usually specified as option: value entries, where value might be a number, a text string, or a list (e.g. a list of further settings).
See also
See the YAML website for more general information about YAML.
Data types¶
Using quotation marks (' or ") to enclose strings is optional, but can help with readability.
The three ways of setting option to text below are equivalent:
Without quotations, the following values in YAML will be converted to different Python types:
- Any unquoted number will be interpreted as numeric (e.g.,
1,1e61e-10). trueorfalsevalues will be interpreted as boolean..infand.nanvalues will be interpreted as the float valuesnp.inf(infinite) andnp.nan(not a number), respectively.nullvalues will interpreted asNone.
Comments¶
Comments can be inserted anywhere in YAML files with the # symbol.
The remainder of a line after # is interpreted as a comment.
Therefore, if you have a string with a # in it, make sure to use explicit quotation marks.
Lists and dictionaries¶
Lists in YAML can be of the form [...] or a series of lines starting with -.
These two lists are equivalent:
Dictionaries can be of the form {...} or a series of lines without a starting -.
These two dictionaries are equivalent:
To continue dictionary nesting, you can add more {} parentheses or you can indent your lines further.
We prefer to use 2 spaces for indenting as this makes the nested data structures more readable than the often-used 4 spaces.
We sometimes also use lists of dictionaries in Calliope, e.g.:
Which is equivalent in Python to {"key": [{"option1": value1, "option2": value2}, {"option3": value3, "option4": value4}]}.
Calliope's additional YAML features¶
To make model definition easier, we add some extra features that go beyond regular YAML formatting.
Abbreviated nesting¶
Calliope allows an abbreviated form for long, nested settings:
can be written as:
Relative file imports¶
Calliope also allows a special import: directive in any YAML file.
This can specify one or several YAML files to import, e.g.:
Data defined in the current and imported file(s) must be mutually exclusive. If both the imported file and the current file define the same option, Calliope will raise an exception.
As you will see in our standard model directory structure, we tend to store our model definition in separate files.
In this case, our model.yaml file tends to have the following import statement:
This means that we have:
Which Calliope will receive as:
import:
- 'model_definition/techs.yaml'
- 'model_definition/nodes.yaml'
- 'scenarios.yaml'
config:
init:
...
build:
...
solve:
...
techs:
tech1:
...
...
nodes:
node1:
...
...
overrides:
override1:
...
scenarios:
scenario1: [override1, ...]
...
Note
- The imported files may include further files, so arbitrary degrees of nested configurations are possible.
- The
importstatement can either give an absolute path or a path relative to the importing file.
Reusing definitions through templates¶
For larger models, duplicate entries can start to crop up and become cumbersome.
To streamline data entry, any section can inherit common data from a template which is defined in the top-level templates section.
Example 1: templates in technologies
If we want to set interest rate to 0.1 across all our technologies, we could define:
Example 2: templates in nodes
Similarly, if we want to allow the same technologies at all our nodes:
Example 3: templates in data tables
Storing common options under the templates key is also useful for data tables.
templates:
common_data_options:
rows: timesteps
columns: nodes
add_dims:
inputs: source_use_max
data_tables:
pv_data:
table: /path/to/pv_timeseries.csv
template: common_data_options
add_dims:
techs: pv
wind_data:
table: /path/to/wind_timeseries.csv
template: common_data_options
add_dims:
techs: wind
hydro_data:
table: /path/to/hydro_timeseries.csv
template: common_data_options
add_dims:
techs: hydro
data_tables:
pv_data:
table: /path/to/pv_timeseries.csv
rows: timesteps
columns: nodes
add_dims:
inputs: source_use_max
techs: pv
wind_data:
table: /path/to/wind_timeseries.csv
rows: timesteps
columns: nodes
add_dims:
inputs: source_use_max
techs: wind
hydro_data:
table: /path/to/hydro_timeseries.csv
rows: timesteps
columns: nodes
add_dims:
inputs: source_use_max
techs: hydro
Inheritance chains can also be created. That is, templates can inherit from other templates.
Example 4: template inheritance chain
A two-level template inheritance chain.
templates:
interest_rate_setter:
cost_interest_rate:
data: 0.1
index: monetary
dims: costs
investment_cost_setter:
template: interest_rate_setter
cost_flow_cap:
data: 100
index: monetary
dims: costs
cost_area_use:
data: 1
index: monetary
dims: costs
techs:
ccgt:
template: investment_cost_setter
flow_out_eff: 0.5
ac_transmission:
template: interest_rate_setter
flow_out_eff: 0.98
techs:
ccgt:
cost_interest_rate:
data: 0.1
index: monetary
dims: costs
cost_flow_cap:
data: 100
index: monetary
dims: costs
cost_area_use:
data: 1
index: monetary
dims: costs
flow_out_eff: 0.5
ac_transmission:
cost_interest_rate:
data: 0.1
index: monetary
dims: costs
cost_flow_cap:
data: 100
index: monetary
dims: costs
cost_area_use:
data: 1
index: monetary
dims: costs
flow_out_eff: 0.98
Template properties can always be overwritten by the inheriting component. That is, a 'local' value has priority over the template value. This can be useful to streamline setting costs for different technologies.
Example 5: overriding template values
In this example, a technology overrides a single templated cost.
templates:
interest_rate_setter:
cost_interest_rate:
data: 0.1
index: monetary
dims: costs
investment_cost_setter:
template: interest_rate_setter
cost_interest_rate.data: 0.2 # this will replace `0.1` in the `interest_rate_setter`.
cost_flow_cap:
data: null
index: monetary
dims: costs
cost_area_use:
data: null
index: monetary
dims: costs
techs:
ccgt:
template: investment_cost_setter
cost_flow_cap.data: 100 # this will replace `null` in the `investment_cost_setter`.
Overriding one file with another¶
Generally, if the imported file and the current file define the same option, Calliope will raise an exception.
However, you can define overrides which you can then reference when loading your Calliope model (see Scenarios and overrides). These override settings will override any data that match the same name and will add new data if it wasn't already there.
It will do so by following the entire nesting chain. For example:
# Initial configuration
one.two.three: x
four.five.six: x
# Override to apply
one.two.four: y
four.five.six: y
The above would lead to:
To entirely replace a nested dictionary you can use our special key _REPLACE_.
Now, using this override:
Will lead to: