EnergyModelsX
EnergyModelsX (EMX) is a flexible multi-horizon energy system optimization framework using JuMP
. It utilizes TimeStruct
from the beginning and influenced some of the added features of TimeStruct
. Its implemtation is outlined in the following sections.
Implementation of the core structures
The core package EnergyModelsBase
differentiates between variables indexed over strategic periods and variables indexed over operational period, similar to the battery sizing example. As an example, consider the following two functions for variable declaration for a given 𝒯::TimeStructure
:
variables_capacity(m, 𝒩::Vector{<:Node}, 𝒳ᵛᵉᶜ, 𝒯, modeltype::EnergyModel)
with, among others,@variable(m, cap_use[𝒩ᶜᵃᵖ, 𝒯] >= 0) @variable(m, cap_inst[𝒩ᶜᵃᵖ, 𝒯] >= 0)
variables_opex(m, 𝒩::Vector{<:Node}, 𝒳ᵛᵉᶜ, 𝒯, modeltype::EnergyModel)
with, among others,𝒯ᴵⁿᵛ = strategic_periods(𝒯) @variable(m, opex_var[𝒩ᵒᵖᵉˣ, 𝒯ᴵⁿᵛ])
These two functions highlight the simplicity of using TimeStruct
as the individual time structures allow for iterations within JuMP
macros. In addition, it simplifies the index sets as changing the number of intermediate time structures through incorporating, e.g., OperationalScenarios
, does not require changes to the variable declarations. The change in the structure through the incorporation of the operational scenarios is instead available within the individual TimePeriod
type.
The same is also true for constraint functions as shown in constraints_capacity(m, n::Node, 𝒯::TimeStructure, modeltype::EnergyModel)
:
@constraint(m, [t ∈ 𝒯], m[:cap_use][n, t] <= m[:cap_inst][n, t])
Variables whose values are dependent on the previous operational period are only available for Storage
nodes. Its implementation is rather complex, but it is entirely relying on the withprev
functionality to decide whether it is the first operational period in a different TimeStructure
as well as how it must behave in this situation.
The individual operational periods are linked in EnergyModelsBase
through the internal function scale_op_sp
for the multiplication
\[duration(t) * multiple\_strat(t_{inv}, t) * probability(t)\]
where $t$ corresponds to an operational period and $t_{inv}$ to a strategic period.
Advanced utilization
withprev
and its application
As outlined, neither OperationalScenarios
or RepresentativePeriods
where available in the initial development of EMX. However, the adjustments towards including these were limited to constraints that require the previous periods, that is constraints declared through the withprev
functionality. All other constraints did not require any changes as the respective TimePeriod
s included the required information.
The implementation of the the Storage
level balance provides an example on how TimeStruct
can be used. It iterates through all potential subtypes of the given TimeStructure
. Multiple dispatch is included to identify whether the TimeStructure
includes OperationalScenarios
or RepresentativePeriods
. If this is the case, additional constraints can be incorporated. Due to the iteration (and storing) of all previous periods, it is possible to identify exactly what constraint should be utilized for the first operational period in a given TimeStructure
.
While it can be tempting to design models from the initial stage to include both operational scenarios and representative periods, it is beneficial to avoid including these. TimeStruct
simplifies the introduction of either TimeStructure
in a latter stage. It is hence significantly easier to develop a model without considering complex time structures.
If you do not have any constraints depending on the previous periods, you even do not have to do any changes to your model when including OperationalScenarios
or RepresentativePeriods
.
Chunks for unit commitment
The functionality of TimeStruct
for chunks based on the minimum required time is utilized in the unit commitment constraints of Reformer
nodes in EnergyModelsHydrogen
. In this context, we require a minimum time for starting the node, shutting the node down, and when the node is offline due to limitations in the dynamics of the chemical plant.
The used approach is similar to the Storage
level balance utilizing the withprev
functionality for the majority of the time structures. However, once on the lowest level, chunk_duration
is used in addition to provide limits on changes between the different states. The eltype
s of the iterator allows for further iterations to have access to the number of operational periods.
Including strategic uncertainty
EMX was not tested to also include strategic uncertainty as described in TwoLevelTree structure. The basic functionalities of EnergyModelsBase
and the majority of the developed packages do however not have any problems with incorporating strategic uncertainty as the strategic periods are not linked. In this case, the internal structure of TimeStruct
allows the direct inclusion of strategic uncertainty without changes to the model. The exception if when using the withprev
functionality on strategic periods as it is the case for the investments in EnergyModelsInvestments
. However, it is expected that the inclusion does not require any changes directly to the code structure due to the function overload on the withprev
functionality.