Temporal#
The scope of the model/problem, in the case of energy systems modeling, describes the spatiotemporal extent of the system. In Energia, Time and Space are discretized independently.
This tutorial discusses the definition of time. It is important to note that overall temporal span (horizon) is the same for all temporal scales, they differ only in the number of discretizations (cardinality of the set). In the context of data-driven modeling, this can be construed as the frequency of sampling information.
Library Initialization#
The initialization time_units from energia.library.components can be used
from energia import Model, time_units
m = Model(init=[time_units])
m.time.periods
[s, min, h, d, y]
Bespoke Definition#
There are three ways to define temporal scales
1. Using the Model.TemporalScales function#
from energia import Model
m = Model()
m.TemporalScales([1, 365, 24, 60, 60], ['y', 'd', 'h', 'min', 's'])
m.time.periods
[s, min, h, d, y]
2. Using TemporalScales object#
from energia import Model, TemporalScales
m = Model()
m.scales = TemporalScales([1, 365, 24, 60, 60], ['y', 'd', 'h', 'min', 's'])
m.time.periods
[s, min, h, d, y]
3. Using Periods#
This provides more flexibility in definition, as periods can be defined relationally
Note that Model.periods can be used directly instead of Model.time.periods
from energia import Model, Periods
m = Model()
m.h = Periods(label='hours')
m.d = 24 * m.h
m.y = 365 * m.d
m.m = m.h / 60
m.periods
[h, d, y, m]
m.h.howmany(m.m)
# m.y.howmany(m.h)
60.0
Horizon#
The horizon is the temporal extent of the modeling exercise.
In Energia, this is just the set of periods with the least cardinality, i.e. the most sparsely discretized set or \(\hat{\mathcal{T}} = arg \text{ } max_{t \in \mathcal{T}^{}} |t|\)
m.horizon
y
Each period in the set is treated as “point” rather than a “span”. There could be cases where two temporal scales with the same number of discretizations (with respect to a common root/horizon, or the horizon itself) could be needed as they represent different sampling timestamps. This has however not been implemented yet.
Indices#
.I gives a tupled index which shows where the temporal period lies
m.h.I
(y, d, h)
Use .i to get the index of the Period/Lag solely
m.h.i
h
Comparison#
Note that all these are using defining procedure “3. Using Periods”
Like Unit, time periods can also be compared using .howmany as shown
m.y.tree, m.m.tree
({y: {d: {h: {}}}}, {m: {h: {}}})
m.y.howmany(m.m)
525600.0
Note that that all Periods have been defined with m.h as the basis.
Thus, minutes (m.m) is defined as a fraction of hours (m.h)
m.m.size, m.m.of
(0.016666666666666666, h)
A convenient way to check how they map is using m.time.tree
Trees always provides a comparison on the basis of the horizon
m.time.tree
{8760: h, 365: d, 1: y, 525600: m}
Search#
A period set of appropriate cardinality can be found using m.time.find
m.time.find(365)
d
Auto-generation#
The laziest way to handle time is if you do not declare any Periods and let Energia declare them based on the cardinality of the parameter sets being passed. This is however prone to modeling error if working with numerous scales. A UserWarning is provided when a new set is created. For single period problems, it is safe to let Energia generate the temporal scale which itself serves as the horizon
m.time.find(2666)
m.periods
💡 Generating period set t4 of size 2666
[h, d, y, m, t4]
Lag#
Lag can be provided in data input, for attributes such as construction lag or production time. Time is essentially treated as a resource.
lag = -3 * m.d
lag, type(lag)
(-3d, energia.components.temporal.lag.Lag)
Lag objects are not saved and are only used to write appropriate constraints. In the example, the index set (.i) is pushed 3 time steps forward
m.d.i._[:5], lag.i._[:5]
([d[0], d[1], d[2], d[3], d[4]], [None, None, None, d[0], d[1]])