calliope-project / calliope

A multi-scale energy systems modelling framework

Home Page:https://www.callio.pe

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.