# Time series

## Time series modeling

In Powsybl, time series are modeled by:

- A name to uniquely identify a time series inside a store.
- A data type which is either
`double`

or`String`

. - A time index to define a list of instants for which data exists. Three different implementations of the time index are available
in the framework, depending on the need:
- Regular index: the time step size is constant
- Irregular index: the time step size varies
- Infinite index: the time series contains only two points, one at instant 0 and another at instant
`Long.MAX_VALUE`

- Metadata: a list of key/value string data
- Data chunks: an ordered list of data that will be associated to instants of the time index. The data chunks may be compressed or uncompressed.

An uncompressed JSON data chunk looks like:

```
{
"offset" : 0,
"values" : [ 1.0, 1.0, 1.0, 3.0 ]
}
```

We can see that an uncompressed data chunk is modeled with a double (or String) array and an offset.
It defines values associated to instants of the time index from `offset`

to `offset + values.length`

.

It is possible to compress the data chunks, using for example the RLE. The JSON serialization of compressed data chunks looks like: Output:

```
{
"offset" : 0,
"uncompressedLength" : 4,
"stepValues" : [ 1.0, 3.0 ],
"stepLengths" : [ 3, 1 ]
}
```

Time series can be imported from CSV data.

## Calculated time series

Starting from a double time series, it is possible to create calculated time series using a Groovy script.

For instance, let us consider the the following example.
Let’s say we have created a first double time series named `dts`

in a script, it is then possible to create new time series `a`

and `b`

by writing:

```
ts['a'] = ts['dts'] + 1
ts['b'] = ts['a'] * 2
```

The time series `a`

and `b`

, serialized in JSON format, then look like:

```
[ {
"name" : "a",
"expr" : {
"binaryOp" : {
"op" : "PLUS",
"timeSeriesName" : "dts",
"integer" : 1
}
}
}, {
"name" : "b",
"expr" : {
"binaryOp" : {
"op" : "MULTIPLY",
"binaryOp" : {
"op" : "PLUS",
"timeSeriesName" : "dts",
"integer" : 1
},
"integer" : 2
}
}
} ]
```

Indeed, the calculated time series are evaluated on the fly during array conversion or iteration (through iterators or streams): only the arithmetic expression is stored.

Here is the list of supported vector operations:

Operator | Purpose | Example |
---|---|---|

+ | addition | ts[‘a’] + ts[‘b’] |

- | substraction | ts[‘a’] - ts[‘b’] |

* | multiplication | ts[‘a’] * ts[‘b’] |

/ | division | ts[‘a’] / ts[‘b’] |

== | 1 if equals, 0 otherwise | ts[‘a’] == ts[‘b’] |

!= | 1 if not equals, 0 otherwise | ts[‘a’] != ts[‘b’] |

< | 1 if less than, 0 otherwise | ts[‘a’] < ts[‘b’] |

<= | 1 if less than or equals to, 0 otherwise | ts[‘a’] <= ts[‘b’] |

> | 1 if greater, 0 otherwise | ts[‘a’] > ts[‘b’] |

>= | 1 if greater than or equals to, 0 otherwise | ts[‘a’] >= ts[‘b’] |

- | negation | -ts[‘a’] |

abs | absolute value | ts[‘a’].abs() |

time | convert to time index vector (epoch) | ts[‘a’].time() |

min | min value | ts[‘a’].min(10) |

max | max value | ts[‘a’].max(10) |

About the Groovy DSL syntax, both `timeSeries['a']`

and `ts['a']`

are supported and are equivalent.

To compare a time index vector to a literal date, the `time('2018-01-01T00:00:01Z')`

function is available. For instance, the
following code create a time series of 0 and 1 values:

```
a = ts['dts'].time() < time('2018-01-01T00:00:01Z')
```