# Utilize `TimeStruct`

`EnergyModelsBase`

uses for the description of time the package `TimeStruct`

. `TimeStruct`

offers a large variety of different options that can appear to be overwhelming, when first exposed to them. Hence, it is important to highlight how it works and which parameters you would want to analyse.

## Structures for time description

`TimeStruct`

introduces individual structures that are used for describing time. In the following introduction, the most important structures are explained. There are other structures, but these will be added once `EnergyModelsbase`

supports their formulation.

### Operational periods

Operational periods correspond to periods in which no investments are allowed. In general, you can imagine operational periods to be the individual hours you want to model, although it is not limited to hours. In each operational period, we have an optimal dispatch problem given the constraints. Operational periods are normally implemented using the type `SimpleTimes`

which has the following structure:

```
op_duration = 1 # Each operational period has a duration of 1
op_number = 24 # There are in total 24 operational periods
operational_periods = SimpleTimes(op_number, op_duration)
```

In above's example, we assume that we have in total 24 operational periods which have the same duration each, *i.e.*, a duration of 1. The unit in itself is not important, but it can be either if you consider that a duration of 1 corresponds to one hour. In this case, the operational periods would correspond to a full day.

All operational periods are continuous. This implies that one is not allowed to have jumps in the representative periods. This affects all "dynamic" constraints, that is, constraints where the current operational period is dependent on the previous operational period. In `EnergyModesBase`

, this is only the case for the level balance in `RefStorage`

. Representative periods allow for jumps between operational periods, as outlined below.

Note that `TimeStruct`

does not require that each operational period has the same length. Consider the following example:

```
op_duration = [4, 2, 1, 1, 2, 4, 2, 1, 1, 2, 4]
op_number = length(op_duration)
operational_periods = SimpleTimes(op_number, op_duration)
# output
SimpleTimes{Int64}(11, [4, 2, 1, 1, 2, 4, 2, 1, 1, 2, 4])
```

In this case, we model the day not with hourly resolution, but only have hourly resolution in the morning and afternoon. The night has a reduced time resolution of 4 hours. However, we still model a full 24 hours as can be seen by the command

```
TimeStruct._total_duration(operational_periods)
# output
24
```

When having an `Array`

as input to `SimpleTimes`

, it is also not necessary to specify `op_number`

. Instead, one can also write

```
operational_periods = SimpleTimes(op_duration)
# output
SimpleTimes{Int64}(11, [4, 2, 1, 1, 2, 4, 2, 1, 1, 2, 4])
```

and a constructor will automatically deduce that there have to be 11 operational periods.

`SimpleTimes`

is also the lowest `TimeStructure`

that is present in `TimeStruct`

. It is used in all subsequent structures. When iterating over a `TimeStructure`

, *e.g.*, as `t ∈ operational_periods`

, you obtain the single operational periods that are required for solving the optimal dispatch.

Energy conversion, production, or emissions of a node as well as all flows are always defined for a duration of length 1 in operational periods. You have to be careful when considering the output from the model. The same holds for capacities provided in the input file.

### Representative periods

Representative periods are introduced through the structure `RepresentativePeriods`

. Representative periods correspond to a repetition of different periods. This is a change from `SimpleTimes`

in which a single period is scaled.

Consider the following example:

`day = SimpleTimes(24, 1)`

This example can represent a single day with hourly resolution. In practice, when including the `day`

into a `TwoLevel`

, it is scaled multiple times. This can lead to an underestimation of storage requirements and makes it impossible to include seasonal storage.

Representative periods can be included through creating multiple instances of `SimpleTimes`

. The following example creates two days with hourly resolution, one winter day and one summer day. These two days are the combined into a `RepresentativePeriod`

with 2 periods. These two periods sum up to a duration of 8760, that is a year. Each representative period is scaled up `365/2=182.5`

times.

```
winter_day = SimpleTimes(24, 1)
summer_day = SimpleTimes(24, 1)
periods = 2 # Number of representative periods
total_duration = 8760 # Total duration
share = [0.5, 0.5] # Share of the total duration of the representative periods
rps = RepresentativePeriods(periods, total_duration, share, winter_day, summer_day)
```

Representative periods only affect the system if storage is included. In the case of storage, this scaling impacts the initial level of the storage in representative periods. Otherwise, the application of `SimpleTimes`

suffices.

### Strategic periods

Strategic periods are introduced through the structure `TwoLevel`

. They correspond to the periods in which changes in capacity, efficiency, or operational expenditures can occur. The general structure is given by

```
day = SimpleTimes(24, 1)
strategic_duration = 5 # Each strategic period has a duration of 5
strategic_number = 5 # here are in total 5 strategic periods
T = TwoLevel(strategic_number, strategic_duration, day)
```

The example above corresponds to 5 strategic periods with a duration of 5 in each strategic period. Each strategic period includes 24 operational periods. One can choose any reference duration for a strategic period and the corresponding duration of an operational period. In above's example, there is no specified link between the duration of 1 of an operational period and a duration of 1 of a strategic period. `TwoLevel`

assumes in this situation that the link is 1, that is both the strategic periods and the operational periods have the same duration.

In general, it is easiest to use a duration of 1 of a strategic period to be equivalent to a single year while a duration of 1 of an operational period should correspond to 1 hour. In this case, we have to specifiy `TwoLevel`

slightly differently:

`𝒯 = TwoLevel(strategic_number, strategic_duration, day; op_per_strat=8760)`

Note, that we used in this example the optional keyword argument `op_per_strat`

which links the duration 1 of an operational period to the duration 1 of a strategic period. If we would like to have a duration of 1 in an operational period corresponding to an hour and a duration of 1 in a strategic period to a year, we need to use the value `op_per_strat = 365*24 = 8760`

.

It is important to be certain which value one should use for `op_per_strat`

. When using the wrong value, one obtains wrong operational results that may affect the analysis.

Similar to the `SimpleTimes`

structure, it is possible to also have strategic periods of varying durations. It can be advantageous to, *e.g.*, have a reduced duration in the initial investment periods, while having an increased duration in the latter. This would allow to reflect the higher uncertainty associated with future decisions and improve computational tractability by reducing model instance size.

You can extract an iterator for the individual strategic periods by using the command:

`𝒯ᴵⁿᵛ = strategic_periods(𝒯)`

When iterating through 𝒯ᴵⁿᵛ, you obtain the individual strategic periods. When iterating through a strategic period, you obtain the individual operational periods:

```
for t_inv ∈ 𝒯ᴵⁿᵛ, t ∈ t_inv end
# is equivalent to
for t ∈ 𝒯 end
```

The advantage of approach 1 is that you can also use the indices of the strategic period. However, it may make the code look more complicated, when this is not required. It does not have any implication on the model building speed and it is up to the user, which approach to choose.

Fixed operational expenditures and emission limits provided to a model have to be provided for a duration of 1 in the strategic period.

### Summary

In the standard case, it is recommended to use **hour** as duration 1 of operational period and **year** as duration 1 of a strategic period. This still allows to utilize a higher resolution, like *e.g.* 15 minutes or less through specifying a duration of 0.25 for these operational periods, but it simplifies the overall design.

```
day = SimpleTimes(24, 1)
strategic_duration = 5 # Each strategic period has a duration of 5
strategic_number = 5 # here are in total 5 strategic periods
𝒯 = TwoLevel(strategic_number, strategic_duration, day; op_per_strat=8760)
```

This is especially relevant for capacities and emission limits, as well as anlysing the values obtained from the model.

## Profiles

Profiles are used for providing parameters to the model. There are in general three main profiles, that have to be considered:

`FixedProfile`

represents using the same value in all periods,`OperationalProfile`

represents using the same profile in all strategic periods, although there can be variations in the individual strategic periods,`RepresentativeProfile`

represents a profile that differes in the individual representative periods, and`StrategicProfile`

represents using different values in the strategic periods.

### FixedProfile

`FixedProfile`

is the simplest profile. It represents a constant value over the whole modelling horizon. Its application is given by:

`profile = FixedProfile(10)`

This would provide a value of `10`

in all operational periods in all strategic periods.

### OperationalProfile

`OperationalProfile`

is used when there are operational variations. Consider the following example time structure, corresponding to 5 strategic periods, each with a duration of 5 years, and 24 operational periods, each with a duration of 24 hours.

`𝒯 = TwoLevel(5, 5, SimpleTimes(24, 1); op_per_strat=8760)`

In this case, we would need to define an `OperationalProfile`

as an array with length 24:

`op_profile = OperationalProfile(collect(1:1.0:24))`

The example has a progressively increasing value going from 1 in the first hour to 24 in the last hour. `collect`

is in this example required to obtain the value as array.

`OperationalProfile`

is normally used for varying demand or profiles for renewable power generation.

It is possible to have an `OperationalProfile`

that is shorter or longer than the profile in the time structure. If the profile is shorter, then the last value is repeated. If the profile is longer, then the last values are ommitted. `EnergyModelsBase`

provides the user with a warning if one of above's cases are present

It is hence strongly advise to use an `OperationalProfile`

with the same length.

### RepresentativeProfile

`RepresentativeProfile`

s can be included in the case of `RepresentativePeriods`

. Each profile in the structure corresponds to the respective representative period.

Consider the following time structure,

```
winter_day = SimpleTimes(24, 1)
summer_day = SimpleTimes(24, 1)
op = RepresentativePeriods(2, 8760, [0.5, 0.5], winter_day, summer_day)
𝒯 = TwoLevel(5, 5, ; op_per_strat=8760)
```

in which two days with hourly resolution are scaled up 182.5 times each. The corresponding profiles then can look like the following:

```
profile_winter = OperationalProfile(collect(range(1, stop=24, length=24)))
profile_summer = FixedProfile(0)
demand = RepresentativeProfile([profile_winter, profile_summer])
```

This implies that we can use both `OperationalProfile`

and `FixedProfile`

combined. The only requirement is that if one is using Integer input, then the other also has to use Integer input.

It is possible to use `RepresentativeProfile`

without `RepresentativePeriods`

. In this case, the first provided profile is used.

`EnergyModelsBase`

provides the user with a warning if this is the case.

### StrategicProfile

`StrategicProfile`

is used when there are strategic variations. Considering the same example time structure,

`𝒯 = TwoLevel(5, 5, SimpleTimes(24, 1); op_per_strat=8760)`

we can define a `StrategicProfile`

as:

`strat_profile = StrategicProfile([1, 2, 3, 4, 5])`

In this case, we have variations between the strategic periods, but use the same value in all operational periods within a strategic period, that is all operational periods in strategic period 1 would use a value of 1, while the once in strategic period 2 a value of 2, and so on. This implementation is frequently used for changing capacities or efficiencies.

It is also possible to have both variations on the strategic and operational level. A `StrategicProfile`

then takes an Array of `OperationalProfile`

s as input:

```
op_profile_1 = OperationalProfile(rand(24))
op_profile_2 = OperationalProfile(rand(24))
op_profile_3 = OperationalProfile(rand(24))
op_profile_4 = OperationalProfile(rand(24))
op_profile_5 = OperationalProfile(rand(24))
strat_profile = StrategicProfile([op_profile_1, op_profile_2, op_profile_3, op_profile_4, op_profile_5])
```

This approach is frequently used for demands where there are changes both on the operational level (*e.g.*, hour) and strategic level (*e.g.*, year).

It is similarly possible to include `RepresentativeProfile`

s.