def _calc_min_max_from_sim_dict(subdict: Dict, key: str): min_trade_stats_daily = {} max_trade_stats_daily = {} indict = subdict[key] trade_stats_daily = dict( (k.format(TIME_FORMAT), []) for k, v in indict.items()) for time, value in indict.items(): value = [] if value is None else value value = [value] if not isinstance(value, list) else value trade_stats_daily[time.format(TIME_FORMAT)] += value for time_str, value in trade_stats_daily.items(): min_trade_stats_daily[time_str] = limit_float_precision(min(value)) \ if len(value) > 0 else FILL_VALUE max_trade_stats_daily[time_str] = limit_float_precision(max(value)) \ if len(value) > 0 else FILL_VALUE min_trade_stats = dict( (time, min_trade_stats_daily[time.format(TIME_FORMAT)]) for time in indict.keys()) max_trade_stats = dict( (time, max_trade_stats_daily[time.format(TIME_FORMAT)]) for time in indict.keys()) _create_or_append_dict(subdict, f"min_{key}", min_trade_stats) _create_or_append_dict(subdict, f"max_{key}", max_trade_stats)
def check_buy_behaviour_ib(context): from integration_tests.steps.integration_tests import get_simulation_raw_results get_simulation_raw_results(context) name_uuid_map = get_area_name_uuid_mapping(context.area_tree_summary_data) grid = context.simulation.area bus = list(filter(lambda x: x.name == "Infinite Bus", grid.children))[0] for time_slot, core_stats in context.raw_sim_data.items(): for trade in core_stats[name_uuid_map['Grid']]['trades']: if trade['seller'] == "Infinite Bus": assert limit_float_precision(trade['energy_rate']) >= \ core_stats[name_uuid_map['Infinite Bus']]['energy_rate'] else: assert limit_float_precision(trade['energy_rate']) <= \ core_stats[name_uuid_map['Infinite Bus']]['energy_rate'] if trade['buyer'] == "Infinite Bus": # TODO: energy_buy_rate is not part of the raw simulation data, therefore # it is obligatory to retrieve it from the strategy. This needs to change once # we add the energy_buy_rate to the infinite bus result data. assert limit_float_precision(trade['energy_rate']) <= \ list(bus.strategy.energy_buy_rate.values())[0] if trade['buyer'] == "H1 General Load": assert trade['energy'] == \ core_stats[name_uuid_map['H1 General Load']]['load_profile_kWh'] elif trade['seller'] == 'Infinite Bus': assert isclose( trade['energy'], (core_stats[ name_uuid_map['H1 General Load']]['load_profile_kWh'] - core_stats[name_uuid_map['H1 PV']]['pv_production_kWh']))
def _plot_candlestick_time_series_price(cls, device_dict, var_name): time, trade_rate_list, longterm_min_trade_rate, longterm_max_trade_rate = \ cls.prepare_input(device_dict, var_name) plot_time = [] plot_local_min_trade_rate = [] plot_local_max_trade_rate = [] plot_longterm_min_trade_rate = [] plot_longterm_max_trade_rate = [] for ii in range(len(trade_rate_list)): if trade_rate_list[ii] is not None: plot_time.append(time[ii]) plot_local_min_trade_rate.append( limit_float_precision(min(trade_rate_list[ii]))) plot_local_max_trade_rate.append( limit_float_precision(max(trade_rate_list[ii]))) plot_longterm_min_trade_rate.append( limit_float_precision(longterm_min_trade_rate[ii])) plot_longterm_max_trade_rate.append( limit_float_precision(longterm_max_trade_rate[ii])) yaxis = "y3" color = _get_color(var_name, OPAQUE_ALPHA) candle_stick = go.Candlestick( x=plot_time, open=plot_local_min_trade_rate, high=plot_longterm_max_trade_rate, low=plot_longterm_min_trade_rate, close=plot_local_max_trade_rate, yaxis=yaxis, xaxis="x", hoverinfo="none", name=var_name, increasing=dict(line=dict(color=color)), decreasing=dict(line=dict(color=color)), ) hoverinfo_local_max = go.Scatter(x=plot_time, y=plot_local_max_trade_rate, mode="none", name="max", hoverinfo="y+name", xaxis="x", showlegend=False, yaxis=yaxis) hoverinfo_loacl_min = go.Scatter(x=plot_time, y=plot_local_min_trade_rate, mode="none", name="min", hoverinfo="y+name", xaxis="x", showlegend=False, yaxis=yaxis) return [candle_stick, hoverinfo_local_max, hoverinfo_loacl_min] + \ cls._hoverinfo(plot_time, plot_longterm_min_trade_rate, plot_longterm_max_trade_rate, yaxis)
def min_max_avg_median_rate_current_market(self): out_dict = copy(default_trade_stats_dict) trade_volumes = [trade.offer.energy for trade in self.current_market.trades] trade_rates = [trade.offer.price/trade.offer.energy for trade in self.current_market.trades] if len(trade_rates) > 0: out_dict["min_trade_rate"] = limit_float_precision(min(trade_rates)) out_dict["max_trade_rate"] = limit_float_precision(max(trade_rates)) out_dict["avg_trade_rate"] = limit_float_precision(mean(trade_rates)) out_dict["median_trade_rate"] = limit_float_precision(median(trade_rates)) out_dict["total_traded_energy_kWh"] = limit_float_precision(sum(trade_volumes)) return out_dict
def check_state(self, time_slot): """ Sanity check of the state variables. """ charge = limit_float_precision(self.used_storage / self.capacity) max_value = self.capacity - self.min_allowed_soc_ratio * self.capacity assert self.min_allowed_soc_ratio < charge or \ isclose(self.min_allowed_soc_ratio, charge, rel_tol=1e-06) assert 0 <= limit_float_precision(self.offered_sell_kWh[time_slot]) <= max_value assert 0 <= limit_float_precision(self.pledged_sell_kWh[time_slot]) <= max_value assert 0 <= limit_float_precision(self.pledged_buy_kWh[time_slot]) <= max_value assert 0 <= limit_float_precision(self.offered_buy_kWh[time_slot]) <= max_value
def has_battery_reached_max_power(self, energy, time_slot): return limit_float_precision(abs(energy + self.pledged_sell_kWh[time_slot] + self.offered_sell_kWh[time_slot] - self.pledged_buy_kWh[time_slot] - self.offered_buy_kWh[time_slot])) > \ self._battery_energy_per_slot
def average_trade_rate_rate_time(context, time1, time2, trade_rate): trade_rates = get_trade_rates_house1(context) assert all([ limit_float_precision(float(trade_rate) - tt[1]) == 0. for tt in trade_rates if (tt[0].time_slot.hour > int(time1)) and ( tt[0].time_slot.hour < int(time2)) ])
def check_buy_behaviour_ib(context): grid = context.simulation.area bus = list(filter(lambda x: x.name == "Infinite Bus", grid.children))[0] house_1 = list(filter(lambda x: x.name == "House 1", grid.children))[0] pv = list(filter(lambda x: x.name == "H1 PV", house_1.children))[0] load = list(filter(lambda x: x.name == "H1 General Load", house_1.children))[0] for market in grid.past_markets: for trade in market.trades: assert limit_float_precision(trade.offer.price / trade.offer.energy) <= \ bus.strategy.energy_rate[market.time_slot] + house_1.transfer_fee_const or \ "Infinite Bus" is not trade.seller if trade.buyer == load.name: assert trade.offer.energy == load.strategy.avg_power_W / 1000. elif trade.seller == bus.name: assert isclose( trade.offer.energy, load.strategy.avg_power_W / 1000. - pv.strategy.energy_production_forecast_kWh[ market.time_slot]) unmatched, unmatched_redis = \ ExportUnmatchedLoads(context.simulation.area).get_current_market_results( all_past_markets=True) assert get_number_of_unmatched_loads(unmatched) == 0
def _track_energy_sell_type(self, trade): energy = trade.offer.energy while limit_float_precision(energy) > 0: first_in_energy_with_origin = self.state.get_used_storage_share[0] if energy >= first_in_energy_with_origin.value: energy -= first_in_energy_with_origin.value self.state.get_used_storage_share.pop(0) elif energy < first_in_energy_with_origin.value: residual = first_in_energy_with_origin.value - energy self.state._used_storage_share[0] = \ EnergyOrigin(first_in_energy_with_origin.origin, residual) energy = 0
def clamp_energy_to_buy_kWh(self, market_slot_time_list): """ Determines amount of energy that can be bought for each active market and writes it to self.energy_to_buy_dict """ accumulated_bought = 0 accumulated_sought = 0 for time_slot in market_slot_time_list: accumulated_bought += self.pledged_buy_kWh[time_slot] accumulated_sought += self.offered_buy_kWh[time_slot] energy = limit_float_precision( (self.capacity - self.used_storage - accumulated_bought - accumulated_sought) / len(market_slot_time_list)) for time_slot in market_slot_time_list: clamped_energy = limit_float_precision( min(energy, self.max_buy_energy_kWh(time_slot), self._battery_energy_per_slot)) clamped_energy = max(clamped_energy, 0) self.energy_to_buy_dict[time_slot] = clamped_energy
def trade_rates_break_even(context): house1 = next( filter(lambda x: x.name == "House 1", context.simulation.area.children)) storage = next(filter(lambda x: "H1 Storage" in x.name, house1.children)) house2 = next( filter(lambda x: x.name == "House 2", context.simulation.area.children)) load = next(filter(lambda x: "H2 General Load" in x.name, house2.children)) for area in [house1, house2, storage, load]: for market in area.past_markets: for trade in market.trades: assert load.strategy.bid_update.initial_rate[market.time_slot] <= \ limit_float_precision(trade.offer.price / trade.offer.energy) <= \ load.strategy.bid_update.final_rate[market.time_slot]
def trade_rates_break_even(context): house1 = next( filter(lambda x: x.name == "House 1", context.simulation.area.children)) storage = next(filter(lambda x: "H1 Storage" in x.name, house1.children)) house2 = next( filter(lambda x: x.name == "House 2", context.simulation.area.children)) load = next(filter(lambda x: "H2 General Load" in x.name, house2.children)) for area in [house1, house2, storage, load]: for market in area.past_markets: for trade in market.trades: assert ConstSettings.StorageSettings.BREAK_EVEN_SELL <= \ limit_float_precision(trade.offer.price / trade.offer.energy) <= \ ConstSettings.GeneralSettings.DEFAULT_MARKET_MAKER_RATE
def clamp_energy_to_sell_kWh(self, market_slot_time_list): """ Determines available energy to sell for each active market and returns a dict[TIME, FLOAT] """ accumulated_pledged = 0 accumulated_offered = 0 for time_slot in market_slot_time_list: accumulated_pledged += self.pledged_sell_kWh[time_slot] accumulated_offered += self.offered_sell_kWh[time_slot] energy = self.used_storage \ - accumulated_pledged \ - accumulated_offered \ - self.min_allowed_soc * self.capacity storage_dict = {} for time_slot in market_slot_time_list: storage_dict[time_slot] = limit_float_precision( min(energy / len(market_slot_time_list), self.max_offer_energy_kWh(time_slot), self._battery_energy_per_slot)) return storage_dict
def check_state(self, time_slot): """ Sanity check of the state variables. """ charge = limit_float_precision(self.used_storage / self.capacity) max_value = self.capacity - self.min_allowed_soc_ratio * self.capacity assert self.min_allowed_soc_ratio <= charge or \ isclose(self.min_allowed_soc_ratio, charge, rel_tol=1e-06), \ f"Battery charge ({charge}) less than min soc ({self.min_allowed_soc_ratio})" assert limit_float_precision(self.used_storage) <= self.capacity or \ isclose(self.used_storage, self.capacity, rel_tol=1e-06), \ f"Battery used_storage ({self.used_storage}) surpassed the capacity ({self.capacity})" assert 0 <= limit_float_precision( self.offered_sell_kWh[time_slot]) <= max_value assert 0 <= limit_float_precision( self.pledged_sell_kWh[time_slot]) <= max_value assert 0 <= limit_float_precision( self.pledged_buy_kWh[time_slot]) <= max_value assert 0 <= limit_float_precision( self.offered_buy_kWh[time_slot]) <= max_value