def __init__(self, job_id, initial_params, area): self.job_id = job_id self.random_seed = initial_params["seed"] if initial_params[ "seed"] is not None else '' self.status = {} self.eta = duration(seconds=0) self.unmatched_loads = {} self.unmatched_loads_redis = {} self.export_unmatched_loads = ExportUnmatchedLoads(area) self.market_unmatched_loads = MarketUnmatchedLoads() self.cumulative_loads = {} self.price_energy_day = MarketPriceEnergyDay() self.cumulative_grid_trades = {} self.accumulated_trades = {} self.accumulated_trades_redis = {} self.accumulated_balancing_trades = {} self.cumulative_grid_trades_redis = {} self.cumulative_grid_balancing_trades = {} self.tree_summary = {} self.tree_summary_redis = {} self.market_bills = MarketEnergyBills() self.balancing_bills = MarketEnergyBills(is_spot_market=False) self.trade_details = {} self.device_statistics = DeviceStatistics() self.energy_trade_profile = {} self.energy_trade_profile_redis = {} self.file_export_endpoints = FileExportEndpoints()
def test_export_unmatched_loads_reports_cell_tower_areas(self): house1 = Area("House1", [self.area1, self.area2]) ct_strategy = MagicMock(spec=CellTowerLoadHoursStrategy) ct_strategy.state = MagicMock(spec=LoadState) ct_strategy.state.desired_energy_Wh = {} cell_tower = Area("Cell Tower", strategy=ct_strategy) self.grid = Area("Grid", [house1, cell_tower]) for i in range(1, 11): timeslot = today(tz=TIME_ZONE).add(hours=12 + i) self.strategy1.state.desired_energy_Wh[timeslot] = 100 self.strategy2.state.desired_energy_Wh[timeslot] = 100 mock_market = MagicMock(spec=Market) mock_market.time_slot = timeslot mock_market.traded_energy = {"load1": -0.09, "load2": -0.099} house1._markets.past_markets[timeslot] = mock_market mock_market_ct = MagicMock(spec=Market) mock_market_ct.time_slot = timeslot mock_market_ct.traded_energy = {"Cell Tower": -0.4} ct_strategy.state.desired_energy_Wh[timeslot] = 1000 cell_tower._markets.past_markets[timeslot] = mock_market_ct self.grid._markets.past_markets[timeslot] = mock_market unmatched_loads, unmatched_loads_redis = \ ExportUnmatchedLoads(self.grid).get_current_market_results(all_past_markets=True) assert get_number_of_unmatched_loads(unmatched_loads) == 30
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 check_user_rate_profile_dict(context): house = next( filter(lambda x: x.name == "House 1", context.simulation.area.children)) unmatched, unmatched_redis = \ ExportUnmatchedLoads(context.simulation.area).get_current_market_results( all_past_markets=True) number_of_loads = 2 # There are two loads with the same final_buying_rate profile that should report unmatched # energy demand for the first 6 hours of the day: assert get_number_of_unmatched_loads(unmatched) == int( number_of_loads * 6. * 60 / house.config.slot_length.minutes)
def test_export_unmatched_loads_is_reporting_correctly_the_device_types(self): self.area1.display_type = "Area 1 type" self.area3.display_type = "Area 3 type" house1 = Area("House1", [self.area1, self.area3]) self.grid = Area("Grid", [house1]) unmatched_loads, unmatched_loads_redis = \ ExportUnmatchedLoads(self.grid).get_current_market_results(all_past_markets=True) assert get_number_of_unmatched_loads(unmatched_loads) == 0 assert "type" not in unmatched_loads["House1"] assert unmatched_loads["House1"]["load1"]["type"] == "Area 1 type" assert unmatched_loads["House1"]["load3"]["type"] == "Area 3 type" assert unmatched_loads_redis[house1.uuid]["load1"]["type"] == "Area 1 type" assert unmatched_loads_redis[house1.uuid]["load3"]["type"] == "Area 3 type" assert "type" not in unmatched_loads["Grid"] assert unmatched_loads["Grid"]["House1"]["type"] == "Area" assert unmatched_loads_redis[self.grid.uuid]["House1"]["type"] == "Area"
def test_export_unmatched_loads_is_reported_correctly_for_predefined_load_strategy(self): house1 = Area("House1", [self.area1, self.area3]) self.grid = Area("Grid", [house1]) self.grid._markets.past_markets = {} for i in range(1, 11): timeslot = today(tz=TIME_ZONE).add(hours=12+i) mock_market = MagicMock(spec=Market) mock_market.time_slot = timeslot self.strategy1.state.desired_energy_Wh[timeslot] = 100 self.strategy3.state.desired_energy_Wh[timeslot] = 80 mock_market.traded_energy = {"load1": -0.099, "load3": -0.079} house1._markets.past_markets[timeslot] = mock_market self.grid._markets.past_markets[timeslot] = mock_market unmatched_loads, unmatched_loads_redis = \ ExportUnmatchedLoads(self.grid).get_current_market_results(all_past_markets=True) assert get_number_of_unmatched_loads(unmatched_loads) == 20
def test_export_unmatched_loads_is_reported_correctly_for_all_loads_matched(self): house1 = Area("House1", [self.area1, self.area2]) self.grid = Area("Grid", [house1]) self.grid._markets.past_markets = {} for i in range(1, 11): timeslot = today(tz=TIME_ZONE).add(hours=12+i) self.strategy1.state.desired_energy_Wh[timeslot] = 100 self.strategy2.state.desired_energy_Wh[timeslot] = 100 mock_market = MagicMock(spec=Market) mock_market.time_slot = timeslot mock_market.traded_energy = {"load1": -0.101, "load2": -0.101} house1._markets.past_markets[timeslot] = mock_market self.grid._markets.past_markets[timeslot] = mock_market unmatched_loads, unmatched_loads_redis = \ ExportUnmatchedLoads(self.grid).get_current_market_results(all_past_markets=True) assert list(unmatched_loads[self.grid.name].keys()) == ['House1'] assert get_number_of_unmatched_loads(unmatched_loads) == 0
def test_output(context, scenario, sim_duration, slot_length, tick_length): if scenario in ["default_2a", "default_2b", "default_3"]: unmatched_loads, unmatched_loads_redis = \ ExportUnmatchedLoads(context.simulation.area).get_current_market_results( all_past_markets=True) assert get_number_of_unmatched_loads(unmatched_loads) == 0 # (check if number of last slot is the maximal number of slots): no_of_slots = int(int(sim_duration) * 60 / int(slot_length)) assert no_of_slots == context.simulation.area.current_slot if scenario == "default": street1 = list( filter(lambda x: x.name == "Street 1", context.simulation.area.children))[0] house1 = list( filter(lambda x: x.name == "S1 House 1", street1.children))[0] permanent_load = list( filter(lambda x: x.name == "S1 H1 Load", house1.children))[0] energy_profile = [ ki for ki in permanent_load.strategy.state.desired_energy_Wh.values() ] assert all( [permanent_load.strategy.energy == ei for ei in energy_profile])
def no_unmatched_loads(context): unmatched, unmatched_redis = \ ExportUnmatchedLoads(context.simulation.area).get_current_market_results( all_past_markets=True) assert get_number_of_unmatched_loads(unmatched) == 0
class SimulationEndpointBuffer: def __init__(self, job_id, initial_params, area): self.job_id = job_id self.random_seed = initial_params["seed"] if initial_params[ "seed"] is not None else '' self.status = {} self.eta = duration(seconds=0) self.unmatched_loads = {} self.unmatched_loads_redis = {} self.export_unmatched_loads = ExportUnmatchedLoads(area) self.market_unmatched_loads = MarketUnmatchedLoads() self.cumulative_loads = {} self.price_energy_day = MarketPriceEnergyDay() self.cumulative_grid_trades = {} self.accumulated_trades = {} self.accumulated_trades_redis = {} self.accumulated_balancing_trades = {} self.cumulative_grid_trades_redis = {} self.cumulative_grid_balancing_trades = {} self.tree_summary = {} self.tree_summary_redis = {} self.market_bills = MarketEnergyBills() self.balancing_bills = MarketEnergyBills(is_spot_market=False) self.trade_details = {} self.device_statistics = DeviceStatistics() self.energy_trade_profile = {} self.energy_trade_profile_redis = {} self.file_export_endpoints = FileExportEndpoints() def generate_result_report(self): return { "job_id": self.job_id, "random_seed": self.random_seed, "unmatched_loads": self.unmatched_loads_redis, "cumulative_loads": self.cumulative_loads, "price_energy_day": self.price_energy_day.redis_output, "cumulative_grid_trades": self.cumulative_grid_trades_redis, "bills": self.market_bills.bills_redis_results, "tree_summary": self.tree_summary_redis, "status": self.status, "eta_seconds": self.eta.seconds, "device_statistics": self.device_statistics.flat_results_time_str, "energy_trade_profile": self.energy_trade_profile_redis } def generate_json_report(self): return { "job_id": self.job_id, "random_seed": self.random_seed, "unmatched_loads": self.unmatched_loads, "cumulative_loads": self.cumulative_loads, "price_energy_day": self.price_energy_day.csv_output, "cumulative_grid_trades": self.cumulative_grid_trades, "bills": self.market_bills.bills_results, "tree_summary": self.tree_summary, "status": self.status, "device_statistics": self.device_statistics.device_stats_time_str, "energy_trade_profile": self.energy_trade_profile } def _update_unmatched_loads(self, area): if self.export_unmatched_loads.load_count == 0: self.unmatched_loads, self.unmatched_loads_redis =\ self.market_unmatched_loads.write_none_to_unmatched_loads(area, {}, {}) else: current_results, current_results_uuid = \ self.export_unmatched_loads.get_current_market_results( all_past_markets=ConstSettings.GeneralSettings.KEEP_PAST_MARKETS) if ConstSettings.GeneralSettings.KEEP_PAST_MARKETS: self.unmatched_loads = current_results self.unmatched_loads_redis = current_results_uuid else: self.unmatched_loads, self.unmatched_loads_redis = \ self.market_unmatched_loads.update_and_get_unmatched_loads( current_results, current_results_uuid) def _update_cumulative_grid_trades(self, area): market_type = \ "past_markets" if ConstSettings.GeneralSettings.KEEP_PAST_MARKETS else "current_market" balancing_market_type = "past_balancing_markets" \ if ConstSettings.GeneralSettings.KEEP_PAST_MARKETS \ else "current_balancing_market" if ConstSettings.GeneralSettings.KEEP_PAST_MARKETS: self.accumulated_trades = {} self.accumulated_trades_redis = {} self.accumulated_balancing_trades = {} self.accumulated_trades_redis, self.cumulative_grid_trades_redis = \ export_cumulative_grid_trades_redis(area, self.accumulated_trades_redis, market_type) self.accumulated_trades, self.cumulative_grid_trades = \ export_cumulative_grid_trades(area, self.accumulated_trades, market_type, all_devices=True) self.accumulated_balancing_trades, self.cumulative_grid_balancing_trades = \ export_cumulative_grid_trades(area, self.accumulated_balancing_trades, balancing_market_type) def update_stats(self, area, simulation_status, eta): self.status = simulation_status self.eta = eta self._update_unmatched_loads(area) # Should always precede tree-summary update self.price_energy_day.update(area) self.cumulative_loads = { "price-currency": "Euros", "load-unit": "kWh", "cumulative-load-price": export_cumulative_loads(area) } self._update_cumulative_grid_trades(area) self.market_bills.update(area) self.balancing_bills.update(area) self._update_tree_summary(area) self.trade_details = generate_inter_area_trade_details( area, "past_markets") self.device_statistics.update(area) self.file_export_endpoints(area) self.energy_trade_profile = self.file_export_endpoints.traded_energy_profile self.energy_trade_profile_redis = self._round_energy_trade_profile( self.file_export_endpoints.traded_energy_profile_redis) def _update_tree_summary(self, area): price_energy_list = self.price_energy_day.csv_output def calculate_prices(key, functor): if area.name not in price_energy_list: return 0. energy_prices = [ price_energy[key] for price_energy in price_energy_list[ area.name]["price-energy-day"] ] return round(functor(energy_prices), 2) if len(energy_prices) > 0 else 0.0 self.tree_summary[area.slug] = { "min_trade_price": calculate_prices("min_price", min), "max_trade_price": calculate_prices("max_price", max), "avg_trade_price": calculate_prices("av_price", mean), } self.tree_summary_redis[area.uuid] = self.tree_summary[area.slug] for child in area.children: if child.children: self._update_tree_summary(child) @classmethod def _round_energy_trade_profile(cls, profile): for k in profile.keys(): for sold_bought in ['sold_energy', 'bought_energy']: for dev in profile[k][sold_bought].keys(): for target in profile[k][sold_bought][dev].keys(): for timestamp in profile[k][sold_bought][dev][ target].keys(): profile[k][sold_bought][dev][target][ timestamp] = round_floats_for_ui( profile[k][sold_bought][dev][target] [timestamp]) return profile