from dataclasses import dataclass from typing import Optional import pandas as pd import numpy as np @dataclass(frozen=True) class DayInput: """ Data class representing the input data for a single day of optimization. For this project, we used perfect foresight, meaning that the prices are known in advance for the entire day. In practice, one could input forecasted prices, but it's a topic on its own. index_ts : Timestamps for each time step in the day. T : Number of time steps in the day. dt : Duration of each time step in hours. price_energy : Energy prices for each time step. price_fcr : FCR prices for each time step. price_afrr_up : aFRR up prices for each time step. price_afrr_down : aFRR down prices for each time step. soc0 : Initial state of charge as a fraction of the battery capacity. """ index_ts: pd.DatetimeIndex T: int dt: float price_energy: np.ndarray[float] price_fcr: np.ndarray[float] price_afrr_up: np.ndarray[float] price_afrr_down: np.ndarray[float] soc0: Optional[float] = 10.0 @classmethod def from_df(cls, day_df: pd.DataFrame, config: dict, soc0: Optional[float] = 10.0) -> "DayInput": """ Infers DayInput from a DataFrame for a single day. day_df : DataFrame containing the data for a single day. The index should be Timestamps. config : Configuration dictionary. soc0 : Initial state of charge as a fraction of the battery capacity """ return cls( index_ts=day_df.index, T=len(day_df), dt=(day_df.index[1] - day_df.index[0]).total_seconds() / 3600.0, price_energy=day_df[config["columns"]["energy"]].to_numpy(), price_fcr=day_df[config["columns"]["fcr"]].to_numpy(), price_afrr_up=day_df[config["columns"]["afrr_up"]].to_numpy(), price_afrr_down=day_df[config["columns"]["afrr_down"]].to_numpy(), soc0=soc0, )