Added functions to compare policies

This commit is contained in:
Victor Mylle
2023-12-19 16:22:13 +00:00
parent fee948cc09
commit d0fa815b68
5 changed files with 715 additions and 88 deletions

View File

@@ -207,4 +207,11 @@ class NrvDataset(Dataset):
return torch.stack(features), torch.stack(targets)
def get_idx_for_date(self, date: datetime.date):
return self.datetime[self.datetime.dt.date == date].index[0]
# check if the date is in the valid indices
if date not in self.datetime.dt.date.unique():
raise ValueError(f"Date {date} not in dataset.")
idx = self.datetime[self.datetime.dt.date == date].index[0]
valid_idx = self.valid_indices.index(idx)
return valid_idx

File diff suppressed because one or more lines are too long

View File

@@ -57,7 +57,8 @@ class Battery:
self.charge_cycles = 0
class BaselinePolicy():
def __init__(self, battery: Battery):
def __init__(self, battery: Battery, data_path: str = ""):
self.data_path = data_path
self.battery = battery
self.train_data = self.load_imbalance_prices(train=True)
self.test_data = self.load_imbalance_prices(train=False)
@@ -67,7 +68,7 @@ class BaselinePolicy():
print(f"Test range: {self.test_data.iloc[0]['DateTime'].strftime('%d-%m-%Y')} - {self.test_data.iloc[-1]['DateTime'].strftime('%d-%m-%Y')}")
def load_imbalance_prices(self, train: bool = True):
imbalance_prices = pd.read_csv('data/imbalance_prices.csv', parse_dates=True, sep=";")
imbalance_prices = pd.read_csv(self.data_path + 'data/imbalance_prices.csv', parse_dates=True, sep=";")
imbalance_prices = imbalance_prices[['DateTime', 'Positive imbalance price']]
imbalance_prices['DateTime'] = pd.to_datetime(imbalance_prices['DateTime'], utc=True)
if train:
@@ -78,15 +79,15 @@ class BaselinePolicy():
imbalance_prices = imbalance_prices.sort_values(by=['DateTime'], ascending=True)
return imbalance_prices
def get_train_score(self, charge_treshold, discharge_treshold):
return self.get_score(self.train_data, charge_treshold, discharge_treshold)
def get_train_score(self, charge_threshold, discharge_threshold):
return self.get_score(self.train_data, charge_threshold, discharge_threshold)
def get_test_score(self, charge_treshold, discharge_treshold):
return self.get_score(self.test_data, charge_treshold, discharge_treshold)
def get_test_score(self, charge_threshold, discharge_threshold):
return self.get_score(self.test_data, charge_threshold, discharge_threshold)
# if price is below charging treshold (cheap charging) -> charge battery: total_profit -= charge * price
# if price is above treshold -> discharge battery: total_profit += discharge * price
def get_score(self, df, charge_treshold, discharge_treshold):
# if price is below charging threshold (cheap charging) -> charge battery: total_profit -= charge * price
# if price is above threshold -> discharge battery: total_profit += discharge * price
def get_score(self, df, charge_threshold, discharge_threshold):
self.battery.reset()
total_charging_cost = 0
total_discharging_profit = 0
@@ -96,41 +97,141 @@ class BaselinePolicy():
number_of_discharges = 0
for index, row in df.iterrows():
if row['Positive imbalance price'] < charge_treshold:
if row['Positive imbalance price'] < charge_threshold:
total_charging_cost += self.battery.charge() * row['Positive imbalance price']
mean_charging_price += row['Positive imbalance price']
number_of_charges += 1
elif row['Positive imbalance price'] > discharge_treshold:
elif row['Positive imbalance price'] > discharge_threshold:
total_discharging_profit += self.battery.discharge() * row['Positive imbalance price']
mean_discharging_price += row['Positive imbalance price']
number_of_discharges += 1
return total_charging_cost, total_discharging_profit, self.battery.charge_cycles, mean_charging_price / number_of_charges, mean_discharging_price / number_of_discharges
def treshold_scores(self, charge_tresholds, discharge_tresholds):
df = pd.DataFrame(columns=["Charge treshold", "Discharge treshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])
df_test = pd.DataFrame(columns=["Charge treshold", "Discharge treshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])
for charge_treshold, discharge_treshold in tqdm(itertools.product(charge_tresholds, discharge_tresholds)):
total_charging_cost, total_discharge_profit, charge_cycles, mean_charging_price, mean_discharging_price = self.get_train_score(charge_treshold, discharge_treshold)
df = pd.concat([df, pd.DataFrame([[charge_treshold, discharge_treshold, total_charging_cost, total_discharge_profit, total_discharge_profit - total_charging_cost, charge_cycles, mean_charging_price, mean_discharging_price]], columns=["Charge treshold", "Discharge treshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])])
def threshold_scores(self, charge_thresholds, discharge_thresholds):
df = pd.DataFrame(columns=["Charge threshold", "Discharge threshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])
df_test = pd.DataFrame(columns=["Charge threshold", "Discharge threshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])
total_charging_cost, total_discharge_profit, charge_cycles, mean_charging_price, mean_discharging_price = self.get_test_score(charge_treshold, discharge_treshold)
df_test = pd.concat([df_test, pd.DataFrame([[charge_treshold, discharge_treshold, total_charging_cost, total_discharge_profit, total_discharge_profit - total_charging_cost, charge_cycles, mean_charging_price, mean_discharging_price]], columns=["Charge treshold", "Discharge treshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])])
threshold_pairs = itertools.product(charge_thresholds, discharge_thresholds)
threshold_pairs = filter(lambda x: x[0] < x[1], threshold_pairs)
for charge_threshold, discharge_threshold in tqdm(threshold_pairs):
total_charging_cost, total_discharge_profit, charge_cycles, mean_charging_price, mean_discharging_price = self.get_train_score(charge_threshold, discharge_threshold)
df = pd.concat([df, pd.DataFrame([[charge_threshold, discharge_threshold, total_charging_cost, total_discharge_profit, total_discharge_profit - total_charging_cost, charge_cycles, mean_charging_price, mean_discharging_price]], columns=["Charge threshold", "Discharge threshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])])
total_charging_cost, total_discharge_profit, charge_cycles, mean_charging_price, mean_discharging_price = self.get_test_score(charge_threshold, discharge_threshold)
df_test = pd.concat([df_test, pd.DataFrame([[charge_threshold, discharge_threshold, total_charging_cost, total_discharge_profit, total_discharge_profit - total_charging_cost, charge_cycles, mean_charging_price, mean_discharging_price]], columns=["Charge threshold", "Discharge threshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])])
df = df.sort_values(by=['Total Profit'], ascending=False)
return df, df_test
def get_optimal_thresholds(self, imbalance_prices, charge_thresholds, discharge_thresholds, tqdm=True):
df = None
threshold_pairs = itertools.product(charge_thresholds, discharge_thresholds)
threshold_pairs = filter(lambda x: x[0] < x[1], threshold_pairs)
# disable tqdm if necessary
if tqdm:
threshold_pairs = tqdm(threshold_pairs)
for charge_threshold, discharge_threshold in threshold_pairs:
self.battery.reset()
total_charging_cost = 0
total_discharging_profit = 0
number_of_charges = 0
number_of_discharges = 0
mean_charging_price = 0
mean_discharging_price = 0
for index, price in enumerate(imbalance_prices):
if price < charge_threshold:
total_charging_cost += self.battery.charge() * price
mean_charging_price += price
number_of_charges += 1
elif price > discharge_threshold:
total_discharging_profit += self.battery.discharge() * price
mean_discharging_price += price
number_of_discharges += 1
if number_of_charges == 0:
mean_charging_price = 0
else:
mean_charging_price /= number_of_charges
if number_of_discharges == 0:
mean_discharging_price = 0
else:
mean_discharging_price /= number_of_discharges
new_df = pd.DataFrame([[charge_threshold, discharge_threshold, total_charging_cost, total_discharging_profit, total_discharging_profit - total_charging_cost, self.battery.charge_cycles, mean_charging_price, mean_discharging_price]], columns=["Charge threshold", "Discharge threshold", "Charging Cost", "Discharging Profit", "Total Profit", "Charge cycles", "Mean charging price", "Mean discharging price"])
if df is None:
df = new_df
else:
df = pd.concat([df, new_df])
df = df.sort_values(by=['Total Profit'], ascending=False)
return df
def simulate(self, imbalance_prices, charge_threshold, discharge_threshold):
self.battery.reset()
total_charging_cost = 0
total_discharging_profit = 0
number_of_charges = 0
number_of_discharges = 0
mean_charging_price = 0
mean_discharging_price = 0
# for each timestep also print what is happening
for i, price in enumerate(imbalance_prices):
if price < charge_threshold:
charge = self.battery.charge()
total_charging_cost += charge * price
mean_charging_price += price
number_of_charges += 1
# print(f"{i}: Charging battery with {charge}MWh at {price}€/MWh")
elif price > discharge_threshold:
discharge = self.battery.discharge()
total_discharging_profit += discharge * price
mean_discharging_price += price
number_of_discharges += 1
# print(f"{i}: Discharging battery with {discharge}MWh at {price}€/MWh")
if number_of_charges == 0:
mean_charging_price = 0
else:
mean_charging_price /= number_of_charges
if number_of_discharges == 0:
mean_discharging_price = 0
else:
mean_discharging_price /= number_of_discharges
# print(f"Total charging cost: {total_charging_cost}")
# print(f"Total discharging profit: {total_discharging_profit}")
# print(f"Total profit: {total_discharging_profit - total_charging_cost}")
# print(f"Charge cycles: {self.battery.charge_cycles}")
# print(f"Mean charging price: {mean_charging_price}")
# print(f"Mean discharging price: {mean_discharging_price}")
return total_discharging_profit - total_charging_cost, self.battery.charge_cycles
battery = Battery(2, 1)
policy = BaselinePolicy(battery)
# battery = Battery(2, 1)
# policy = BaselinePolicy(battery)
charge_tresholds = np.arange(-100, 250, 50)
discharge_tresholds = np.arange(-100, 250, 50)
df, df_test = policy.treshold_scores(charge_tresholds, discharge_tresholds)
print(df.to_markdown())
# charge_thresholds = np.arange(-100, 250, 25)
# discharge_thresholds = np.arange(-100, 250, 25)
print(df_test.to_markdown())
# df, df_test = policy.threshold_scores(charge_thresholds, discharge_thresholds)
# print(df.to_markdown())
# print(policy.get_test_score(150, 100))
# print(df_test.to_markdown())
# # print(policy.get_test_score(150, 100))

View File

@@ -1,6 +1,6 @@
from datetime import datetime
import plotly.graph_objects as go
import numpy as np
import pytz
import pandas as pd
incremental_bids = "../../data/incremental_bids.csv"
@@ -66,8 +66,6 @@ class ImbalancePriceCalculator:
dec_bids = row["bid_ladder_dec"].values[0]
inc_bids = row["bid_ladder_inc"].values[0]
# Prepare data for plot
x_inc_interpolated = [vol for i in range(len(inc_bids) - 1) for vol in [inc_bids[i][0], inc_bids[i+1][0]]]
y_inc_interpolated = [price for cum_vol, price in inc_bids for _ in (0, 1)]
@@ -90,6 +88,14 @@ class ImbalancePriceCalculator:
fig.show()
def get_imbalance_prices_2023_for_date(self, date, NRV_predictions):
imbalance_prices = []
for i in range(1, len(NRV_predictions)):
datetime = date + pd.Timedelta(hours=i-1)
datetime = pytz.utc.localize(datetime)
imbalance_prices.append(self.get_imbalance_price_2023(datetime, NRV_predictions[i-1], NRV_predictions[i]))
return [x[1] for x in imbalance_prices]
def get_imbalance_price_2023(self, datetime, NRV_PREV, NRV):
MIP = self.get_imbalance_price(datetime, abs(NRV))
MDP = self.get_imbalance_price(datetime, -abs(NRV))