yaml
Other than Tessif, Calliope does usually read the model from yaml files. Examples of these are stored in the calliope folder inside the tessif examples data folder. Additionally any model created with tessif and transformed to calliope will be stored as yaml in the calliope folder inside the tessif write folder.
For deeper information on how to build, run and analyse an energy system model using calliope refer to the documentation of calliope.
Minimum working example
Note
Original yaml data can be found in
tessif/examples/data/calliope/mwe/
as well as its subfolders.
Original Data yaml Files
mwe/model.yaml
import: # Import files (path relative to model file)
- model_config/locations.yaml # models technologies
- model_config/techs.yaml # models locations
# Model configuration: all settings that affect the built model
model:
name: Minimum_Working_Example
calliope_version: 0.6.6-post1
timeseries_data_path: timeseries_data
subset_time:
- '1990-07-13 00:00:00'
- '1990-07-13 03:00:00'
group_constraints:
systemwide_emission_cap:
cost_max:
emissions:
run:
solver: cbc
cyclic_storage: false
objective_options.cost_class:
monetary: 1
mwe/model_config/techs.yaml
# calliope defaults are $ and kW, but since there is no conversion
# any unit can be chosen as long as it is used consistent.
# So defaults here are, just like in tessif, usually € and MW
techs:
electricity_Demand:
essentials:
name: Demand
parent: demand
carrier: electricity
constraints:
energy_con: true
resource_unit: energy
resource: file=electricity_Demand.csv:electricity_Demand
force_resource: true
Gas Station:
essentials:
name: Gas Station
parent: supply
carrier_out: fuel
constraints:
resource: .inf
energy_ramping: true
Generator:
essentials:
name: Generator
parent: conversion
carrier_in: fuel
carrier_out: electricity
constraints:
energy_eff: 0.42
energy_ramping: true
costs:
monetary:
om_con: 0
om_prod: 2
Battery:
essentials:
name: Battery
parent: storage
carrier: electricity
constraints:
storage_cap_max: 20
energy_cap_min: 20
energy_cap_max: 20
energy_ramping: true
storage_cap_min: 20
storage_initial: 0.5
costs:
monetary:
om_prod: 0.1
fuel transmission:
essentials:
name: fuel transmission
parent: transmission
carrier: fuel
constraints:
one_way: true
electricity transmission:
essentials:
name: electricity transmission
parent: transmission
carrier: electricity
constraints:
one_way: true
mwe/model_config/locations.yaml
locations:
Pipeline:
coordinates:
lat: 0.0
lon: 0.0
Powerline:
coordinates:
lat: 0.0
lon: 0.0
electricity_Demand location:
coordinates:
lat: 0.0
lon: 0.0
techs:
electricity_Demand:
Gas Station location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Gas Station:
Generator location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Generator:
Battery location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Battery:
links:
Gas Station location,Pipeline:
techs:
fuel transmission:
constraints:
one_way: true
Pipeline,Generator location:
techs:
fuel transmission:
constraints:
one_way: true
Battery location,Powerline:
techs:
electricity transmission:
constraints:
one_way: false
Generator location,Powerline:
techs:
electricity transmission:
constraints:
one_way: true
Powerline,electricity_Demand location:
techs:
electricity transmission:
constraints:
one_way: true
Use Case
Read the energy system model and optimize it
>>> from tessif.frused.paths import example_dir >>> import pprint >>> import calliope >>> calliope.set_log_verbosity('ERROR', include_solver_output=False) >>> es = calliope.Model(f'{example_dir}/data/calliope/mwe/model.yaml') >>> es.run()
Print out the objective value
>>> # See the set production costs >>> print(f'Objective: {es.results.objective_function_value}') Objective: 61.0
Use Tessif post processing
>>> from tessif.transform.es2mapping.cllp import LoadResultier >>> loads = LoadResultier(es) >>> print(loads.node_load['Powerline']) Powerline Battery Generator Battery Demand 1990-07-13 00:00:00 -10.0 -0.0 0.0 10.0 1990-07-13 01:00:00 -0.0 -10.0 0.0 10.0 1990-07-13 02:00:00 -0.0 -10.0 0.0 10.0 1990-07-13 03:00:00 -0.0 -10.0 0.0 10.0
>>> from tessif.transform.es2mapping.cllp import IntegratedGlobalResultier >>> global_res = IntegratedGlobalResultier(es) >>> pprint.pprint(global_res.global_results) {'capex (ppcd)': 0.0, 'costs (sim)': 61.0, 'emissions (sim)': 0.0, 'opex (ppcd)': 61.0}
Fully parameterized working example
Note
Original yaml data can be found in
tessif/examples/data/calliope/fpwe/
as well as its subfolders.
Original Data – yaml Files
fpwe/model.yaml
# this file is called for building the model with calliope
import: # calling the needed yaml files with path relative to this file
- model_config/locations.yaml
- model_config/techs.yaml
model:
name: Fully_Parameterized_Working_Example
calliope_version: 0.6.6-post1 # optional but useful if this is going to be used in future for other calliope versions and problems occure
timeseries_data_path: timeseries_data # folder name, where the .csv files are; relative to this yaml file
subset_time: # optional, but useful e.g. for testing to set timeframe to 3 steps, when csv actually are 8760
- '1990-07-13 00:00:00'
- '1990-07-13 02:00:00'
group_constraints: # optional
systemwide_emission_cap:
cost_max:
emissions:
run:
solver: cbc # default solver in calliope
cyclic_storage: false # all storages are either cyclic or none is
objective_options.cost_class: # only monetary are objective to minimize, no emission cost
monetary: 1
fpwe/model_config/techs.yaml
# This example is build to be like Tessif fpwe and describe the most common
# used calliope components with most important parameters a little bit.
#
# For more information see also
# https://calliope.readthedocs.io/en/stable/user/config_defaults.html#group-constraints
# as well as
# in installed packages in calliope - config - defaults.yaml
techs:
# Demand
electricity_Demand: # this name cant be 'demand' cause demand is already a 'parent' name ! (same for other preset parents)
essentials:
name: Demand.Germany.Power.electricity.demand # This way tessif uid is stored in calliope. name.region.sector.carrier.node_type
color: '#cc0033' # colors can be set for native calliope visualization
parent: demand # parent gives some presets like energy production is false and consumption is true. Custom parents can be defined as tech_group
carrier: electricity
constraints:
energy_con: true
resource_unit: energy
resource: file=electricity_Demand.csv:electricity_Demand # Resource can either be like Tessif's accumulated amount or give an upper bound as timeseries. Timeseries give in " file=file_name.csv:column_name " style. Negative signs for demands are needed.
force_resource: true # can force to use full resource rather than making it optional. Preset on demands is true while sources are false
costs:
monetary:
om_con: 0 # Costs to produce 1 unit of carrier output.
emissions:
om_con: 0 # Emissions are handled like costs. They can be (if wanted) included in solver objective to minimize. In tessif they are not included.
# Supply
Gas Station:
essentials:
name: Gas Station.Germany.Power.Gas.source
color: '#FF7700'
parent: supply
carrier_out: fuel
constraints:
energy_prod: true
resource: .inf
resource_unit: energy
energy_cap_min: 100.0 # The tessif installed capacity will be called here since calliope does not have installed capacities. Except if installed is infinite
energy_cap_max: 100.0
energy_cap_min_use: 0.0
energy_eff: 1 # sources do have an efficiency in calliope.
energy_ramping: true # Energy ramping as a fraction of capacity or true which is same as 1. Important cause default is false which equals 0
costs:
monetary:
om_prod: 10
emissions:
om_prod: 3
Solar Panel:
essentials:
name: Solar Panel.Germany.Power.electricity.Renewable
color: '#FF7700'
parent: supply
carrier_out: electricity
constraints:
energy_prod: true
resource: file=Solar Panel.csv:Solar Panel
resource_unit: energy_per_cap
energy_cap_min: 20.0
energy_cap_max: 20.0
energy_eff: 1
energy_ramping: true
force_resource: true
costs:
monetary:
om_prod: 0
emissions:
om_prod: 0
# Conversion
Generator:
essentials:
name: Generator.Germany.Power.electricity.transformer
color: '#99ccff'
parent: conversion
carrier_in: fuel
carrier_out: electricity
constraints:
energy_con: true
energy_prod: true
energy_cap_min: 15.0
energy_cap_max: 15.0
energy_cap_min_use: 0.0
energy_eff: 0.42
energy_ramping: true
costs:
monetary:
om_con: 0
om_prod: 10
emissions:
om_con: 0
om_prod: 10
# Storage
Battery:
essentials:
name: Battery.Germany.Power.electricity.storage
color: '#ffcc00'
parent: storage
carrier: electricity
constraints:
energy_con: true
energy_prod: true
storage_cap_max: 10
energy_cap_min: 10
energy_cap_max: 10 # Energy flow capacity maximum for charge as well as discharge.
energy_cap_min_use: 0.0
energy_eff: 1.0 # this efficiency is taken into account on charge as well as discharge
energy_ramping: true
storage_cap_min: 10
storage_initial: 0.9 # 9/10 units is in storage when starting the optimization.
storage_loss: 0.1 # each timestep 1/10 units of storage state of charge get lost. No standing loss from timestep -1 (initial) to 0
energy_cap_per_storage_cap_min: 0
energy_cap_per_storage_cap_max: 1
costs:
monetary:
om_prod: 0
emissions:
om_prod: 0
# transmissions to connect the technologies which will all be located in different locations
fuel transmission:
essentials:
name: fuel transmission
color: '#8465A9'
parent: transmission
carrier: fuel
constraints:
energy_eff: 1
one_way: true
electricity transmission:
essentials:
name: electricity transmission
color: '#8465A9'
parent: transmission
carrier: electricity
constraints:
energy_eff: 1
one_way: true
fpwe/model_config/locations.yaml
locations:
Pipeline:
coordinates:
lat: 42.0 # different locations can have same coordinates
lon: 42.0 # different locations can have same coordinates
Powerline:
coordinates:
lat: 42.0
lon: 42.0
electricity_Demand location:
coordinates:
lat: 42.0
lon: 42.0
techs: # calling all technologies that are acting in this location.
electricity_Demand:
Gas Station location:
coordinates:
lat: 42.0
lon: 42.0
techs:
Gas Station:
Solar Panel location:
coordinates:
lat: 42.0
lon: 42.0
techs:
Solar Panel:
Generator location:
coordinates:
lat: 42.0
lon: 42.0
techs:
Generator:
Battery location:
coordinates:
lat: 42.0
lon: 42.0
techs:
Battery:
links:
Gas Station location,Pipeline:
techs:
fuel transmission:
constraints:
one_way: true
Pipeline,Generator location:
techs:
fuel transmission:
constraints:
one_way: true
Battery location,Powerline:
techs:
electricity transmission:
constraints:
one_way: false
Generator location,Powerline:
techs:
electricity transmission:
constraints:
one_way: true
Solar Panel location,Powerline:
techs:
electricity transmission:
constraints:
one_way: true
Powerline,electricity_Demand location:
techs:
electricity transmission:
constraints:
one_way: true
# a small example like this doesnt need multiple locations
# connected via transmission lines.
# And all techs could be stored in one location instead
# But keep in mind for tessif post processing different nodes are needed,
# and each location is acting like a node.
Use Case
Read the energy system model and optimize it
>>> from tessif.frused.paths import example_dir >>> import pprint >>> import calliope >>> calliope.set_log_verbosity('ERROR', include_solver_output=False) >>> es = calliope.Model(f'{example_dir}/data/calliope/fpwe/model.yaml') >>> es.run()
Print out the objective value
>>> # See the set production costs >>> print(f'Objective: {es.results.objective_function_value}') Objective: 104.809524
Use Tessif post processing
>>> from tessif.transform.es2mapping.cllp import LoadResultier >>> loads = LoadResultier(es) >>> print(loads.node_load['Powerline']) Powerline Battery Generator Solar Panel Battery Demand 1990-07-13 00:00:00 -0.0 -0.0 -12.0 1.0 11.0 1990-07-13 01:00:00 -8.0 -0.0 -3.0 0.0 11.0 1990-07-13 02:00:00 -0.9 -3.1 -7.0 0.0 11.0
>>> from tessif.transform.es2mapping.cllp import IntegratedGlobalResultier >>> global_res = IntegratedGlobalResultier(es) >>> pprint.pprint(global_res.global_results) {'capex (ppcd)': 0.0, 'costs (sim)': 105.0, 'emissions (sim)': 53.0, 'opex (ppcd)': 105.0}
CHP expansion example
Note
Original yaml data can be found in
tessif/examples/data/calliope/chp_expansion/
as well as its subfolders.
This energy system model was created to further inspect the parameter definitions of CHPs when they are expandable. It can be optimized using calliope and then be inspected using either the usual calliope commands as well as the tessif post processing.
Original Data – yaml Files
chp_expansion/model.yaml
# CHP expansion example to further inspect the treatment of
# parameters like energy_cap as it is not trivial whether it
# refers to in or output
import:
- model_config/techs.yaml
- model_config/locations.yaml
model:
name: CHP_Example
calliope_version: 0.6.6-post1
timeseries_data_path: timeseries_data
subset_time:
- '1990-07-13 00:00:00'
- '1990-07-13 03:00:00'
group_constraints:
systemwide_emission_cap:
cost_max:
emissions:
run:
solver: cbc
cyclic_storage: false
objective_options.cost_class:
monetary: 1
chp_expansion/model_config/techs.yaml
techs:
Power Demand:
essentials:
name: Power Demand.None.None.None.None
parent: demand
carrier: electricity
constraints:
energy_con: true
resource_unit: energy
resource: file=Power Demand.csv:Power Demand
force_resource: true
costs:
monetary:
om_con: 0.0
emissions:
om_con: 0.0
Heat Demand:
essentials:
name: Heat Demand.None.None.None.None
parent: demand
carrier: heat
constraints:
energy_con: true
resource_unit: energy
resource: file=Heat Demand.csv:Heat Demand
force_resource: true
costs:
monetary:
om_con: 0.0
emissions:
om_con: 0.0
Gas Source:
essentials:
name: Gas Source.None.None.None.None
parent: supply
carrier_out: gas
constraints:
energy_prod: true
resource: inf
resource_unit: energy
energy_cap_min: 0
energy_cap_max: .inf
energy_cap_min_use: 0
energy_eff: 1
energy_ramping: true
costs:
monetary:
om_prod: 0.0
emissions:
om_prod: 0.0
Backup Power:
essentials:
name: Backup Power.None.None.None.None
parent: supply
carrier_out: electricity
constraints:
energy_prod: true
resource: inf
resource_unit: energy
energy_cap_min: 0
energy_cap_max: .inf
energy_cap_min_use: 0
energy_eff: 1
energy_ramping: true
costs:
monetary:
om_prod: 1000
emissions:
om_prod: 0.0
Backup Heat:
essentials:
name: Backup Heat.None.None.None.None
parent: supply
carrier_out: heat
constraints:
energy_prod: true
resource: inf
resource_unit: energy
energy_cap_min: 0
energy_cap_max: .inf
energy_cap_min_use: 0
energy_eff: 1
energy_ramping: true
costs:
monetary:
om_prod: 1000
emissions:
om_prod: 0.0
CHP:
essentials:
name: CHP.None.None.None.None
parent: conversion_plus
carrier_in: gas
carrier_out: electricity
primary_carrier_out: electricity
carrier_out_2: heat
constraints:
energy_con: true
energy_prod: true
carrier_ratios.carrier_out_2.heat: 0.8
energy_eff: 0.5
energy_cap_max: 8
energy_cap_min: 0
energy_ramping: true
lifetime: 0.00045662100456621003
costs:
monetary:
om_prod: 1
energy_cap: 1
interest_rate: 0
emissions:
om_prod: 1
gas transmission:
essentials:
name: gas transmission
parent: transmission
carrier: gas
constraints:
energy_eff: 1
one_way: true
electricity transmission:
essentials:
name: electricity transmission
parent: transmission
carrier: electricity
constraints:
energy_eff: 1
one_way: true
heat transmission:
essentials:
name: heat transmission
parent: transmission
carrier: heat
constraints:
energy_eff: 1
one_way: true
chp_expansion/model_config/locations.yaml
locations:
Gas Grid:
coordinates:
lat: 0.0
lon: 0.0
Powerline:
coordinates:
lat: 0.0
lon: 0.0
Heat Grid:
coordinates:
lat: 0.0
lon: 0.0
Power Demand location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Power Demand:
Heat Demand location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Heat Demand:
Gas Source location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Gas Source:
Backup Power location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Backup Power:
Backup Heat location:
coordinates:
lat: 0.0
lon: 0.0
techs:
Backup Heat:
CHP location:
coordinates:
lat: 0.0
lon: 0.0
techs:
CHP:
links:
Gas Source location,Gas Grid:
techs:
gas transmission:
constraints:
one_way: true
Gas Grid,CHP location:
techs:
gas transmission:
constraints:
one_way: true
CHP location,Powerline:
techs:
electricity transmission:
constraints:
one_way: true
Backup Power location,Powerline:
techs:
electricity transmission:
constraints:
one_way: true
Powerline,Power Demand location:
techs:
electricity transmission:
constraints:
one_way: true
Backup Heat location,Heat Grid:
techs:
heat transmission:
constraints:
one_way: true
CHP location,Heat Grid:
techs:
heat transmission:
constraints:
one_way: true
Heat Grid,Heat Demand location:
techs:
heat transmission:
constraints:
one_way: true
Use Case
Read the energy system model and optimize it
>>> from tessif.frused.paths import example_dir >>> import pprint >>> import calliope >>> calliope.set_log_verbosity('ERROR', include_solver_output=False) >>> es = calliope.Model(f'{example_dir}/data/calliope/chp_expansion/model.yaml') >>> es.run()
Print out the flow result
>>> # See the set production costs >>> print(es.inputs.cost_om_prod.loc[{'loc_techs_om_cost': 'CHP location::CHP'}].loc[{'costs': 'monetary'}].data) array(1.)
>>> # See the production result for each CHP carrier >>> print(es.get_formatted_array('carrier_prod').loc[{'carriers':'electricity'}].sum('locs').to_pandas().T['CHP']) timesteps 1990-07-13 00:00:00 8.0 1990-07-13 01:00:00 8.0 1990-07-13 02:00:00 8.0 1990-07-13 03:00:00 8.0 Name: CHP, dtype: float64 >>> print(es.get_formatted_array('carrier_prod').loc[{'carriers':'heat'}].sum('locs').to_pandas().T['CHP']) timesteps 1990-07-13 00:00:00 6.4 1990-07-13 01:00:00 6.4 1990-07-13 02:00:00 6.4 1990-07-13 03:00:00 6.4 Name: CHP, dtype: float64
>>> # See the variable costs of the CHP >>> print(es.get_formatted_array('cost_var').loc[{'costs':'monetary'}].loc[{'locs':'CHP location'}].sum('techs')) Out[64]: <xarray.DataArray 'cost_var' (timesteps: 4)> array([8., 8., 8., 8.]) Coordinates: costs <U8 'monetary' locs <U12 'CHP location' * timesteps (timesteps) datetime64[ns] 1990-07-13 ... 1990-07-13T03:00:00
So it can be seen that production costs of CHP refer to the primary output.
Print out the capacity
>>> # See the input expansion costs >>> print(es.get_formatted_array('cost_energy_cap').sum('locs').to_pandas().T) costs emissions monetary techs CHP 0.0 1.0
>>> # See the expansion cost result >>> print(es.get_formatted_array('cost_investment').sum('locs').to_pandas().T) costs emissions monetary techs CHP 0.0 8.0
With the already known flow maximum it can be seen that the energy capacity costs of CHP refer to the primary output.
Compare to tessif post processing
>>> from tessif.transform.es2mapping.cllp import FlowResultier >>> flow = FlowResultier(es) >>> pprint.pprint(flow.edge_net_energy_flow) {Edge(source='Backup Heat', target='Heat Grid'): 14.4, Edge(source='Backup Power', target='Powerline'): 8.0, Edge(source='CHP', target='Heat Grid'): 25.6, Edge(source='CHP', target='Powerline'): 32.0, Edge(source='Gas Grid', target='CHP'): 64.0, Edge(source='Gas Source', target='Gas Grid'): 64.0, Edge(source='Heat Grid', target='Heat Demand'): 40.0, Edge(source='Powerline', target='Power Demand'): 40.0}
>>> pprint.pprint(flow.edge_specific_flow_costs) {Edge(source='Backup Heat', target='Heat Grid'): 1000.0, Edge(source='Backup Power', target='Powerline'): 1000.0, Edge(source='CHP', target='Heat Grid'): 0, Edge(source='CHP', target='Powerline'): 1.0, Edge(source='Gas Grid', target='CHP'): 0, Edge(source='Gas Source', target='Gas Grid'): 0.0, Edge(source='Heat Grid', target='Heat Demand'): 0.0, Edge(source='Powerline', target='Power Demand'): 0.0}
>>> from tessif.transform.es2mapping.cllp import CapacityResultier >>> cap_res = CapacityResultier(es) >>> print(cap_res.node_original_capacity['CHP']) Heat Grid 0.0 Powerline 0.0 dtype: float64 >>> print(cap_res.node_installed_capacity['CHP']) Heat Grid 6.4 Powerline 8.0 dtype: float64 >>> print(cap_res.node_expansion_costs['CHP']) Heat Grid 0.0 Powerline 1.0 dtype: float64
>>> from tessif.transform.es2mapping.cllp import LoadResultier >>> loads = LoadResultier(es) >>> print(loads.node_load['Powerline']) Powerline Backup Power CHP Power Demand 1990-07-13 00:00:00 -2.0 -8.0 10.0 1990-07-13 01:00:00 -2.0 -8.0 10.0 1990-07-13 02:00:00 -2.0 -8.0 10.0 1990-07-13 03:00:00 -2.0 -8.0 10.0 >>> print(loads.node_load['Heat Grid']) Heat Grid Backup Heat CHP Heat Demand 1990-07-13 00:00:00 -3.6 -6.4 10.0 1990-07-13 01:00:00 -3.6 -6.4 10.0 1990-07-13 02:00:00 -3.6 -6.4 10.0 1990-07-13 03:00:00 -3.6 -6.4 10.0
>>> from tessif.transform.es2mapping.cllp import IntegratedGlobalResultier >>> global_res = IntegratedGlobalResultier(es) >>> pprint.pprint(global_res.global_results) {'capex (ppcd)': 8.0, 'costs (sim)': 22440.0, 'emissions (sim)': 32.0, 'opex (ppcd)': 22432.0}
>>> print(f'Objective: {es.results.objective_function_value}') Objective: 22440.0