From 49b89413c931401458dd10d3bdbe343a3aa0239c Mon Sep 17 00:00:00 2001 From: Florian Maurer Date: Mon, 22 Jan 2024 14:02:35 +0100 Subject: [PATCH] add tests too policies --- tests/test_policies.py | 131 +++++++++++++++++++++++++ tests/test_policies_contracts.py | 64 ++++++++++++ tests/test_simple_market_mechanisms.py | 7 +- 3 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 tests/test_policies.py create mode 100644 tests/test_policies_contracts.py diff --git a/tests/test_policies.py b/tests/test_policies.py new file mode 100644 index 000000000..5e6982e28 --- /dev/null +++ b/tests/test_policies.py @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: ASSUME Developers +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import asyncio +from datetime import datetime + +import pandas as pd +from dateutil import rrule as rr +from dateutil.relativedelta import relativedelta as rd +from mango import Agent, RoleAgent, create_container +from mango.util.clock import ExternalClock + +from assume.common.forecasts import NaiveForecast +from assume.common.market_objects import MarketConfig, MarketProduct +from assume.common.units_operator import UnitsOperator +from assume.markets.base_market import MarketRole +from assume.strategies.naive_strategies import NaiveStrategy +from assume.units.demand import Demand + +start = datetime(2020, 1, 1) +end = datetime(2020, 12, 2) + + +class DataRequester(Agent): + def __init__(self, container, suggested_aid): + super().__init__(container, suggested_aid) + self.await_message: asyncio.Future = None + + async def send_data_request( + self, receiver_addr, receiver_id, content: dict, reply_with + ): + self.await_message = asyncio.Future() + await self.send_acl_message( + content, + receiver_addr=receiver_addr, + receiver_id=receiver_id, + acl_metadata={ + "sender_addr": self.addr, + "sender_id": self.aid, + "reply_with": reply_with, + }, + ) + + return await self.await_message + + def handle_message(self, content, meta): + self.await_message.set_result((content, meta)) + + +async def test_request_messages(): + market_name = "Test" + marketconfig = MarketConfig( + name=market_name, + opening_hours=rr.rrule(rr.HOURLY, dtstart=start, until=end), + opening_duration=rd(hours=1), + market_mechanism="pay_as_clear", + market_products=[MarketProduct(rd(hours=1), 1, rd(hours=1))], + ) + clock = ExternalClock(0) + container = await create_container( + addr="world", connection_type="external_connection", clock=clock + ) + units_agent = RoleAgent(container, "test_operator") + units_role = UnitsOperator(available_markets=[marketconfig]) + units_agent.add_role(units_role) + + index = pd.date_range(start=start, end=end + pd.Timedelta(hours=4), freq="1h") + + params_dict = { + "bidding_strategies": {"energy": NaiveStrategy()}, + "technology": "energy", + "unit_operator": "test_operator", + "max_power": 1000, + "min_power": 0, + "forecaster": NaiveForecast(index, demand=1000), + } + unit = Demand("testdemand", index=index, **params_dict) + await units_role.add_unit(unit) + + market_role = MarketRole(marketconfig) + market_agent = RoleAgent(container, "market") + market_agent.add_role(market_role) + + dr = DataRequester(container, "data_requester") + + market_content = { + "context": "data_request", + "market_id": "Test", + "metric": "price", + "start_time": index[0], + "end_time": index[1], + } + unit_content = { + "context": "data_request", + "unit": "testdemand", + "metric": "energy", + "start_time": index[0], + "end_time": index[3], + } + + # market results are empty for now + content, meta = await dr.send_data_request( + "world", "market", market_content, "market_request" + ) + assert meta["in_reply_to"] == "market_request" + assert content["context"] == "data_response" + assert content["data"].empty + + market_role.results.append({"time": index[0], "price": 12}) + market_role.results.append({"time": index[1], "price": 18}) + content, meta = await dr.send_data_request( + "world", "market", market_content, "market_request" + ) + # price is now returned correctly + assert content["data"][index[0]] == 12 + + unit.outputs["energy"][index[1]] = 100 + unit.outputs["energy"][index[3]] = 200 + + content, meta = await dr.send_data_request( + "world", "test_operator", unit_content, "unit_request" + ) + assert meta["in_reply_to"] == "unit_request" + assert content["context"] == "data_response" + assert isinstance(content["data"], pd.Series) + assert content["data"][index[1]] == 100 + assert content["data"][index[2]] == 0 + assert content["data"][index[3]] == 200 + + await container.shutdown() diff --git a/tests/test_policies_contracts.py b/tests/test_policies_contracts.py new file mode 100644 index 000000000..543308f53 --- /dev/null +++ b/tests/test_policies_contracts.py @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: ASSUME Developers +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import asyncio +from datetime import datetime + +import pandas as pd +from dateutil import rrule as rr +from dateutil.relativedelta import relativedelta as rd +from mango import Agent, RoleAgent, create_container +from mango.util.clock import ExternalClock + +from assume.common.forecasts import NaiveForecast +from assume.common.market_objects import MarketConfig, MarketProduct +from assume.common.units_operator import UnitsOperator +from assume.markets.base_market import MarketRole +from assume.markets.clearing_algorithms.contracts import ( + available_contracts, + market_premium, +) +from assume.strategies.extended import is_co2emissionless +from assume.strategies.naive_strategies import NaiveStrategy +from assume.units.demand import Demand + + +def test_contract_functions(): + start = datetime(2019, 1, 1) + end = datetime(2019, 2, 1) + + index = pd.date_range( + start=start, + end=end, + freq="H", + ) + + contract = { + "start_time": start, + "end_time": end, + "only_hours": None, + "price": 10, + "volume": 1000, + "sender_id": "nuclear1", + "eligible_lambda": is_co2emissionless, + "evaluation_frequency": rr.WEEKLY, + "agent_id": ("world", "my_operator"), + "bid_id": "nuclear1_1", + "unit_id": "nuclear1", + "accepted_volume": 1000, + "accepted_price": 4.5, + "contractor_unit_id": "demand1", + "contractor_id": ("world", "brd"), + "market_id": "Support", + } + + market_idx = pd.Series(3, index) + gen_series = pd.Series(1000, index) + + for c_function in available_contracts.values(): + result = c_function(contract, market_idx, gen_series, start, end) + assert result + + result = market_premium(contract, market_idx, gen_series, start, end) + assert result diff --git a/tests/test_simple_market_mechanisms.py b/tests/test_simple_market_mechanisms.py index 3ad038f71..943cb5bd3 100644 --- a/tests/test_simple_market_mechanisms.py +++ b/tests/test_simple_market_mechanisms.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-or-later +import copy from datetime import datetime, timedelta from dateutil import rrule as rr @@ -60,11 +61,9 @@ def test_market(): print(meta) -def test_simple_market_mechanism(): - import copy - +async def test_simple_market_mechanism(): for name, role in clearing_mechanisms.items(): - if "complex" in name: + if "complex" in name or "contract" in name: continue print(name)