How does SpineOpt perceive time?
This section answers the following questions:
- What are time slices?
- What are time slice convenience functions?
- How can they be used?
What are time slices?
A TimeSlice
is simply a slice of time with a start and an end. We use them in SpineOpt to represent the temporal dimension.
More specifically, we build the model using TimeSlice
s for the temporal indices. This happens in the run_spineopt function and it's done in two steps:
- Generate the temporal structure for the model:
- Translate the temporal_blocks in the input DB to a set of
TimeSlice
objects. - Create relationships between these
TimeSlice
objects:- Relationships between two consecutive time slices (
t_before
ending right whent_after
starts). - Relationship between overlapping time slices (
t_short
contained int_long
).
- Relationships between two consecutive time slices (
- Store all the above within
m.ext[:spineopt].temporal_structure
.
- Translate the temporal_blocks in the input DB to a set of
- Build the model:
- Query
m.ext[:spineopt].temporal_structure
to collect generatedTimeSlice
objects and relationships. - Use them for indexing variables and generating constraints and objective.
- Query
To translate the temporal_blocks into TimeSlice
objects, we basically look at the value of model_start and model_end for the model object, as well as the value of the resolution for the different temporal_block objects. Then we build as many TimeSlice
s as needed to cover the period between model_start and model_end at each resolution.
m
is the JuMP.Model
object that SpineOpt builds and solves using JuMP
. It has a field called ext
which is a Dict
where one can store custom data. m.ext[:spineopt].temporal_structure
is just another Dict
where we store data related to the temporal structure.
What are the time slice convenience functions?
To facilitate querying the temporal structure, we have developed the following convenience functions:
To further figure out what the time slice convenience functions do, you can play around with them. To do so, you first need to make a database (e.g. in Spine Toolbox). Then you can call run_spineopt
with that database and collect the model m
. If you are impatient you do not even need to solve the model, you can pass optimize=false
as keyword argument to run_spineopt
. And then you can start calling the time slice convenience functions with m
(e.g. t_in_t
).
How can the time slice convenience functions be used?
When building constraints you typically want to know which TimeSlice
s come after/before another, overlap another, or contain/are contained in another. You can obtain this type of info by calling the above convenience functions.
For example, say you're generating a constraint at a 3-hour resolution. This means you have a TimeSlice
in your constraint index, and that TimeSlice
covers 3 hours. Now, say you want to sum a certain variable over those 3 hours in your constraint expression. You need to know all the TimeSlice
s contained in the one from your constraint index. You can find this out by calling t_in_t with it.
More information can be found in the Write a constraint for SpineOpt section.
A fool proof way of writing a constraint - that may not be the most efficient - is to always take the highest resolution among the overlapping TimeSlice
s to generate the constraint indices. The other TimeSlice
s can then be obtained from t_overlaps_t.