Added functions to compare policies
This commit is contained in:
@@ -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
@@ -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))
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user