Optimization Input#

How to access aggregation results for energy system optimization models.

This notebook shows how to access:

  • Cluster weights (occurrence counts)

  • Cluster assignments (period ordering)

  • Typical period data

Import pandas and the relevant time series aggregation class

[1]:
%load_ext autoreload
%autoreload 2

import pandas as pd
import plotly.express as px

import tsam
from tsam import ClusterConfig, ExtremeConfig

Input data#

Read in time series from testdata.csv with pandas

[2]:
raw = pd.read_csv("testdata.csv", index_col=0)

Transform the index to a datetime index

[3]:
raw.index = pd.to_datetime(raw.index)

Plot raw data

[4]:
fig = px.line(
    raw, facet_row="variable", labels={"index": "Time", "value": ""}
).update_yaxes(matches=None)
fig.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

Aggregate the data#

Aggregate to typical weeks, including days with minimum temperature and maximum load as extreme periods.

[5]:
result = tsam.aggregate(
    raw,
    n_clusters=5,
    period_duration=24 * 7,  # Weekly periods
    cluster=ClusterConfig(method="hierarchical"),
    extremes=ExtremeConfig(
        method="new_cluster",
        min_value=["T"],
        max_value=["Load"],
    ),
)

Create the typical periods

[6]:
cluster_representatives = result.cluster_representatives
cluster_representatives.head()
[6]:
GHI Load T Wind
timestep
0 0 0.0 416.893227 0.304081 0.312325
1 0.0 409.367248 0.090194 0.000000
2 0.0 403.570841 -0.123693 0.000000
3 0.0 404.420754 -0.016750 0.208217
4 0.0 410.034429 -0.123693 0.312325

Show the resulting order of aggregated periods#

Calculates how the original index is represented by the old index

[7]:
# Advanced: Access the internal aggregation object for features not exposed in the public API.
# Note: The _aggregation attribute is internal and may change in future versions.
index_matching = result._aggregation.indexMatching()
index_matching.head()
[7]:
PeriodNum TimeStep
2009-12-31 23:30:00 3 0
2010-01-01 00:30:00 3 1
2010-01-01 01:30:00 3 2
2010-01-01 02:30:00 3 3
2010-01-01 03:30:00 3 4

Plot the appearance of the 5+2 aggregated periods in the original timeframe

[8]:
visualization_df = pd.DataFrame(
    0, index=index_matching.index, columns=result.period_index
)
for col in visualization_df.columns:
    visualization_df.loc[index_matching["PeriodNum"] == col, col] = 1
[9]:
fig = px.area(
    visualization_df,
    labels={"index": "Time", "value": "Occurrence"},
    color_discrete_sequence=px.colors.sample_colorscale(
        "Viridis", len(visualization_df.columns)
    ),
)
fig.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

Get input for potential energy system optimization#

i. cluster_weights - The occurrence count of each typical period for weighting in the objective function.

Note: Period three is only partially evaluated since its appearance at the end of the year exceeds the original time series.

[10]:
result.cluster_weights
[10]:
{np.int64(0): np.int64(10),
 np.int64(1): np.int64(17),
 np.int64(2): np.int64(7),
 np.int64(3): np.float64(4.142857142857142),
 np.int64(4): np.int64(8),
 np.int64(5): np.int64(2),
 np.int64(6): np.int64(4)}
[11]:
weights = pd.Series(result.cluster_weights)
fig = px.bar(
    x=weights.index,
    y=weights.values,
    labels={"x": "Period index", "y": "Number of occurence"},
)
fig.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

ii. Accessing period data by index Access aggregated time series values using period and time step indices. This uses internal API methods that may change in future versions.

[12]:
# Advanced: Access internal dictionary-style data access.
# Note: The _aggregation attribute and its methods are internal and may change in future versions.
agg = result._aggregation
agg.clusterPeriodDict["GHI"][(agg.clusterPeriodIdx[3], agg.stepIdx[12])]
[12]:
132.49920893072988

Alternatively this is given as data frame

[13]:
result.cluster_representatives.head()
[13]:
GHI Load T Wind
timestep
0 0 0.0 416.893227 0.304081 0.312325
1 0.0 409.367248 0.090194 0.000000
2 0.0 403.570841 -0.123693 0.000000
3 0.0 404.420754 -0.016750 0.208217
4 0.0 410.034429 -0.123693 0.312325

iii. cluster_assignments The order of the typical periods to represent the original time series, e.g., to model seasonal storage.

[14]:
result.cluster_assignments
[14]:
array([3, 2, 6, 6, 5, 2, 6, 6, 3, 0, 0, 0, 4, 0, 0, 4, 1, 4, 4, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 4, 4, 0, 0, 3, 0, 0,
       0, 2, 2, 2, 2, 5, 2, 3, 3])