flexmeasures.utils.calculations

Various calculations

Functions

flexmeasures.utils.calculations.apply_stock_changes_and_losses(initial: float, changes: list[float], storage_efficiency: float | list[float], how: str = 'linear', decimal_precision: int | None = None) list[float]

Assign stock changes and determine losses from storage efficiency.

The initial stock is exponentially decayed, as with each consecutive (constant-resolution) time step, some constant percentage of the previous stock remains. For example:

\[100 \rightarrow 90 \rightarrow 81 \rightarrow 72.9 \rightarrow ...\]

For computing the decay of the changes, we make an assumption on how a delta \(d\) is distributed within a given time step. In case it happens at a constant rate, this leads to a linear stock change from one time step to the next.

An \(e\) is introduced when we apply exponential decay to that. To see that, imagine we cut one time step in \(n\) pieces (each with a stock change \(\frac{d}{n}\) ), apply the efficiency to each piece \(k\) (for the corresponding fraction of the time step \(k/n\)), and then take the limit \(n \rightarrow \infty\):

\[\lim_{n \rightarrow \infty} \sum_{k=0}^{n}{\frac{d}{n} \eta^{k/n}}\]

which is:

\[d \cdot \frac{\eta - 1}{e^{\eta}}\]
Parameters:
  • initial – initial stock

  • changes – stock change for each step

  • storage_efficiency – ratio of stock left after a step (constant ratio or one per step)

  • how – left, right or linear; how stock changes should be applied, which affects how losses are applied

  • decimal_precision – Optional decimal precision to round off results (useful for tests failing over machine precision)

flexmeasures.utils.calculations.drop_nan_rows(a, b)
flexmeasures.utils.calculations.integrate_time_series(series: pd.Series, initial_stock: float, up_efficiency: float | pd.Series = 1, down_efficiency: float | pd.Series = 1, storage_efficiency: float | pd.Series = 1, decimal_precision: int | None = None) pd.Series

Integrate time series of length n and inclusive=”left” (representing a flow) to a time series of length n+1 and inclusive=”both” (representing a stock), given an initial stock (i.e. the constant of integration). The unit of time is hours: i.e. the stock unit is flow unit times hours (e.g. a flow in kW becomes a stock in kWh). Optionally, set a decimal precision to round off the results (useful for tests failing over machine precision).

>>> s = pd.Series([1, 2, 3, 4], index=pd.date_range(datetime(2001, 1, 1, 5), datetime(2001, 1, 1, 6), freq=timedelta(minutes=15), inclusive="left"))
>>> integrate_time_series(s, 10)
    2001-01-01 05:00:00    10.00
    2001-01-01 05:15:00    10.25
    2001-01-01 05:30:00    10.75
    2001-01-01 05:45:00    11.50
    2001-01-01 06:00:00    12.50
    Freq: D, dtype: float64
>>> s = pd.Series([1, 2, 3, 4], index=pd.date_range(datetime(2001, 1, 1, 5), datetime(2001, 1, 1, 7), freq=timedelta(minutes=30), inclusive="left"))
>>> integrate_time_series(s, 10)
    2001-01-01 05:00:00    10.0
    2001-01-01 05:30:00    10.5
    2001-01-01 06:00:00    11.5
    2001-01-01 06:30:00    13.0
    2001-01-01 07:00:00    15.0
    dtype: float64
flexmeasures.utils.calculations.mean_absolute_error(y_true: ndarray, y_forecast: ndarray)
flexmeasures.utils.calculations.mean_absolute_percentage_error(y_true: ndarray, y_forecast: ndarray)
flexmeasures.utils.calculations.weighted_absolute_percentage_error(y_true: ndarray, y_forecast: ndarray)