Node

Caution

Proper transformation (from Julia docs to Python docs) of math mode rendering, and therefore the “detailed model reference”, is partially broken. Until this is fixed, please refer to the original Julia documentation for any math mode rendering.

Overview

Note

This section of the documentation is auto-generated from the code of the Julia-based core model. Refer to IESopt.jl and its documentation for any further details (which may require some familiarity with Julia).

A Node represents a basic intersection/hub for energy flows. This can for example be some sort of bus (for electrical systems). It enforces a nodal balance equation (= “energy that flows into it must flow out”) for every Snapshot. Enabling the internal state of the Node allows it to act as energy storage, modifying the nodal balance equation. This allows using Nodes for various storage tasks (like batteries, hydro reservoirs, heat storages, …).

Basic Examples

A Node that represents an electrical bus:

bus:
  type: Node
  carrier: electricity

A Node that represents a simplified hydrogen storage:

store:
  type: Node
  carrier: hydrogen
  has_state: true
  state_lb: 0
  state_ub: 50

Parameters

carrier

Carrier of this Node. All connecting components need to respect that.

Mandatory:

yes

Values:

string

Unit:
Default:

has_state

If true, the Node is considered to have an internal state (“stateful Node”). This allows it to act as energy storage. Connect Connections or Units to it, acting as charger/discharger.

Mandatory:

no

Values:

true, false

Unit:
Default:

false

state_lb

Lower bound of the internal state, requires has_state = true.

Mandatory:

no

Values:

numeric, col@file, decision:value

Unit:

energy

Default:

\(-\infty\)

state_ub

Upper bound of the internal state, requires has_state = true.

Mandatory:

no

Values:

numeric, col@file, decision:value

Unit:

energy

Default:

\(+\infty\)

state_cyclic

Controls how the state considers the boundary between last and first Snapshot. disabled disables cyclic behaviour of the state (see also state_initial), eq leads to the state at the end of the year being the initial state at the beginning of the year, while geq does the same while allowing the end-of-year state to be higher (= “allowing to destroy energy at the end of the year”).

Mandatory:

no

Values:

eq, geq, or disabled

Unit:
Default:

eq

state_initial

Sets the initial state. Must be used in combination with state_cyclic = disabled.

Mandatory:

no

Values:

numeric

Unit:

energy

Default:

state_final

Sets the final state. Must be used in combination with state_cyclic = disabled.

Mandatory:

no

Values:

numeric

Unit:

energy

Default:

state_percentage_loss

Per Snapshot percentage loss of state (loosing 1% should be set as 0.01).

Mandatory:

no

Values:

\(\in [0, 1]\)

Unit:
Default:

0

nodal_balance

Can only be used for has_state = false. enforce forces total injections to always be zero (similar to Kirchhoff’s current law), create allows “supply < demand”, destroy allows “supply > demand”, at this Node.

Mandatory:

no

Values:

enforce, destroy, or create

Unit:
Default:

enforce

sum_window_size

TODO.

Mandatory:

no

Values:

integer

Unit:
Default:

sum_window_step

TODO.

Mandatory:

no

Values:

integer

Unit:
Default:

1

build_priority

Priority for the build order of components. Components with higher build_priority are built before. This can be useful for addons, that connect multiple components and rely on specific components being initialized before others.

Mandatory:

no

Values:

numeric

Unit:
Default:

0

Detailed model reference

Variables

pf_theta

state

Add the variable representing the state of this node to the model, if node.has_state == true. This can be accessed via node.var.state[t]. Additionally, if the state’s initial value is specified via state_initial the following gets added: $\( \text{state}_1 = \text{state}_{initial} \)$ math

Expressions

injection

Add an empty (JuMP.AffExpr(0)) expression to the node that keeps track of feed-in and withdrawal of energy. This constructs the expression \(\text{injection}_t, \forall t \in T\) that is utilized in node.con.nodalbalance. Core components (Connections, Profiles, and Units) that feed energy into this node add to it, all others subtract from it. A stateless node forces this nodal balance to always equal 0 which essentially describes “generation = demand”.

Constraints

last_state

Add the constraint defining the bounds of the node’s state during the last Snapshot to the model, if node.has_state == true. This is necessary since it could otherwise happen, that the state following the last Snapshot is actually not feasible (e.g. we could charge a storage by more than it’s state allows for). The equations are based on the construction of the overall state variable. $\( \begin{aligned} & \text{state}_{end} \cdot \text{factor}^\omega_t + \text{injection}_{end} \cdot \omega_t \geq \text{state}_{lb} \\ & \text{state}_{end} \cdot \text{factor}^\omega_t + \text{injection}_{end} \cdot \omega_t \leq \text{state}_{ub} \end{aligned} \)\( math Here \)\omega_t\( is the `weight` of `Snapshot` `t`, and \)\text{factor}$ is either 1.0 (if there are now percentage losses configured), or (1.0 - node.state_percentage_loss) otherwise. !!! note “Constraint safety” The lower and upper bound constraint are subject to penalized slacks.

nodalbalance

Add the constraint describing the nodal balance to the model. Depending on whether the node is stateful or not, this constructs different representations:

if node.has_state == true

\[\begin{split} > \begin{aligned} > & \text{state}_t = \text{state}_{t-1} \cdot \text{factor}^\omega_{t-1} + \text{injection}_{t-1} \cdot \omega_{t-1}, \qquad \forall t \in T \setminus \{1\} \\ > \\ > & \text{state}_1 = \text{state}_{end} \cdot \text{factor}^\omega_{end} + \text{injection}_{end} \cdot \omega_{end} > \end{aligned} > \end{split}\]

math Here \(\omega_t\) is the weight of Snapshot t, and \(\text{factor}\) is either 1.0 (if there are now percentage losses configured), or (1.0 - node.state_percentage_loss) otherwise. \(\text{injection}_{t}\) describes the overall injection (all feed-ins minus all withdrawals). \(end\) indicates the last snapshot in \(T\). Depending on the setting of state_cyclic the second constraint is written as \(=\) ("eq") or \(\leq\) ("leq"). The latter allows the destruction of excess energy at the end of the total time period to help with feasibility. if node.has_state == false

\[\begin{split} > \begin{aligned} > & \text{injection}_{t} = 0, \qquad \forall t \in T \\ > \end{aligned} > \end{split}\]

math This equation can further be configured using the nodal_balance parameter, which accepts enforce (resulting in \(=\)), create (resulting in \(\leq\); allowing the creation of energy - or “negative injections”), and destroy ( resulting in \(\geq\); allowing the destruction of energy - or “positive injections”). This can be used to model some form of energy that can either be sold (using a destroy Profile connected to this Node), or “wasted into the air” using the destroy setting of this Node.

state_bounds

Add the constraint defining the bounds of the node’s state to the model, if node.has_state == true. $\( \begin{aligned} & \text{state}_t \geq \text{state}_{lb}, \qquad \forall t \in T \\ & \text{state}_t \leq \text{state}_{ub}, \qquad \forall t \in T \end{aligned} \)$ math !!! note “Constraint safety” The lower and upper bound constraint are subject to penalized slacks.

Objectives