Flatten technology configuration
brynpickering opened this issue · comments
Problem description
There is possibly unnecessary nesting going on when defining technologies, where we use essentials
, constraints
and costs
(and in 0.7.0-dev, switches
). These are beneficial for handling the data internally in Calliope, but are of limited use to a user. Hence, we'd do better to flatten this and handle the differences internally. So, we'd go from:
techs:
ccgt:
essentials:
name: 'Combined cycle gas turbine'
color: '#E37A72'
parent: supply
carrier_out: power
constraints:
resource: inf
energy_eff: 0.5
energy_cap_max: 40000 # kW
energy_cap_max_systemwide: 100000 # kW
energy_ramping: 0.8
lifetime: 25
costs:
monetary:
interest_rate: 0.10
energy_cap: 750 # USD per kW
om_con: 0.02 # USD per kWh
to:
techs:
ccgt:
name: 'Combined cycle gas turbine'
color: '#E37A72'
parent: supply
carrier_out: power
resource: inf
energy_eff: 0.5
energy_cap_max: 40000 # kW
energy_cap_max_systemwide: 100000 # kW
energy_ramping: 0.8
lifetime: 25
costs_interest_rate: {monetary: 0.10}
costs_energy_cap: {monetary: 750} # USD per kW
costs_om_con: {monetary: 0.02} # USD per kWh
The major change here is prepending the cost parameters with costs
, which brings greater consistency to the process as they then match the naming of the parameters in the xarray Dataset (model.inputs
).
The major drawback is that one could change certain information about a technology on a location-basis, which we can't easily handle without hardcoding which parameters can and can't be changed in such a way. This was previously handled by flagging all essentials
as being editable only on a per-tech basis. However, it might not be a problem in v0.7.0 if the input or output carrier of a technology changes on a per-tech basis. It would be weird, but I think the model would (and possibly should) just handle it gracefully.
The rule
branch incorporates typedconfig
and flattens these attributes. There are tests for typedconfig
under test/typedconfig
, and a couple of tests that reads calliope config in test/test_typedconfig.py
.
To add to this, we might want to also use this chance to also update the definition of lists of dicts. It's generally less easy for a user to parse, but is much easier for handling the data internally and for passing the data to other applications. E.g., for the above:
techs:
- id: ccgt
name: 'Combined cycle gas turbine'
color: '#E37A72'
parent: supply
carrier_out: power
resource: inf
energy_eff: 0.5
energy_cap_max: 40000 # kW
energy_cap_max_systemwide: 100000 # kW
energy_ramping: 0.8
lifetime: 25
costs_interest_rate: {monetary: 0.10}
costs_energy_cap: {monetary: 750} # USD per kW
costs_om_con: {monetary: 0.02} # USD per kWh
Some advancements of this to create a further list-of-dictification:
a:
techs:
- id: ccgt
name: 'Combined cycle gas turbine'
color: '#E37A72'
parent: supply
carrier_out: power
resource: inf
energy_eff: 0.5
energy_cap_max: 40000 # kW
energy_cap_max_systemwide: 100000 # kW
energy_ramping: 0.8
lifetime: 25
costs:
- class: monetary
interest_rate: 0.10
energy_cap: 750 # USD per kW
om_con: 0.02 # USD per kWh
b:
techs:
- id: ccgt
name: 'Combined cycle gas turbine'
color: '#E37A72'
parent: supply
carriers:
- tier: out
carrier: power
resource: inf
energy_eff: 0.5
energy_cap_max: 40000 # kW
energy_cap_max_systemwide: 100000 # kW
energy_ramping: 0.8
lifetime: 25
costs:
- class: monetary
interest_rate: 0.10
energy_cap: 750 # USD per kW
om_con: 0.02 # USD per kWh
As another example, with more complicated carriers:
chp:
essentials:
name: 'Combined heat and power'
color: '#E4AB97'
parent: conversion_plus
primary_carrier_out: electricity
carrier_in: gas
carrier_out: electricity
carrier_out_2: heat
switches:
export: true
constraints:
export_carrier: electricity
energy_cap_max: 1500
energy_eff: 0.405
carrier_ratios.carrier_out_2.heat: 0.8
lifetime: 25
costs:
monetary:
interest_rate: 0.10
energy_cap: 750
om_prod: 0.004 # .4p/kWh for 4500 operating hours/year
export: file=export_power.csv
c:
techs:
id: chp
name: 'Combined heat and power'
color: '#E4AB97'
parent: conversion_plus
carriers:
- tier: out
carrier: electricity
primary: true # or 'electricity'
export: true # or 'electricity'
- tier: in
carrier: gas
- tier: out_2
carrier: [high_T_heat, low_T_heat]
ratios: [0.1, 0.8] # Needs a better descriptor, it means the ratio of out_2:out e.g. carrier_prod[high_T_heat] / carrier_prod[electricity] == 0.1
energy_cap_max: 1500
energy_eff: 0.405
lifetime: 25
costs:
- class: monetary
interest_rate: 0.10
energy_cap: 750
om_prod: 0.004 # .4p/kWh for 4500 operating hours/year
export: file=export_power.csv
RE the above: it is the handling of costs and carriers that is most important to deal with in this implementation. I think other details associated with flattening are relatively minor.
Fixed in #518. Flattened with the ability to define any parameter over additional dimensions (including the costs
dimension for costs) using our parameter
syntax. This means the above examples are all discounted in favour of:
techs:
chp:
name: 'Combined heat and power'
carrier_out: [electricity, high_T_heat, low_T_heat]
carrier_export: electricity
carrier_in: gas
flow_out_eff:
data: [0.405, 0.1, 0.8] # Needs custom constraint to set flow_out[high_T_heat] / flow_out[electricity] == 0.1 etc.
index: [electricity, high_T_heat, low_T_heat]
dims: carriers
flow_cap_max:
data: 1500
index: electricity
dims: carriers
lifetime: 25
cost_interest_rate:
data: 0.1
index: monetary
dims: costs
cost_flow_out:
data: 750
index: monetary
dims: costs
cost_flow_out:
data: 0.004 # .4p/kWh for 4500 operating hours/year
index: [[electricity, monetary]]
dims: [carriers, costs]
cost_export:
data: file=export_power.csv
index: [[electricity, monetary]]
dims: [carriers, costs]
There's potential to simplify this further by having some kind of automatic expansion of costs to the parameter
syntax, or using tech_groups
to inherit duplications.