Optimization variables
EnergyModelsBase
creates a variety of default variables for the individual nodes and edges. These default variables are in general also created when new Node
s or Link
s are developed. It is not necessary to utilize all of the default variables in the individual nodes. It is however recommended to include in this situation constraints or fixes using either the @constraint
macro or alternatively the JuMP
function fix(x, value)
. The latter is the recommended approach.
The majority of the variables in EnergyModelsBase
are rate variables. This imples that they are calculated for either an operational period duration of 1, when indexed over operational period $t$ or a strategic period duration of 1, when indexed over strategic period $t_\texttt{inv}$. Typical units for rates are MW for energy streams, tonne/hour for mass streams, tonne/year for strategic emissions, and €/year for operational expenditures. In this example, the duration of an operational period of 1 corresponds to an hour, while the duration of a strategic period of 1 corresponds to a year.
Variables that are energy/mass based have that property highlighted in the documentation below. In the standard implementation of EnergyModelsBase
, this is only the case for the level of a Storage
node, the change of level of the node, and its installed capacity.
Rate variables can as well be translated to mass/energy variables. As an example, the total quantity that flows into a node $n$ during the operational period $t$ can found by
m[:flow_in][n, t, p] * duration(t)
The multiplication then leads to an energy/mass quantity in stead of an energy/mass flow.
The coupling of strategic and operational periods can be achieved through the function scale_op_sp(t, t_inv)
. This functions allows for considering the scaling of the operational periods within a strategic period.
Operational cost variables
Operational cost variables are included to account for operational expenditures (OPEX) of the model. These costs are pure dependent on either the use or the installed capacity of a node $n$. All nodes $n$ (except Availability
-nodes) have the following variables representing the operational costs of the nodes:
- $\texttt{opex\_var}[n, t_\texttt{inv}]$: Variable OPEX of node $n$ in strategic period $t_\texttt{inv}$.
- $\texttt{opex\_fixed}[n, t_\texttt{inv}]$: Fixed OPEX of node $n$ in strategic period $t_\texttt{inv}$.
The variable OPEX is a cost that derives from using a technology. It is calculated using the function constraints_opex_var
. In general, it represents unmodelled feed to a process and the associated costs. Examples are catalyst replacement, cooling water or process water. The variable OPEX can also be utilized to provide values for a profit through using a technology.
The fixed OPEX is a cost that is independent of the usage of a technology. Instead, it is only dependent on the installed capacity. It is calculated using the function constraints_opex_fixed
. It represents fixed costs like labour cost, maintenance, as well as insurances and taxes.
We also introduce the potential for links with operational costs. By default, links do not introduce new variables. Operational cost variables are only created for a link $l$ if the function has_opex(n::Link)
returns true
. The following link variables are then declared representing the operational costs of the links:
- $\texttt{link\_opex\_var}[l, t_\texttt{inv}]$: Variable OPEX of link $l$ in strategic period $t_\texttt{inv}$.
- $\texttt{link\_opex\_foxed}[l, t_\texttt{inv}]$: Fixed OPEX of link $l$ in strategic period $t_\texttt{inv}$.
All links introduced in EnergyModelsBase
do not allow for operational costs. If you plan to introduce a link with operational costs, you have to create a new method for the function has_opex
for your introduced link.
Capacity variables
Capacity variables focus on both the capacity usage and installed capacity. The capacity variables are also created for all nodes except for Availability
nodes. Capacity variables are differentiated between Storage
nodes and all other Node
s. The implementation of the capacity variables allows for a time-varying capacity during an operational period for inclusion of variations in the demand in Sink
nodes. It is however not possible to invest into a time-varying capacity.
The following capacity variables are created for node types other than Storage
:
- $\texttt{cap\_use}[n, t]$: Absolute capacity usage of node $n$ at operational period $t$, and
- $\texttt{cap\_inst}[n, t]$: Installed capacity of node $n$ at operational period $t$.
The capacity usage $\texttt{cap\_use}$ is the utilization of the installed capacity. It is declared in absolute values to avoid bilinearities when investing in capacities. It is normally constrained by the variable $\texttt{cap\_inst}$ of the individual nodes, except for Sink
nodes.
The capacity variables for Storage
nodes differentiate between storage capacity (stored energy in the Storage
node) and rate of storage (storage rate of a Storage
node). The latter is furthermore differentiated between charging and discharging a Storage
node. A key reasoning for this approach is that it is in general possible to invest both in the storage rate (e.g., the AC-DC transformer required in battery storage) as well as the storage capacity (e.g. the number of cells in battery storage). The same holds as well for pumped hydro storage and storage of gases where there is a further differentiation between the maximum charging and discharging rates. The differentiation leads to the following variables for Storage
nodes:
- $\texttt{stor\_level}[n, t]$: Absolute level of energy/mass stored in a
Storage
node $n$ at operational period $t$ with a typical unit of GWh or t, - $\texttt{stor\_level\_inst}[n, t]$: Installed storage capacity in a
Storage
node $n$ at operational period $t$ , that is the upper bound for the variable $\texttt{stor\_level}[n, t]$, with a typical unit of GWh or t, - $\texttt{stor\_charge\_use}[n, t]$: Usage of the charging rate of a
Storage
node $n$ at operational period $t$ with a typical unit of GW or t/h, - $\texttt{stor\_charge\_inst}[n, t]$: Maximum available charging rate of a
Storage
node $n$ at operational period $t$, that is the upper bound for the variable $\texttt{stor\_charge\_use}[n, t]$, with a typical unit of GW or t/h. - $\texttt{stor\_discharge\_use}[n, t]$: Usage of the discharging rate of a
Storage
node $n$ at operational period $t$ with a typical unit of GW or t/h, and - $\texttt{stor\_discharge\_inst}[n, t]$: Maximum available discharging rate of a
Storage
node $n$ at operational period $t$, that is the upper bound for the variable $\texttt{stor\_discharge\_use}[n, t]$, with a typical unit of GW or t/h.
It is not necessary that a Storage
node has a charge and discharge capacity. It is possible to not specify a capacity for charge and discharge. In this instance, the variables for the intalled capacities are omitted and the charge and discharge usage is unlimited.
The storage level is always defined for the end of the operational period it is indexed over. There are in addition two variables for the storage level that behave slightly different:
- $\texttt{stor\_level\_Δ\_op}[n, t]$: Change of the absolute level of energy/mass stored in a
Storage
node $n$ in operational period $t$ with a typical unit of GWh or t, and - $\texttt{stor\_level\_Δ\_rp}[n, t_{rp}]$: Change of the absolute level of energy/mass stored in a
Storage
node $n$ in representative period $t_{rp}$ with a typical unit of GWh or t, and - $\texttt{stor\_level\_Δ\_sp}[n, t_\texttt{inv}]$: Change of the absolute level of energy/mass stored in a
Storage
node $n$ in strategic period $t_\texttt{inv}$ with a typical unit of GWh or t.
These variables are introduced to track the change in the storage level in an operational period, a representative period, or an investment period, respectively. They can be considered as helper variables to account for the duration of the operational period as well as the total change within a representative period. $\texttt{stor\_level\_Δ\_rp}$ is only declared if the TimeStructure
includes RepresentativePeriods
while $\texttt{stor\_level\_Δ\_sp}$ is introduced as an empty SparseVariables
container. The application of RepresentativePeriods
is explained in How to use TimeStruct.jl. The utilization of $\texttt{stor\_level\_Δ\_sp}$ requires to include in the function variables_node
for the given Storage
array 𝒩ˢᵘᵇ::Vector{<:NewStorageNode}
as, e.g., the following loop
for t_inv ∈ 𝒯ᴵⁿᵛ, n ∈ 𝒩ˢᵘᵇ
insertvar!(m[:stor_level_Δ_sp], n, t_inv)
end
We also introduce the potential for links with capacities. By default, links do not introduce new variables. The capacity variable is only created for a link $l$ if the function has_capacity(n::Link)
returns true
. The following link variable ise then declared representing the capacity of links:
- $\texttt{link\_cap\_inst}[l, t]$: Installed capacity of link $l$ at operational period $t$.
All links introduced in EnergyModelsBase
do not allow for a capacity limiting the transfer. If you plan to introduce a link with a capacity, you have to create a new method for the function has_capacity
for your introduced link.
The variables $\texttt{cap\_inst}$, $\texttt{stor\_charge\_inst}$, $\texttt{stor\_level\_inst}$, $\texttt{stor\_discharge\_inst}$, and $\texttt{link\_cap\_inst}$ are used in EnergyModelsInvestment
to allow for investments in capacity of individual nodes.
Flow variables
Flow variables correspond to the input to and output from both technology nodes and links. They are always positive to avoid backflow.
The following flow variables are defined for the nodes:
- $\texttt{flow\_in}[n, t, p]$ represents the flow rate of resource $p$ into node $n$ at operational period $t$. It is created for subtypes of the types
NetworkNode
andSink
based on the fieldinput
in thecomposite type
. - $\texttt{flow\_out}[n, t, p]$ represents the flow rate of resource $p$ out of node $n$ at operational period $t$. It is created for subtypes of the types
Source
andNetworkNode
based on the fieldoutput
in thecomposite type
.
Links also have corresponding flow variables given by:
- $\texttt{link\_in}[n, t, p]$ represents the flow rate of resource $p$ into link $l$ at operational period $t$, and
- $\texttt{link\_out}[n, t, p]$ represents the flow rate of resource $p$ out of link $l$ at operational period $t$.
The resource index $p$ is created based on the intersection of the output of the input node $n_{in}$ and the input of the output node $n_{out}$ through the function EMB.link_res(l::Link)
. Mathematically, this is given as
$\mathcal{P}^{link} = \mathcal{P}^{n^{out}_{in}} \cap \mathcal{P}^{n^{in}_{out}}.$
It is also possible to create a new method for this function to limit the resources a link can transport.
Emission variables
Emission variables are used for accounting for emissions of the individual technologies. Resources that can be emitted are defined through the type ResourceEmit
. Nodes do not necessarily have associated emission variables. Emission variables are only created for a node $n$ if the function has_emissions(n::EMB.Node)
returns true
. This is the case for all nodes that have EmissionsData
within their field data
as well as for a RefStorage
node if a ResourceEmit
is stored. The following node variable is then declared for all emission resource 𝒫ᵉᵐ:
- $\texttt{emissions\_node}[n, t, p_\texttt{em}]$: Emissions of node $n$ at operational period $t$ of emission resource $p_\texttt{em}$.
Similarly, it is not necessary that links have associated emission variables. Emission variables are only created for a link $l$ if the function has_emissions(n::Link)
returns true
. The following link variable is then declared for all emission resource 𝒫ᵉᵐ:
- $\texttt{emissions\_link}[n, t, p_\texttt{em}]$: Emissions of link $l$ at operational period $t$ of emission resource $p_\texttt{em}$.
All links introduced in EnergyModelsBase
do not allow for emissions. If you plan to introduce a link with emissions, you have to create a new method for the function has_emissions
for your introduced link.
We have not implemented a similar approach as for nodes. It is however planned to allow for transmission emissions in the near future, similar to the concept employed for process emissions for nodes.
In addition, EnergyModelsBase
declares the following variables for the global emissions:
- $\texttt{emissions\_total}[t, p_\texttt{em}]$: Total emissions of
ResourceEmit
$p_\texttt{em}$ in operational period $t$, and - $\texttt{emissions\_strategic}[t_\texttt{inv}, p_\texttt{em}]$: Total emissions of
ResourceEmit
$p_\texttt{em}$ in strategic period $t_\texttt{inv}$.
These emission variables introduce limits on the total emissions of a resource through the field emission_limit
of an EnergyModel
in the function EMB.variables_emission
.
Sink
variables
Sink
nodes are somehow different to the other nodes as they have additional variables associated with them. A key point here is to keep the overall mass balance intact while allowing for both overfulfilling and not meeting the demand. These variables are:
- $\texttt{sink\_surplus}[n, t]$: Surplus of energy/mass to
Sink
$n$ at operational period $t$, and - $\texttt{sink\_deficit}[n, t]$: Deficit of energy/mass to
Sink
$n$ at operational period $t$.
The surplus in a sink corresponds to the energy/mass that is supplied to the sink in addition to the demand. The deficit in a sink corresponds to the energy/mass that is not supplied to the sink although the demand is specified. Both variables correspond to slack variables of the optimization problem. They simplify the problem and can make certain types of formulations feasible. It is possible to provide penalties for both surplus and deficits. This is implemented through the field penalty
in the RefSource
node.
Node types and respective variables
As outlined in the introduction, EnergyModelsBase
declares different variables for each Node
. These variables are for the individual nodes given in the subsections below.
Source
- $\texttt{opex\_var}$
- $\texttt{opex\_fixed}$
- $\texttt{cap\_use}$
- $\texttt{cap\_inst}$
- $\texttt{flow\_out}$
- $\texttt{emissions\_node}$ if
EmissionsData
is added to the fielddata
NetworkNode
, except for Storage
- $\texttt{opex\_var}$
- $\texttt{opex\_fixed}$
- $\texttt{cap\_use}$
- $\texttt{cap\_inst}$
- $\texttt{flow\_in}$
- $\texttt{flow\_out}$
- $\texttt{emissions\_node}$ if
EmissionsData
is added to the fielddata
Storage
- $\texttt{opex\_var}$
- $\texttt{opex\_fixed}$
- $\texttt{stor\_level}$
- $\texttt{stor\_level\_inst}$
- $\texttt{stor\_charge\_use}$
- $\texttt{stor\_charge\_inst}$, if the
Storage
node has a field:charge
with theStorageParameters
corresponding to capacity storage parameters - $\texttt{stor\_discharge\_use}$
- $\texttt{stor\_discharge\_inst}$, if the
Storage
node has a field:discharge
with theStorageParameters
corresponding to capacity storage parameters - $\texttt{stor\_level\_Δ\_op}$
- $\texttt{stor\_level\_Δ\_rp}$ if the
TimeStruct
includesRepresentativePeriods
- $\texttt{stor\_level\_Δ\_sp}$ if the function
variables_node
is declared for the newStorage
type - $\texttt{flow\_in}$
- $\texttt{flow\_out}$
- $\texttt{emissions\_node}$ if
ResourceEmit
is stored
Sink
- $\texttt{opex\_var}$
- $\texttt{opex\_fixed}$
- $\texttt{cap\_use}$
- $\texttt{cap\_inst}$
- $\texttt{flow\_in}$
- $\texttt{sink\_surplus}$
- $\texttt{sink\_deficit}$
- $\texttt{emissions\_node}$ if
EmissionsData
is added to the fielddata