Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSYE-651: Adapt heat pump validator to also allow parcial provision o… #480

Merged
merged 8 commits into from
Oct 26, 2023
3 changes: 2 additions & 1 deletion gsy_framework/constants_limits.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class GeneralSettings:

# Max energy price (market maker rate) in ct / kWh
DEFAULT_MARKET_MAKER_RATE = 30 # 0.3 Eur
DEFAULT_FEED_IN_TARIFF = 0
# interval between offer/bid postings
DEFAULT_UPDATE_INTERVAL = 1 # in minutes
MIN_UPDATE_INTERVAL = 1 # in minutes
Expand Down Expand Up @@ -273,8 +274,8 @@ class GlobalConfig:
RANDOM_SEED = 0
MARKET_MAKER_RATE = ConstSettings.GeneralSettings.DEFAULT_MARKET_MAKER_RATE
POWER_FLOW = False
FEED_IN_TARIFF = 0
CONFIG_TYPE = ConfigurationType.SIMULATION.value
FEED_IN_TARIFF = 20

# Default simulation settings gsy-e side:
start_date = instance((datetime.combine(START_DATE, datetime.min.time())))
Expand Down
25 changes: 15 additions & 10 deletions gsy_framework/validators/heat_pump_validator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from gsy_framework.constants_limits import ConstSettings
from gsy_framework.constants_limits import ConstSettings, GlobalConfig
from gsy_framework.exceptions import GSyDeviceException
from gsy_framework.validators.base_validator import BaseValidator
from gsy_framework.validators.utils import validate_range_limit
Expand Down Expand Up @@ -67,20 +67,23 @@ def _validate_temp(cls, **kwargs):
@classmethod
def validate_rate(cls, **kwargs):
"""Validate energy rate related arguments."""
if not(kwargs.get("initial_buying_rate")
and kwargs.get("final_buying_rate")
and kwargs.get("update_interval")):
Comment on lines -70 to -72
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spyrostz Sorry to drag you into this one more time.
We need this clause in order to allow the user to not provide pricing at all and let the strategy use the default values.
For this case, we do not need to validate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rea-added it in the last commit

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood and thank you for correcting the clause! It now is correct and reflects the condition of all being None, contrary to the former implementation which evaluated if one of them was None.

if (kwargs.get("initial_buying_rate") is None
and kwargs.get("final_buying_rate") is None
and kwargs.get("update_interval") is None):
Comment on lines +71 to +72
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the fix, however I think that this is or, not and. The original clause says: if not all 3 are not-None. Therefore the converted clause should say: if any of the 3 is None

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at the following clause though, I think that this clause is redundant, because we raise an exception if any of the 3 is None. I would recommend to remove this completely actually.

return
if (not kwargs.get("initial_buying_rate")
or not kwargs.get("final_buying_rate")
or not kwargs.get("update_interval")):
if (kwargs.get("initial_buying_rate") is None
or kwargs.get("update_interval") is None):
raise GSyDeviceException(
{"misconfiguration": [
"All pricing parameters of heat pump should be provided:"
"initial_buying_rate, final_buying_rate, update_interval"]})
"initial_buying_rate, update_interval"]})

if kwargs.get("update_interval") == 0:
raise GSyDeviceException(
{"misconfiguration": ["update_interval should not be zero"]})

buying_rate_arg_names = [
"initial_buying_rate", "preferred_buying_rate", "final_buying_rate"]
"initial_buying_rate", "preferred_buying_rate"]
for buying_rate_arg_name in buying_rate_arg_names:
cls._check_range(
name=buying_rate_arg_name, value=kwargs[buying_rate_arg_name],
Expand All @@ -89,7 +92,9 @@ def validate_rate(cls, **kwargs):

initial_buying_rate = kwargs["initial_buying_rate"]
preferred_buying_rate = kwargs["preferred_buying_rate"]
final_buying_rate = kwargs["final_buying_rate"]
final_buying_rate = (
kwargs.get("final_buying_rate") if kwargs.get("final_buying_rate")
else GlobalConfig.MARKET_MAKER_RATE)

validate_range_limit(
initial_buying_rate, preferred_buying_rate, final_buying_rate,
Expand Down
16 changes: 9 additions & 7 deletions tests/test_savings_kpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@


class FakeEndpointBuffer:
"""Fake class for EndpointBuffer"""

grid_uuid = str(uuid4())
house1_uuid = str(uuid4())
house2_uuid = str(uuid4())
Expand Down Expand Up @@ -35,19 +37,19 @@ class FakeEndpointBuffer:
]}
]}
core_stats = {
grid_uuid: {"const_fee_rate": 1, "feed_in_tariff": 20.0, "market_maker_rate": 30.0},
house1_uuid: {"const_fee_rate": 0.5, "feed_in_tariff": 20.0, "market_maker_rate": 30.0}
grid_uuid: {"const_fee_rate": 1, "feed_in_tariff": 0.0, "market_maker_rate": 30.0},
house1_uuid: {"const_fee_rate": 0.5, "feed_in_tariff": 0.0, "market_maker_rate": 30.0}
}
current_market_slot = "2021-09-13T12:45"


@pytest.fixture(name="savings_kpi")
def savings_kpi_fixture():
def fixture_savings_kpi():
return SavingsKPI()


@pytest.fixture(name="kpi")
def kpi_fixture():
def fixture_kpi():
return KPI()


Expand Down Expand Up @@ -106,12 +108,12 @@ def test_market_maker_rate_including_path_grid_fees(kpi, savings_kpi):
endpoint_buffer.current_market_slot)
house1_core_stats = endpoint_buffer.core_stats.get(endpoint_buffer.house1_uuid, {})

expected_mmr_minus_glp = savings_kpi._get_market_maker_rate_including_path_grid_fees(
actual_mmr_minus_glp = savings_kpi._get_market_maker_rate_including_path_grid_fees(
house1_core_stats,
kpi.area_uuid_cum_grid_fee_mapping[endpoint_buffer.house1_uuid])

actual_mmr_minus_glp = GlobalConfig.market_maker_rate + (
expected_mmr_minus_glp = GlobalConfig.market_maker_rate + (
endpoint_buffer.core_stats[endpoint_buffer.grid_uuid]["const_fee_rate"] +
endpoint_buffer.core_stats[endpoint_buffer.house1_uuid]["const_fee_rate"])

assert actual_mmr_minus_glp == expected_mmr_minus_glp
assert expected_mmr_minus_glp == actual_mmr_minus_glp
15 changes: 15 additions & 0 deletions tests/test_validators/test_heatpump_validator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from copy import copy

import pytest

from gsy_framework.exceptions import GSyDeviceException
Expand Down Expand Up @@ -90,6 +92,19 @@ def test_heatpump_validator_checks_price_params(hp_validator_class, hp_params):
with pytest.raises(GSyDeviceException):
hp_validator_class().validate(**{**hp_params, "preferred_buying_rate": 31})

hp_validator_class().validate(**{**hp_params})

wrong_price_params = copy(hp_params)
wrong_price_params["initial_buying_rate"] = 0
wrong_price_params["update_interval"] = 0 # not allowed value
with pytest.raises(GSyDeviceException):
hp_validator_class().validate(**wrong_price_params)

for none_param_key in ["update_interval", "initial_buying_rate"]:
wrong_price_params[none_param_key] = None
with pytest.raises(GSyDeviceException):
hp_validator_class().validate(**wrong_price_params)

@staticmethod
def test_heatpump_validator_checks_profile_params():
with pytest.raises(GSyDeviceException):
Expand Down