diff --git a/assume/common/forecasts.py b/assume/common/forecasts.py index d8a1d324b..f79cd7881 100644 --- a/assume/common/forecasts.py +++ b/assume/common/forecasts.py @@ -466,7 +466,9 @@ def __init__( *args, **kwargs, ): - super().__init__(index, powerplants_units, demand_units, market_configs, *args, **kwargs) + super().__init__( + index, powerplants_units, demand_units, market_configs, *args, **kwargs + ) self.index = FastIndex(start=index[0], end=index[-1], freq=pd.infer_freq(index)) self.sigma = sigma diff --git a/assume/common/units_operator.py b/assume/common/units_operator.py index bcef0e27e..b130f5d5a 100644 --- a/assume/common/units_operator.py +++ b/assume/common/units_operator.py @@ -8,7 +8,6 @@ from itertools import groupby from operator import itemgetter -import pandas as pd from mango import Role, create_acl, sender_addr from mango.messages.message import Performatives @@ -294,7 +293,7 @@ def set_unit_dispatch( def get_actual_dispatch( self, product_type: str, last: datetime - ) -> tuple[pd.DataFrame, list[pd.DataFrame]]: + ) -> tuple[list[tuple[datetime, float, str, str]], list[dict]]: """ Retrieves the actual dispatch and commits it in the unit. We calculate the series of the actual market results dataframe with accepted bids. @@ -305,7 +304,7 @@ def get_actual_dispatch( last (datetime): the last date until which the dispatch was already sent Returns: - tuple[pd.DataFrame, list[pd.DataFrame]]: market_dispatch and unit_dispatch dataframes + tuple[list[tuple[datetime, float, str, str]], list[dict]]: market_dispatch and unit_dispatch dataframes """ now = timestamp2datetime(self.context.current_timestamp) start = timestamp2datetime(last + 1) diff --git a/assume/units/demand.py b/assume/units/demand.py index 38f5ec828..0c5cbe9a5 100644 --- a/assume/units/demand.py +++ b/assume/units/demand.py @@ -3,8 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later import numbers - -import pandas as pd +from datetime import datetime from assume.common.base import SupportsMinMax from assume.common.fast_pandas import FastSeries @@ -41,7 +40,7 @@ def __init__( min_power: float, forecaster: Forecaster, node: str = "node0", - price: float | pd.Series = 3000.0, + price: float | FastSeries = 3000.0, location: tuple[float, float] = (0.0, 0.0), **kwargs, ): @@ -71,8 +70,8 @@ def __init__( def execute_current_dispatch( self, - start: pd.Timestamp, - end: pd.Timestamp, + start: datetime, + end: datetime, ): """ Execute the current dispatch of the unit. @@ -83,14 +82,14 @@ def execute_current_dispatch( end (pandas.Timestamp): The end time of the dispatch. Returns: - pd.Series: The volume of the unit within the gicen time range. + FastSeries: The volume of the unit within the gicen time range. """ return self.volume[start:end] def calculate_min_max_power( - self, start: pd.Timestamp, end: pd.Timestamp, product_type="energy" - ) -> tuple[pd.Series, pd.Series]: + self, start: datetime, end: datetime, product_type="energy" + ) -> tuple[FastSeries, FastSeries]: """ Calculates the minimum and maximum power output of the unit and returns the bid volume as both the minimum and maximum power output of the unit. @@ -105,7 +104,7 @@ def calculate_min_max_power( bid_volume = (self.volume - self.outputs[product_type]).loc[start:end_excl] return bid_volume, bid_volume - def calculate_marginal_cost(self, start: pd.Timestamp, power: float) -> float: + def calculate_marginal_cost(self, start: datetime, power: float) -> float: """ Calculate the marginal cost of the unit returns the marginal cost of the unit based on the provided time and power. diff --git a/assume/units/powerplant.py b/assume/units/powerplant.py index 24b2efe14..4088561b6 100644 --- a/assume/units/powerplant.py +++ b/assume/units/powerplant.py @@ -6,9 +6,8 @@ from datetime import datetime, timedelta from functools import lru_cache -import pandas as pd - from assume.common.base import SupportsMinMax +from assume.common.fast_pandas import FastSeries from assume.common.forecasts import Forecaster from assume.common.market_objects import MarketConfig, Orderbook from assume.common.utils import get_products_index @@ -29,7 +28,7 @@ class PowerPlant(SupportsMinMax): max_power (float): The maximum power output capacity of the power plant in MW. min_power (float, optional): The minimum power output capacity of the power plant in MW. Defaults to 0.0 MW. efficiency (float, optional): The efficiency of the power plant in converting fuel to electricity. Defaults to 1.0. - additional_cost (Union[float, pd.Series], optional): Additional costs associated with power generation, in EUR/MWh. Defaults to 0. + additional_cost (Union[float, FastSeries], optional): Additional costs associated with power generation, in EUR/MWh. Defaults to 0. partial_load_eff (bool, optional): Does the efficiency vary at part loads? Defaults to False. fuel_type (str, optional): The type of fuel used by the power plant for power generation. Defaults to "others". emission_factor (float, optional): The emission factor associated with the power plant's fuel type (CO2 emissions per unit of energy produced). Defaults to 0.0. @@ -59,7 +58,7 @@ def __init__( max_power: float, min_power: float = 0.0, efficiency: float = 1.0, - additional_cost: float | pd.Series = 0.0, + additional_cost: float | FastSeries = 0.0, partial_load_eff: bool = False, fuel_type: str = "others", emission_factor: float = 0.0, @@ -127,8 +126,8 @@ def init_marginal_cost(self): def execute_current_dispatch( self, - start: pd.Timestamp, - end: pd.Timestamp, + start: datetime, + end: datetime, ): """ Executes the current dispatch of the unit based on the provided timestamps. @@ -141,7 +140,7 @@ def execute_current_dispatch( end (pandas.Timestamp): The end time of the dispatch. Returns: - pd.Series: The volume of the unit within the given time range. + FastSeries: The volume of the unit within the given time range. """ start = max(start, self.index[0]) @@ -242,18 +241,18 @@ def calc_simple_marginal_cost( def calc_marginal_cost_with_partial_eff( self, power_output: float, - timestep: pd.Timestamp = None, - ) -> float | pd.Series: + timestep: datetime = None, + ) -> float | FastSeries: """ Calculates the marginal cost of the unit based on power output and timestamp, considering partial efficiency. Returns the marginal cost of the unit. Args: power_output (float): The power output of the unit. - timestep (pd.Timestamp, optional): The timestamp of the unit. Defaults to None. + timestep (datetime, optional): The timestamp of the unit. Defaults to None. Returns: - float | pd.Series: The marginal cost of the unit. + float | FastSeries: The marginal cost of the unit. """ fuel_price = self.forecaster.get_price(self.fuel_type).at[timestep] @@ -294,7 +293,7 @@ def calc_marginal_cost_with_partial_eff( additional_cost = ( self.additional_cost.at[timestep] - if isinstance(self.additional_cost, pd.Series) + if isinstance(self.additional_cost, FastSeries) else self.additional_cost ) @@ -307,8 +306,8 @@ def calc_marginal_cost_with_partial_eff( return marginal_cost def calculate_min_max_power( - self, start: pd.Timestamp, end: pd.Timestamp, product_type="energy" - ) -> tuple[pd.Series, pd.Series]: + self, start: datetime, end: datetime, product_type="energy" + ) -> tuple[FastSeries, FastSeries]: """ Calculates the minimum and maximum power output of the unit and returns it. diff --git a/assume/units/steel_plant.py b/assume/units/steel_plant.py index eaa09c2d8..283a65ecd 100644 --- a/assume/units/steel_plant.py +++ b/assume/units/steel_plant.py @@ -37,7 +37,7 @@ class SteelPlant(DSMFlex, SupportsMinMax): bidding_strategies (dict): The bidding strategies of the unit. technology (str): The technology of the unit. node (str): The node of the unit. - index (pd.DatetimeIndex): The index for the data of the unit. + index (FastIndex): The index for the data of the unit. location (tuple[float, float]): The location of the unit. components (dict[str, dict]): The components of the unit such as Electrolyser, DRI Plant, DRI Storage, and Electric Arc Furnace. objective (str): The objective of the unit, e.g. minimize variable cost ("min_variable_cost"). @@ -552,7 +552,7 @@ def set_dispatch_plan( orderbook=orderbook, ) - def calculate_marginal_cost(self, start: pd.Timestamp, power: float) -> float: + def calculate_marginal_cost(self, start: datetime, power: float) -> float: """ Calculate the marginal cost of the unit based on the provided time and power. diff --git a/assume/units/storage.py b/assume/units/storage.py index 2531fc044..12529e652 100644 --- a/assume/units/storage.py +++ b/assume/units/storage.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later import logging -from datetime import timedelta +from datetime import datetime, timedelta from functools import lru_cache import numpy as np @@ -160,7 +160,7 @@ def __init__( self.warm_start_cost = warm_start_cost * max_power_discharge self.cold_start_cost = cold_start_cost * max_power_discharge - def execute_current_dispatch(self, start: pd.Timestamp, end: pd.Timestamp): + def execute_current_dispatch(self, start: datetime, end: datetime): """ Executes the current dispatch of the unit based on the provided timestamps. @@ -286,7 +286,7 @@ def set_dispatch_plan( @lru_cache(maxsize=256) def calculate_marginal_cost( self, - start: pd.Timestamp, + start: datetime, power: float, ) -> float: """ @@ -359,8 +359,8 @@ def calculate_soc_max_charge( return power def calculate_min_max_charge( - self, start: pd.Timestamp, end: pd.Timestamp, product_type="energy" - ) -> tuple[pd.Series]: + self, start: datetime, end: datetime, product_type="energy" + ) -> tuple[FastSeries, FastSeries]: """ Calculates the min and max charging power for the given time period. This is relative to the already sold output on other markets for the same period. @@ -372,7 +372,7 @@ def calculate_min_max_charge( product_type (str): The product type of the storage unit. Returns: - tuple[pd.Series]: The minimum and maximum charge power levels of the storage unit in MW. + tuple[FastSeries, FastSeries]: The minimum and maximum charge power levels of the storage unit in MW. """ end_excl = end - self.index.freq @@ -408,8 +408,8 @@ def calculate_min_max_charge( return min_power_charge, max_power_charge def calculate_min_max_discharge( - self, start: pd.Timestamp, end: pd.Timestamp, product_type="energy" - ) -> tuple[pd.Series]: + self, start: datetime, end: datetime, product_type="energy" + ) -> tuple[FastSeries, FastSeries]: """ Calculates the min and max discharging power for the given time period. This is relative to the already sold output on other markets for the same period. @@ -421,7 +421,7 @@ def calculate_min_max_discharge( product_type (str): The product type of the storage unit. Returns: - tuple[pd.Series]: The minimum and maximum discharge power levels of the storage unit in MW. + tuple[FastSeries, FastSeries]: The minimum and maximum discharge power levels of the storage unit in MW. """ end_excl = end - self.index.freq diff --git a/tests/conftest.py b/tests/conftest.py index 34dc37965..3e3b6e71c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,13 +27,13 @@ def __init__(self, forecaster, **kwargs): self.ramp_up = 400 def calculate_min_max_power( - self, start: pd.Timestamp, end: pd.Timestamp, product_type="energy" - ) -> tuple[pd.Series, pd.Series]: + self, start: datetime, end: datetime, product_type="energy" + ) -> tuple[FastSeries, FastSeries]: min = FastSeries(value=100, index=self.index).loc[start:end] max = FastSeries(value=400, index=self.index).loc[start:end] return min, max - def calculate_marginal_cost(self, start: pd.Timestamp, power: float) -> float: + def calculate_marginal_cost(self, start: datetime, power: float) -> float: return 3