Esempio n. 1
0
 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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
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
Esempio n. 5
0
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]
Esempio n. 6
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.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()
Esempio n. 7
0
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
Esempio n. 8
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.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