From dcef5e70d2f098c1c4661882733abfda6cd4b0cc Mon Sep 17 00:00:00 2001 From: Nick Harder Date: Fri, 22 Nov 2024 12:25:57 +0100 Subject: [PATCH] -update usage of loc and at for consistency across the whole code --- assume/common/base.py | 8 +++--- assume/common/units_operator.py | 2 +- assume/markets/base_market.py | 2 +- .../markets/clearing_algorithms/contracts.py | 21 ++++++++-------- .../learning_unit_operator.py | 10 ++++---- assume/strategies/advanced_orders.py | 10 +++++--- assume/strategies/dmas_powerplant.py | 2 +- assume/strategies/flexable.py | 5 ++-- assume/strategies/flexable_storage.py | 6 ++--- assume/strategies/learning_advanced_orders.py | 4 +-- assume/strategies/learning_strategies.py | 25 +++++++++++-------- assume/strategies/naive_strategies.py | 4 +-- assume/units/powerplant.py | 4 +-- assume/units/steel_plant.py | 2 +- assume/units/storage.py | 18 +++++++------ .../04_reinforcement_learning_example.ipynb | 2 +- 16 files changed, 67 insertions(+), 58 deletions(-) diff --git a/assume/common/base.py b/assume/common/base.py index 3ee60d80..9554e633 100644 --- a/assume/common/base.py +++ b/assume/common/base.py @@ -181,7 +181,7 @@ def calculate_generation_cost( product_type_mc = product_type + "_marginal_costs" # Adjusted code for accessing product data and mapping over the index - product_data = self.outputs[product_type][ + product_data = self.outputs[product_type].loc[ start:end ] # Slicing directly without `.loc` @@ -210,7 +210,7 @@ def execute_current_dispatch( Returns: The volume of the unit within the given time range. """ - return self.outputs["energy"][start:end] + return self.outputs["energy"].loc[start:end] def get_output_before(self, dt: datetime, product_type: str = "energy") -> float: """ @@ -394,7 +394,7 @@ def get_operation_time(self, start: datetime) -> int: return max_time # Check energy output in the defined time window, reversed for most recent state - arr = (self.outputs["energy"][begin:end] > 0)[::-1] + arr = (self.outputs["energy"].loc[begin:end] > 0)[::-1] # Determine initial state (off if the first period shows zero energy output) is_off = not arr[0] @@ -425,7 +425,7 @@ def get_average_operation_times(self, start: datetime) -> tuple[float, float]: op_series = [] before = start - self.index.freq - arr = self.outputs["energy"][self.index[0] : before][::-1] > 0 + arr = self.outputs["energy"].loc[self.index[0] : before][::-1] > 0 if len(arr) < 1: # before start of index diff --git a/assume/common/units_operator.py b/assume/common/units_operator.py index 0d3a219a..e85b421e 100644 --- a/assume/common/units_operator.py +++ b/assume/common/units_operator.py @@ -332,7 +332,7 @@ def get_actual_dispatch( for key in unit.outputs.keys(): for output in valid_outputs: if output in key: - dispatch[key] = unit.outputs[key][start:end] + dispatch[key] = unit.outputs[key].loc[start:end] dispatch["time"] = unit.index.get_date_list(start, end) dispatch["unit"] = unit_id unit_dispatch.append(dispatch) diff --git a/assume/markets/base_market.py b/assume/markets/base_market.py index 6264a53a..1b9d6648 100644 --- a/assume/markets/base_market.py +++ b/assume/markets/base_market.py @@ -536,7 +536,7 @@ def handle_data_request(self, content: DataRequestMessage, meta: MetaDict): data = pd.DataFrame(self.results) data.index = data["time"] - data = data[metric_type][start:end] + data = data[metric_type].loc[start:end] except Exception: logger.exception("Error handling data request") diff --git a/assume/markets/clearing_algorithms/contracts.py b/assume/markets/clearing_algorithms/contracts.py index 2e5ea841..c5f755b5 100644 --- a/assume/markets/clearing_algorithms/contracts.py +++ b/assume/markets/clearing_algorithms/contracts.py @@ -401,7 +401,7 @@ def ppa( tuple[dict, dict]: the buyer order and the seller order as a tuple """ buyer_agent, seller_agent = contract["contractor_id"], contract["agent_addr"] - volume = sum(future_generation_series[start:end]) + volume = sum(future_generation_series.loc[start:end]) buyer: Orderbook = [ { "bid_id": contract["contractor_unit_id"], @@ -461,7 +461,7 @@ def swingcontract( outer_price = contract["price"] * 1.5 # ct/kwh # TODO does not work with multiple markets with differing time scales.. # this only works for whole trading hours (as x MW*1h == x MWh) - demand = -demand_series[start:end] + demand = -demand_series.loc[start:end] normal = demand[minDCQ < demand and demand < maxDCQ] * set_price expensive = ~demand[minDCQ < demand and demand < maxDCQ] * outer_price price = sum(normal) + sum(expensive) @@ -522,13 +522,12 @@ def cfd( # TODO does not work with multiple markets with differing time scales.. # this only works for whole trading hours (as x MW*1h == x MWh) - # price_series = (contract["price"] - market_index[start:end]) * gen_series[seller][ - # start:end - # ] - price_series = (market_index[start:end] - contract["price"]) * gen_series[start:end] + price_series = (market_index.loc[start:end] - contract["price"]) * gen_series.loc[ + start:end + ] price_series = price_series.dropna() price = sum(price_series) - volume = sum(gen_series[start:end]) + volume = sum(gen_series.loc[start:end]) # volume is hard to calculate with differing units? # unit conversion is quite hard regarding the different intervals buyer: Orderbook = [ @@ -586,11 +585,13 @@ def market_premium( buyer_agent, seller_agent = contract["contractor_id"], contract["agent_addr"] # TODO does not work with multiple markets with differing time scales.. # this only works for whole trading hours (as x MW*1h == x MWh) - price_series = (market_index[start:end] - contract["price"]) * gen_series[start:end] + price_series = (market_index.loc[start:end] - contract["price"]) * gen_series.loc[ + start:end + ] price_series = price_series.dropna() # sum only where market price is below contract price price = sum(price_series[price_series < 0]) - volume = sum(gen_series[start:end]) + volume = sum(gen_series.loc[start:end]) # volume is hard to calculate with differing units? # unit conversion is quite hard regarding the different intervals buyer: Orderbook = [ @@ -634,7 +635,7 @@ def feed_in_tariff( buyer_agent, seller_agent = contract["contractor_id"], contract["agent_addr"] # TODO does not work with multiple markets with differing time scales.. # this only works for whole trading hours (as x MW*1h == x MWh) - price_series = contract["price"] * client_series[start:end] + price_series = contract["price"] * client_series.loc[start:end] price = sum(price_series) # volume is hard to calculate with differing units? # unit conversion is quite hard regarding the different intervals diff --git a/assume/reinforcement_learning/learning_unit_operator.py b/assume/reinforcement_learning/learning_unit_operator.py index 0ebe8283..97c71194 100644 --- a/assume/reinforcement_learning/learning_unit_operator.py +++ b/assume/reinforcement_learning/learning_unit_operator.py @@ -140,14 +140,14 @@ def write_learning_to_output(self, orderbook: Orderbook, market_id: str) -> None else: output_dict.update( { - "profit": unit.outputs["profit"].loc[start], - "reward": unit.outputs["reward"].loc[start], - "regret": unit.outputs["regret"].loc[start], + "profit": unit.outputs["profit"].at[start], + "reward": unit.outputs["reward"].at[start], + "regret": unit.outputs["regret"].at[start], } ) - action_tuple = unit.outputs["actions"].loc[start] - noise_tuple = unit.outputs["exploration_noise"].loc[start] + action_tuple = unit.outputs["actions"].at[start] + noise_tuple = unit.outputs["exploration_noise"].at[start] action_dim = action_tuple.numel() for i in range(action_dim): diff --git a/assume/strategies/advanced_orders.py b/assume/strategies/advanced_orders.py index 4022ad77..bf707c69 100644 --- a/assume/strategies/advanced_orders.py +++ b/assume/strategies/advanced_orders.py @@ -129,9 +129,10 @@ def calculate_bids( avg_op_time=avg_op_time, ) - if unit.outputs["heat"][start] > 0: + if unit.outputs["heat"].at[start] > 0: power_loss_ratio = ( - unit.outputs["power_loss"][start] / unit.outputs["heat"][start] + unit.outputs["power_loss"].at[start] + / unit.outputs["heat"].at[start] ) else: power_loss_ratio = 0.0 @@ -320,9 +321,10 @@ def calculate_bids( avg_op_time=avg_op_time, ) - if unit.outputs["heat"][start] > 0: + if unit.outputs["heat"].at[start] > 0: power_loss_ratio = ( - unit.outputs["power_loss"][start] / unit.outputs["heat"][start] + unit.outputs["power_loss"].at[start] + / unit.outputs["heat"].at[start] ) else: power_loss_ratio = 0.0 diff --git a/assume/strategies/dmas_powerplant.py b/assume/strategies/dmas_powerplant.py index 9cad9ea1..0647c5af 100644 --- a/assume/strategies/dmas_powerplant.py +++ b/assume/strategies/dmas_powerplant.py @@ -418,7 +418,7 @@ def optimize( for key in ["power", "emission", "fuel", "start", "profit"]: self.opt_results[step][key] = np.zeros(self.T) self.opt_results[step]["obj"] = 0 - return unit.outputs["generation"][start:] + return unit.outputs["generation"].loc[start:] def calculate_bids( self, diff --git a/assume/strategies/flexable.py b/assume/strategies/flexable.py index b6293742..b2e05a5b 100644 --- a/assume/strategies/flexable.py +++ b/assume/strategies/flexable.py @@ -120,9 +120,10 @@ def calculate_bids( avg_op_time=avg_op_time, ) - if unit.outputs["heat"][start] > 0: + if unit.outputs["heat"].at[start] > 0: power_loss_ratio = ( - unit.outputs["power_loss"][start] / unit.outputs["heat"][start] + unit.outputs["power_loss"].at[start] + / unit.outputs["heat"].at[start] ) else: power_loss_ratio = 0.0 diff --git a/assume/strategies/flexable_storage.py b/assume/strategies/flexable_storage.py index e24ff967..71ef518a 100644 --- a/assume/strategies/flexable_storage.py +++ b/assume/strategies/flexable_storage.py @@ -66,7 +66,7 @@ def calculate_bids( previous_power = unit.get_output_before(start) # save a theoretic SOC to calculate the ramping - theoretic_SOC = unit.outputs["soc"][start] + theoretic_SOC = unit.outputs["soc"].at[start] # calculate min and max power for charging and discharging min_power_charge, max_power_charge = unit.calculate_min_max_charge( @@ -246,7 +246,7 @@ def calculate_bids( _, max_power_discharge = unit.calculate_min_max_discharge(start, end) bids = [] - theoretic_SOC = unit.outputs["soc"][start] + theoretic_SOC = unit.outputs["soc"].at[start] for product, max_dis in zip(product_tuples, max_power_discharge): start = product[0] @@ -372,7 +372,7 @@ def calculate_bids( previous_power = unit.get_output_before(start) - theoretic_SOC = unit.outputs["soc"][start] + theoretic_SOC = unit.outputs["soc"].at[start] _, max_power_charge = unit.calculate_min_max_charge(start, end) diff --git a/assume/strategies/learning_advanced_orders.py b/assume/strategies/learning_advanced_orders.py index 63b01b66..63395782 100644 --- a/assume/strategies/learning_advanced_orders.py +++ b/assume/strategies/learning_advanced_orders.py @@ -214,8 +214,8 @@ def calculate_bids( unit.outputs["rl_actions"].append(actions) # store results in unit outputs as series to be written to the database by the unit operator - unit.outputs["actions"][start] = actions - unit.outputs["exploration_noise"][start] = noise + unit.outputs["actions"].at[start] = actions + unit.outputs["exploration_noise"].at[start] = noise bids = self.remove_empty_bids(bids) diff --git a/assume/strategies/learning_strategies.py b/assume/strategies/learning_strategies.py index 985e4b54..dde11007 100644 --- a/assume/strategies/learning_strategies.py +++ b/assume/strategies/learning_strategies.py @@ -286,8 +286,8 @@ def calculate_bids( unit.outputs["rl_actions"].append(actions) # store results in unit outputs as series to be written to the database by the unit operator - unit.outputs["actions"][start] = actions - unit.outputs["exploration_noise"][start] = noise + unit.outputs["actions"].at[start] = actions + unit.outputs["exploration_noise"].at[start] = noise return bids @@ -524,7 +524,7 @@ def calculate_reward( # depending on way the unit calculates marginal costs we take costs marginal_cost = unit.calculate_marginal_cost( - start, unit.outputs[product_type].loc[start] + start, unit.outputs[product_type].at[start] ) duration = (end - start) / timedelta(hours=1) @@ -551,12 +551,12 @@ def calculate_reward( # consideration of start-up costs, which are evenly divided between the # upward and downward regulation events if ( - unit.outputs[product_type].loc[start] != 0 + unit.outputs[product_type].at[start] != 0 and unit.outputs[product_type].loc[start - unit.index.freq] == 0 ): costs += unit.hot_start_cost / 2 elif ( - unit.outputs[product_type].loc[start] == 0 + unit.outputs[product_type].at[start] == 0 and unit.outputs[product_type].loc[start - unit.index.freq] != 0 ): costs += unit.hot_start_cost / 2 @@ -821,8 +821,8 @@ def calculate_bids( unit.outputs["rl_actions"].append(actions) # store results in unit outputs as series to be written to the database by the unit operator - unit.outputs["actions"][start] = actions - unit.outputs["exploration_noise"][start] = noise + unit.outputs["actions"].at[start] = actions + unit.outputs["exploration_noise"].at[start] = noise return bids @@ -922,7 +922,7 @@ def calculate_reward( # Calculate marginal and starting costs marginal_cost = unit.calculate_marginal_cost( - start_time, unit.outputs[product_type].loc[start_time] + start_time, unit.outputs[product_type].at[start_time] ) marginal_cost += unit.get_starting_costs(int(duration_hours)) @@ -935,12 +935,15 @@ def calculate_reward( order_profit = order["accepted_price"] * accepted_volume * duration_hours order_cost = abs(marginal_cost * accepted_volume * duration_hours) - current_soc = unit.outputs["soc"][start_time] - next_soc = unit.outputs["soc"][next_time] + current_soc = unit.outputs["soc"].at[start_time] + next_soc = unit.outputs["soc"].at[next_time] # Calculate and clip the energy cost for the start time unit.outputs["energy_cost"].at[next_time] = np.clip( - (unit.outputs["energy_cost"][start_time] * current_soc - order_profit) + ( + unit.outputs["energy_cost"].at[start_time] * current_soc + - order_profit + ) / next_soc, 0, self.max_bid_price, diff --git a/assume/strategies/naive_strategies.py b/assume/strategies/naive_strategies.py index 12e731b4..89b02aa0 100644 --- a/assume/strategies/naive_strategies.py +++ b/assume/strategies/naive_strategies.py @@ -159,7 +159,7 @@ def calculate_bids( """ start = product[0] - volume = unit.opt_power_requirement.loc[start] + volume = unit.opt_power_requirement.at[start] marginal_price = unit.calculate_marginal_cost(start, volume) bids.append( { @@ -192,7 +192,7 @@ def calculate_bids( and the volume of the product. Dispatch the order to the market. """ start = product[0] - volume = unit.flex_power_requirement.loc[start] + volume = unit.flex_power_requirement.at[start] marginal_price = unit.calculate_marginal_cost(start, volume) bids.append( { diff --git a/assume/units/powerplant.py b/assume/units/powerplant.py index fd8e59f8..c8127c6f 100644 --- a/assume/units/powerplant.py +++ b/assume/units/powerplant.py @@ -201,7 +201,7 @@ def set_dispatch_plan( self.calculate_cashflow(product_type, orderbook) for start, max_pwr in zip(products_index, max_power): - current_power = self.outputs[product_type][start] + current_power = self.outputs[product_type].at[start] previous_power = self.get_output_before(start) op_time = self.get_operation_time(start) @@ -212,7 +212,7 @@ def set_dispatch_plan( current_power = min(current_power, max_pwr) current_power = max(current_power, self.min_power) - self.outputs[product_type][start] = current_power + self.outputs[product_type].at[start] = current_power self.bidding_strategies[marketconfig.market_id].calculate_reward( unit=self, diff --git a/assume/units/steel_plant.py b/assume/units/steel_plant.py index 0704028b..e88b5dd4 100644 --- a/assume/units/steel_plant.py +++ b/assume/units/steel_plant.py @@ -554,7 +554,7 @@ def set_dispatch_plan( for start in products_index: current_power = self.outputs[product_type][start] - self.outputs[product_type][start] = current_power + self.outputs[product_type].at[start] = current_power self.bidding_strategies[marketconfig.market_id].calculate_reward( unit=self, diff --git a/assume/units/storage.py b/assume/units/storage.py index 48725118..68a8e179 100644 --- a/assume/units/storage.py +++ b/assume/units/storage.py @@ -216,7 +216,7 @@ def execute_current_dispatch(self, start: datetime, end: datetime) -> np.array: -self.outputs["energy"].at[t] * time_delta * self.efficiency_charge ) - self.outputs["soc"].loc[t + self.index.freq] = soc + delta_soc + self.outputs["soc"].at[t + self.index.freq] = soc + delta_soc return self.outputs["energy"].loc[start:end] @@ -248,19 +248,19 @@ def set_dispatch_plan( for start in products_index: delta_soc = 0 - soc = self.outputs["soc"][start] - current_power = self.outputs[product_type][start] + soc = self.outputs["soc"].at[start] + current_power = self.outputs[product_type].at[start] # discharging if current_power > 0: max_soc_discharge = self.calculate_soc_max_discharge(soc) if current_power > max_soc_discharge: - self.outputs[product_type][start] = max_soc_discharge + self.outputs[product_type].at[start] = max_soc_discharge time_delta = self.index.freq / timedelta(hours=1) delta_soc = ( - -self.outputs["energy"][start] + -self.outputs["energy"].at[start] * time_delta / self.efficiency_discharge ) @@ -270,14 +270,16 @@ def set_dispatch_plan( max_soc_charge = self.calculate_soc_max_charge(soc) if current_power < max_soc_charge: - self.outputs[product_type][start] = max_soc_charge + self.outputs[product_type].at[start] = max_soc_charge time_delta = self.index.freq / timedelta(hours=1) delta_soc = ( - -self.outputs["energy"][start] * time_delta * self.efficiency_charge + -self.outputs["energy"].at[start] + * time_delta + * self.efficiency_charge ) - self.outputs["soc"][start + self.index.freq :] = soc + delta_soc + self.outputs["soc"].loc[start + self.index.freq :] = soc + delta_soc self.bidding_strategies[marketconfig.market_id].calculate_reward( unit=self, diff --git a/examples/notebooks/04_reinforcement_learning_example.ipynb b/examples/notebooks/04_reinforcement_learning_example.ipynb index d85f4b33..d352c2f4 100644 --- a/examples/notebooks/04_reinforcement_learning_example.ipynb +++ b/examples/notebooks/04_reinforcement_learning_example.ipynb @@ -2571,7 +2571,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.12.7" } }, "nbformat": 4,