Building Energy System#

Optimal combination of segments and periods for building energy supply systems.

Author: Leander Kotzur

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 plotly.io as pio

import tsam
from tsam import ClusterConfig, SegmentConfig
from tsam.tuning import find_pareto_front

pio.renderers.default = "notebook"

Input data#

Read in time series from testdata.csv with pandas

[2]:
raw = pd.read_csv("testdata.csv", index_col=0)
raw = raw.rename(
    columns={
        "T": "Temperature [°C]",
        "Load": "Load [kW]",
        "Wind": "Wind [m/s]",
        "GHI": "Solar [W/m²]",
    }
)
[3]:
raw = raw.drop(
    columns=[
        "Wind [m/s]",
    ],
)

Use tsam’s built-in heatmap plotting for visual comparison of the time series

Plot an example series - in this case the temperature

[4]:
# Original data heatmaps using tsam.unstack_to_periods() with plotly
unstacked = tsam.unstack_to_periods(raw, period_duration=24)
for col in raw.columns:
    px.imshow(
        unstacked[col].values.T,
        labels={"x": "Day", "y": "Hour", "color": col},
        title=f"Original {col}",
        aspect="auto",
    ).show()

Tune a hierarchical aggregation with segments in combination with distribution representation#

Use the new find_pareto_front() function to explore the Pareto-optimal combinations.

[5]:
pareto_results = find_pareto_front(
    raw,
    period_duration=24,
    max_timesteps=100,
    cluster=ClusterConfig(
        method="hierarchical",
        representation="distribution",
    ),
    n_jobs=-1,
)
Building Pareto front: 100%|██████████| 100/100 [00:42<00:00,  2.37it/s]

And determine the pareto optimal aggregation up to 100 total time steps. This may take some time…

[6]:
# Show the last result in the Pareto front
last_result = pareto_results[-1]
print(
    f"Final configuration: {last_result.n_clusters} periods, {last_result.n_segments} segments"
)
Final configuration: 20 periods, 5 segments

And show the results for the last aggregation

[7]:
# Reconstruct the data from the last Pareto result
reconstructed = last_result.reconstructed
[8]:
# Reconstructed data heatmaps from last tuned aggregation
unstacked_recon = tsam.unstack_to_periods(reconstructed, period_duration=24)
for col in reconstructed.columns:
    px.imshow(
        unstacked_recon[col].values.T,
        labels={"x": "Day", "y": "Hour", "color": col},
        title=f"Reconstructed {col}",
        aspect="auto",
    ).show()
[9]:
last_result.n_segments
[9]:
5
[10]:
last_result.n_clusters
[10]:
20
[11]:
# Example with specific configuration using distribution_minmax representation
result = tsam.aggregate(
    raw,
    n_clusters=14,
    period_duration=24,
    cluster=ClusterConfig(
        method="hierarchical",
        representation="distribution_minmax",
    ),
    segments=SegmentConfig(n_segments=8),
    preserve_column_means=False,
)
[12]:
# Reconstructed data heatmaps with 8 segments and 14 periods
recon = result.reconstructed
unstacked_recon2 = tsam.unstack_to_periods(recon, period_duration=24)
for col in recon.columns:
    px.imshow(
        unstacked_recon2[col].values.T,
        labels={"x": "Day", "y": "Hour", "color": col},
        title=f"Reconstructed {col} (8 seg, 14 periods)",
        aspect="auto",
    ).show()