Skip to content

Results Postprocessing

Our Results class, gives users some tools to visualize the final schedule, as determined by the rolling intrinsic simulation, and evaluate some key statistics. Of course, the user is encouraged to look at all simulation outputs in detail to understand the intricacies of the battery's trading behavior.

Source code in bitepy/results.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class Results:
    def __init__(self, logs: dict):
        """
        Initialize a Simulation instance.

        Args:
            logs (dict): A dictionary containing the get_logs() output of the simulation class.
        """

        self.logs = logs

    def get_total_reward(self):
        return np.round(self.logs["decision_record"]['real_reward'].sum(),2)

    def plot_decision_chart(self,lleft: int = 0,lright: int = -1):
        """
        Plot the storage, market-position, and reward of the agent over the selected simulation period.

        Args:
            lleft (int): The left index of the simulation period.
            lright (int): The right index of the simulation period.
        """
        df = self.logs["decision_record"]

        # plot storage, position, and reward where reward is in a seperate axis below
        fig1, ax1 = plt.subplots(figsize=(18, 10))
        ax2 = ax1.twinx()
        ax1.plot(df["hour"][lleft:lright], df['storage'][lleft:lright], color='blue')
        #plot position as points not line
        ax1.plot(df["hour"][lleft:lright], df['position'][lleft:lright], 'o', color='red')


        ax2.plot(df["hour"][lleft:lright], df['real_reward'][lleft:lright], color='green')
        ax1.set_xlabel('Time ')
        ax1.set_ylabel('Storage (MWh)')
        ax2.set_ylabel('Reward (€)')
        # plot a horizontal line at 0
        ax2.axhline(y=0, color='green', linestyle='--', linewidth=1.5, alpha=0.5)
        ax1.legend(['storage', 'position'], loc='upper left')
        ax2.legend(['reward'], loc='upper right')
        #set gridlines
        # plot vertical grid line for each hour

        # # array for each hour between lleft and lright
        # hours = pd.date_range(start=df["hour"].iloc[lleft], end=df["hour"].iloc[lright], freq='D')
        # for hour in hours:
        #     ax1.axvline(x=hour, color='gray', linestyle='--', linewidth=0.5)

        ax1.grid(True, alpha=0.5)
        plt.show()

        fig1, ax1 = plt.subplots(figsize=(18, 10))
        #plot cumulative reward
        ax1.plot(df["hour"][lleft:lright], df['real_reward'].cumsum()[lleft:lright], color='blue')
        ax1.set_xlabel('Time ')
        ax1.set_ylabel('Cumulative Reward (€)')
        ax1.grid(True, alpha=0.5)
        plt.show()

    def plot_heatmap(self):
        """
        Plot a heatmap of the final storage positions and visualize the executed orders over the simulation period.
        Heatmap plots adapted from: https://github.com/bitstoenergy/iclr-smartmeteranalytics by Markus Kreft.
        """

        df = self.logs["decision_record"]
        df.index = df["hour"]
        df = df.drop(columns=["hour"])

        exec_df = self.logs["executed_orders"].drop(columns=["dp_run", "last_solve_time", "final_pos", "final_stor"])
        exec_df.set_index('hour', inplace=True)

        # Create an empty list to store results
        daily_volumes = []

        # Iterate through unique dates in df
        for day in np.unique(df.index.date):
            # Filter the data for the current day
            daily_data = exec_df.loc[exec_df.index.date == day]

            # Calculate the largest daily volume and the summed daily volume
            largest_daily_vol = daily_data["volume"].max()
            summed_daily_vol = daily_data["volume"].sum()

            # Append the results as a dictionary
            daily_volumes.append({
                "date": day,
                "max_vol": largest_daily_vol,
                "summed_vol": summed_daily_vol
            })

        # Create a DataFrame from the list of dictionaries
        daily_volumes_df = pd.DataFrame(daily_volumes)

        # Set the 'date' column as the index
        daily_volumes_df.set_index("date", inplace=True)
        daily_volumes_df.index = pd.to_datetime(daily_volumes_df.index).tz_localize("UTC")


        fig = hm.HeatmapFigure(df, daily_volumes_df, 'storage', interval_minutes=60, figsize=(14, 8))
        plt.show()

__init__(logs)

Initialize a Simulation instance.

Parameters:

Name Type Description Default
logs dict

A dictionary containing the get_logs() output of the simulation class.

required
Source code in bitepy/results.py
17
18
19
20
21
22
23
24
25
def __init__(self, logs: dict):
    """
    Initialize a Simulation instance.

    Args:
        logs (dict): A dictionary containing the get_logs() output of the simulation class.
    """

    self.logs = logs

plot_decision_chart(lleft=0, lright=-1)

Plot the storage, market-position, and reward of the agent over the selected simulation period.

Parameters:

Name Type Description Default
lleft int

The left index of the simulation period.

0
lright int

The right index of the simulation period.

-1
Source code in bitepy/results.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def plot_decision_chart(self,lleft: int = 0,lright: int = -1):
    """
    Plot the storage, market-position, and reward of the agent over the selected simulation period.

    Args:
        lleft (int): The left index of the simulation period.
        lright (int): The right index of the simulation period.
    """
    df = self.logs["decision_record"]

    # plot storage, position, and reward where reward is in a seperate axis below
    fig1, ax1 = plt.subplots(figsize=(18, 10))
    ax2 = ax1.twinx()
    ax1.plot(df["hour"][lleft:lright], df['storage'][lleft:lright], color='blue')
    #plot position as points not line
    ax1.plot(df["hour"][lleft:lright], df['position'][lleft:lright], 'o', color='red')


    ax2.plot(df["hour"][lleft:lright], df['real_reward'][lleft:lright], color='green')
    ax1.set_xlabel('Time ')
    ax1.set_ylabel('Storage (MWh)')
    ax2.set_ylabel('Reward (€)')
    # plot a horizontal line at 0
    ax2.axhline(y=0, color='green', linestyle='--', linewidth=1.5, alpha=0.5)
    ax1.legend(['storage', 'position'], loc='upper left')
    ax2.legend(['reward'], loc='upper right')
    #set gridlines
    # plot vertical grid line for each hour

    # # array for each hour between lleft and lright
    # hours = pd.date_range(start=df["hour"].iloc[lleft], end=df["hour"].iloc[lright], freq='D')
    # for hour in hours:
    #     ax1.axvline(x=hour, color='gray', linestyle='--', linewidth=0.5)

    ax1.grid(True, alpha=0.5)
    plt.show()

    fig1, ax1 = plt.subplots(figsize=(18, 10))
    #plot cumulative reward
    ax1.plot(df["hour"][lleft:lright], df['real_reward'].cumsum()[lleft:lright], color='blue')
    ax1.set_xlabel('Time ')
    ax1.set_ylabel('Cumulative Reward (€)')
    ax1.grid(True, alpha=0.5)
    plt.show()

plot_heatmap()

Plot a heatmap of the final storage positions and visualize the executed orders over the simulation period. Heatmap plots adapted from: https://github.com/bitstoenergy/iclr-smartmeteranalytics by Markus Kreft.

Source code in bitepy/results.py
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def plot_heatmap(self):
    """
    Plot a heatmap of the final storage positions and visualize the executed orders over the simulation period.
    Heatmap plots adapted from: https://github.com/bitstoenergy/iclr-smartmeteranalytics by Markus Kreft.
    """

    df = self.logs["decision_record"]
    df.index = df["hour"]
    df = df.drop(columns=["hour"])

    exec_df = self.logs["executed_orders"].drop(columns=["dp_run", "last_solve_time", "final_pos", "final_stor"])
    exec_df.set_index('hour', inplace=True)

    # Create an empty list to store results
    daily_volumes = []

    # Iterate through unique dates in df
    for day in np.unique(df.index.date):
        # Filter the data for the current day
        daily_data = exec_df.loc[exec_df.index.date == day]

        # Calculate the largest daily volume and the summed daily volume
        largest_daily_vol = daily_data["volume"].max()
        summed_daily_vol = daily_data["volume"].sum()

        # Append the results as a dictionary
        daily_volumes.append({
            "date": day,
            "max_vol": largest_daily_vol,
            "summed_vol": summed_daily_vol
        })

    # Create a DataFrame from the list of dictionaries
    daily_volumes_df = pd.DataFrame(daily_volumes)

    # Set the 'date' column as the index
    daily_volumes_df.set_index("date", inplace=True)
    daily_volumes_df.index = pd.to_datetime(daily_volumes_df.index).tz_localize("UTC")


    fig = hm.HeatmapFigure(df, daily_volumes_df, 'storage', interval_minutes=60, figsize=(14, 8))
    plt.show()