Skip to content

Commit

Permalink
fix storage tests
Browse files Browse the repository at this point in the history
  • Loading branch information
maurerle committed Nov 10, 2024
1 parent 1bca986 commit 68f4d33
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 71 deletions.
40 changes: 20 additions & 20 deletions assume/strategies/flexable_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def calculate_bids(
# Calculate bids
# =============================================================================
bids = []
for product in product_tuples:
for idx, product in enumerate(product_tuples):
start = product[0]
end = product[1]

Expand All @@ -89,33 +89,33 @@ def calculate_bids(
current_power_charge = min(current_power, 0)

# calculate ramping constraints
max_power_discharge[start] = unit.calculate_ramp_discharge(
max_power_discharge[idx] = unit.calculate_ramp_discharge(
theoretic_SOC,
previous_power,
max_power_discharge[start],
max_power_discharge[idx],
current_power_discharge,
min_power_discharge[start],
min_power_discharge[idx],
)
min_power_discharge[start] = unit.calculate_ramp_discharge(
min_power_discharge[idx] = unit.calculate_ramp_discharge(
theoretic_SOC,
previous_power,
min_power_discharge[start],
min_power_discharge[idx],
current_power_discharge,
min_power_discharge[start],
min_power_discharge[idx],
)
max_power_charge[start] = unit.calculate_ramp_charge(
max_power_charge[idx] = unit.calculate_ramp_charge(
theoretic_SOC,
previous_power,
max_power_charge[start],
max_power_charge[idx],
current_power_charge,
min_power_charge[start],
min_power_charge[idx],
)
min_power_charge[start] = unit.calculate_ramp_charge(
min_power_charge[idx] = unit.calculate_ramp_charge(
theoretic_SOC,
previous_power,
min_power_charge[start],
min_power_charge[idx],
current_power_charge,
min_power_charge[start],
min_power_charge[idx],
)

price_forecast = unit.forecaster[f"price_{market_config.market_id}"]
Expand All @@ -131,12 +131,12 @@ def calculate_bids(
# if price is higher than average price, discharge
# if price is lower than average price, charge
# if price forecast favors discharge, but max discharge is zero, set a bid for charging
if price_forecast[start] >= average_price and max_power_discharge[start]:
if price_forecast[start] >= average_price and max_power_discharge[idx]:
price = average_price / unit.efficiency_discharge
bid_quantity = max_power_discharge[start]
bid_quantity = max_power_discharge[idx]
else:
price = average_price * unit.efficiency_charge
bid_quantity = max_power_charge[start]
bid_quantity = max_power_charge[idx]

bids.append(
{
Expand Down Expand Up @@ -262,15 +262,15 @@ def calculate_bids(
_, max_power_discharge = unit.calculate_min_max_discharge(start, end)
bids = []
theoretic_SOC = unit.outputs["soc"][start]
for product in product_tuples:
for idx, product in enumerate(product_tuples):
start = product[0]
current_power = unit.outputs["energy"].at[start]

# calculate ramping constraints for discharge
bid_quantity = unit.calculate_ramp_discharge(
theoretic_SOC,
previous_power,
max_power_discharge[start],
max_power_discharge[idx],
current_power,
)

Expand Down Expand Up @@ -391,14 +391,14 @@ def calculate_bids(
_, max_power_charge = unit.calculate_min_max_charge(start, end)

bids = []
for product in product_tuples:
for idx, product in enumerate(product_tuples):
start = product[0]
current_power = unit.outputs["energy"].at[start]
bid_quantity = abs(
unit.calculate_ramp_charge(
theoretic_SOC,
previous_power,
max_power_charge[start],
max_power_charge[idx],
current_power,
)
)
Expand Down
2 changes: 1 addition & 1 deletion assume/units/powerplant.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def calculate_min_max_power(
end_excl = end - self.index.freq

base_load = self.outputs["energy"].loc[start:end_excl]
heat_demand = self.outputs["heat"].loc[start:end_excl]
# heat_demand = self.outputs["heat"].loc[start:end_excl]
# assert heat_demand.min() >= 0

capacity_neg = self.outputs["capacity_neg"].loc[start:end_excl]
Expand Down
55 changes: 26 additions & 29 deletions assume/units/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from functools import lru_cache

import pandas as pd
import numpy as np

from assume.common.base import SupportsMinMaxCharge
from assume.common.market_objects import MarketConfig, Orderbook
Expand Down Expand Up @@ -105,8 +106,8 @@ def __init__(
self.max_power_discharge = abs(max_power_discharge)
self.min_power_discharge = abs(min_power_discharge)

self.outputs["soc"] = pd.Series(self.initial_soc, index=self.index, dtype=float)
self.outputs["energy_cost"] = pd.Series(0.0, index=self.index, dtype=float)
self.outputs["soc"] = self.index.copy_empty(self.initial_soc)
self.outputs["energy_cost"] = self.index.copy_empty(0.0)

self.soc_tick = soc_tick

Expand Down Expand Up @@ -171,9 +172,9 @@ def execute_current_dispatch(self, start: pd.Timestamp, end: pd.Timestamp):
Returns:
pd.Series: The volume of the unit within the given time range.
"""
time_delta = self.freq / timedelta(hours=1)
time_delta = self.index.freq / timedelta(hours=1)

for t in self.outputs["energy"][start : end - self.freq].index:
for t in self.outputs["energy"].get_date_list(start, end - self.index.freq):
delta_soc = 0
soc = self.outputs["soc"][t]
if self.outputs["energy"][t] > self.max_power_discharge:
Expand All @@ -194,7 +195,7 @@ def execute_current_dispatch(self, start: pd.Timestamp, end: pd.Timestamp):
if self.outputs["energy"][t] > max_soc_discharge:
self.outputs["energy"][t] = max_soc_discharge

time_delta = self.freq / timedelta(hours=1)
time_delta = self.index.freq / timedelta(hours=1)
delta_soc = (
-self.outputs["energy"][t] * time_delta / self.efficiency_discharge
)
Expand All @@ -206,12 +207,12 @@ def execute_current_dispatch(self, start: pd.Timestamp, end: pd.Timestamp):
if self.outputs["energy"][t] < max_soc_charge:
self.outputs["energy"][t] = max_soc_charge

time_delta = self.freq / timedelta(hours=1)
time_delta = self.index.freq / timedelta(hours=1)
delta_soc = (
-self.outputs["energy"][t] * time_delta * self.efficiency_charge
)

self.outputs["soc"][t + self.freq] = soc + delta_soc
self.outputs["soc"][t + self.index.freq] = soc + delta_soc

return self.outputs["energy"].loc[start:end]

Expand All @@ -233,7 +234,7 @@ def set_dispatch_plan(
for order in orderbook:
start = order["start_time"]
end = order["end_time"]
end_excl = end - self.freq
end_excl = end - self.index.freq
if isinstance(order["accepted_volume"], dict):
added_volume = list(order["accepted_volume"].values())
else:
Expand All @@ -253,7 +254,7 @@ def set_dispatch_plan(
if current_power > max_soc_discharge:
self.outputs[product_type][start] = max_soc_discharge

time_delta = self.freq / timedelta(hours=1)
time_delta = self.index.freq / timedelta(hours=1)
delta_soc = (
-self.outputs["energy"][start]
* time_delta
Expand All @@ -267,12 +268,12 @@ def set_dispatch_plan(
if current_power < max_soc_charge:
self.outputs[product_type][start] = max_soc_charge

time_delta = self.freq / timedelta(hours=1)
time_delta = self.index.freq / timedelta(hours=1)
delta_soc = (
-self.outputs["energy"][start] * time_delta * self.efficiency_charge
)

self.outputs["soc"][start + self.freq :] = soc + delta_soc
self.outputs["soc"][start + self.index.freq :] = soc + delta_soc

self.bidding_strategies[marketconfig.market_id].calculate_reward(
unit=self,
Expand Down Expand Up @@ -328,7 +329,7 @@ def calculate_soc_max_discharge(self, soc) -> float:
Returns:
float: The maximum discharge power.
"""
duration = self.freq / timedelta(hours=1)
duration = self.index.freq / timedelta(hours=1)
power = max(
0,
((soc - self.min_soc) * self.efficiency_discharge / duration),
Expand All @@ -348,7 +349,7 @@ def calculate_soc_max_charge(
Returns:
float: The maximum charge power.
"""
duration = self.freq / timedelta(hours=1)
duration = self.index.freq / timedelta(hours=1)
power = min(
0,
((soc - self.max_soc) / self.efficiency_charge / duration),
Expand All @@ -371,7 +372,7 @@ def calculate_min_max_charge(
Returns:
tuple[pd.Series]: The minimum and maximum charge power levels of the storage unit in MW.
"""
end_excl = end - self.freq
end_excl = end - self.index.freq

base_load = self.outputs["energy"][start:end_excl]
capacity_pos = self.outputs["capacity_pos"][start:end_excl]
Expand All @@ -383,25 +384,21 @@ def calculate_min_max_charge(
else self.min_power_charge
)
min_power_charge -= base_load + capacity_pos
min_power_charge = min_power_charge.clip(upper=0)
min_power_charge = min_power_charge.clip(max=0)

max_power_charge = (
self.max_power_charge[start:end_excl]
if isinstance(self.max_power_charge, pd.Series)
else self.max_power_charge
)
max_power_charge -= base_load + capacity_neg
max_power_charge = max_power_charge.where(
max_power_charge <= min_power_charge, 0
)
max_power_charge = np.where(max_power_charge <= min_power_charge, 0, max_power_charge)

min_power_charge = min_power_charge.where(
min_power_charge >= max_power_charge, 0
)
min_power_charge = np.where(min_power_charge >= max_power_charge, 0, min_power_charge)

# restrict charging according to max_soc
max_soc_charge = self.calculate_soc_max_charge(self.outputs["soc"][start])
max_power_charge = max_power_charge.clip(lower=max_soc_charge)
max_power_charge = max_power_charge.clip(min=max_soc_charge)

return min_power_charge, max_power_charge

Expand All @@ -421,7 +418,7 @@ def calculate_min_max_discharge(
Returns:
tuple[pd.Series]: The minimum and maximum discharge power levels of the storage unit in MW.
"""
end_excl = end - self.freq
end_excl = end - self.index.freq

base_load = self.outputs["energy"][start:end_excl]
capacity_pos = self.outputs["capacity_pos"][start:end_excl]
Expand All @@ -433,25 +430,25 @@ def calculate_min_max_discharge(
else self.min_power_discharge
)
min_power_discharge -= base_load + capacity_neg
min_power_discharge = min_power_discharge.clip(lower=0)
min_power_discharge = min_power_discharge.clip(min=0)

max_power_discharge = (
self.max_power_discharge[start:end_excl]
if isinstance(self.max_power_discharge, pd.Series)
else self.max_power_discharge
)
max_power_discharge -= base_load + capacity_pos
max_power_discharge = max_power_discharge.where(
max_power_discharge >= min_power_discharge, 0
max_power_discharge = np.where(
max_power_discharge >= min_power_discharge, 0, max_power_discharge
)

min_power_discharge = min_power_discharge.where(
min_power_discharge < max_power_discharge, 0
min_power_discharge = np.where(
min_power_discharge < max_power_discharge, 0, min_power_discharge
)

# restrict according to min_soc
max_soc_discharge = self.calculate_soc_max_discharge(self.outputs["soc"][start])
max_power_discharge = max_power_discharge.clip(upper=max_soc_discharge)
max_power_discharge = max_power_discharge.clip(max=max_soc_discharge)

return min_power_discharge, max_power_discharge

Expand Down
5 changes: 3 additions & 2 deletions tests/test_advanced_order_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from datetime import datetime

import pandas as pd
from assume.common.fds import FastDatetimeSeries
import pytest

from assume.common.forecasts import NaiveForecast
Expand All @@ -21,7 +22,7 @@
@pytest.fixture
def power_plant() -> PowerPlant:
# Create a PowerPlant instance with some example parameters
index = pd.date_range("2023-07-01", periods=48, freq="h")
index = FastDatetimeSeries(datetime(2023,7,1),datetime(2023,7,3), "h")
ff = NaiveForecast(index, availability=1, fuel_price=10, co2_price=10)
return PowerPlant(
id="test_pp",
Expand All @@ -41,7 +42,7 @@ def power_plant() -> PowerPlant:

def test_eom_with_blocks(mock_market_config, power_plant):
power_plant.ramp_up = 400
product_index = pd.date_range("2023-07-01", periods=24, freq="h")
product_index = FastDatetimeSeries(datetime(2023,7,1),datetime(2023,7,2), "h").get_date_list()
strategy = flexableEOMBlock()
mc = mock_market_config
mc.product_type = "energy_eom"
Expand Down
Loading

0 comments on commit 68f4d33

Please sign in to comment.