def _create_and_activate_strategy_area(self, strategy): self.config = MagicMock() self.config.max_panel_power_W = 160 GlobalConfig.end_date = GlobalConfig.start_date + Duration(days=1) self.area = Area(name="test_area", config=self.config, strategy=strategy) parent = Area(name="parent_area", children=[self.area]) parent.activate() strategy.connected = True market = MagicMock() market.time_slot = GlobalConfig.start_date parent.get_future_market_from_id = lambda _: market self.area.get_future_market_from_id = lambda _: market
def create_areas_markets_for_strategy_fixture(strategy): config = Mock() config.slot_length = duration(minutes=15) config.tick_length = duration(seconds=15) config.ticks_per_slot = 60 config.start_date = GlobalConfig.start_date config.grid_fee_type = ConstSettings.IAASettings.GRID_FEE_TYPE config.end_date = GlobalConfig.start_date + duration(days=1) config.market_count = 1 area = Area(name="forecast_pv", config=config, strategy=strategy, external_connection_available=True) parent = Area(name="parent_area", children=[area], config=config) parent.activate() strategy.connected = True market = MagicMock() market.time_slot = GlobalConfig.start_date return strategy
class TestLiveEvents(unittest.TestCase): def setUp(self): self.config = SimulationConfig(sim_duration=duration(hours=12), slot_length=duration(minutes=15), tick_length=duration(seconds=15), market_count=1, cloud_coverage=0, external_connection_enabled=False) self.live_events = LiveEvents(self.config) self.strategy_load = LoadHoursStrategy( avg_power_W=123, hrs_per_day=3, hrs_of_day=[2, 3, 4, 5], fit_to_limit=False, energy_rate_increase_per_update=2, update_interval=5, initial_buying_rate=11, final_buying_rate=31) self.strategy_pv = PVStrategy(panel_count=3, initial_selling_rate=34, final_selling_rate=12, fit_to_limit=False, update_interval=6, energy_rate_decrease_per_update=4, max_panel_power_W=432) self.strategy_battery = StorageStrategy( initial_soc=11, min_allowed_soc=10, battery_capacity_kWh=6, max_abs_battery_power_kW=123, cap_price_strategy=False, initial_selling_rate=32, final_selling_rate=20, initial_buying_rate=10, final_buying_rate=19, fit_to_limit=False, energy_rate_increase_per_update=5, energy_rate_decrease_per_update=8, update_interval=9) self.area1 = Area("load", None, None, self.strategy_load, SwitchableAppliance(), self.config, None, grid_fee_percentage=0) self.area2 = Area("pv", None, None, self.strategy_pv, PVAppliance(), self.config, None, grid_fee_percentage=0) self.area3 = Area("storage", None, None, self.strategy_battery, SwitchableAppliance(), self.config, None, grid_fee_percentage=0) self.area_house1 = Area("House 1", children=[self.area1, self.area2], config=self.config) self.area_house2 = Area("House 2", children=[self.area3], config=self.config) self.area_grid = Area("Grid", children=[self.area_house1, self.area_house2], config=self.config) def test_create_area_event_is_creating_a_new_area(self): event_dict = { "eventType": "create_area", "parent_uuid": self.area_house1.uuid, "area_representation": { "type": "LoadHours", "name": "new_load", "avg_power_W": 234 } } self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) new_load = [ c for c in self.area_house1.children if c.name == "new_load" ][0] assert type(new_load.strategy) == LoadHoursStrategy assert new_load.strategy.avg_power_W == 234 def test_delete_area_event_is_deleting_an_area(self): event_dict = {"eventType": "delete_area", "area_uuid": self.area1.uuid} self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert len(self.area_house1.children) == 1 assert all(c.uuid != self.area1.uuid for c in self.area_house1.children) def test_update_area_event_is_updating_the_parameters_of_a_load(self): event_dict = { "eventType": "update_area", "area_uuid": self.area1.uuid, "area_representation": { "avg_power_W": 234, "hrs_per_day": 6, "hrs_of_day": [0, 1, 2, 3, 4, 5, 6, 7], "energy_rate_increase_per_update": 3, "update_interval": 9, "initial_buying_rate": 12 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area1.strategy.avg_power_W == 234 assert self.area1.strategy.hrs_per_day[0] == 6 assert self.area1.strategy.hrs_of_day == [0, 1, 2, 3, 4, 5, 6, 7] assert set(self.area1.strategy.bid_update. energy_rate_change_per_update.values()) == {3} assert self.area1.strategy.bid_update.update_interval.minutes == 9 assert set( self.area1.strategy.bid_update.initial_rate.values()) == {12} def test_update_area_event_is_updating_the_parameters_of_a_pv(self): event_dict = { "eventType": "update_area", "area_uuid": self.area2.uuid, "area_representation": { "panel_count": 12, "initial_selling_rate": 68, "final_selling_rate": 42, "fit_to_limit": True, "update_interval": 12, "max_panel_power_W": 999 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area2.strategy.panel_count == 12 assert set( self.area2.strategy.offer_update.initial_rate.values()) == {68} assert set( self.area2.strategy.offer_update.final_rate.values()) == {42} assert self.area2.strategy.offer_update.fit_to_limit is True assert self.area2.strategy.offer_update.update_interval.minutes == 12 assert self.area2.strategy.max_panel_power_W == 999 def test_update_area_event_is_updating_the_parameters_of_a_storage(self): event_dict = { "eventType": "update_area", "area_uuid": self.area3.uuid, "area_representation": { "cap_price_strategy": True, "initial_selling_rate": 123, "final_selling_rate": 120, "initial_buying_rate": 2, "final_buying_rate": 101, "energy_rate_increase_per_update": 4, "energy_rate_decrease_per_update": 13, "update_interval": 14 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area3.strategy.cap_price_strategy is False assert set( self.area3.strategy.offer_update.initial_rate.values()) == {123} assert set( self.area3.strategy.offer_update.final_rate.values()) == {120} assert set(self.area3.strategy.offer_update. energy_rate_change_per_update.values()) == {13} assert set(self.area3.strategy.bid_update.initial_rate.values()) == {2} assert set(self.area3.strategy.bid_update.final_rate.values()) == {101} assert set(self.area3.strategy.bid_update. energy_rate_change_per_update.values()) == {-4} assert self.area3.strategy.offer_update.update_interval.minutes == 14 assert self.area3.strategy.bid_update.update_interval.minutes == 14 def test_update_area_event_is_updating_the_parameters_of_an_area(self): event_dict = { "eventType": "update_area", "area_uuid": self.area_house1.uuid, "area_representation": { 'transfer_fee_const': 12, 'baseline_peak_energy_import_kWh': 123, 'baseline_peak_energy_export_kWh': 456, 'import_capacity_kVA': 987, 'export_capacity_kVA': 765 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area_house1.transfer_fee_const == 12 assert self.area_house1.baseline_peak_energy_import_kWh == 123 assert self.area_house1.baseline_peak_energy_export_kWh == 456 assert self.area_house1.import_capacity_kWh == \ 987 * self.config.slot_length.total_minutes() / 60.0 assert self.area_house1.export_capacity_kWh == \ 765 * self.config.slot_length.total_minutes() / 60.0
class TestAreaClass(unittest.TestCase): def setUp(self): ConstSettings.BalancingSettings.ENABLE_BALANCING_MARKET = True DeviceRegistry.REGISTRY = { "H1 General Load": (33, 35), "H2 General Load": (33, 35), "H1 Storage1": (23, 25), "H1 Storage2": (23, 25), } self.appliance = MagicMock(spec=SimpleAppliance) self.strategy = MagicMock(spec=StorageStrategy) self.config = MagicMock(spec=SimulationConfig) self.config.slot_length = duration(minutes=15) self.config.tick_length = duration(seconds=15) self.config.start_date = today(tz=TIME_ZONE) self.config.sim_duration = duration(days=1) self.area = Area("test_area", None, None, self.strategy, self.appliance, self.config, None, transfer_fee_pct=1) self.area.parent = self.area self.area.children = [self.area] self.area.transfer_fee_pct = 1 self.dispatcher = AreaDispatcher(self.area) self.stats = AreaStats(self.area._markets) def tearDown(self): GlobalConfig.market_count = 1 ConstSettings.GeneralSettings.KEEP_PAST_MARKETS = False def test_respective_area_grid_fee_is_applied(self): self.area = Area(name="Street", children=[Area(name="House")], config=GlobalConfig, transfer_fee_pct=5) self.area.parent = Area(name="GRID") self.area.config.market_count = 1 self.area.activate() assert self.area.next_market.transfer_fee_ratio == 0.05 self.area.next_market.offer(1, 1, "test") assert list(self.area.next_market.offers.values())[0].price == 1.05 def test_markets_are_cycled_according_to_market_count(self): self.area._bc = False for i in range(2, 97): self.config.market_count = i self.area._cycle_markets(False, False) assert len(self.area.all_markets) == i def test_delete_past_markets_instead_of_last(self): self.area = Area(name="Street", children=[Area(name="House")], config=GlobalConfig, transfer_fee_pct=5) self.area.config.market_count = 1 self.area.activate() self.area._bc = False self.area._cycle_markets(False, False, False) assert len(self.area.past_markets) == 0 current_time = today(tz=TIME_ZONE).add(hours=1) self.area._markets.rotate_markets(current_time, self.stats, self.dispatcher) assert len(self.area.past_markets) == 1 self.area._markets.create_future_markets(current_time, True, self.area) current_time = today(tz=TIME_ZONE).add(hours=2) self.area._markets.rotate_markets(current_time, self.stats, self.dispatcher) assert len(self.area.past_markets) == 1 assert list(self.area.past_markets)[-1].time_slot == today( tz=TIME_ZONE).add(hours=1) def test_keep_past_markets(self): ConstSettings.GeneralSettings.KEEP_PAST_MARKETS = True self.area = Area(name="Street", children=[Area(name="House")], config=GlobalConfig, transfer_fee_pct=5) self.area.config.market_count = 1 self.area.activate() self.area._bc = False self.area._cycle_markets(False, False, False) assert len(self.area.past_markets) == 0 current_time = today(tz=TIME_ZONE).add(hours=1) self.area._markets.rotate_markets(current_time, self.stats, self.dispatcher) assert len(self.area.past_markets) == 1 self.area._markets.create_future_markets(current_time, True, self.area) current_time = today(tz=TIME_ZONE).add(hours=2) self.area._markets.rotate_markets(current_time, self.stats, self.dispatcher) assert len(self.area.past_markets) == 2 def test_market_with_most_expensive_offer(self): m1 = MagicMock(spec=Market) o1 = MagicMock(spec=Offer) o1.price = 12 o1.energy = 1 m2 = MagicMock(spec=Market) o2 = MagicMock(spec=Offer) o2.price = 12 o2.energy = 1 m3 = MagicMock(spec=Market) o3 = MagicMock(spec=Offer) o3.price = 12 o3.energy = 1 markets = OrderedDict() td = today(tz=TIME_ZONE) td1 = td + self.config.slot_length m1.time_slot = td1 markets[m1.time_slot] = m1 td2 = td1 + self.config.slot_length m2.time_slot = td2 markets[m2.time_slot] = m2 td3 = td2 + self.config.slot_length m3.time_slot = td3 markets[m3.time_slot] = m3 self.area._markets = MagicMock(spec=AreaMarkets) self.area._markets.markets = markets m1.sorted_offers = [o1, o1] m2.sorted_offers = [o2, o2] m3.sorted_offers = [o3, o3] assert self.area.market_with_most_expensive_offer is m1 o1.price = 19 o2.price = 20 o3.price = 18 assert self.area.market_with_most_expensive_offer is m2 o1.price = 18 o2.price = 19 o3.price = 20 assert self.area.market_with_most_expensive_offer is m3 def test_cycle_markets(self): self.area = Area(name="Street", children=[Area(name="House")], config=GlobalConfig, transfer_fee_pct=1) self.area.parent = Area(name="GRID") self.area.config.market_count = 5 self.area.activate() assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5 self.area.current_tick = 900 self.area.tick(is_root_area=True) assert len(self.area.past_markets) == 1 assert len(self.area.past_balancing_markets) == 1 assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5
class TestLiveEvents(unittest.TestCase): def setUp(self): self.config = SimulationConfig(sim_duration=duration(hours=12), slot_length=duration(minutes=15), tick_length=duration(seconds=15), market_count=1, cloud_coverage=0, external_connection_enabled=False) self.live_events = LiveEvents(self.config) self.strategy_load = LoadHoursStrategy( avg_power_W=123, hrs_per_day=3, hrs_of_day=[2, 3, 4, 5], fit_to_limit=False, energy_rate_increase_per_update=2, update_interval=5, initial_buying_rate=11, final_buying_rate=31) self.strategy_pv = PVStrategy(panel_count=3, initial_selling_rate=34, final_selling_rate=12, fit_to_limit=False, update_interval=6, energy_rate_decrease_per_update=4, max_panel_power_W=432) self.strategy_battery = StorageStrategy( initial_soc=11, min_allowed_soc=10, battery_capacity_kWh=6, max_abs_battery_power_kW=123, cap_price_strategy=False, initial_selling_rate=32, final_selling_rate=20, initial_buying_rate=10, final_buying_rate=19, fit_to_limit=False, energy_rate_increase_per_update=5, energy_rate_decrease_per_update=8, update_interval=9) self.home_meter_profile = Path( d3a_path) / "resources/home_meter_profile.csv" self.strategy_home_meter = HomeMeterStrategy( initial_selling_rate=30, final_selling_rate=5, home_meter_profile=self.home_meter_profile) self.area1 = Area("load", None, None, self.strategy_load, self.config, None, grid_fee_percentage=0) self.area2 = Area("pv", None, None, self.strategy_pv, self.config, None, grid_fee_percentage=0) self.area3 = Area("storage", None, None, self.strategy_battery, self.config, None, grid_fee_percentage=0) self.area_home_meter = Area("home meter", None, None, self.strategy_home_meter, self.config, None, grid_fee_percentage=0) self.area_house1 = Area("House 1", children=[self.area1, self.area2], config=self.config) self.area_house2 = Area("House 2", children=[self.area3, self.area_home_meter], config=self.config) self.area_grid = Area("Grid", children=[self.area_house1, self.area_house2], config=self.config) def tearDown(self) -> None: GlobalConfig.sim_duration = duration(days=GlobalConfig.DURATION_D) def test_create_area_event_is_creating_a_new_area(self): event_dict = { "eventType": "create_area", "parent_uuid": self.area_house1.uuid, "area_representation": { "type": "LoadHours", "name": "new_load", "avg_power_W": 234 } } self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) new_load = [ c for c in self.area_house1.children if c.name == "new_load" ][0] assert isinstance(new_load.strategy, LoadHoursStrategy) assert new_load.strategy.avg_power_W == 234 def test_create_area_event(self): """The CreateAreaEvent tries to create an area when the passed area is valid.""" event_dict = { "eventType": "create_area", "parent_uuid": self.area_house1.uuid, "area_representation": { "type": "LoadHours", "name": "new_load", "avg_power_W": 234 } } event = CreateAreaEvent( parent_uuid=event_dict["parent_uuid"], area_representation=event_dict["area_representation"], config=self.config) assert event.apply(self.area_house1) is True # If we pass the wrong parent UUID, the CreateAreaEvent gracefully fails and returns False event = CreateAreaEvent( parent_uuid="some wrong UUID", area_representation=event_dict["area_representation"], config=self.config) assert event.apply(self.area_house1) is False def test_create_area_event_fails(self): """The CreateAreaEvent is not instantiated when trying to create an invalid area.""" event_dict = { "eventType": "create_area", "parent_uuid": self.area_house1.uuid, "area_representation": { "type": "Wrong Device", "name": "wrong", "some_attribute": 24 } } with self.assertRaises(ValueError): CreateAreaEvent( parent_uuid=event_dict["parent_uuid"], area_representation=event_dict["area_representation"], config=self.config) def test_delete_area_event_is_deleting_an_area(self): event_dict = {"eventType": "delete_area", "area_uuid": self.area1.uuid} self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert len(self.area_house1.children) == 1 assert all(c.uuid != self.area1.uuid for c in self.area_house1.children) def test_update_area_event(self): """The UpdateAreaEvent tries to update an area when the passed area is valid.""" event_dict = { "eventType": "update_area", "area_uuid": self.area1.uuid, "area_representation": { "avg_power_W": 234, "hrs_per_day": 6, "hrs_of_day": [0, 1, 2, 3, 4, 5, 6, 7], "energy_rate_increase_per_update": 3, "update_interval": 9, "initial_buying_rate": 12 } } event = UpdateAreaEvent(area_uuid=self.area1.uuid, area_params=event_dict["area_representation"]) self.area1.area_reconfigure_event = Mock() assert self.area1.area_reconfigure_event.is_called_once() assert event.apply(self.area1) is True # If we pass the wrong parent UUID, the CreateAreaEvent gracefully fails and returns False event = UpdateAreaEvent(area_uuid="Some wrong UUID", area_params=event_dict["area_representation"]) assert event.apply(self.area_house1) is False def test_update_area_event_is_updating_the_parameters_of_a_load(self): event_dict = { "eventType": "update_area", "area_uuid": self.area1.uuid, "area_representation": { "avg_power_W": 234, "hrs_per_day": 6, "hrs_of_day": [0, 1, 2, 3, 4, 5, 6, 7], "energy_rate_increase_per_update": 3, "update_interval": 9, "initial_buying_rate": 12 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area1.strategy.avg_power_W == 234 assert self.area1.strategy.hrs_per_day[0] == 6 assert self.area1.strategy.hrs_of_day == [0, 1, 2, 3, 4, 5, 6, 7] assert set(self.area1.strategy.bid_update. energy_rate_change_per_update.values()) == {-3} assert self.area1.strategy.bid_update.update_interval.minutes == 9 assert set( self.area1.strategy.bid_update.initial_rate.values()) == {12} def test_update_area_event_is_updating_the_parameters_of_a_home_meter( self): """The Home Meter parameters are updated when an update area event is triggered.""" event_dict = { "eventType": "update_area", "area_uuid": self.area_home_meter.uuid, "area_representation": { "initial_selling_rate": 25, "final_selling_rate": 15, "initial_buying_rate": 15, "final_buying_rate": 30, "update_interval": 10 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) strategy = self.area_home_meter.strategy assert set( strategy.offer_update.energy_rate_change_per_update.values()) == { 10 } assert set( strategy.bid_update.energy_rate_change_per_update.values()) == { -15 } assert strategy.bid_update.update_interval.minutes == 10 assert strategy.offer_update.update_interval.minutes == 10 def test_update_area_event_is_updating_the_parameters_of_a_pv(self): event_dict = { "eventType": "update_area", "area_uuid": self.area2.uuid, "area_representation": { "panel_count": 12, "initial_selling_rate": 68, "final_selling_rate": 42, "fit_to_limit": True, "update_interval": 12, "max_panel_power_W": 999 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area2.strategy.panel_count == 12 assert set( self.area2.strategy.offer_update.initial_rate.values()) == {68} assert set( self.area2.strategy.offer_update.final_rate.values()) == {42} assert self.area2.strategy.offer_update.fit_to_limit is True assert self.area2.strategy.offer_update.update_interval.minutes == 12 assert self.area2.strategy.max_panel_power_W == 999 def test_update_area_event_is_updating_the_parameters_of_a_storage(self): event_dict = { "eventType": "update_area", "area_uuid": self.area3.uuid, "area_representation": { "cap_price_strategy": True, "initial_selling_rate": 123, "final_selling_rate": 120, "initial_buying_rate": 2, "final_buying_rate": 101, "energy_rate_increase_per_update": 4, "energy_rate_decrease_per_update": 13, "update_interval": 14 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area3.strategy.cap_price_strategy is False assert set( self.area3.strategy.offer_update.initial_rate.values()) == {123} assert set( self.area3.strategy.offer_update.final_rate.values()) == {120} assert set(self.area3.strategy.offer_update. energy_rate_change_per_update.values()) == {13} assert set(self.area3.strategy.bid_update.initial_rate.values()) == {2} assert set(self.area3.strategy.bid_update.final_rate.values()) == {101} assert self.area3.strategy.bid_update.energy_rate_change_per_update[ self.area_house2.next_market.time_slot] == -4 assert self.area3.strategy.offer_update.update_interval.minutes == 14 assert self.area3.strategy.bid_update.update_interval.minutes == 14 def test_update_area_event_is_updating_the_parameters_of_an_area(self): event_dict = { "eventType": "update_area", "area_uuid": self.area_house1.uuid, "area_representation": { 'grid_fee_constant': 12, 'baseline_peak_energy_import_kWh': 123, 'baseline_peak_energy_export_kWh': 456, 'import_capacity_kVA': 987, 'export_capacity_kVA': 765 } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area_house1.grid_fee_constant == 12 assert self.area_house1.throughput.baseline_peak_energy_import_kWh == 123 assert self.area_house1.throughput.baseline_peak_energy_export_kWh == 456 assert self.area_house1.throughput.import_capacity_kWh == \ 987 * self.config.slot_length.total_minutes() / 60.0 assert self.area_house1.throughput.export_capacity_kWh == \ 765 * self.config.slot_length.total_minutes() / 60.0 def test_update_area_event_can_switch_strategy_from_market_maker_to_infinite_bus( self): self.strategy_mmr = MarketMakerStrategy(energy_rate=30) self.area_mmr = Area("mmr", None, None, self.strategy_mmr, self.config, None, grid_fee_percentage=0) self.area_mmr.parent = self.area_grid self.area_grid.children.append(self.area_mmr) event_dict = { "eventType": "update_area", "area_uuid": self.area_mmr.uuid, "area_representation": { 'type': 'InfiniteBus' } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert type(self.area_mmr.strategy) == InfiniteBusStrategy def test_update_area_event_can_switch_strategy_from_infinite_bus_to_market_maker( self): self.strategy_mmr = InfiniteBusStrategy(energy_sell_rate=30, energy_buy_rate=25) self.area_mmr = Area("mmr", None, None, self.strategy_mmr, self.config, None, grid_fee_percentage=0) self.area_mmr.parent = self.area_grid self.area_grid.children.append(self.area_mmr) event_dict = { "eventType": "update_area", "area_uuid": self.area_mmr.uuid, "area_representation": { 'type': 'MarketMaker' } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert type(self.area_mmr.strategy) == MarketMakerStrategy def test_update_area_event_cannot_switch_non_strategy_area_to_any_strategy( self): self.area_mmr = Area("mmr", None, None, None, self.config, None, grid_fee_percentage=0) self.area_mmr.parent = self.area_grid self.area_grid.children.append(self.area_mmr) event_dict = { "eventType": "update_area", "area_uuid": self.area_mmr.uuid, "area_representation": { 'type': 'MarketMaker' } } self.area_grid.activate() self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) assert self.area_mmr.strategy is None def test_create_area_event_failing_due_to_wrong_parameter_settings_no_exception_raised( self): event_dict = { "eventType": "create_area", "parent_uuid": self.area_house1.uuid, "area_representation": { "type": "LoadHours", "name": "new_load", "avg_power_W": 234, "initial_buying_rate": 20, "final_buying_rate": 10 } } try: self.live_events.add_event(event_dict) self.live_events.handle_all_events(self.area_grid) except Exception: assert False assert self.area_house1.children == [self.area1, self.area2]
class TestAreaClass(unittest.TestCase): def setUp(self): ConstSettings.BalancingSettings.ENABLE_BALANCING_MARKET = True DeviceRegistry.REGISTRY = { "H1 General Load": (33, 35), "H2 General Load": (33, 35), "H1 Storage1": (23, 25), "H1 Storage2": (23, 25), } self.strategy = MagicMock(spec=StorageStrategy) self.config = MagicMock(spec=SimulationConfig) self.config.slot_length = duration(minutes=15) self.config.tick_length = duration(seconds=15) self.config.ticks_per_slot = int(self.config.slot_length.seconds / self.config.tick_length.seconds) self.config.start_date = today(tz=constants.TIME_ZONE) GlobalConfig.sim_duration = duration(days=1) self.config.sim_duration = duration(days=1) self.config.grid_fee_type = 1 self.config.end_date = self.config.start_date + self.config.sim_duration self.area = Area("test_area", None, None, self.strategy, self.config, None, grid_fee_percentage=1) self.area_child = Area("test_area_c", None, None, self.strategy, self.config, None, grid_fee_percentage=1) self.area_child.parent = self.area self.area.children = [self.area_child] self.area.grid_fee_percentage = 1 self.dispatcher = AreaDispatcher(self.area) self.stats = AreaStats(self.area._markets, self.area) def tearDown(self): GlobalConfig.market_count = GlobalConfig.MARKET_COUNT constants.RETAIN_PAST_MARKET_STRATEGIES_STATE = False def test_respective_area_grid_fee_is_applied(self): self.config.grid_fee_type = 2 self.area = Area(name="Street", children=[Area(name="House")], grid_fee_percentage=5, config=self.config) self.area.parent = Area(name="GRID", config=self.config) self.area.config.market_count = 1 self.area.activate() assert self.area.next_market.fee_class.grid_fee_rate == 0.05 self.area.next_market.offer(1, 1, "test", "test") assert list(self.area.next_market.offers.values())[0].price == 1.05 def test_markets_are_cycled_according_to_market_count(self): self.area._bc = None for i in range(2, 97): self.config.market_count = i self.config.grid_fee_type = ConstSettings.IAASettings.GRID_FEE_TYPE self.area.cycle_markets(False, False) assert len(self.area.all_markets) == i def test_delete_past_markets_instead_of_last(self): constants.RETAIN_PAST_MARKET_STRATEGIES_STATE = False self.area = Area(name="Street", children=[Area(name="House")], config=self.config, grid_fee_percentage=5) self.area.config.market_count = 1 self.area.activate() self.area._bc = None self.area.cycle_markets(False, False, False) assert len(self.area.past_markets) == 0 current_time = today(tz=constants.TIME_ZONE).add(hours=1) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 1 self.area._markets.create_future_markets(current_time, True, self.area) current_time = today(tz=constants.TIME_ZONE).add(hours=2) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 1 assert (list(self.area.past_markets)[-1].time_slot == today( tz=constants.TIME_ZONE).add(hours=1)) def test_keep_past_markets(self): constants.RETAIN_PAST_MARKET_STRATEGIES_STATE = True self.area = Area(name="Street", children=[Area(name="House")], config=self.config, grid_fee_percentage=5) self.area.config.market_count = 1 self.area.activate() self.area._bc = None self.area.cycle_markets(False, False, False) assert len(self.area.past_markets) == 0 current_time = today(tz=constants.TIME_ZONE).add(hours=1) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 1 self.area._markets.create_future_markets(current_time, True, self.area) current_time = today(tz=constants.TIME_ZONE).add(hours=2) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 2 def test_market_with_most_expensive_offer(self): m1 = MagicMock(spec=Market) m1.in_sim_duration = True o1 = MagicMock(spec=Offer) o1.price = 12 o1.energy = 1 o1.energy_rate = 12 m2 = MagicMock(spec=Market) m2.in_sim_duration = True o2 = MagicMock(spec=Offer) o2.price = 12 o2.energy = 1 o2.energy_rate = 12 m3 = MagicMock(spec=Market) m3.in_sim_duration = True o3 = MagicMock(spec=Offer) o3.price = 12 o3.energy = 1 o3.energy_rate = 12 markets = OrderedDict() td = today(tz=constants.TIME_ZONE) td1 = td + self.config.slot_length m1.time_slot = td1 markets[m1.time_slot] = m1 td2 = td1 + self.config.slot_length m2.time_slot = td2 markets[m2.time_slot] = m2 td3 = td2 + self.config.slot_length m3.time_slot = td3 markets[m3.time_slot] = m3 self.area._markets = MagicMock(spec=AreaMarkets) self.area._markets.markets = markets m1.sorted_offers = [o1, o1] m2.sorted_offers = [o2, o2] m3.sorted_offers = [o3, o3] assert self.area.market_with_most_expensive_offer is m1 o1.energy_rate = 19 o2.energy_rate = 20 o3.energy_rate = 18 assert self.area.market_with_most_expensive_offer is m2 o1.energy_rate = 18 o2.energy_rate = 19 o3.energy_rate = 20 assert self.area.market_with_most_expensive_offer is m3 def test_cycle_markets(self): GlobalConfig.end_date = GlobalConfig.start_date + GlobalConfig.sim_duration self.area = Area(name="Street", children=[Area(name="House")], config=GlobalConfig, grid_fee_percentage=1) self.area.parent = Area(name="GRID") self.area.config.market_count = 5 self.area.activate() assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5 self.area.current_tick = 900 self.area.cycle_markets() assert len(self.area.past_markets) == 1 assert len(self.area.past_balancing_markets) == 1 assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5 def test_get_restore_state_get_called_on_all_areas(self): strategy = MagicMock(spec=StorageStrategy) bat = Area(name="battery", strategy=strategy) house = Area(name="House", children=[bat]) house.stats.get_state = MagicMock() house.stats.restore_state = MagicMock() area = Area(name="Street", children=[house]) area.stats.get_state = MagicMock() area.stats.restore_state = MagicMock() area.parent = Area(name="GRID") area.get_state() area.stats.get_state.assert_called_once() area.restore_state({"current_tick": 200, "area_stats": None}) area.stats.restore_state.assert_called_once() assert area.current_tick == 200 house.get_state() house.stats.get_state.assert_called_once() house.restore_state({"current_tick": 2432, "area_stats": None}) house.stats.restore_state.assert_called_once() assert house.current_tick == 2432 bat.get_state() strategy.get_state.assert_called_once()
class TestGlobalObjects(unittest.TestCase): def setUp(self): self.config = MagicMock(spec=SimulationConfig) self.config.slot_length = duration(minutes=15) self.config.tick_length = duration(seconds=15) self.config.ticks_per_slot = int(self.config.slot_length.seconds / self.config.tick_length.seconds) self.config.start_date = today(tz=TIME_ZONE) self.config.sim_duration = duration(days=1) self.config.grid_fee_type = 1 self.config.end_date = self.config.start_date + self.config.sim_duration self.config.market_count = 1 self.config.max_panel_power_W = 1000 self.config.external_redis_communicator = \ MagicMock(spec=ExternalConnectionCommunicator(True)) self.storage = Area("Storage", strategy=StorageExternalStrategy(), config=self.config, external_connection_available=True) self.load = Area("Load", strategy=LoadHoursExternalStrategy(avg_power_W=100), config=self.config, external_connection_available=True) self.pv = Area("PV", strategy=PVExternalStrategy(), config=self.config, external_connection_available=True) self.house_area = Area("House", children=[self.storage, self.load, self.pv], config=self.config) self.grid_area = Area("Grid", children=[self.house_area], config=self.config) self.grid_area.activate() def test_global_objects_area_stats_tree_dict_general_structure(self): go = ExternalConnectionGlobalStatistics() go(self.grid_area, self.config.ticks_per_slot) self.grid_area.current_tick += 15 self.house_area.current_tick += 15 self.grid_area.cycle_markets(_trigger_event=True) go.update() expected_area_stats_tree_dict = { self.grid_area.uuid: {'last_market_bill': {'accumulated_trades': {}, 'external_trades': {}}, 'last_market_stats': {'min_trade_rate': None, 'max_trade_rate': None, 'avg_trade_rate': None, 'median_trade_rate': None, 'total_traded_energy_kWh': None}, 'last_market_fee': 0.0, 'current_market_fee': None, 'area_name': 'Grid', 'children': { self.house_area.uuid: { 'last_market_bill': {'accumulated_trades': {}, 'external_trades': {}}, 'last_market_stats': {'min_trade_rate': None, 'max_trade_rate': None, 'avg_trade_rate': None, 'median_trade_rate': None, 'total_traded_energy_kWh': None}, 'last_market_fee': 0.0, 'current_market_fee': None, 'area_name': 'House', 'children': { self.storage.uuid: { 'asset_info': {'energy_to_sell': 0.0, 'energy_active_in_bids': 0, 'energy_to_buy': 1.08, 'energy_active_in_offers': 0, 'free_storage': 1.08, 'used_storage': 0.12, 'energy_traded': 0.0, 'total_cost': 0.0}, 'last_slot_asset_info': {'energy_traded': 0.0, 'total_cost': 0.0}, 'asset_bill': None, 'area_name': 'Storage'}, self.load.uuid: {'asset_info': { 'energy_requirement_kWh': 0.025, 'energy_active_in_bids': 0.0, 'energy_traded': 0.0, 'total_cost': 0.0}, 'last_slot_asset_info': { 'energy_traded': 0.0, 'total_cost': 0.0}, 'asset_bill': None, 'area_name': 'Load'}, self.pv.uuid: {'asset_info': { 'available_energy_kWh': 0.0, 'energy_active_in_offers': 0, 'energy_traded': 0, 'total_cost': 0}, 'last_slot_asset_info': { 'energy_traded': 0, 'total_cost': 0}, 'asset_bill': None, 'area_name': 'PV' }}}}}} assert expected_area_stats_tree_dict == go.area_stats_tree_dict
class TestAreaClass(unittest.TestCase): def setUp(self): ConstSettings.BalancingSettings.ENABLE_BALANCING_MARKET = True DeviceRegistry.REGISTRY = { "H1 General Load": (33, 35), "H2 General Load": (33, 35), "H1 Storage1": (23, 25), "H1 Storage2": (23, 25), } self.appliance = MagicMock(spec=SimpleAppliance) self.strategy = MagicMock(spec=StorageStrategy) self.config = MagicMock(spec=SimulationConfig) self.config.slot_length = duration(minutes=15) self.config.tick_length = duration(seconds=15) self.area = Area("test_area", None, self.strategy, self.appliance, self.config, None) self.area.parent = self.area self.area.children = [self.area] def tearDown(self): pass def test_markets_are_cycled_according_to_market_count(self): self.area._bc = False for i in range(2, 100): self.config.market_count = i self.area._cycle_markets(False, False) assert len(self.area.all_markets) == i def test_market_with_most_expensive_offer(self): m1 = MagicMock(spec=Market) o1 = MagicMock(spec=Offer) o1.price = 12 o1.energy = 1 m2 = MagicMock(spec=Market) o2 = MagicMock(spec=Offer) o2.price = 12 o2.energy = 1 m3 = MagicMock(spec=Market) o3 = MagicMock(spec=Offer) o3.price = 12 o3.energy = 1 markets = OrderedDict() markets[DateTime(2018, 1, 1, 12, 0, 0)] = m1 markets[DateTime(2018, 1, 1, 12, 15, 0)] = m2 markets[DateTime(2018, 1, 1, 12, 30, 0)] = m3 self.area._markets = MagicMock(spec=AreaMarkets) self.area._markets.markets = markets m1.sorted_offers = [o1, o1] m2.sorted_offers = [o2, o2] m3.sorted_offers = [o3, o3] assert self.area.market_with_most_expensive_offer is m1 o1.price = 19 o2.price = 20 o3.price = 18 assert self.area.market_with_most_expensive_offer is m2 o1.price = 18 o2.price = 19 o3.price = 20 assert self.area.market_with_most_expensive_offer is m3 def test_cycle_markets(self): self.area = Area(name="Street", children=[Area(name="House")]) self.area.parent = Area(name="GRID") self.area.config.market_count = 5 self.area.activate() assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5 self.area.current_tick = 900 self.area.tick(is_root_area=True) assert len(self.area.past_markets) == 1 assert len(self.area.past_balancing_markets) == 1 assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5