Internal annuity calculation (ex. 55)

Overview

The relevant part of this example is inside the template Asset, which looks like this:

parameters:
  from: null
  to: null
  invest: null
  _annuity: null

components:
  asset:
    type: Connection
    node_from: <from>
    node_to: <to>
    capacity: <self>.invest:value
  
  invest:
    type: Decision
    lb: 0
    ub: 100
    cost: <_annuity>

# NOTE:
#   - The `|` at the start indicates in the YAML that what follows will be a multi-line string.
#   - You can use `this.get("...")` to access any parameter known in this template.
#   - Accessing `wacc` is possible since it is NOT a parameter of this template AND is a known template in the global
#     parameters defined in the top-level config file (these are "passed down").
#   - You can set the value of a parameter using `this.set("...", value)`.
#   - Using `_annuity` indicates that this parameter is "private": It cannot be set from the outside like normal
#     parameters (IESopt will error if a user tries to) and can only be used by functions like below.
#   - The `prepare` function is called before any components are constructed from this template; this allows accessing
#     the total `capex` and `lifetime`, using them together with the `annuity(...)` function in `IESU` (which is just
#     a quality-of-life renaming of `IESopt.Utilities`) to calculate the annuity, and finally setting the value of
#     the parameter `_annuity` - which is then used in the `invest` (Decision) component.
#   - `IESU.annuity(...)` will per default already factor in the total time span of the model, properly scaling the
#     annuity for models that do not span a 1hourly-1year model exactly. Refer to its documentation for more info.
#   - We are using a dict-valued parameter (`invest`) here - simply to showcase that this is a possibility. Not using
#     that and relying on simple parameters (like almost everywhere else) is perfectly possible as well!
functions:
  prepare: |
    capex = this.get("invest")["capex"]
    lifetime = this.get("invest")["lifetime"]
    annuity = IESU.annuity(capex; lifetime=lifetime, rate=this.get("wacc"))
    this.set("_annuity", annuity)

Check out the top-level config file, etc., to see how this template is used in the model.

Running the example

First, import iesopt.

import iesopt

Then, create a local copy of the IESopt example.

config = iesopt.make_example("55_annuity", "opt")
INFO:iesopt:Data folder for examples already exists; NOT copying ANY contents
INFO:iesopt:Creating example ('55_annuity') at: 'opt/55_annuity.iesopt.yaml'
INFO:iesopt:Set write permissions for example ('opt/55_annuity.iesopt.yaml'), and data folder ('opt/files')

Finally, run the model and observe some results.

model = iesopt.run(config, config={"general.verbosity.core": "error"})

model.results.to_pandas().query(
    "component == 'pipeline.invest' and field == 'value' and mode == 'primal'"
)
snapshot component fieldtype field value mode
73 None pipeline.invest var value 4.200000e+01 primal
75 None pipeline.invest obj value 2.522829e+06 primal